traitsui-4.1.0/0000755000175100001440000000000011674464651014357 5ustar ischnellusers00000000000000traitsui-4.1.0/TODO.txt0000644000175100001440000000016011674463545015663 0ustar ischnellusers00000000000000* Remove the dependency on AppTools project (caused by imports of pyface.resource in traits/ui/image.py.) traitsui-4.1.0/integrationtests/0000755000175100001440000000000011674463545017766 5ustar ischnellusers00000000000000traitsui-4.1.0/integrationtests/ui/0000755000175100001440000000000011674463546020404 5ustar ischnellusers00000000000000traitsui-4.1.0/integrationtests/ui/table_editor_test.py0000644000175100001440000002036211674463545024454 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # TableEditor test case for Traits UI # # Written by: David C. Morrill # # Date: 07/05/2005 # # (c) Copyright 2005 by Enthought, Inc. # Copyright (c) 2007, Enthought, Inc. # License: BSD Style. # #------------------------------------------------------------------------------- #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from traits.api \ import HasStrictTraits, Str, Int, Regex, List, Instance from traitsui.api \ import View, Group, Item, TableEditor, EnumEditor from traitsui.table_column \ import ObjectColumn from traitsui.table_filter \ import TableFilter, RuleTableFilter, RuleFilterTemplate, \ MenuFilterTemplate, EvalFilterTemplate #------------------------------------------------------------------------------- # 'Person' class: #------------------------------------------------------------------------------- class Person ( HasStrictTraits ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- name = Str age = Int phone = Regex( value = '000-0000', regex = '\d\d\d[-]\d\d\d\d' ) state = Str #--------------------------------------------------------------------------- # Traits view definition: #--------------------------------------------------------------------------- traits_view = View( 'name', 'age', 'phone', 'state', title = 'Create new person', width = 0.18, buttons = [ 'OK', 'Cancel' ] ) #------------------------------------------------------------------------------- # Sample data: #------------------------------------------------------------------------------- people = [ Person( name = 'Dave', age = 39, phone = '555-1212' ), Person( name = 'Mike', age = 28, phone = '555-3526' ), Person( name = 'Joe', age = 34, phone = '555-6943' ), Person( name = 'Tom', age = 22, phone = '555-7586' ), Person( name = 'Dick', age = 63, phone = '555-3895' ), Person( name = 'Harry', age = 46, phone = '555-3285' ), Person( name = 'Sally', age = 43, phone = '555-8797' ), Person( name = 'Fields', age = 31, phone = '555-3547' ) ] #------------------------------------------------------------------------------- # 'AgeFilter' class: #------------------------------------------------------------------------------- class AgeFilter ( TableFilter ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- name = "Age filter" _name = "Age filter" age = Int( 0 ) #--------------------------------------------------------------------------- # Traits view definitions: #--------------------------------------------------------------------------- #filter_view = Group( 'age{Age >=}' ) #--------------------------------------------------------------------------- # Returns whether an object passes the filter or not: #--------------------------------------------------------------------------- def filter ( self, person ): """ Returns whether an object passes the filter or not. """ return (person.age >= self.age) #--------------------------------------------------------------------------- # Returns a user readable description of what the filter does: #--------------------------------------------------------------------------- def description ( self ): """ Returns a user readable description of what the filter does. """ return 'Age >= %d' % self.age def _age_changed(self, old, new): self.name = self.description() print 'AgeFilter _age_changed', self.name #------------------------------------------------------------------------------- # 'NameFilter' class: #------------------------------------------------------------------------------- class NameFilter ( TableFilter ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- mname = Str #--------------------------------------------------------------------------- # Traits view definitions: #--------------------------------------------------------------------------- filter_view = Group( 'mname{Name contains}' ) #--------------------------------------------------------------------------- # Returns whether an object passes the filter or not: #--------------------------------------------------------------------------- def filter ( self, person ): """ Returns whether an object passes the filter or not. """ return (person.name.lower().find( self.mname.lower() ) >= 0) #--------------------------------------------------------------------------- # Returns a user readable description of what the filter does: #--------------------------------------------------------------------------- def description ( self ): """ Returns a user readable description of what the filter does. """ return "Name contains '%s'" % self.mname #------------------------------------------------------------------------------- # Table editor definition: #------------------------------------------------------------------------------- filters = [ AgeFilter( age = 30 ), NameFilter( mname = 'd' ), EvalFilterTemplate, MenuFilterTemplate, RuleFilterTemplate, ] def evaluate_value(v): print 'evaluate_value', v return str(v) #------------------------------------------------------------------------------- # 'TableTest' class: #------------------------------------------------------------------------------- class TableTest ( HasStrictTraits ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- #people = Instance( Person ) people = List( Person ) #--------------------------------------------------------------------------- # Traits view definitions: #--------------------------------------------------------------------------- _valid_states = List(["AL", "AR", "AZ", "AK"]) _state_editor = EnumEditor( name = "_valid_states", evaluate = evaluate_value, object = 'table_editor_object' ) table_editor = TableEditor( columns = [ ObjectColumn( name = 'name' ), ObjectColumn( name = 'age' ), ObjectColumn( name = 'phone' ), ObjectColumn( name = 'state', editor=_state_editor), ], editable = True, deletable = True, sortable = True, sort_model = True, show_lines = True, orientation = 'vertical', show_column_labels = True, edit_view = View( [ 'name', 'age', 'phone', 'state', '|[]' ], resizable = True ), filter = None, filters = filters, row_factory = Person ) traits_view = View( [ Item( 'people', id = 'people', editor = table_editor ), '|[]<>' ], title = 'Table Editor Test', id = 'traitsui.tests.table_editor_test', dock = 'horizontal', width = .4, height = .3, resizable = True, kind = 'live' ) #------------------------------------------------------------------------------- # Run the tests: #------------------------------------------------------------------------------- if __name__ == '__main__': tt = TableTest( people = people ) tt.configure_traits() for p in tt.people: p.print_traits() print '--------------' traitsui-4.1.0/integrationtests/ui/test_ui.py0000644000175100001440000002345011674463545022435 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in /LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # Thanks for using Enthought open source! # # Author: David C. Morrill Date: 11/02/2004 Description: Test case for Traits # User Interface # ------------------------------------------------------------------------------ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx from traits.api \ import Trait, HasTraits, Str, Int, Range, List, Event, File, Directory, \ Bool, Color, Font, Enum from traitsui.api \ import View, Handler, Item, CheckListEditor, ButtonEditor, FileEditor, \ DirectoryEditor, ImageEnumEditor #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- origin_values = [ 'top left', 'top right', 'bottom left', 'bottom right' ] #------------------------------------------------------------------------------- # 'Instance' class: #------------------------------------------------------------------------------- class Instance ( HasTraits ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- integer_text = Int( 1 ) enumeration = Enum( 'one', 'two', 'three', 'four', 'five', 'six', cols = 3 ) float_range = Range( 0.0, 10.0, 10.0 ) int_range = Range( 1, 5 ) boolean = Bool( True ) view = View( 'integer_text', 'enumeration', 'float_range', 'int_range', 'boolean' ) #------------------------------------------------------------------------------- # 'TraitsTest' class #------------------------------------------------------------------------------- class TraitsTest ( HasTraits ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- integer_text = Int( 1 ) enumeration = Enum( 'one', 'two', 'three', 'four', 'five', 'six', cols = 3 ) float_range = Range( 0.0, 10.0, 10.0 ) int_range = Range( 1, 6 ) int_range2 = Range( 1, 50 ) compound = Trait( 1, Range( 1, 6 ), 'one', 'two', 'three', 'four', 'five', 'six' ) boolean = Bool( True ) instance = Trait( Instance() ) color = Color font = Font check_list = List( editor = CheckListEditor( values = [ 'one', 'two', 'three', 'four' ], cols = 4 ) ) list = List( Str, [ 'East of Eden', 'The Grapes of Wrath', 'Of Mice and Men' ] ) button = Event( 0, editor = ButtonEditor( label = 'Click' ) ) file = File directory = Directory image_enum = Trait( editor = ImageEnumEditor( values = origin_values, suffix = '_origin', cols = 4, klass = Instance ), *origin_values ) #--------------------------------------------------------------------------- # View definitions: #--------------------------------------------------------------------------- view = View( ( '|{Enum}', ( '|<[Enumeration]', 'enumeration[Simple]', '_', 'enumeration[Custom]@', '_', 'enumeration[Text]*', '_', 'enumeration[Readonly]~' ), ( '|<[Check List]', 'check_list[Simple]', '_', 'check_list[Custom]@', '_', 'check_list[Text]*', '_', 'check_list[Readonly]~' ) ), ( '|{Range}', ( '|<[Float Range]', 'float_range[Simple]', '_', 'float_range[Custom]@', '_', 'float_range[Text]*', '_', 'float_range[Readonly]~' ), ( '|<[Int Range]', 'int_range[Simple]', '_', 'int_range[Custom]@', '_', 'int_range[Text]*', '_', 'int_range[Readonly]~' ), ( '|<[Int Range 2]', 'int_range2[Simple]', '_', 'int_range2[Custom]@', '_', 'int_range2[Text]*', '_', 'int_range2[Readonly]~' ) ), ( '|{Misc}', ( '|<[Integer Text]', 'integer_text[Simple]', '_', 'integer_text[Custom]@', '_', 'integer_text[Text]*', '_', 'integer_text[Readonly]~' ), ( '|<[Compound]', 'compound[Simple]', '_', 'compound[Custom]@', '_', 'compound[Text]*', '_', 'compound[Readonly]~' ), ( '|<[Boolean]', 'boolean[Simple]', '_', 'boolean[Custom]@', '_', 'boolean[Text]*', '_', 'boolean[Readonly]~' ) ), ( '|{Color/Font}', ( '|<[Color]', 'color[Simple]', '_', 'color[Custom]@', '_', 'color[Text]*', '_', 'color[Readonly]~' ), ( '|<[Font]', 'font[Simple]', '_', 'font[Custom]@', '_', 'font[Text]*', '_', 'font[Readonly]~' ) ), ( '|{List}', ( '|<[List]', 'list[Simple]', '_', 'list[Custom]@', '_', 'list[Text]*', '_', 'list[Readonly]~' ) ), ( '|{Button}', ( '|<[Button]', 'button[Simple]', '_', 'button[Custom]@' ), # 'button[Text]*', # 'button[Readonly]~' ), ( '|<[Image Enum]', 'image_enum[Simple]', '_', 'image_enum[Custom]@', '_', 'image_enum[Text]*', '_', 'image_enum[Readonly]~' ), ( '|<[Instance]', 'instance[Simple]', '_', 'instance[Custom]@', '_', 'instance[Text]*', '_', 'instance[Readonly]~' ), ), ( '|{File}', ( '|<[File]', 'file[Simple]', '_', 'file[Custom]@', '_', 'file[Text]*', '_', 'file[Readonly]~', ), ( '|<[Directory]', 'directory[Simple]', '_', 'directory[Custom]@', '_', 'directory[Text]*', '_', 'directory[Readonly]~' ) ), buttons = [ 'Apply', 'Revert', 'Undo', 'OK' ] ) #------------------------------------------------------------------------------- # 'TraitSheetApp' class: #------------------------------------------------------------------------------- class TraitSheetApp ( wx.App ): #--------------------------------------------------------------------------- # Initialize the object: #--------------------------------------------------------------------------- def __init__ ( self, object ): self.object = object wx.InitAllImageHandlers() wx.App.__init__( self, 1, 'debug.log' ) self.MainLoop() #--------------------------------------------------------------------------- # Handle application initialization: #--------------------------------------------------------------------------- def OnInit ( self ): ui = self.object.edit_traits( kind = 'modal' ) ui = self.object.edit_traits( kind = 'wizard' ) ui = self.object.edit_traits( kind = 'nonmodal' ) ui = self.object.edit_traits( kind = 'live' ) self.SetTopWindow( ui.control ) return True #------------------------------------------------------------------------------- # Main program: #------------------------------------------------------------------------------- if __name__ == '__main__': TraitSheetApp( TraitsTest() ) traitsui-4.1.0/integrationtests/ui/text_editor_invalid.py0000644000175100001440000000143611674463546025022 0ustar ischnellusers00000000000000# Test for TextEditor 'invalid' trait. # # Look for: # # background color should be correctly to the error indicating color # whenever the name is invalid (all whitespace). In particular: # # background color should be set at initialization. from traits.api import Bool, HasTraits, Property, Str from traitsui.api import Item, View from traitsui.api import TextEditor class Person(HasTraits): name = Str invalid = Property(Bool, depends_on='name') def _get_invalid(self): # Name is valid iff it doesn't consist entirely of whitespace. stripped_name = self.name.strip() return stripped_name == '' traits_view = View( Item('name', editor=TextEditor(invalid='invalid')), ) if __name__ == '__main__': Person().configure_traits() traitsui-4.1.0/integrationtests/ui/table_editor_color_test.py0000644000175100001440000000502311674463545025647 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # TableEditor test case for Traits UI # # Written by: David C. Morrill # # Date: 07/05/2005 # # (c) Copyright 2005 by Enthought, Inc. # License: BSD Style. # #------------------------------------------------------------------------------- #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from traits.api \ import HasTraits, List from traitsui.api \ import View, Item, TableEditor from traitsui.wx.color_column \ import ColorColumn from enable.api \ import ColorTrait class Thingy ( HasTraits ): color = ColorTrait( 'black' ) #------------------------------------------------------------------------------- # Sample data: #------------------------------------------------------------------------------- colors = [ Thingy( color = 'red'), Thingy( color = 'orange'), Thingy( color = 'yellow'), Thingy( color = 'green'), Thingy( color = 'blue'), Thingy( color = 'indigo'), Thingy( color = 'violet'), Thingy( color = 'black'), Thingy( color = 'white'), ] class TableTest ( HasTraits ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- colors = List( Thingy ) table_editor = TableEditor( columns = [ ColorColumn( name = 'color' ), ], editable = True, deletable = True, sortable = True, # sort_model = True, show_lines = True, # orientation = 'vertical', show_column_labels = True, # row_factory = Thingy ) traits_view = View( [ Item( 'colors', id = 'colors', editor = table_editor ), '|[]<>' ], title = 'Table Editor Test', id = 'traitsui.tests.table_editor_color_test', dock = 'horizontal', width = .4, height = .3, resizable = True, kind = 'live' ) #------------------------------------------------------------------------------- # Run the tests: #------------------------------------------------------------------------------- if __name__ == '__main__': tt = TableTest( colors = colors ) tt.configure_traits() traitsui-4.1.0/integrationtests/ui/large_range_editor.py0000644000175100001440000000271311674463545024574 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. from traits.api import HasTraits, Float, List from traitsui.api import View, Item, RangeEditor # Tests the Large Range Slider editor. It also tests the case where the # editor is embedded in a list. class TestRangeEditor(HasTraits): x = Float low = Float(123.123) high = Float(1123.123) list = List(Float( editor = RangeEditor(low_name='low', high_name = 'high', # These force the large range # slider to be used. low=100.0, high=10000.123) ) ) view = View(Item(name='x', editor = RangeEditor(low_name='low', high_name = 'high', # These force the large range # slider to be used. low=100.0, high=10000.123) ), Item('list'), resizable=True ) def test(): a = TestRangeEditor() a.x = 500 a.list.append(500) a.edit_traits() # Just close the resulting dialog. assert a.x == 500 assert a.list[0] == 500 test() traitsui-4.1.0/integrationtests/ui/instance_editor_test.py0000644000175100001440000000537211674463545025175 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. from traits.api import * from traitsui.api import * from traitsui.instance_choice import InstanceChoice #------------------------------------------------------------------------------- # 'Person' class: #------------------------------------------------------------------------------- class Person ( HasStrictTraits ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- name = Str age = Int phone = Regex( value = '000-0000', regex = '\d\d\d[-]\d\d\d\d' ) #--------------------------------------------------------------------------- # Traits view definition: #--------------------------------------------------------------------------- traits_view = View( 'name', 'age', 'phone' ) #------------------------------------------------------------------------------- # Sample data: #------------------------------------------------------------------------------- people = [ Person( name = 'Dave', age = 39, phone = '555-1212' ), Person( name = 'Mike', age = 28, phone = '555-3526' ), Person( name = 'Joe', age = 34, phone = '555-6943' ), Person( name = 'Tom', age = 22, phone = '555-7586' ), Person( name = 'Dick', age = 63, phone = '555-3895' ), Person( name = 'Harry', age = 46, phone = '555-3285' ), Person( name = 'Sally', age = 43, phone = '555-8797' ), Person( name = 'Fields', age = 31, phone = '555-3547' ) ] #------------------------------------------------------------------------------- # 'Team' class: #------------------------------------------------------------------------------- class Team ( HasStrictTraits ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- name = Str captain = Instance( Person ) roster = List( Person ) #--------------------------------------------------------------------------- # Traits view definitions: #--------------------------------------------------------------------------- traits_view = View( 'name', '_', Item( 'captain@', editor = InstanceEditor( name = 'roster' ) ), buttons = [ 'Undo', 'OK', 'Cancel' ] ) #------------------------------------------------------------------------------- # Run the test: #------------------------------------------------------------------------------- if __name__ == '__main__': Team( name = 'Vultures', captain = people[0], roster = people ).configure_traits() traitsui-4.1.0/integrationtests/ui/html_editor_test.py0000644000175100001440000000450611674463545024333 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Test case for the HTMLEditor. # # Written by: David C. Morrill # # Date: 09/22/2005 # # (c) Copyright 2005 by Enthought, Inc. # License: BSD Style. # #------------------------------------------------------------------------------- #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from traits.api \ import HasPrivateTraits, Code from traitsui.api \ import View, Group, Item, HTMLEditor #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- sample = """This is a code block: def foo ( bar ): print 'bar:', bar This is an unordered list: - An - unordered - list This is an ordered list: * One * Two * Three Lists can be nested: * One * 1.1 * 1.2 * Two * 2.1 * 2.2 """ #------------------------------------------------------------------------------- # 'TestHTML' class: #------------------------------------------------------------------------------- class TestHTML ( HasPrivateTraits ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Text string to display as HTML: html = Code( sample ) #--------------------------------------------------------------------------- # Traits view definitions: #--------------------------------------------------------------------------- view = View( Group( [ Item( 'html#@', editor = HTMLEditor() ), '|<>' ], [ '{Enter formatted text and/or HTML below:}@', 'html#@', '|<>' ], '|<>', layout = 'split' ), title = 'HTML Editor Test', resizable = True, width = 0.4, height = 0.6 ) #------------------------------------------------------------------------------- # Run the test: #------------------------------------------------------------------------------- if __name__ == '__main__': TestHTML().configure_traits() traitsui-4.1.0/integrationtests/ui/images/0000755000175100001440000000000011674463545021650 5ustar ischnellusers00000000000000traitsui-4.1.0/integrationtests/ui/images/bottom_left_origin.gif0000644000175100001440000000125011674463545026222 0ustar ischnellusers00000000000000GIF89a< ccc]]]KKKqqqVVVzyy~~~bbbƆuu>xRR((GG飣dd[["""쟟ZZZUUhUUooo׻XXaa,<      ɂʿҶ  !"#$$%&'b*Np - ,2j܈F bX$!c&8F y 8q2". 9TL=|@) ,H!=5 !-@B@3B (|G@* ;traitsui-4.1.0/integrationtests/ui/images/bottom_right_origin.gif0000644000175100001440000000125011674463545026405 0ustar ischnellusers00000000000000GIF89a< bbb]]]KKKqqqVVVyyy\\\~~~Ɔuu>xRR((kkkLLhhh !!!wwwWW..Ӿ??||˴SSaa,<       ņ  ׻߲!"#$%L8B>B R|RA nVBA*_Pq@16*Xi &fHP@4Ԩa?m#GMtCNq GmC V!!5@H[ v'* ;traitsui-4.1.0/integrationtests/ui/images/top_right_origin.gif0000644000175100001440000000123411674463545025705 0ustar ischnellusers00000000000000GIF89a<JJkkk ddޝ!!!wwwWW&&Ӿ?? lYYkEEZc$$KKK~~~^^^555oooaaaWWW ===,<   ± "#$%&'('&)&$+,-(./.'0//023456&u@ IN5G 9^ X5 E  nH1cG;>`dH%[D SD7`ƴKY)^, %ʩ0~bCH!@׃ ?@ؕ<@ݔ#Eo;traitsui-4.1.0/integrationtests/ui/images/top_left_origin.gif0000644000175100001440000000125011674463545025520 0ustar ischnellusers00000000000000GIF89a<JJ]]dd[[ """쟟[[[tttaaa]]]UU `MMnnn¸oIIZe&&JIIyyy555~~~WWWfff===Ǔ,<   ȶ !"#$$%&Я'()*+,-,,./%01 234567H5G&bIAtqP++&X#ǓxLA*0Uf̕4_(3Γ=].VZ- %ʁ-,L2 Ä?nH0Z @48AnxÞ^ m'BN ;traitsui-4.1.0/integrationtests/ui/instance_editor_test6.py0000644000175100001440000000636511674463545025266 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. from traits.api import * from traitsui.api import * from traitsui.instance_choice \ import InstanceChoice, InstanceFactoryChoice #------------------------------------------------------------------------------- # 'Person' class: #------------------------------------------------------------------------------- class Person ( HasStrictTraits ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- name = Str age = Int phone = Regex( value = '000-0000', regex = '\d\d\d[-]\d\d\d\d' ) #--------------------------------------------------------------------------- # Traits view definition: #--------------------------------------------------------------------------- traits_view = View( 'name', 'age', 'phone', buttons = [ 'OK', 'Cancel' ] ) #------------------------------------------------------------------------------- # Sample data: #------------------------------------------------------------------------------- people = [ Person( name = 'Dave', age = 39, phone = '555-1212' ), Person( name = 'Mike', age = 28, phone = '555-3526' ), Person( name = 'Joe', age = 34, phone = '555-6943' ), Person( name = 'Tom', age = 22, phone = '555-7586' ), Person( name = 'Dick', age = 63, phone = '555-3895' ), Person( name = 'Harry', age = 46, phone = '555-3285' ), Person( name = 'Sally', age = 43, phone = '555-8797' ), Person( name = 'Fields', age = 31, phone = '555-3547' ) ] #------------------------------------------------------------------------------- # 'Team' class: #------------------------------------------------------------------------------- class Team ( HasStrictTraits ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- name = Str captain = Instance( Person ) roster = List( Person ) #--------------------------------------------------------------------------- # Traits view definitions: #--------------------------------------------------------------------------- traits_view = View( [ 'name', '_', Item( 'captain', editor = InstanceEditor( name = 'roster', label = 'Edit...', values = [ InstanceFactoryChoice( klass = Person, name = 'Non player', view = 'edit_view' ) ] ) ) ], buttons = [ 'OK', 'Cancel' ] ) #------------------------------------------------------------------------------- # Run the test: #------------------------------------------------------------------------------- if __name__ == '__main__': Team( name = 'Vultures', captain = people[0], roster = people ).configure_traits() traitsui-4.1.0/integrationtests/ui/instance_drag_test.py0000644000175100001440000002034111674463545024615 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in /LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 12/04/2004 # Description: Test case for the traits tree editor. #------------------------------------------------------------------------------ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from traits.api \ import HasTraits, Str, Regex, List, Instance from traitsui.api \ import TreeEditor, TreeNode, View, Group, Item, Handler, InstanceEditor from traitsui.instance_choice \ import InstanceDropChoice from traitsui.menu \ import Menu, Action, Separator from traitsui.wx.tree_editor \ import NewAction, CopyAction, CutAction, PasteAction, DeleteAction, \ RenameAction #------------------------------------------------------------------------------- # 'Employee' class: #------------------------------------------------------------------------------- class Employee ( HasTraits ): name = Str( '' ) title = Str phone = Regex( regex = r'\d\d\d-\d\d\d\d' ) view = View( 'title', 'phone' ) def default_title ( self ): self.title = 'Senior Engineer' #------------------------------------------------------------------------------- # 'Department' class: #------------------------------------------------------------------------------- class Department ( HasTraits ): name = Str( '' ) employees = List( Employee ) view = View( [ 'employees', '|<>' ] ) #------------------------------------------------------------------------------- # 'Company' class: #------------------------------------------------------------------------------- class Company ( HasTraits ): name = Str( '' ) departments = List( Department ) employees = List( Employee ) #------------------------------------------------------------------------------- # 'Partner' class: #------------------------------------------------------------------------------- class Partner ( HasTraits ): name = Str( '' ) company = Instance( Company ) eom = Instance( Employee ) dom = Instance( Department ) #------------------------------------------------------------------------------- # Create a hierarchy: #------------------------------------------------------------------------------- jason = Employee( name = 'Jason', title = 'Sr. Engineer', phone = '536-1057' ) mike = Employee( name = 'Mike', title = 'Sr. Engineer', phone = '536-1057' ) dave = Employee( name = 'Dave', title = 'Sr. Engineer', phone = '536-1057' ) martin = Employee( name = 'Martin', title = 'Sr. Engineer', phone = '536-1057' ) duncan = Employee( name = 'Duncan', title = 'Sr. Engineer' ) partner = Partner( name = 'eric', company = Company( name = 'Enthought, Inc.', departments = [ Department( name = 'Business', employees = [ jason, mike ] ), Department( name = 'Scientific', employees = [ dave, martin, duncan ] ) ], employees = [ dave, martin, mike, duncan, jason ] ) ) #------------------------------------------------------------------------------- # Define the tree trait editor: #------------------------------------------------------------------------------- no_view = View() tree_editor = TreeEditor( editable = False, nodes = [ TreeNode( node_for = [ Company ], auto_open = True, children = '', label = 'name', view = View( [ 'name', '|<' ] ) ), TreeNode( node_for = [ Company ], auto_open = True, children = 'departments', label = '=Departments', view = no_view, add = [ Department ] ), TreeNode( node_for = [ Company ], auto_open = True, children = 'employees', label = '=Employees', view = no_view, add = [ Employee ] ), TreeNode( node_for = [ Department ], auto_open = True, children = 'employees', label = 'name', menu = Menu( NewAction, Separator(), DeleteAction, Separator(), RenameAction, Separator(), CopyAction, CutAction, PasteAction ), view = View( [ 'name', '|<' ] ), add = [ Employee ] ), TreeNode( node_for = [ Employee ], auto_open = True, label = 'name', menu = Menu( NewAction, Separator(), Action( name = 'Default title', action = 'object.default_title' ), Action( name = 'Department', action = 'handler.employee_department(editor,object)' ), Separator(), CopyAction, CutAction, PasteAction, Separator(), DeleteAction, Separator(), RenameAction ), view = View( [ 'name', 'title', 'phone', '|<' ] ) ) ] ) #------------------------------------------------------------------------------- # 'TreeHandler' class: #------------------------------------------------------------------------------- class TreeHandler ( Handler ): def employee_department ( self, editor, object ): dept = editor.get_parent( object ) print '%s works in the %s department.' % ( object.name, dept.name ) #------------------------------------------------------------------------------- # Define the View to use: #------------------------------------------------------------------------------- view = View( Group( [ Item( 'company', editor = tree_editor, resizable = True ), '|<>' ], Group( [ '{Employee of the Month}@', Item( 'eom@', editor = InstanceEditor( values = [ InstanceDropChoice( klass = Employee, selectable = True ) ] ), resizable = True ), '|<>' ], [ '{Department of the Month}@', Item( 'dom@', editor = InstanceEditor( values = [ InstanceDropChoice( klass = Department ) ] ), resizable = True ), '|<>' ], show_labels = False, layout = 'split' ), orientation = 'horizontal', show_labels = False, layout = 'split' ), title = 'Company Structure', handler = TreeHandler(), buttons = [ 'OK', 'Cancel' ], resizable = True, width = .5, height = .5 ) #------------------------------------------------------------------------------- # Edit it: #------------------------------------------------------------------------------- if __name__ == '__main__': partner.configure_traits( view = view ) traitsui-4.1.0/integrationtests/ui/code_editor_test.py0000644000175100001440000000545111674463545024301 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Test using a KeyBindings object with the traits Codeditor # # Written by: David C. Morrill # # Date: 09/22/2005 # # (c) Copyright 2005 by Enthought, Inc. # License: BSD Style. # #------------------------------------------------------------------------------- #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from traits.api \ import HasPrivateTraits, Code, Str from traitsui.api \ import View, Item, Handler, CodeEditor from traitsui.key_bindings \ import KeyBinding, KeyBindings #------------------------------------------------------------------------------- # Define a KeyBindings object: #------------------------------------------------------------------------------- key_bindings = KeyBindings( KeyBinding( binding1 = 'Ctrl-s', description = 'Save to a file', method_name = 'save_file' ), KeyBinding( binding1 = 'Ctrl-r', description = 'Run script', method_name = 'run_script' ), KeyBinding( binding1 = 'Ctrl-q', description = 'Edit key bindings', method_name = 'edit_bindings' ) ) #------------------------------------------------------------------------------- # 'CodeHandler' class: #------------------------------------------------------------------------------- class CodeHandler ( Handler ): def save_file ( self, info ): info.object.status = "save file" def run_script ( self, info ): info.object.status = "run script" def edit_bindings ( self, info ): info.object.status = "edit bindings" key_bindings.edit_traits() #------------------------------------------------------------------------------- # 'TestCode' class: #------------------------------------------------------------------------------- class TestCode ( HasPrivateTraits ): code = Code status = Str view = View( [ Item( 'code', style = 'custom', resizable = True, editor = CodeEditor( key_bindings = key_bindings ) ), 'status~', '|<>' ], id = 'traitsui.tests.test_code_editor.TestCode', title = 'Sample Code Editor', width = 0.4, height = 0.4, resizable = True, handler = CodeHandler() ) #------------------------------------------------------------------------------- # Run the test: #------------------------------------------------------------------------------- if __name__ == '__main__': TestCode().configure_traits() traitsui-4.1.0/integrationtests/ui/check_list_editor_test2.py0000644000175100001440000000471111674463545025557 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # CheckListEditor test case for Traits UI # # Written by: David C. Morrill # # Date: 06/29/2005 # # (c) Copyright 2005 by Enthought, Inc. # License: BSD Style. # #------------------------------------------------------------------------------- #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from traits.api \ import Enum, List, Str from traitsui.api \ import Handler, View, Item, CheckListEditor #------------------------------------------------------------------------------- # 'CheckListTest' class: #------------------------------------------------------------------------------- class CheckListTest ( Handler ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- value = List( editor = CheckListEditor( name = 'values', cols = 5 ) ) values = List( Str ) values_text = Str( 'red orange yellow green blue indigo violet' ) #--------------------------------------------------------------------------- # Traits view definitions: #--------------------------------------------------------------------------- simple_view = View( 'value', 'values_text@' ) custom_view = View( 'value@', 'values_text@' ) #--------------------------------------------------------------------------- # 'Initializes the object: #--------------------------------------------------------------------------- def __init__ ( self, **traits ): super( CheckListTest, self ).__init__( **traits ) self._values_text_changed() #--------------------------------------------------------------------------- # Event handlers: #--------------------------------------------------------------------------- def _values_text_changed ( self ): self.values = self.values_text.split() #------------------------------------------------------------------------------- # Run the tests: #------------------------------------------------------------------------------- if __name__ == '__main__': clt = CheckListTest() clt.configure_traits( view = 'simple_view' ) print 'value:', clt.value clt.configure_traits( view = 'custom_view' ) print 'value:', clt.value traitsui-4.1.0/integrationtests/ui/tree_editor_test.py0000644000175100001440000001747011674463546024333 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in /LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 12/04/2004 # Description: Test case for the traits tree editor. #------------------------------------------------------------------------------ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from traits.api import HasTraits, Str, Regex, List, Instance from traitsui.api import TreeEditor, TreeNode, View, Item, VSplit, \ HGroup, Handler from traitsui.menu import Menu, Action, Separator from traitsui.wx.tree_editor import NewAction, CopyAction, \ CutAction, PasteAction, DeleteAction, RenameAction #------------------------------------------------------------------------------- # 'Employee' class: #------------------------------------------------------------------------------- class Employee ( HasTraits ): name = Str( '' ) title = Str phone = Regex( regex = r'\d\d\d-\d\d\d\d' ) def default_title ( self ): self.title = 'Senior Engineer' #------------------------------------------------------------------------------- # 'Department' class: #------------------------------------------------------------------------------- class Department ( HasTraits ): name = Str( '' ) employees = List( Employee ) #------------------------------------------------------------------------------- # 'Company' class: #------------------------------------------------------------------------------- class Company ( HasTraits ): name = Str( '' ) departments = List( Department ) employees = List( Employee ) #------------------------------------------------------------------------------- # 'Partner' class: #------------------------------------------------------------------------------- class Partner ( HasTraits ): name = Str( '' ) company = Instance( Company ) #------------------------------------------------------------------------------- # Create a hierarchy: #------------------------------------------------------------------------------- jason = Employee( name = 'Jason', title = 'Sr. Engineer', phone = '536-1057' ) mike = Employee( name = 'Mike', title = 'Sr. Engineer', phone = '536-1057' ) dave = Employee( name = 'Dave', title = 'Sr. Engineer', phone = '536-1057' ) martin = Employee( name = 'Martin', title = 'Sr. Engineer', phone = '536-1057' ) duncan = Employee( name = 'Duncan', title = 'Sr. Engineer' ) partner = Partner( name = 'eric', company = Company( name = 'Enthought, Inc.', departments = [ Department( name = 'Business', employees = [ jason, mike ] ), Department( name = 'Scientific', employees = [ dave, martin, duncan ] ) ], employees = [ dave, martin, mike, duncan, jason ] ) ) #------------------------------------------------------------------------------- # Define the tree trait editor: #------------------------------------------------------------------------------- no_view = View() tree_editor = TreeEditor( nodes = [ TreeNode( node_for = [ Company ], auto_open = True, children = '', label = 'name', view = View( [ 'name', '|<' ] ) ), TreeNode( node_for = [ Company ], auto_open = True, children = 'departments', label = '=Departments', view = no_view, add = [ Department ] ), TreeNode( node_for = [ Company ], auto_open = True, children = 'employees', label = '=Employees', view = no_view, add = [ Employee ] ), TreeNode( node_for = [ Department ], auto_open = True, children = 'employees', label = 'name', menu = Menu( NewAction, Separator(), DeleteAction, Separator(), RenameAction, Separator(), CopyAction, CutAction, PasteAction ), view = View( [ 'name', '|<' ] ), add = [ Employee ] ), TreeNode( node_for = [ Employee ], auto_open = True, label = 'name', menu = Menu( NewAction, Separator(), Action( name = 'Default title', action = 'object.default_title' ), Action( name = 'Department', action = 'handler.employee_department(editor,object)' ), Separator(), CopyAction, CutAction, PasteAction, Separator(), DeleteAction, Separator(), RenameAction ), view = View( VSplit( HGroup( '3', 'name' ), HGroup( '9', 'title' ), HGroup( 'phone' ), id = 'vsplit' ), id = 'traitsui.test.tree_editor_test.employee', dock = 'vertical' ) ) ] ) #------------------------------------------------------------------------------- # 'TreeHandler' class: #------------------------------------------------------------------------------- class TreeHandler ( Handler ): def employee_department ( self, editor, object ): dept = editor.get_parent( object ) print '%s works in the %s department.' % ( object.name, dept.name ) #------------------------------------------------------------------------------- # Define the View to use: #------------------------------------------------------------------------------- view = View( [ Item( name = 'company', id = 'company', editor = tree_editor, resizable = True ), '|<>' ], title = 'Company Structure', id = 'traitsui.tests.tree_editor_test', dock = 'horizontal', drop_class = HasTraits, handler = TreeHandler(), buttons = [ 'Undo', 'OK', 'Cancel' ], resizable = True, width = .3, height = .3 ) #------------------------------------------------------------------------------- # Edit it: #------------------------------------------------------------------------------- if __name__ == '__main__': partner.configure_traits( view = view ) traitsui-4.1.0/integrationtests/ui/enum_dynamic_test.py0000644000175100001440000000116411674463545024466 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. from traits.api import * from traitsui.api import * def evaluate_value(v): print 'evaluate_value', v return str(v) class Team ( HasTraits ): captain = Str( 'Dick' ) players = List( [ 'Tom', 'Dick', 'Harry', 'Sally' ], Str ) captain_editor = EnumEditor( name = 'players', evaluate=evaluate_value ) view = View( Item( 'captain', editor = captain_editor), '_', 'players@', height=200 ) if __name__ == '__main__': team = Team() team.configure_traits() team.print_traits() traitsui-4.1.0/integrationtests/ui/set_dynamic_test.py0000644000175100001440000000106111674463545024311 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. from traits.api import * from traitsui.api import * class Team ( HasTraits ): batting_order = List( Str ) roster = List( [ 'Tom', 'Dick', 'Harry', 'Sally' ], Str ) view = View( Item( 'batting_order', editor = SetEditor( name = 'roster', ordered = True ) ), '_', 'roster@', height=500, resizable=True) if __name__ == '__main__': Team().configure_traits() traitsui-4.1.0/integrationtests/ui/table_list_editor_test.py0000644000175100001440000000613511674463545025511 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # TableEditor test case for Traits UI which tests editing of lists instead of # editing of objects. # # Written by: David C. Morrill # # Date: 07/06/2005 # # (c) Copyright 2005 by Enthought, Inc. # Copyright (c) 2007, Enthought, Inc. # License: BSD Style. # #------------------------------------------------------------------------------- #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from traits.api \ import HasStrictTraits, List from traitsui.api \ import View, Item, TableEditor from traitsui.table_column \ import ListColumn from traitsui.table_filter \ import TableFilter #------------------------------------------------------------------------------- # Sample data: #------------------------------------------------------------------------------- people = [ [ 'Dave', 39, '555-1212' ], [ 'Mike', 28, '555-3526' ], [ 'Joe', 34, '555-6943' ], [ 'Tom', 22, '555-7586' ], [ 'Dick', 63, '555-3895' ], [ 'Harry', 46, '555-3285' ], [ 'Sally', 43, '555-8797' ], [ 'Fields', 31, '555-3547' ] ] #------------------------------------------------------------------------------- # Table editor definition: #------------------------------------------------------------------------------- table_editor = TableEditor( columns = [ ListColumn( index = 0, label = 'Name' ), ListColumn( index = 1, label = 'Age' ), ListColumn( index = 2, label = 'Phone' ) ], editable = False, show_column_labels = True, # ) #------------------------------------------------------------------------------- # 'TableTest' class: #------------------------------------------------------------------------------- class TableTest ( HasStrictTraits ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- people = List #--------------------------------------------------------------------------- # Traits view definitions: #--------------------------------------------------------------------------- traits_view = View( [ Item( 'people', editor = table_editor, resizable = True ), '|[]<>' ], title = 'Table Editor Test', width = .17, height = .23, buttons = [ 'OK', 'Cancel' ], kind = 'live' ) #------------------------------------------------------------------------------- # Run the tests: #------------------------------------------------------------------------------- if __name__ == '__main__': tt = TableTest( people = people ) tt.configure_traits() for p in tt.people: print p print '--------------' traitsui-4.1.0/integrationtests/ui/instance_editor_test5.py0000644000175100001440000000644711674463545025266 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. from traits.api import * from traitsui.api import * from traitsui.instance_choice \ import InstanceChoice, InstanceFactoryChoice #------------------------------------------------------------------------------- # 'Person' class: #------------------------------------------------------------------------------- class Person ( HasStrictTraits ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- name = Str age = Int phone = Regex( value = '000-0000', regex = '\d\d\d[-]\d\d\d\d' ) #--------------------------------------------------------------------------- # Traits view definition: #--------------------------------------------------------------------------- traits_view = View( 'name~', 'age~', 'phone~' ) edit_view = View( 'name', 'age', 'phone' ) #------------------------------------------------------------------------------- # Sample data: #------------------------------------------------------------------------------- people = [ Person( name = 'Dave', age = 39, phone = '555-1212' ), Person( name = 'Mike', age = 28, phone = '555-3526' ), Person( name = 'Joe', age = 34, phone = '555-6943' ), Person( name = 'Tom', age = 22, phone = '555-7586' ), Person( name = 'Dick', age = 63, phone = '555-3895' ), Person( name = 'Harry', age = 46, phone = '555-3285' ), Person( name = 'Sally', age = 43, phone = '555-8797' ), Person( name = 'Fields', age = 31, phone = '555-3547' ) ] #------------------------------------------------------------------------------- # 'Team' class: #------------------------------------------------------------------------------- class Team ( HasStrictTraits ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- name = Str captain = Instance( Person ) roster = List( Person ) #--------------------------------------------------------------------------- # Traits view definitions: #--------------------------------------------------------------------------- traits_view = View( [ [ 'name', '_', Item( 'captain@', editor = InstanceEditor( name = 'roster', editable = False, values = [ InstanceFactoryChoice( klass = Person, name = 'Non player', view = 'edit_view' ) ] ) ), '_' ], [ 'captain@', '|<>' ] ] ) #------------------------------------------------------------------------------- # Run the test: #------------------------------------------------------------------------------- if __name__ == '__main__': Team( name = 'Vultures', captain = people[0], roster = people ).configure_traits() traitsui-4.1.0/integrationtests/ui/numeric_editor_test.py0000644000175100001440000001135511674463545025031 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # NumericEditor test case for Traits UI # # Written by: David C. Morrill # # Date: 11/29/2005 # # (c) Copyright 2005 by Enthought, Inc. # License: BSD Style. # #------------------------------------------------------------------------------- #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from traits.api \ import HasPrivateTraits, Array, Instance from traitsui.api \ import View, Item, HGroup from traitsui.table_column \ import NumericColumn from traitsui.wx.numeric_editor \ import ToolkitEditorFactory as NumericEditor from blockcanvas.model.api \ import ANumericModel, NumericArrayModel, ReductionModel, SelectionModel, \ NumericItem, ExpressionFilter, IndexFilter from numpy \ import array, sin, arange #------------------------------------------------------------------------------- # Defines the numeric editor: #------------------------------------------------------------------------------- number_editor = NumericEditor( extendable = True, new_columns = 'last', configurable = True, columns = [ NumericColumn( name = 'model_indices', label = 'i' ), NumericColumn( name = 'x', label = 'x', format = '%.2f' ), NumericColumn( name = 'sinx', label = 'sin(x)', format = '%.3f' ), NumericColumn( name = 'xsinx', label = 'x*sin(x)', format = '%.3f' ) ], other_columns = [], choose_selection_filter = True, edit_selection_filter = True, edit_selection_colors = False, selection_filter = None, selection_filter_name = '', user_selection_filter = IndexFilter(), choose_reduction_filter = True, edit_reduction_filter = True, reduction_filter = None, reduction_filter_name = '', deletable = True, sortable = True, sort_model = False, editable = True, auto_size = False, show_lines = True, menu = None, show_column_labels = True, #line_color = 0xC4C0A9, #cell_font = Font, #cell_color = Color( 'black' ) #cell_bg_color = Color( 'white' ) #cell_read_only_bg_color = Color( 0xF8F7F1 ) #label_font = Font #label_color = Color( 'black' ) #label_bg_color = Color( 0xD7D2BF ) #selection_bg_color = Color( 0x0D22DF ) #selection_color = Color( 'white' ) #column_label_height = Int( 25 ) #row_label_width = Int( 82 ) #on_select = Callable #on_dclick = Callable ) #------------------------------------------------------------------------------- # 'BunchANumbersApp' class: #------------------------------------------------------------------------------- class BunchANumbersApp ( HasPrivateTraits ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- model = Instance( ANumericModel ) #--------------------------------------------------------------------------- # Traits view definitions: #--------------------------------------------------------------------------- view = View( HGroup( Item( 'model', editor = number_editor, id = 'model' ), # Item( 'model', editor = number_editor ), show_labels = False ), title = 'Numeric Editor Test', id = 'traitsui.tests.numeric_editor_test', width = 0.28, height = 0.6, resizable = True ) #------------------------------------------------------------------------------- # Run the test: #------------------------------------------------------------------------------- if __name__ == '__main__': x = arange( 0.0, 20.005, 0.1 ) model = NumericArrayModel( x = x, sinx = sin( x ), xsinx = x * sin( x ) ) BunchANumbersApp( model = model ).configure_traits() traitsui-4.1.0/integrationtests/ui/table_editor_test2.py0000644000175100001440000001003211674463545024527 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # TableEditor test case for Traits UI # # Written by: David C. Morrill # # Date: 07/05/2005 # # (c) Copyright 2005 by Enthought, Inc. # License: BSD Style. # #------------------------------------------------------------------------------- #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from traits.api \ import HasStrictTraits, Str, Int, Regex, List from traitsui.api \ import View #------------------------------------------------------------------------------- # 'Person' class: #------------------------------------------------------------------------------- class Person ( HasStrictTraits ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- name = Str age = Int phone = Regex( value = '000-0000', regex = '\d\d\d[-]\d\d\d\d' ) #--------------------------------------------------------------------------- # Traits view definition: #--------------------------------------------------------------------------- traits_view = View( 'name', 'age', 'phone', title = 'Create new person', width = 0.18, buttons = [ 'OK', 'Cancel' ] ) #------------------------------------------------------------------------------- # 'WorkingPerson' class #------------------------------------------------------------------------------- class WorkingPerson ( Person ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- job = Str #--------------------------------------------------------------------------- # Traits view definition: #--------------------------------------------------------------------------- traits_view = View( 'name', 'age', 'phone', 'job', title = 'Create new working person.........', width = 0.18, buttons = [ 'OK', 'Cancel' ] ) #------------------------------------------------------------------------------- # Sample data: #------------------------------------------------------------------------------- people = [ Person( name = 'Dave', age = 39, phone = '555-1212' ), Person( name = 'Mike', age = 28, phone = '555-3526' ), WorkingPerson( name = 'Joe', age = 34, phone = '555-6943', job = 'Fireman' ), Person( name = 'Tom', age = 22, phone = '555-7586' ), Person( name = 'Dick', age = 63, phone = '555-3895' ), Person( name = 'Harry', age = 46, phone = '555-3285' ), WorkingPerson( name = 'Sally', age = 43, phone = '555-8797', job = 'Soldier' ), Person( name = 'Fields', age = 31, phone = '555-3547' ) ] #------------------------------------------------------------------------------- # 'TableTest' class: #------------------------------------------------------------------------------- class TableTest ( HasStrictTraits ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- people = List( Person ) #--------------------------------------------------------------------------- # Traits view definitions: #--------------------------------------------------------------------------- traits_view = View( [ 'people#', '|<>' ], resizable = True ) #------------------------------------------------------------------------------- # Run the tests: #------------------------------------------------------------------------------- if __name__ == '__main__': tt = TableTest( people = people ) tt.configure_traits() for p in tt.people: p.print_traits() print '--------------' traitsui-4.1.0/integrationtests/ui/instance_editor_test2.py0000644000175100001440000000574711674463545025265 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. from traits.api import * from traitsui.api import * from traitsui.instance_choice \ import InstanceChoice, InstanceFactoryChoice #------------------------------------------------------------------------------- # 'Person' class: #------------------------------------------------------------------------------- class Person ( HasStrictTraits ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- name = Str age = Int phone = Regex( value = '000-0000', regex = '\d\d\d[-]\d\d\d\d' ) #--------------------------------------------------------------------------- # Traits view definition: #--------------------------------------------------------------------------- traits_view = View( 'name', 'age', 'phone' ) #------------------------------------------------------------------------------- # Sample data: #------------------------------------------------------------------------------- people = [ Person( name = 'Dave', age = 39, phone = '555-1212' ), Person( name = 'Mike', age = 28, phone = '555-3526' ), Person( name = 'Joe', age = 34, phone = '555-6943' ), Person( name = 'Tom', age = 22, phone = '555-7586' ), Person( name = 'Dick', age = 63, phone = '555-3895' ), Person( name = 'Harry', age = 46, phone = '555-3285' ), Person( name = 'Sally', age = 43, phone = '555-8797' ), Person( name = 'Fields', age = 31, phone = '555-3547' ) ] #------------------------------------------------------------------------------- # 'Team' class: #------------------------------------------------------------------------------- class Team ( HasStrictTraits ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- name = Str captain = Instance( Person ) roster = List( Person ) #--------------------------------------------------------------------------- # Traits view definitions: #--------------------------------------------------------------------------- traits_view = View( 'name', '_', Item( 'captain@', editor = InstanceEditor( name = 'roster', values = [ InstanceFactoryChoice( klass = Person, name = 'Non player' ) ] ) ) ) #------------------------------------------------------------------------------- # Run the test: #------------------------------------------------------------------------------- if __name__ == '__main__': Team( name = 'Vultures', captain = people[0], roster = people ).configure_traits() traitsui-4.1.0/integrationtests/ui/instance_editor_test4.py0000644000175100001440000000546011674463545025257 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. from traits.api import * from traitsui.api import * from traitsui.instance_choice import InstanceChoice #------------------------------------------------------------------------------- # 'Person' class: #------------------------------------------------------------------------------- class Person ( HasStrictTraits ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- name = Str age = Int phone = Regex( value = '000-0000', regex = '\d\d\d[-]\d\d\d\d' ) #--------------------------------------------------------------------------- # Traits view definition: #--------------------------------------------------------------------------- traits_view = View( 'name', 'age', 'phone' ) #------------------------------------------------------------------------------- # Sample data: #------------------------------------------------------------------------------- people = [ Person( name = 'Dave', age = 39, phone = '555-1212' ), Person( name = 'Mike', age = 28, phone = '555-3526' ), Person( name = 'Joe', age = 34, phone = '555-6943' ), Person( name = 'Tom', age = 22, phone = '555-7586' ), Person( name = 'Dick', age = 63, phone = '555-3895' ), Person( name = 'Harry', age = 46, phone = '555-3285' ), Person( name = 'Sally', age = 43, phone = '555-8797' ), Person( name = 'Fields', age = 31, phone = '555-3547' ) ] #------------------------------------------------------------------------------- # 'Team' class: #------------------------------------------------------------------------------- class Team ( HasStrictTraits ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- name = Str captain = Instance( Person ) roster = List( Person ) #--------------------------------------------------------------------------- # Traits view definitions: #--------------------------------------------------------------------------- traits_view = View( 'name', '_', Item( 'captain@', editor = InstanceEditor( name = 'roster', editable = False ) ), '_', 'roster' ) #------------------------------------------------------------------------------- # Run the test: #------------------------------------------------------------------------------- if __name__ == '__main__': Team( name = 'Vultures', captain = people[0], roster = people ).configure_traits() traitsui-4.1.0/integrationtests/ui/test_ui3.py0000644000175100001440000000570211674463545022520 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in /LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 11/02/2004 # Description: Test case for Traits User Interface #------------------------------------------------------------------------------ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx from traits.api import Trait, HasTraits, Str, Int from traitsui.api import View, Group from traits.api import Color #------------------------------------------------------------------------------- # Model/View classes: #------------------------------------------------------------------------------- class Employer ( HasTraits ): company = Str boss = Str view = View( 'company', 'boss' ) class Person ( HasTraits ): name = Str( 'David Morrill' ) age = Int( 39 ) view = View( 'name', '', 'age', kind = 'modal' ) class ExtraPerson ( Person ): sex = Trait( 'Male', 'Female' ) eye_color = Color extra = Group( 'sex', 'eye_color' ) class LocatedPerson ( Person ): street = Str city = Str state = Str zip = Int( 78663 ) extra = Group( 'street', 'city', 'state', 'zip' ) class EmployedPerson ( LocatedPerson ): employer = Trait( Employer( company = 'Enthought, Inc.', boss = 'eric' ) ) extra = Group( 'employer', '' ) #------------------------------------------------------------------------------- # 'TraitSheetApp' class: #------------------------------------------------------------------------------- class TraitSheetApp ( wx.App ): #--------------------------------------------------------------------------- # Initialize the object: #--------------------------------------------------------------------------- def __init__ ( self ): wx.InitAllImageHandlers() wx.App.__init__( self, 1, 'debug.log' ) self.MainLoop() #--------------------------------------------------------------------------- # Handle application initialization: #--------------------------------------------------------------------------- def OnInit ( self ): Person().edit_traits() ExtraPerson().edit_traits() LocatedPerson().edit_traits() EmployedPerson().edit_traits() return True #------------------------------------------------------------------------------- # Main program: #------------------------------------------------------------------------------- TraitSheetApp() traitsui-4.1.0/integrationtests/ui/buttons_test.py0000644000175100001440000000663211674463545023521 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. from traits.api \ import * from traitsui.api \ import * from traitsui.menu \ import * #------------------------------------------------------------------------------- # 'Person' class: #------------------------------------------------------------------------------- class Person ( Handler ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- name = Str age = Int phone = Regex( value = '000-0000', regex = '\d\d\d[-]\d\d\d\d' ) notes = Str #--------------------------------------------------------------------------- # Handles the 'Annoy' button being clicked: #--------------------------------------------------------------------------- def _annoy_clicked ( self, info ): self.edit_traits( view = View( title = 'Annoying', kind = 'modal', buttons = [ 'OK' ] ) ) #------------------------------------------------------------------------------- # Run the tests: #------------------------------------------------------------------------------- if __name__ == '__main__': AnnoyButton = Action( name = 'Annoy', tooltip = 'Click me to be annoyed', enabled_when = 'age >= 40' ) person = Person( name = 'Bill', age = 42, phone = '555-1212' ) fields = Group( 'name', 'age', 'phone', 'notes~' ) person.notes = ("Should have 6 standard 'live' buttons: Undo, Redo, " "Revert, OK, Cancel, Help") person.configure_traits( view = View( fields, kind = 'livemodal', buttons = LiveButtons ) ) person.notes = ("Should have 5 standard 'modal' buttons: Apply, Revert, " "OK, Cancel, Help") person.configure_traits( view = View( fields, buttons = ModalButtons ) ) person.notes = "Should have 2 standard buttons: OK, Cancel" person.configure_traits( view = View( fields, buttons = [ OKButton, CancelButton ] ) ) person.notes = "Should have 1 standard button: OK (enabled when age >= 40)" person.configure_traits( view = View( fields, buttons = [ Action( name = 'OK', enabled_when = 'age >= 40' ) ] ) ) person.notes = "Should have 1 standard button: OK (visible when age >= 40)" person.configure_traits( view = View( fields, buttons = [ Action( name = 'OK', visible_when = 'age >= 40' ) ] ) ) person.notes = ("Should have 2 standard buttons: OK, Help (defined when " "age >= 50)") person.configure_traits( view = View( fields, buttons = [ 'OK', Action( name = 'Help', defined_when = 'age >= 50' ) ] ) ) person.notes = ("Should have 1 user and 5 standard buttons: Annoy (enabled " "when age >= 40), Apply, Revert, OK, Cancel, Help") person.configure_traits( view = View( fields, buttons = [ AnnoyButton ] + ModalButtons ) ) traitsui-4.1.0/integrationtests/ui/test_ui2.py0000644000175100001440000001675511674463545022531 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in /LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # Thanks for using Enthought open source! # # Author: David C. Morrill Date: 11/02/2004 Description: Test case for Traits # User Interface # ------------------------------------------------------------------------------ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx from kiva.traits.kiva_font_trait \ import KivaFont from enable.traits.api \ import RGBAColor from traits.api \ import Trait, HasTraits, Str, Int, Range, List, Event, Bool from traitsui.api \ import View, Handler, Item, CheckListEditor, ButtonEditor, FileEditor, \ DirectoryEditor, ImageEnumEditor #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- origin_values = [ 'top left', 'top right', 'bottom left', 'bottom right' ] #------------------------------------------------------------------------------- # 'PersonHandler' class: #------------------------------------------------------------------------------- class PersonHandler ( Handler ): def object_zip_changed ( self, info ): obj = info.object enabled = (obj.zip >= 10000) info.street.enabled = enabled info.city.enabled = enabled info.state.enabled = enabled if obj.zip == 78664: obj.street = '901 Morning View Place' obj.city = 'Round Rock' obj.state = 'Texas' def object_call_changed ( self, info ): print 'You called?' #------------------------------------------------------------------------------- # 'WizardHandler' class: #------------------------------------------------------------------------------- class WizardHandler ( Handler ): def object_sex_changed ( self, info ): if info.object.sex == 'Female': info.p1.next = 'p3' else: info.p1.next = 'p2' info.p2.next = None def object_name_changed ( self, info ): info.p2.enabled = info.p3.enabled = (info.object.name != '') if not info.p2.enabled: info.p2.msg = info.p3.msg = 'You must enter a valid name.' #------------------------------------------------------------------------------- # 'Employer' class: #------------------------------------------------------------------------------- class Employer ( HasTraits ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- company = Str boss = Str view = View( 'company', 'boss' ) #------------------------------------------------------------------------------- # 'Person' class #------------------------------------------------------------------------------- class Person ( HasTraits ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- name = Str( 'David Morrill' ) age = Int( 39 ) sex = Trait( 'Male', 'Female' ) coolness = Range( 0.0, 10.0, 10.0 ) number = Trait( 1, Range( 1, 6 ), 'one', 'two', 'three', 'four', 'five', 'six' ) human = Bool( True ) employer = Trait( Employer( company = 'Enthought, Inc.', boss = 'eric' ) ) eye_color = RGBAColor set = List( editor = CheckListEditor( values = [ 'one', 'two', 'three', 'four' ], cols = 4 ) ) font = KivaFont street = Str city = Str state = Str zip = Int( 78663 ) password = Str books = List( Str, [ 'East of Eden', 'The Grapes of Wrath', 'Of Mice and Men' ] ) call = Event( 0, editor = ButtonEditor( label = 'Click to call' ) ) info = Str( editor = FileEditor() ) location = Str( editor = DirectoryEditor() ) origin = Trait( editor = ImageEnumEditor( values = origin_values, suffix = '_origin', cols = 4, klass = Employer ), *origin_values ) nm = Item( 'name', enabled_when = 'object.age >= 21' ) pw = Item( 'password', defined_when = 'object.zip == 78664' ) view = View( ( ( nm, 'age', 'coolness', '_', 'eye_color', 'eye_color@', 'eye_color*', 'eye_color~', '_', 'font', 'font@', 'font*', 'font~', '_', 'set', 'set@', 'set*', 'set~', '_', 'sex', 'sex@', 'sex*', 'sex~', '_', 'human', 'human@', 'human*', 'human~', '_', 'number', 'number@', 'number*', 'number~', '_', 'books', '_', 'books@', '_', 'books*', '_', 'books~', '_', 'info', 'location', 'origin', 'origin@', 'call', 'employer', 'employer[]@', 'employer*', 'employer~', pw, '|<[Person:]' ), ( ' ', 'street', 'city', 'state', 'zip', '|<[Address:]' ), ( nm, nm, nm, nm, nm, nm, nm, nm, nm, nm, nm, nm, nm, nm, '|<[Names:]' ), '|' ), title = 'Traits 2 User Interface Test', handler = PersonHandler(), buttons = [ 'Apply', 'Revert', 'Undo', 'OK' ], height = 0.5 ) wizard = View( ( '|p1:', 'name', 'age', 'sex' ), ( '|p2:', 'street', 'city', 'state', 'zip' ), ( '|p3:', 'eye_color', 'origin', 'human' ), handler = WizardHandler() ) #------------------------------------------------------------------------------- # 'TraitSheetApp' class: #------------------------------------------------------------------------------- class TraitSheetApp ( wx.App ): #--------------------------------------------------------------------------- # Initialize the object: #--------------------------------------------------------------------------- def __init__ ( self, object ): self.object = object wx.InitAllImageHandlers() wx.App.__init__( self, 1, 'debug.log' ) self.MainLoop() object.print_traits() #--------------------------------------------------------------------------- # Handle application initialization: #--------------------------------------------------------------------------- def OnInit ( self ): #ui = self.object.edit_traits( 'view', kind = 'live' ) ui = self.object.edit_traits( 'wizard', kind = 'wizard' ) self.SetTopWindow( ui.control ) return True #------------------------------------------------------------------------------- # Main program: #------------------------------------------------------------------------------- TraitSheetApp( Person() ) traitsui-4.1.0/integrationtests/ui/array_editor_test.py0000644000175100001440000000331611674463545024503 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # ArrayEditor test case # # Written by: David C. Morrill # # Date: 01/10/2006 # # (c) Copyright 2006 by Enthought, Inc. # License: BSD Style. # #------------------------------------------------------------------------------- #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from traits.api \ import HasPrivateTraits, Array from traitsui.api \ import View, ArrayEditor #------------------------------------------------------------------------------- # 'Test' class: #------------------------------------------------------------------------------- class Test ( HasPrivateTraits ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- three = Array( int, (3,3) ) four = Array( float, (4,4), editor = ArrayEditor( width = -50 ) ) #--------------------------------------------------------------------------- # Traits view definitions: #--------------------------------------------------------------------------- view = View( 'three', '_', 'three', '_', 'three~', '_', 'four', '_', 'four', '_', 'four~', title = 'ArrayEditor Test Case', resizable = True ) #------------------------------------------------------------------------------- # Run the test case: #------------------------------------------------------------------------------- if __name__ == '__main__': Test().configure_traits() traitsui-4.1.0/integrationtests/ui/check_list_editor_test.py0000644000175100001440000000447311674463545025502 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # CheckListEditor test case for Traits UI # # Written by: David C. Morrill # # Date: 06/29/2005 # # (c) Copyright 2005 by Enthought, Inc. # License: BSD Style. # #------------------------------------------------------------------------------- #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from traits.api \ import Enum, List from traitsui.api \ import Handler, View, Item, CheckListEditor #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- colors = [ 'red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet' ] numbers = [ 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten' ] #------------------------------------------------------------------------------- # 'CheckListTest' class: #------------------------------------------------------------------------------- class CheckListTest ( Handler ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- case = Enum( 'Colors', 'Numbers' ) value = List( editor = CheckListEditor( values = colors, cols = 5 ) ) #--------------------------------------------------------------------------- # Event handlers: #--------------------------------------------------------------------------- def object_case_changed ( self, info ): if self.case == 'Colors': info.value.factory.values = colors else: info.value.factory.values = numbers #------------------------------------------------------------------------------- # Run the tests: #------------------------------------------------------------------------------- if __name__ == '__main__': clt = CheckListTest() clt.configure_traits( view = View( 'case', '_', Item( 'value', id = 'value' ) ) ) print 'value:', clt.value clt.configure_traits( view = View( 'case', '_', Item( 'value@', id = 'value' ) ) ) print 'value:', clt.value traitsui-4.1.0/integrationtests/ui/table_editor_focus_bug.py0000644000175100001440000000372711674463545025457 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. from traits.api import HasTraits, Str, List from traitsui.api import Group, Item, TableEditor, View from traitsui.table_column \ import ObjectColumn class Word(HasTraits): word = Str class Foo(HasTraits): # arbitrary string containing spaces input = Str # input split on space parsed = List def _input_changed(self): words = self.input.split() for word in self.parsed[:]: if word.word in words: words.remove(word.word) else: self.parsed.remove(word) for word in words: self.parsed.append(Word(word=word)) return table_editor = TableEditor( columns = [ ObjectColumn( name='word') ], editable=True ) help = Str("""Type in the 'input' box before clicking the Parsed tab. The first non-whitespace character will cause changes to the parsed trait and therefore changes to the table rows. That is expected. BUG: the table grabs the focus from 'input' and thus subsequent typing goes into one of the table cells. If you click the 'Parsed' tab, to view the table, and then the 'Inputs' tab the focus will stay with the 'input' box. """) traits_view = View( Group( Item( 'help', style='readonly'), Item( 'input' ), label='Input'), Group( Item( 'parsed', editor=table_editor), label='Parsed' ), dock = 'tab', resizable=True, width=320, height=240 ) if __name__ == '__main__': # simple test of the model foo = Foo() foo.input = 'these words in the list' assert( [word.word for word in foo.parsed] == ['these', 'words', 'in', 'the', 'list'] ) foo.input = 'these dudes in the bar' assert( [word.word for word in foo.parsed] == ['these', 'in', 'the', 'dudes', 'bar'] ) foo.configure_traits( kind='modal' ) print foo.input, [word.word for word in foo.parsed] traitsui-4.1.0/integrationtests/ui/shell_editor_test.py0000644000175100001440000000324711674463545024477 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Traits UI Python ShellEditor test. # # Written by: David C. Morrill # # Date: 10/13/2005 # # (c) Copyright 2005 by Enthought, Inc. # License: BSD Style. # #------------------------------------------------------------------------------- from traits.api import * from traitsui.api import * from traitsui.menu import * #------------------------------------------------------------------------------- # 'ShellTest' class: #------------------------------------------------------------------------------- class ShellTest ( HasPrivateTraits ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- name = Str age = Int weight = Float shell_1 = Str shell_2 = Dict #--------------------------------------------------------------------------- # Traits view definitions: #--------------------------------------------------------------------------- view = View( 'name', 'age', 'weight', '_', Item( 'shell_1', editor = ShellEditor() ), Item( 'shell_2', editor = ShellEditor() ), id = 'traitsui.tests.shell_editor_test', resizable = True, width = 0.3, height = 0.3 ) #------------------------------------------------------------------------------- # Run the test: #------------------------------------------------------------------------------- if __name__ == '__main__': ShellTest().configure_traits() traitsui-4.1.0/integrationtests/ui/test_ui4.py0000644000175100001440000000655611674463545022531 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in /LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 11/02/2004 # Description: Test case for Traits User Interface #------------------------------------------------------------------------------ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx from traits.api import Trait, HasTraits, Str, Int from traitsui.api import View, Group from traits.api import Color #------------------------------------------------------------------------------- # Model classes: #------------------------------------------------------------------------------- class Employer ( HasTraits ): company = Str( 'Enthought, Inc.' ) boss = Str( 'eric' ) view = View( 'company', 'boss' ) class Person ( HasTraits ): name = Str( 'David Morrill' ) age = Int( 39 ) class ExtraPerson ( Person ): sex = Trait( 'Male', 'Female' ) eye_color = Color class LocatedPerson ( Person ): street = Str city = Str state = Str zip = Int( 78663 ) class EmployedPerson ( LocatedPerson ): employer = Trait( Employer() ) #------------------------------------------------------------------------------- # View classes: #------------------------------------------------------------------------------- class PersonView ( HasTraits ): view = View( 'name', '', 'age', kind = 'modal' ) class ExtraPersonView ( PersonView ): extra = Group( 'sex', 'eye_color' ) class LocatedPersonView ( PersonView ): extra = Group( 'street', 'city', 'state', 'zip' ) class EmployedPersonView ( LocatedPersonView ): extra = Group( 'employer', '' ) #------------------------------------------------------------------------------- # 'TraitSheetApp' class: #------------------------------------------------------------------------------- class TraitSheetApp ( wx.App ): #--------------------------------------------------------------------------- # Initialize the object: #--------------------------------------------------------------------------- def __init__ ( self ): wx.InitAllImageHandlers() wx.App.__init__( self, 1, 'debug.log' ) self.MainLoop() #--------------------------------------------------------------------------- # Handle application initialization: #--------------------------------------------------------------------------- def OnInit ( self ): PersonView().edit_traits( context = Person() ) ExtraPersonView().edit_traits( context = ExtraPerson() ) LocatedPersonView().edit_traits( context = LocatedPerson() ) EmployedPersonView().edit_traits( context = EmployedPerson() ) return True #------------------------------------------------------------------------------- # Main program: #------------------------------------------------------------------------------- TraitSheetApp() traitsui-4.1.0/integrationtests/ui/test_ui5.py0000644000175100001440000002503111674463545022517 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in /LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 11/02/2004 # # ------------------------------------------------------------------------------ """ Traits Test case """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx from traits.api \ import Trait, HasTraits, Str, Int, Range, List, Event, File, Directory, Bool from traitsui.api \ import View, Handler, Item, CheckListEditor, ButtonEditor, FileEditor, \ DirectoryEditor, ImageEnumEditor from traits.api \ import Color, Font #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- origin_values = [ 'top left', 'top right', 'bottom left', 'bottom right' ] #------------------------------------------------------------------------------- # 'Instance' class: #------------------------------------------------------------------------------- class Instance ( HasTraits ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- integer_text = Int( 1 ) enumeration = Trait( 'one', 'two', 'three', 'four', 'five', 'six', cols = 3 ) float_range = Range( 0.0, 10.0, 10.0 ) int_range = Range( 1, 5 ) boolean = Bool( True ) view = View( 'integer_text', 'enumeration', 'float_range', 'int_range', 'boolean' ) #------------------------------------------------------------------------------- # 'TraitsTestHandler' class: #------------------------------------------------------------------------------- class TraitsTestHandler ( Handler ): def object_enabled_changed ( self, info ): enabled = info.object.enabled for i in range( 1, 63 ): getattr( info, 'f%d' % i ).enabled = enabled #------------------------------------------------------------------------------- # 'TraitsTest' class #------------------------------------------------------------------------------- class TraitsTest ( HasTraits ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- enabled = Bool( True ) integer_text = Int( 1 ) enumeration = Trait( 'one', 'two', 'three', 'four', 'five', 'six', cols = 3 ) float_range = Range( 0.0, 10.0, 10.0 ) int_range = Range( 1, 6 ) int_range2 = Range( 1, 50 ) compound = Trait( 1, Range( 1, 6 ), 'one', 'two', 'three', 'four', 'five', 'six' ) boolean = Bool( True ) instance = Trait( Instance() ) color = Color( 'cyan' ) font = Font() check_list = List( editor = CheckListEditor( values = [ 'one', 'two', 'three', 'four' ], cols = 4 ) ) list = List( Str, [ 'East of Eden', 'The Grapes of Wrath', 'Of Mice and Men' ] ) button = Event( 0, editor = ButtonEditor( label = 'Click' ) ) file = File() directory = Directory() image_enum = Trait( editor = ImageEnumEditor( values = origin_values, suffix = '_origin', cols = 4, klass = Instance ), *origin_values ) #--------------------------------------------------------------------------- # View definitions: #--------------------------------------------------------------------------- view = View( ( '|{Enum}', ( 'enabled', ), ( '|<[Enumeration]', 'f1:enumeration[Simple]', '_', 'f2:enumeration[Custom]@', '_', 'f3:enumeration[Text]*', '_', 'f4:enumeration[Readonly]~' ), ( '|<[Check List]', 'f5:check_list[Simple]', '_', 'f6:check_list[Custom]@', '_', 'f7:check_list[Text]*', '_', 'f8:check_list[Readonly]~' ) ), ( '|{Range}', ( '|<[Float Range]', 'f9:float_range[Simple]', '_', 'f10:float_range[Custom]@', '_', 'f11:float_range[Text]*', '_', 'f12:float_range[Readonly]~' ), ( '|<[Int Range]', 'f13:int_range[Simple]', '_', 'f14:int_range[Custom]@', '_', 'f15:int_range[Text]*', '_', 'f16:int_range[Readonly]~' ), ( '|<[Int Range 2]', 'f17:int_range2[Simple]', '_', 'f18:int_range2[Custom]@', '_', 'f19:int_range2[Text]*', '_', 'f20:int_range2[Readonly]~' ) ), ( '|{Misc}', ( '|<[Integer Text]', 'f21:integer_text[Simple]', '_', 'f22:integer_text[Custom]@', '_', 'f23:integer_text[Text]*', '_', 'f24:integer_text[Readonly]~' ), ( '|<[Compound]', 'f25:compound[Simple]', '_', 'f26:compound[Custom]@', '_', 'f27:compound[Text]*', '_', 'f28:compound[Readonly]~' ), ( '|<[Boolean]', 'f29:boolean[Simple]', '_', 'f30:boolean[Custom]@', '_', 'f31:boolean[Text]*', '_', 'f32:boolean[Readonly]~' ) ), ( '|{Color/Font}', ( '|<[Color]', 'f33:color[Simple]', '_', 'f34:color[Custom]@', '_', 'f35:color[Text]*', '_', 'f36:color[Readonly]~' ), ( '|<[Font]', 'f37:font[Simple]', '_', 'f38:font[Custom]@', '_', 'f39:font[Text]*', '_', 'f40:font[Readonly]~' ) ), ( '|{List}', ( '|<[List]', 'f41:list[Simple]', '_', 'f42:list[Custom]@', '_', 'f43:list[Text]*', '_', 'f44:list[Readonly]~' ) ), ( '|{Button}', ( '|<[Button]', 'f45:button[Simple]', '_', 'f46:button[Custom]@' ), # 'button[Text]*', # 'button[Readonly]~' ), ( '|<[Image Enum]', 'f47:image_enum[Simple]', '_', 'f48:image_enum[Custom]@', '_', 'f49:image_enum[Text]*', '_', 'f50:image_enum[Readonly]~' ), ( '|<[Instance]', 'f51:instance[Simple]', '_', 'f52:instance[Custom]@', '_', 'f53:instance[Text]*', '_', 'f54:instance[Readonly]~' ), ), ( '|{File}', ( '|<[File]', 'f55:file[Simple]', '_', 'f56:file[Custom]@', '_', 'f57:file[Text]*', '_', 'f58:file[Readonly]~', ), ( '|<[Directory]', 'f59:directory[Simple]', '_', 'f60:directory[Custom]@', '_', 'f61:directory[Text]*', '_', 'f62:directory[Readonly]~' ) ), buttons = [ 'Apply', 'Revert', 'Undo', 'OK' ], handler = TraitsTestHandler() ) #------------------------------------------------------------------------------- # 'TraitSheetApp' class: #------------------------------------------------------------------------------- class TraitSheetApp ( wx.App ): #--------------------------------------------------------------------------- # Initialize the object: #--------------------------------------------------------------------------- def __init__ ( self, object ): self.object = object wx.InitAllImageHandlers() wx.App.__init__( self, 1, 'debug.log' ) self.MainLoop() #--------------------------------------------------------------------------- # Handle application initialization: #--------------------------------------------------------------------------- def OnInit ( self ): ui = self.object.edit_traits( kind = 'live' ) ui = self.object.edit_traits( kind = 'modal' ) ui = self.object.edit_traits( kind = 'nonmodal' ) ui = self.object.edit_traits( kind = 'wizard' ) self.SetTopWindow( ui.control ) return True #------------------------------------------------------------------------------- # Main program: #------------------------------------------------------------------------------- TraitSheetApp( TraitsTest() ) traitsui-4.1.0/integrationtests/ui/list_traits_ui_test.py0000644000175100001440000001143011674463545025051 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # TableEditor test case for Traits UI # # Written by: David C. Morrill # # Date: 11/11/2005 # # (c) Copyright 2005 by Enthought, Inc. # License: BSD Style. # #------------------------------------------------------------------------------- #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from traits.api \ import HasStrictTraits, Str, Int, Regex, List, Instance from traitsui.api \ import View, Item, VSplit, TableEditor, ListEditor from traitsui.table_column \ import ObjectColumn from traitsui.table_filter \ import TableFilter, RuleTableFilter, RuleFilterTemplate, \ MenuFilterTemplate, EvalFilterTemplate #------------------------------------------------------------------------------- # 'Person' class: #------------------------------------------------------------------------------- class Person ( HasStrictTraits ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- name = Str age = Int phone = Regex( value = '000-0000', regex = '\d\d\d[-]\d\d\d\d' ) #--------------------------------------------------------------------------- # Traits view definition: #--------------------------------------------------------------------------- traits_view = View( 'name', 'age', 'phone', width = 0.18, buttons = [ 'OK', 'Cancel' ] ) #------------------------------------------------------------------------------- # Sample data: #------------------------------------------------------------------------------- people = [ Person( name = 'Dave', age = 39, phone = '555-1212' ), Person( name = 'Mike', age = 28, phone = '555-3526' ), Person( name = 'Joe', age = 34, phone = '555-6943' ), Person( name = 'Tom', age = 22, phone = '555-7586' ), Person( name = 'Dick', age = 63, phone = '555-3895' ), Person( name = 'Harry', age = 46, phone = '555-3285' ), Person( name = 'Sally', age = 43, phone = '555-8797' ), Person( name = 'Fields', age = 31, phone = '555-3547' ) ] #------------------------------------------------------------------------------- # Table editor definition: #------------------------------------------------------------------------------- filters = [ EvalFilterTemplate, MenuFilterTemplate, RuleFilterTemplate ] table_editor = TableEditor( columns = [ ObjectColumn( name = 'name' ), ObjectColumn( name = 'age' ), ObjectColumn( name = 'phone' ) ], editable = True, deletable = True, sortable = True, sort_model = True, filters = filters, search = RuleTableFilter(), row_factory = Person ) #------------------------------------------------------------------------------- # 'ListTraitTest' class: #------------------------------------------------------------------------------- class ListTraitTest ( HasStrictTraits ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- people = List( Person ) #--------------------------------------------------------------------------- # Traits view definitions: #--------------------------------------------------------------------------- traits_view = View( VSplit( Item( 'people', id = 'table', editor = table_editor ), Item( 'people@', id = 'list', editor = ListEditor( style = 'custom', rows = 5 ) ), Item( 'people@', id = 'notebook', editor = ListEditor( use_notebook = True, deletable = True, export = 'DockShellWindow', page_name = '.name' ) ), id = 'splitter', show_labels = False ), title = 'List Trait Editor Test', id = 'traitsui.tests.list_traits_ui_test', dock = 'horizontal', width = .4, height = .6, resizable = True, kind = 'live' ) #------------------------------------------------------------------------------- # Run the tests: #------------------------------------------------------------------------------- if __name__ == '__main__': ListTraitTest( people = people ).configure_traits() traitsui-4.1.0/integrationtests/ui/instance_editor_test3.py0000644000175100001440000000534311674463545025256 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. from traits.api import * from traitsui.api import * from traitsui.instance_choice import InstanceChoice #------------------------------------------------------------------------------- # 'Person' class: #------------------------------------------------------------------------------- class Person ( HasStrictTraits ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- name = Str age = Int phone = Regex( value = '000-0000', regex = '\d\d\d[-]\d\d\d\d' ) #--------------------------------------------------------------------------- # Traits view definition: #--------------------------------------------------------------------------- traits_view = View( 'name', 'age', 'phone' ) #------------------------------------------------------------------------------- # Sample data: #------------------------------------------------------------------------------- people = [ Person( name = 'Dave', age = 39, phone = '555-1212' ), Person( name = 'Mike', age = 28, phone = '555-3526' ), Person( name = 'Joe', age = 34, phone = '555-6943' ), Person( name = 'Tom', age = 22, phone = '555-7586' ), Person( name = 'Dick', age = 63, phone = '555-3895' ), Person( name = 'Harry', age = 46, phone = '555-3285' ), Person( name = 'Sally', age = 43, phone = '555-8797' ), Person( name = 'Fields', age = 31, phone = '555-3547' ) ] #------------------------------------------------------------------------------- # 'Team' class: #------------------------------------------------------------------------------- class Team ( HasStrictTraits ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- name = Str captain = Instance( Person ) roster = List( Person ) #--------------------------------------------------------------------------- # Traits view definitions: #--------------------------------------------------------------------------- traits_view = View( 'name', '_', Item( 'captain@', editor = InstanceEditor( name = 'roster' ) ), '_', 'roster' ) #------------------------------------------------------------------------------- # Run the test: #------------------------------------------------------------------------------- if __name__ == '__main__': Team( name = 'Vultures', captain = people[0], roster = people ).configure_traits() traitsui-4.1.0/integrationtests/ui/enum_editor_test.py0000644000175100001440000000401611674463545024327 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in /LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 04/06/2005 # Description: Test the EnumEditor trait editor. #------------------------------------------------------------------------------ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from traits.api \ import HasTraits, Trait, Enum, Range from traitsui.api \ import EnumEditor #------------------------------------------------------------------------------- # Trait definitions: #------------------------------------------------------------------------------- values = [ 'one', 'two', 'three', 'four' ] enum = Enum( *values ) range = Range( 1, 4 ) #------------------------------------------------------------------------------- # 'TestEnumEditor' class: #------------------------------------------------------------------------------- class TestEnumEditor ( HasTraits ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- value = Trait( 1, enum, range, editor = EnumEditor( values = values, evaluate = int ) ) #------------------------------------------------------------------------------- # Run the test: #------------------------------------------------------------------------------- if __name__ == '__main__': test = TestEnumEditor() test.configure_traits() test.print_traits() traitsui-4.1.0/integrationtests/styled_date_editor_test.py0000644000175100001440000000252411674463545025251 0ustar ischnellusers00000000000000 from datetime import date from traits.etsconfig.api import ETSConfig ETSConfig.toolkit = 'qt4' from traits.api import Date, Dict, HasTraits, List, on_trait_change from traitsui.api import View, Item, StyledDateEditor from traitsui.editors.styled_date_editor import CellFormat class Foo(HasTraits): dates = Dict() styles = Dict() fast_dates = List slow_dates = List current_date = Date() traits_view = View(Item("current_date", style="custom", show_label=False, editor=StyledDateEditor(dates_trait="dates", styles_trait="styles"))) def __init__(self, *args, **kw): HasTraits.__init__(self, *args, **kw) self.styles = { "fast" : CellFormat(bold=True, fgcolor="darkGreen"), "slow" : CellFormat(italics=True, fgcolor="lightGray"), } self.fast_dates = [date(2010,7,4), date(2010,7,3), date(2010,7,2)] self.slow_dates = [date(2010,6,28), date(2010,6,27), date(2010,6,24)] @on_trait_change("fast_dates,slow_dates") def _update_dates_dict(self): self.dates["fast"] = self.fast_dates self.dates["slow"] = self.slow_dates def _current_date_changed(self, old, new): print "Old:", old, "New:", new def main(): foo = Foo() foo.configure_traits() if __name__ == "__main__": main() traitsui-4.1.0/LICENSE.txt0000644000175100001440000000352711674463545016212 0ustar ischnellusers00000000000000This software is OSI Certified Open Source Software. OSI Certified is a certification mark of the Open Source Initiative. Copyright (c) 2006, Enthought, Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Enthought, Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. The software contained in the traits/protocols/ directory is the pyprotocols project (http://peak.telecommunity.com/PyProtocols.html), it is originaly licensed under the terms of the Python Software Foundation License, which is compatible with the above terms. traitsui-4.1.0/image_LICENSE_Eclipse.txt0000644000175100001440000002604311674463545021016 0ustar ischnellusers00000000000000Eclipse Public License - v 1.0 THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENTS ACCEPTANCE OF THIS AGREEMENT. 1. DEFINITIONS "Contribution" means: a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and b) in the case of each subsequent Contributor: i)changes to the Program, and ii)additions to the Program; where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributors behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program. "Contributor" means any person or entity that distributes the Program. "Licensed Patents " mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. "Program" means the Contributions distributed in accordance with this Agreement. "Recipient" means anyone who receives the Program under this Agreement, including all Contributors. 2. GRANT OF RIGHTS a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form. b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipients responsibility to acquire that license before distributing the Program. d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. 3. REQUIREMENTS A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that: a) it complies with the terms and conditions of this Agreement; and b) its license agreement: i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange. When the Program is made available in source code form: a) it must be made available under this Agreement; and b) a copy of this Agreement must be included with each copy of the Program. Contributors may not remove or alter any copyright notices contained within the Program. Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution. 4. COMMERCIAL DISTRIBUTION Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributors responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. 5. NO WARRANTY EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. 6. DISCLAIMER OF LIABILITY EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 7. GENERAL If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipients patent(s), then such Recipients rights granted under Section 2(b) shall terminate as of the date such litigation is filed. All Recipients rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipients rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipients obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. traitsui-4.1.0/README.rst0000644000175100001440000000132611674463545016051 0ustar ischnellusers00000000000000============================================ traitsui: traits-capable windowing framework ============================================ The traitsui project contains a toolkit-independent GUI abstraction layer, which is used to support the "visualization" features of the Traits package. Thus, you can write code in terms of the Traits API (views, items, editors, etc.), and let traitsui and your selected toolkit and back-end take care of the details of displaying them. The following GUI backends are supported: - wxPython - PyQt - PySide Prerequisites ------------- If you want to run traitsui, you must also install: * `traits `_ * `pyface `_ traitsui-4.1.0/setup.py0000644000175100001440000000325611674463546016101 0ustar ischnellusers00000000000000# Copyright (c) 2008-2011 by Enthought, Inc. # All rights reserved. from os.path import join from setuptools import setup, find_packages info = {} execfile(join('traitsui', '__init__.py'), info) setup( name = 'traitsui', version = info['__version__'], author = 'David C. Morrill, et. al.', author_email = 'dmorrill@enthought.com', classifiers = [c.strip() for c in """\ Development Status :: 5 - Production/Stable Intended Audience :: Developers Intended Audience :: Science/Research License :: OSI Approved :: BSD License Operating System :: MacOS Operating System :: Microsoft :: Windows Operating System :: OS Independent Operating System :: POSIX Operating System :: Unix Programming Language :: C Programming Language :: Python Topic :: Scientific/Engineering Topic :: Software Development Topic :: Software Development :: Libraries """.splitlines() if len(c.strip()) > 0], description = 'traitsui: traits-capable user interfaces', long_description = open('README.rst').read(), url = 'https://github.com/enthought/traitsui', download_url = ('http://www.enthought.com/repo/ets/traitsui-%s.tar.gz' % info['__version__']), install_requires = info['__requires__'], license = 'BSD', maintainer = 'ETS Developers', maintainer_email = 'enthought-dev@enthought.com', package_data = dict(traitsui=['image/library/*.zip', 'wx/images/*', 'qt4/images/*']), packages = find_packages(), platforms = ["Windows", "Linux", "Mac OS-X", "Unix", "Solaris"], zip_safe = False, ) traitsui-4.1.0/image_LICENSE_Nuvola.txt0000644000175100001440000005664511674463545020711 0ustar ischnellusers00000000000000GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: * a) The modified work must itself be a software library. * b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. * c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. * d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: * a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) * b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. * c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. * d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. * e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: * a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. * b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. traitsui-4.1.0/traitsui/0000755000175100001440000000000011674463546016225 5ustar ischnellusers00000000000000traitsui-4.1.0/traitsui/delegating_handler.py0000644000175100001440000001354511674463546022407 0ustar ischnellusers00000000000000#----------------------------------------------------------------------------- # # Copyright (c) 2006, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: Dave Peterson # #----------------------------------------------------------------------------- """ A handler that delegates the handling of events to a set of sub-handlers. This is typically used as the handler for dynamic views. See the **traits.has_dynamic_view** module. """ # Enthought library imports from traits.api import HasTraits, List from .ui import Dispatcher # Local imports. from .handler import Handler # Set up a logger: import logging logger = logging.getLogger( __name__ ) class DelegatingHandler ( Handler ): """ A handler that delegates the handling of events to a set of sub-handlers. """ #-- Public 'DelegatingHandler' Interface ----------------------------------- # The list of sub-handlers this object delegates to: sub_handlers = List( HasTraits ) #-- Protected 'DelegatingHandler' Interface -------------------------------- # A list of dispatchable handler methods: _dispatchers = List #--------------------------------------------------------------------------- # 'Handler' interface: #--------------------------------------------------------------------------- #-- Public Methods --------------------------------------------------------- def closed ( self, info, is_ok ): """ Handles the user interface being closed by the user. This method is overridden here to unregister any dispatchers that were set up in the *init()* method. """ for d in self._dispatchers: d.remove() def init ( self, info ): """ Initializes the controls of a user interface. Parameters ---------- info : *UIInfo* object The UIInfo object associated with the view Returns ------- A boolean, indicating whether the user interface was successfully initialized. A True value indicates that the UI can be displayed; a False value indicates that the display operation should be cancelled. Description ----------- This method is called after all user interface elements have been created, but before the user interface is displayed. Use this method to further customize the user interface before it is displayed. This method is overridden here to delegate to sub-handlers. """ # Iterate through our sub-handlers, and for each method whose name is # of the form 'object_name_changed', where 'object' is the name of an # object in the UI's context, create a trait notification handler that # will call the method whenever object's 'name' trait changes. logger.debug( 'Initializing delegation in DelegatingHandler [%s]', self ) context = info.ui.context for h in self.sub_handlers: # fixme: I don't know why this wasn't here before... I'm not # sure this is right! h.init( info ) for name in self._each_trait_method( h ): if name[-8:] == '_changed': prefix = name[:-8] col = prefix.find( '_', 1 ) if col >= 0: object = context.get( prefix[ :col ] ) if object is not None: logger.debug( '\tto method [%s] on handler[%s]', name, h ) method = getattr( h, name ) trait_name = prefix[col + 1:] self._dispatchers.append( Dispatcher( method, info, object, trait_name ) ) # Also invoke the method immediately so initial # user interface state can be correctly set. if object.base_trait( trait_name ).type != 'event': method( info ) # fixme: These are explicit workarounds for problems with:- # # 'GeometryHierarchyViewHandler' # # which is used in the :- # # 'GeometryHierarchyTreeEditor' # # which are in the 'encode.cad.ui.geometry' package. # # The tree editor has dynamic views, and hence the handler gets # wrapped by a 'DelegatingHandler'. Unfortunately the handler # has a couple of methods that aren't picked up by the usual # wrapping strategy:- # # 1) 'tree_item_selected' # # - which is obviously called when a tree item is selected. # # 2) 'inspect_object' # # - which is called directly as as action from the context menu # defined in the tree editor. # elif name in [ 'tree_item_selected', 'inspect_object' ]: self.__dict__[ name ] = self._create_delegate( h, name ) return True def _create_delegate ( self, h, name ): """ Quick fix for handler methods that are currently left out! """ def delegate ( *args, **kw ): method = getattr( h, name ) return method( *args, **kw ) return delegate traitsui-4.1.0/traitsui/value_tree.py0000644000175100001440000007020311674463546020734 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2006, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 01/05/2006 # #------------------------------------------------------------------------------ """ Defines tree node classes and editors for various types of values. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import import inspect from types import FunctionType, MethodType from traits.api import Any, Bool, HasPrivateTraits, HasTraits, Instance, List, Str from .tree_node import ObjectTreeNode, TreeNode, TreeNodeObject from .editors.tree_editor import TreeEditor #------------------------------------------------------------------------------- # 'SingleValueTreeNodeObject' class: #------------------------------------------------------------------------------- class SingleValueTreeNodeObject ( TreeNodeObject ): """ A tree node for objects of types that have a single value. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # The parent of this node parent = Instance( TreeNodeObject ) # Name of the value name = Str # User-specified override of the default label label = Str # The value itself value = Any # Is the value readonly? readonly = Bool( False ) #--------------------------------------------------------------------------- # Returns whether chidren of this object are allowed or not: #--------------------------------------------------------------------------- def tno_allows_children ( self, node ): """ Returns whether this object can have children (False for this class). """ return False #--------------------------------------------------------------------------- # Returns whether or not the object has children: #--------------------------------------------------------------------------- def tno_has_children ( self, node ): """ Returns whether the object has children (False for this class). """ return False #--------------------------------------------------------------------------- # Returns whether or not the object's children can be renamed: #--------------------------------------------------------------------------- def tno_can_rename ( self, node ): """ Returns whether the object's children can be renamed (False for this class). """ return False #--------------------------------------------------------------------------- # Returns whether or not the object's children can be copied: #--------------------------------------------------------------------------- def tno_can_copy ( self, node ): """ Returns whether the object's children can be copied (True for this class). """ return True #--------------------------------------------------------------------------- # Returns whether or not the object's children can be deleted: #--------------------------------------------------------------------------- def tno_can_delete ( self, node ): """ Returns whether the object's children can be deleted (False for this class). """ return False #--------------------------------------------------------------------------- # Returns whether or not the object's children can be inserted (or just # appended): #--------------------------------------------------------------------------- def tno_can_insert ( self, node ): """ Returns whether the object's children can be inserted (False, meaning children are appended, for this class). """ return False #--------------------------------------------------------------------------- # Returns the icon for a specified object: #--------------------------------------------------------------------------- def tno_get_icon ( self, node, is_expanded ): """ Returns the icon for a specified object. """ return ('@icons:%s_node' % self.__class__.__name__[ : -4 ].lower()) #--------------------------------------------------------------------------- # Sets the label for a specified node: #--------------------------------------------------------------------------- def tno_set_label ( self, node, label ): """ Sets the label for a specified object. """ if label == '?': label = '' self.label = label #--------------------------------------------------------------------------- # Gets the label to display for a specified object: #--------------------------------------------------------------------------- def tno_get_label ( self, node ): """ Gets the label to display for a specified object. """ if self.label != '': return self.label if self.name == '': return self.format_value( self.value ) return '%s: %s' % ( self.name, self.format_value( self.value ) ) #--------------------------------------------------------------------------- # Returns the formatted version of the value: #--------------------------------------------------------------------------- def format_value ( self, value ): """ Returns the formatted version of the value. """ return repr( value ) #--------------------------------------------------------------------------- # Returns the correct node type for a specified value: #--------------------------------------------------------------------------- def node_for ( self, name, value ): """ Returns the correct node type for a specified value. """ for type, node in basic_types(): if isinstance( value, type ): break else: node = OtherNode if inspect.isclass( value ): node = ClassNode elif hasattr( value, '__class__' ): node = ObjectNode return node( parent = self, name = name, value = value, readonly = self.readonly ) #------------------------------------------------------------------------------- # 'MultiValueTreeNodeObject' class: #------------------------------------------------------------------------------- class MultiValueTreeNodeObject ( SingleValueTreeNodeObject ): """ A tree node for objects of types that have multiple values. """ #--------------------------------------------------------------------------- # Returns whether chidren of this object are allowed or not: #--------------------------------------------------------------------------- def tno_allows_children ( self, node ): """ Returns whether this object can have children (True for this class). """ return True #--------------------------------------------------------------------------- # Returns whether or not the object has children: #--------------------------------------------------------------------------- def tno_has_children ( self, node ): """ Returns whether the object has children (True for this class). """ return True #------------------------------------------------------------------------------- # 'StringNode' class: #------------------------------------------------------------------------------- class StringNode ( SingleValueTreeNodeObject ): """ A tree node for strings. """ #--------------------------------------------------------------------------- # Returns the formatted version of the value: #--------------------------------------------------------------------------- def format_value ( self, value ): """ Returns the formatted version of the value. """ n = len( value ) if len( value ) > 80: value = '%s...%s' % ( value[ :42 ], value[ -35: ] ) return '%s [%d]' % ( repr( value ), n ) #------------------------------------------------------------------------------- # 'NoneNode' class: #------------------------------------------------------------------------------- class NoneNode ( SingleValueTreeNodeObject ): """ A tree node for None values. """ pass #------------------------------------------------------------------------------- # 'BoolNode' class: #------------------------------------------------------------------------------- class BoolNode ( SingleValueTreeNodeObject ): """ A tree node for Boolean values. """ pass #------------------------------------------------------------------------------- # 'IntNode' class: #------------------------------------------------------------------------------- class IntNode ( SingleValueTreeNodeObject ): """ A tree node for integer values. """ pass #------------------------------------------------------------------------------- # 'FloatNode' class: #------------------------------------------------------------------------------- class FloatNode ( SingleValueTreeNodeObject ): """ A tree node for floating point values. """ pass #------------------------------------------------------------------------------- # 'ComplexNode' class: #------------------------------------------------------------------------------- class ComplexNode ( SingleValueTreeNodeObject ): """ A tree node for complex number values. """ pass #------------------------------------------------------------------------------- # 'OtherNode' class: #------------------------------------------------------------------------------- class OtherNode ( SingleValueTreeNodeObject ): """ A tree node for single-value types for which there is not another node type. """ pass #------------------------------------------------------------------------------- # 'TupleNode' class: #------------------------------------------------------------------------------- class TupleNode ( MultiValueTreeNodeObject ): """ A tree node for tuples. """ #--------------------------------------------------------------------------- # Returns the formatted version of the value: #--------------------------------------------------------------------------- def format_value ( self, value ): """ Returns the formatted version of the value. """ return 'Tuple(%d)' % len( value ) #--------------------------------------------------------------------------- # Returns whether or not the object has children: #--------------------------------------------------------------------------- def tno_has_children ( self, node ): """ Returns whether the object has children, based on the length of the tuple. """ return (len( self.value ) > 0) #--------------------------------------------------------------------------- # Gets the object's children: #--------------------------------------------------------------------------- def tno_get_children ( self, node ): """ Gets the object's children. """ node_for = self.node_for value = self.value if len( value ) > 500: return ([ node_for( '[%d]' % i, x ) for i, x in enumerate( value[ : 250 ] ) ] + [ StringNode( value = '...', readonly = True ) ] + [ node_for( '[%d]' % i, x ) for i, x in enumerate( value[ -250: ] ) ]) return [ node_for( '[%d]' % i, x ) for i, x in enumerate( value ) ] #------------------------------------------------------------------------------- # 'ListNode' class: #------------------------------------------------------------------------------- class ListNode ( TupleNode ): """ A tree node for lists. """ #--------------------------------------------------------------------------- # Returns the formatted version of the value: #--------------------------------------------------------------------------- def format_value ( self, value ): """ Returns the formatted version of the value. """ return 'List(%d)' % len( value ) #--------------------------------------------------------------------------- # Returns whether or not the object's children can be deleted: #--------------------------------------------------------------------------- def tno_can_delete ( self, node ): """ Returns whether the object's children can be deleted. """ return (not self.readonly) #--------------------------------------------------------------------------- # Returns whether or not the object's children can be inserted (or just # appended): #--------------------------------------------------------------------------- def tno_can_insert ( self, node ): """ Returns whether the object's children can be inserted (vs. appended). """ return (not self.readonly) #------------------------------------------------------------------------------- # 'SetNode' class: #------------------------------------------------------------------------------- class SetNode ( ListNode ): """ A tree node for sets. """ #--------------------------------------------------------------------------- # Returns the formatted version of the value: #--------------------------------------------------------------------------- def format_value ( self, value ): """ Returns the formatted version of the value. """ return 'Set(%d)' % len( value ) #------------------------------------------------------------------------------- # 'ArrayNode' class: #------------------------------------------------------------------------------- class ArrayNode ( TupleNode ): """ A tree node for arrays. """ #--------------------------------------------------------------------------- # Returns the formatted version of the value: #--------------------------------------------------------------------------- def format_value ( self, value ): """ Returns the formatted version of the value. """ return 'Array(%s)' % ','.join( [ str( n ) for n in value.shape ] ) #------------------------------------------------------------------------------- # 'DictNode' class: #------------------------------------------------------------------------------- class DictNode ( TupleNode ): """ A tree node for dictionaries. """ #--------------------------------------------------------------------------- # Returns the formatted version of the value: #--------------------------------------------------------------------------- def format_value ( self, value ): """ Returns the formatted version of the value. """ return 'Dict(%d)' % len( value ) #--------------------------------------------------------------------------- # Gets the object's children: #--------------------------------------------------------------------------- def tno_get_children ( self, node ): """ Gets the object's children. """ node_for = self.node_for items = [ ( repr( k ), v ) for k, v in self.value.items() ] items.sort( lambda l, r: cmp( l[0], r[0] ) ) if len( items ) > 500: return ([ node_for( '[%s]' % k, v ) for k, v in items[: 250 ] ] + [ StringNode( value = '...', readonly = True ) ] + [ node_for( '[%s]' % k, v ) for k, v in items[ -250: ] ]) return [ node_for( '[%s]' % k, v ) for k, v in items ] #--------------------------------------------------------------------------- # Returns whether or not the object's children can be deleted: #--------------------------------------------------------------------------- def tno_can_delete ( self, node ): """ Returns whether the object's children can be deleted. """ return (not self.readonly) #------------------------------------------------------------------------------- # 'FunctionNode' class: #------------------------------------------------------------------------------- class FunctionNode ( SingleValueTreeNodeObject ): """ A tree node for functions """ #--------------------------------------------------------------------------- # Returns the formatted version of the value: #--------------------------------------------------------------------------- def format_value ( self, value ): """ Returns the formatted version of the value. """ return 'Function %s()' % ( value.func_code.co_name ) #--------------------------------------------------------------------------- # 'MethodNode' class: #--------------------------------------------------------------------------- class MethodNode ( MultiValueTreeNodeObject ): #--------------------------------------------------------------------------- # Returns the formatted version of the value: #--------------------------------------------------------------------------- def format_value ( self, value ): """ Returns the formatted version of the value. """ type = 'B' if value.im_self is None: type = 'Unb' return '%sound method %s.%s()' % ( type, value.im_class.__name__, value.im_func.func_code.co_name ) #--------------------------------------------------------------------------- # Returns whether or not the object has children: #--------------------------------------------------------------------------- def tno_has_children ( self, node ): """ Returns whether the object has children. """ return (self.value.im_func != None) #--------------------------------------------------------------------------- # Gets the object's children: #--------------------------------------------------------------------------- def tno_get_children ( self, node ): """ Gets the object's children. """ return [ self.node_for( 'Object', self.value.im_self ) ] #------------------------------------------------------------------------------- # 'ObjectNode' class: #------------------------------------------------------------------------------- class ObjectNode ( MultiValueTreeNodeObject ): """ A tree node for objects. """ #--------------------------------------------------------------------------- # Returns the formatted version of the value: #--------------------------------------------------------------------------- def format_value ( self, value ): """ Returns the formatted version of the value. """ try: klass = value.__class__.__name__ except: klass = '???' return '%s(0x%08X)' % ( klass, id( value ) ) #--------------------------------------------------------------------------- # Returns whether or not the object has children: #--------------------------------------------------------------------------- def tno_has_children ( self, node ): """ Returns whether the object has children. """ try: return (len( self.value.__dict__ ) > 0) except: return False #--------------------------------------------------------------------------- # Gets the object's children: #--------------------------------------------------------------------------- def tno_get_children ( self, node ): """ Gets the object's children. """ items = [ ( k, v ) for k, v in self.value.__dict__.items() ] items.sort( lambda l, r: cmp( l[0], r[0] ) ) return [ self.node_for( '.' + k, v ) for k, v in items ] #------------------------------------------------------------------------------- # 'ClassNode' class: #------------------------------------------------------------------------------- class ClassNode ( ObjectNode ): """ A tree node for classes. """ #--------------------------------------------------------------------------- # Returns the formatted version of the value: #--------------------------------------------------------------------------- def format_value ( self, value ): """ Returns the formatted version of the value. """ return value.__name__ #------------------------------------------------------------------------------- # 'TraitsNode' class: #------------------------------------------------------------------------------- class TraitsNode ( ObjectNode ): """ A tree node for traits. """ #--------------------------------------------------------------------------- # Returns whether or not the object has children: #--------------------------------------------------------------------------- def tno_has_children ( self, node ): """ Returns whether the object has children. """ return (len( self._get_names() ) > 0) #--------------------------------------------------------------------------- # Gets the object's children: #--------------------------------------------------------------------------- def tno_get_children ( self, node ): """ Gets the object's children. """ names = self._get_names() names.sort() value = self.value node_for = self.node_for nodes = [] for name in names: try: item_value = getattr( value, name, '' ) except Exception, excp: item_value = '<%s>' % excp nodes.append( node_for( '.' + name, item_value ) ) return nodes #--------------------------------------------------------------------------- # Gets the names of all defined traits/attributes: #--------------------------------------------------------------------------- def _get_names ( self ): """ Gets the names of all defined traits or attributes. """ value = self.value names = {} for name in value.trait_names( type = lambda x: x != 'event' ): names[ name ] = None for name in value.__dict__.keys(): names[ name ] = None return names.keys() #--------------------------------------------------------------------------- # Sets up/Tears down a listener for 'children replaced' on a specified # object: #--------------------------------------------------------------------------- def tno_when_children_replaced ( self, node, listener, remove ): """ Sets up or removes a listener for children being replaced on a specified object. """ self._listener = listener self.value.on_trait_change( self._children_replaced, remove = remove, dispatch = 'ui' ) def _children_replaced ( self ): self._listener( self ) #--------------------------------------------------------------------------- # Sets up/Tears down a listener for 'children changed' on a specified # object: #--------------------------------------------------------------------------- def tno_when_children_changed ( self, node, listener, remove ): """ Sets up or removes a listener for children being changed on a specified object. """ pass #------------------------------------------------------------------------------- # 'RootNode' class: #------------------------------------------------------------------------------- class RootNode ( MultiValueTreeNodeObject ): """ A root node. """ #--------------------------------------------------------------------------- # Returns the formatted version of the value: #--------------------------------------------------------------------------- def format_value ( self, value ): """ Returns the formatted version of the value. """ return '' #--------------------------------------------------------------------------- # Gets the object's children: #--------------------------------------------------------------------------- def tno_get_children ( self, node ): """ Gets the object's children. """ return [ self.node_for( '', self.value ) ] #------------------------------------------------------------------------------- # Define the mapping of object types to nodes: #------------------------------------------------------------------------------- _basic_types = None def basic_types ( ): global _basic_types if _basic_types is None: # Create the mapping of object types to nodes: _basic_types = [ ( type( None ), NoneNode ), ( str, StringNode ), ( unicode, StringNode ), ( bool, BoolNode ), ( int, IntNode ), ( float, FloatNode ), ( complex, ComplexNode ), ( tuple, TupleNode ), ( list, ListNode ), ( set, SetNode ), ( dict, DictNode ), ( FunctionType, FunctionNode ), ( MethodType, MethodNode ), ( HasTraits, TraitsNode ) ] try: from numpy import array _basic_types.append( ( type( array( [ 1 ] ) ), ArrayNode ) ) except ImportError: pass return _basic_types #------------------------------------------------------------------------------- # '_ValueTree' class: #------------------------------------------------------------------------------- class _ValueTree ( HasPrivateTraits ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # List of arbitrary Python values contained in the tree: values = List( SingleValueTreeNodeObject ) #------------------------------------------------------------------------------- # Defines the value tree editor(s): #------------------------------------------------------------------------------- # Nodes in a value tree: value_tree_nodes = [ ObjectTreeNode( node_for = [ NoneNode, StringNode, BoolNode, IntNode, FloatNode, ComplexNode, OtherNode, TupleNode, ListNode, ArrayNode, DictNode, SetNode, FunctionNode, MethodNode, ObjectNode, TraitsNode, RootNode, ClassNode ] ) ] # Editor for a value tree: value_tree_editor = TreeEditor( auto_open = 3, hide_root = True, editable = False, nodes = value_tree_nodes ) # Editor for a value tree with a root: value_tree_editor_with_root = TreeEditor( auto_open = 3, editable = False, nodes = [ ObjectTreeNode( node_for = [ NoneNode, StringNode, BoolNode, IntNode, FloatNode, ComplexNode, OtherNode, TupleNode, ListNode, ArrayNode, DictNode, SetNode, FunctionNode, MethodNode, ObjectNode, TraitsNode, RootNode, ClassNode ] ), TreeNode( node_for = [ _ValueTree ], auto_open = True, children = 'values', move = [ SingleValueTreeNodeObject ], copy = False, label = '=Values', icon_group = 'traits_node', icon_open = 'traits_node' ) ] ) #------------------------------------------------------------------------------- # Defines a 'ValueTree' trait: #------------------------------------------------------------------------------- # Trait for a value tree: ValueTree = Instance( _ValueTree, (), editor = value_tree_editor_with_root ) traitsui-4.1.0/traitsui/dock_window_theme.py0000644000175100001440000000567211674463546022302 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2007, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 07/14/2007 # #------------------------------------------------------------------------------- """ Defines the theme style information for a DockWindow and its components. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import HasPrivateTraits, Bool from .ui_traits import Image, ATheme #------------------------------------------------------------------------------- # 'DockWindowTheme' class: #------------------------------------------------------------------------------- class DockWindowTheme ( HasPrivateTraits ): """ Defines the theme style information for a DockWindow and its components. """ #-- Public Trait Definitions ----------------------------------------------- # Use the theme background color as the DockWindow background color? use_theme_color = Bool( True ) # Draw notebook tabs at the top (True) or the bottom (False)? tabs_at_top = Bool( True ) # Active tab theme: tab_active = ATheme # Inactive tab theme: tab_inactive = ATheme # Optional image to use for right edge of rightmost inactive tab: tab_inactive_edge = Image # Tab hover theme (used for inactive tabs): tab_hover = ATheme # Optional image to use for right edge of rightmost hover tab: tab_hover_edge = Image # Tab background theme: tab_background = ATheme # Tab theme: tab = ATheme # Vertical splitter bar theme: vertical_splitter = ATheme # Horizontal splitter bar theme: horizontal_splitter = ATheme # Vertical drag bar theme: vertical_drag = ATheme # Horizontal drag bar theme: horizontal_drag = ATheme #------------------------------------------------------------------------------- # Define the default theme: #------------------------------------------------------------------------------- # The current default DockWindow theme: _dock_window_theme = None # Gets/Sets the default DockWindow theme: def dock_window_theme ( theme = None ): global _dock_window_theme if _dock_window_theme is None: from .default_dock_window_theme import default_dock_window_theme _dock_window_theme = default_dock_window_theme old_theme = _dock_window_theme if theme is not None: _dock_window_theme = theme return old_theme traitsui-4.1.0/traitsui/ui_editors/0000755000175100001440000000000011674463546020373 5ustar ischnellusers00000000000000traitsui-4.1.0/traitsui/ui_editors/__init__.py0000644000175100001440000000123211674463546022502 0ustar ischnellusers00000000000000#---------------------------------------------------------------------------- # # Copyright (c) 2005-2011, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 03/24/2008 # #---------------------------------------------------------------------------- from __future__ import absolute_import traitsui-4.1.0/traitsui/ui_editors/array_view_editor.py0000644000175100001440000001375211674463546024473 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2007, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 08/29/2007 #------------------------------------------------------------------------------- """ Defines an ArrayViewEditor for displaying 1-d or 2-d arrays of values. """ #-- Imports -------------------------------------------------------------------- from __future__ import absolute_import from traits.api import Instance, Property, List, Str, Bool, Font from ..api import View, Item, TabularEditor, BasicEditorFactory from ..tabular_adapter import TabularAdapter from ..toolkit import toolkit_object from ..ui_editor import UIEditor #-- Tabular Adapter Definition ------------------------------------------------- class ArrayViewAdapter ( TabularAdapter ): # Is the array 1D or 2D? is_2d = Bool( True ) # Should array rows and columns be transposed: transpose = Bool( False ) alignment = 'right' index_text = Property def _get_index_text ( self ): return str( self.row ) def _get_content ( self ): if self.is_2d: return self.item[ self.column_id ] return self.item def get_item ( self, object, trait, row ): """ Returns the value of the *object.trait[row]* item. """ if self.is_2d: if self.transpose: return getattr( object, trait )[:,row] return super( ArrayViewAdapter, self ).get_item( object, trait, row ) return getattr( object, trait )[ row ] def len ( self, object, trait ): """ Returns the number of items in the specified *object.trait* list. """ if self.transpose: return getattr( object, trait ).shape[1] return super( ArrayViewAdapter, self ).len( object, trait ) # Define the actual abstract Traits UI array view editor (each backend should # implement its own editor that inherits from this class. class _ArrayViewEditor ( UIEditor ): # Indicate that the editor is scrollable/resizable: scrollable = True # Should column titles be displayed: show_titles = Bool( False ) # The tabular adapter being used for the editor view: adapter = Instance( ArrayViewAdapter ) #-- Private Methods -------------------------------------------------------- def _array_view ( self ): """ Return the view used by the editor. """ return View( Item( 'object.object.' + self.name, id = 'tabular_editor', show_label = False, editor = TabularEditor( show_titles = self.show_titles, editable = False, adapter = self.adapter ) ), id = 'array_view_editor', resizable = True ) def init_ui ( self, parent ): """ Creates the Traits UI for displaying the array. """ # Make sure that the value is an array of the correct shape: shape = self.value.shape len_shape = len( shape ) if (len_shape == 0) or (len_shape > 2): raise ValueError( "ArrayViewEditor can only display 1D or 2D " "arrays" ) factory = self.factory cols = 1 titles = factory.titles n = len( titles ) self.show_titles = (n > 0) is_2d = (len_shape == 2) if is_2d: index = 1 if factory.transpose: index = 0 cols = shape[ index ] if self.show_titles: if n > cols: titles = titles[:cols] elif n < cols: if (cols % n) == 0: titles, old_titles, i = [], titles, 0 while len( titles ) < cols: titles.extend( '%s%d' % ( title, i ) for title in old_titles ) i += 1 else: titles.extend( [ '' ] * (cols - n) ) else: titles = [ 'Data %d' % i for i in range( cols ) ] columns = [ ( title, i ) for i, title in enumerate( titles ) ] if factory.show_index: columns.insert( 0, ( 'Index', 'index' ) ) self.adapter = ArrayViewAdapter( is_2d = is_2d, columns = columns, transpose = factory.transpose, format = factory.format, font = factory.font ) return self.edit_traits( view = '_array_view', parent = parent, kind = 'subpanel' ) # Define the ArrayViewEditor class used by client code: class ArrayViewEditor ( BasicEditorFactory ): # The editor implementation class: klass = Property # Should an index column be displayed: show_index = Bool( True ) # List of (optional) column titles: titles = List( Str ) # Should the array be logically transposed: transpose = Bool( False ) # The format used to display each array element: format = Str( '%s' ) # The font to use for displaying each array element: font = Font( 'Courier 10' ) def _get_klass( self ): """ The class used to construct editor objects. """ return toolkit_object('array_view_editor:_ArrayViewEditor') traitsui-4.1.0/traitsui/instance_choice.py0000644000175100001440000002331511674463546021721 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 08/25/2005 # #------------------------------------------------------------------------------ """ Defines the various instance descriptors used by the instance editor and instance editor factory classes. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import HasPrivateTraits, Str, Any, Dict, Tuple, Callable, Bool from .ui_traits import AView from .helper import user_name_for #------------------------------------------------------------------------------- # 'InstanceChoiceItem' class: #------------------------------------------------------------------------------- class InstanceChoiceItem ( HasPrivateTraits ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # User interface name for the item name = Str # View associated with this item view = AView # Does this item create new instances? is_factory = Bool( False ) #--------------------------------------------------------------------------- # Returns the name of the item: #--------------------------------------------------------------------------- def get_name ( self, object = None ): """ Returns the name of the item. """ return self.name #--------------------------------------------------------------------------- # Return the view associated with the object: #--------------------------------------------------------------------------- def get_view ( self ): """ Returns the view associated with the object. """ return self.view #--------------------------------------------------------------------------- # Returns the object associated with the item: #--------------------------------------------------------------------------- def get_object ( self ): """ Returns the object associated with the item. """ raise NotImplementedError #--------------------------------------------------------------------------- # Indicates whether a specified object is compatible with the item: #--------------------------------------------------------------------------- def is_compatible ( self, object ): """ Indicates whether a specified object is compatible with the item. """ raise NotImplementedError #--------------------------------------------------------------------------- # Indicates whether the item can be selected by the user: #--------------------------------------------------------------------------- def is_selectable ( self ): """ Indicates whether the item can be selected by the user. """ return True #--------------------------------------------------------------------------- # Indicates whether the item supports drag and drop: #--------------------------------------------------------------------------- def is_droppable ( self ): """ Indicates whether the item supports drag and drop. """ return False #------------------------------------------------------------------------------- # 'InstanceChoice' class: #------------------------------------------------------------------------------- class InstanceChoice ( InstanceChoiceItem ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Object associated with the item object = Any # The name of the object trait containing its user interface name: name_trait = Str( 'name' ) #--------------------------------------------------------------------------- # Returns the name of the item: #--------------------------------------------------------------------------- def get_name ( self, object = None ): """ Returns the name of the item. """ if self.name != '': return self.name name = getattr( self.object, self.name_trait, None ) if isinstance( name, basestring ): return name return user_name_for( self.object.__class__.__name__ ) #--------------------------------------------------------------------------- # Returns the object associated with the item: #--------------------------------------------------------------------------- def get_object ( self ): """ Returns the object associated with the item. """ return self.object #--------------------------------------------------------------------------- # Indicates whether a specified object is compatible with the item: #--------------------------------------------------------------------------- def is_compatible ( self, object ): """ Indicates whether a specified object is compatible with the item. """ return (object is self.object) #------------------------------------------------------------------------------- # 'InstanceFactoryChoice' class: #------------------------------------------------------------------------------- class InstanceFactoryChoice ( InstanceChoiceItem ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Indicates whether an instance compatible with this item can be dragged and # dropped rather than created droppable = Bool( False ) # Indicates whether the item can be selected by the user selectable = Bool( True ) # A class (or other callable) that can be used to create an item compatible # with this item klass = Callable # Tuple of arguments to pass to **klass** to create an instance args = Tuple # Dictionary of arguments to pass to **klass** to create an instance kw_args = Dict( Str, Any ) # Does this item create new instances? This value overrides the default. is_factory = True #--------------------------------------------------------------------------- # Returns the name of the item: #--------------------------------------------------------------------------- def get_name ( self, object = None ): """ Returns the name of the item. """ if self.name != '': return self.name name = getattr( object, 'name', None ) if isinstance(name, basestring): return name if issubclass( type( self.klass ), type ): klass = self.klass else: klass = self.get_object().__class__ return user_name_for( klass.__name__ ) #--------------------------------------------------------------------------- # Returns the object associated with the item: #--------------------------------------------------------------------------- def get_object ( self ): """ Returns the object associated with the item. """ return self.klass( *self.args, **self.kw_args ) #--------------------------------------------------------------------------- # Indicates whether the item supports drag and drop: #--------------------------------------------------------------------------- def is_droppable ( self ): """ Indicates whether the item supports drag and drop. """ return self.droppable #--------------------------------------------------------------------------- # Indicates whether a specified object is compatible with the item: #--------------------------------------------------------------------------- def is_compatible ( self, object ): """ Indicates whether a specified object is compatible with the item. """ if issubclass( type( self.klass ), type ): return isinstance( object, self.klass ) return isinstance( object, self.get_object().__class__ ) #--------------------------------------------------------------------------- # Indicates whether the item can be selected by the user: #--------------------------------------------------------------------------- def is_selectable ( self ): """ Indicates whether the item can be selected by the user. """ return self.selectable #------------------------------------------------------------------------------- # 'InstanceDropChoice' class: #------------------------------------------------------------------------------- class InstanceDropChoice ( InstanceFactoryChoice ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Indicates whether an instance compatible with this item can be dragged and # dropped rather than created . This value overrides the default. droppable = True # Indicates whether the item can be selected by the user. This value # overrides the default. selectable = False # Does this item create new instances? This value overrides the default. is_factory = False traitsui-4.1.0/traitsui/tree_node.py0000644000175100001440000025163711674463546020561 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 12/03/2004 # #------------------------------------------------------------------------------ """ Defines the tree node descriptor used by the tree editor and tree editor factory classes. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import (AdaptedTo, Adapter, Any, Bool, Callable, Either, HasPrivateTraits, Instance, Interface, List, Property, Str, cached_property) from traits.trait_base import SequenceTypes, get_resource_path, xgetattr, xsetattr from .ui_traits import AView #------------------------------------------------------------------------------- # 'TreeNode' class: #------------------------------------------------------------------------------- class TreeNode ( HasPrivateTraits ): """ Represents a tree node. Used by the tree editor and tree editor factory classes. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Name of trait containing children (if '', the node is a leaf). children = Str # Either the name of a trait containing a label, or a constant label, if # the string starts with '='. label = Str # The name of a trait containing a list of labels for any columns. column_labels = Str # Either the name of a trait containing a tooltip, or constant tooltip, if # the string starts with '='. tooltip = Str # Name to use for a new instance name = Str # Can the object's children be renamed? rename = Bool( True ) # Can the object be renamed? rename_me = Bool( True ) # Can the object's children be copied? copy = Bool( True ) # Can the object's children be deleted? delete = Bool( True ) # Can the object be deleted (if its parent allows it)? delete_me = Bool( True ) # Can children be inserted (vs. appended)? insert = Bool( True ) # Should tree nodes be automatically opened (expanded)? auto_open = Bool( False ) # Automatically close sibling tree nodes? auto_close = Bool( False ) # List of object classes than can be added or copied add = List( Any ) # List of object classes that can be moved move = List( Any ) # List of object classes and/or interfaces that the node applies to node_for = List( Any ) # Tuple of object classes that the node applies to node_for_class = Property( depends_on = 'node_for' ) # List of object interfaces that the node applies to node_for_interface = Property( depends_on = 'node_for' ) # Function for formatting the label formatter = Callable # Functions for formatting the other columns. column_formatters = List(Either(None, Callable)) # Function for formatting the tooltip tooltip_formatter = Callable # Function for handling selecting an object on_select = Callable # Function for handling clicking an object on_click = Callable # Function for handling double-clicking an object on_dclick = Callable # View to use for editing the object view = AView # Right-click context menu. The value can be one of: # # - Instance( Menu ): Use this menu as the context menu # - None: Use the default context menu # - False: Do not display a context menu menu = Any # Name of leaf item icon icon_item = Str( '' ) # Name of group item icon icon_group = Str( '' ) # Name of opened group item icon icon_open = Str( '' ) # Resource path used to locate the node icon icon_path = Str # Selector or name for background color background = Any # Selector or name for foreground color foreground = Any # fixme: The 'menu' trait should really be defined as: # Instance( 'traitsui.menu.MenuBar' ), but it doesn't work # right currently. #--------------------------------------------------------------------------- # Initializes the object: #--------------------------------------------------------------------------- def __init__ ( self, **traits ): super( TreeNode, self ).__init__( **traits ) if self.icon_path == '': self.icon_path = get_resource_path() #-- Property Implementations ----------------------------------------------- @cached_property def _get_node_for_class ( self ): return tuple( [ klass for klass in self.node_for if not issubclass( klass, Interface ) ] ) @cached_property def _get_node_for_interface ( self ): return [ klass for klass in self.node_for if issubclass( klass, Interface ) ] #-- Overridable Methods: --------------------------------------------------- #--------------------------------------------------------------------------- # Returns whether chidren of this object are allowed or not: #--------------------------------------------------------------------------- def allows_children ( self, object ): """ Returns whether this object can have children. """ return (self.children != '') #--------------------------------------------------------------------------- # Returns whether or not the object has children: #--------------------------------------------------------------------------- def has_children ( self, object ): """ Returns whether the object has children. """ return (len( self.get_children( object ) ) > 0) #--------------------------------------------------------------------------- # Gets the object's children: #--------------------------------------------------------------------------- def get_children ( self, object ): """ Gets the object's children. """ return getattr( object, self.children ) #--------------------------------------------------------------------------- # Gets the object's children identifier: #--------------------------------------------------------------------------- def get_children_id ( self, object ): """ Gets the object's children identifier. """ return self.children #--------------------------------------------------------------------------- # Appends a child to the object's children: #--------------------------------------------------------------------------- def append_child ( self, object, child ): """ Appends a child to the object's children. """ getattr( object, self.children ).append( child ) #--------------------------------------------------------------------------- # Inserts a child into the object's children: #--------------------------------------------------------------------------- def insert_child ( self, object, index, child ): """ Inserts a child into the object's children. """ getattr( object, self.children )[ index: index ] = [ child ] #--------------------------------------------------------------------------- # Confirms that a specified object can be deleted or not: # Result = True: Delete object with no further prompting # = False: Do not delete object # = other: Take default action (may prompt user to confirm delete) #--------------------------------------------------------------------------- def confirm_delete ( self, object ): """ Checks whether a specified object can be deleted. Returns ------- * **True** if the object should be deleted with no further prompting. * **False** if the object should not be deleted. * Anything else: Caller should take its default action (which might include prompting the user to confirm deletion). """ return None #--------------------------------------------------------------------------- # Deletes a child at a specified index from the object's children: #--------------------------------------------------------------------------- def delete_child ( self, object, index ): """ Deletes a child at a specified index from the object's children. """ del getattr( object, self.children )[ index ] #--------------------------------------------------------------------------- # Sets up/Tears down a listener for 'children replaced' on a specified # object: #--------------------------------------------------------------------------- def when_children_replaced ( self, object, listener, remove ): """ Sets up or removes a listener for children being replaced on a specified object. """ object.on_trait_change( listener, self.children, remove = remove, dispatch = 'fast_ui' ) #--------------------------------------------------------------------------- # Sets up/Tears down a listener for 'children changed' on a specified # object: #--------------------------------------------------------------------------- def when_children_changed ( self, object, listener, remove ): """ Sets up or removes a listener for children being changed on a specified object. """ object.on_trait_change( listener, self.children + '_items', remove = remove, dispatch = 'fast_ui' ) #--------------------------------------------------------------------------- # Gets the label to display for a specified object: #--------------------------------------------------------------------------- def get_label ( self, object ): """ Gets the label to display for a specified object. """ label = self.label if label[:1] == '=': return label[1:] label = xgetattr( object, label, '' ) if self.formatter is None: return label return self.formatter( object, label ) #--------------------------------------------------------------------------- # Sets the label for a specified object: #--------------------------------------------------------------------------- def set_label ( self, object, label ): """ Sets the label for a specified object. """ label_name = self.label if label_name[:1] != '=': xsetattr( object, label_name, label ) #--------------------------------------------------------------------------- # Sets up/Tears down a listener for 'label changed' on a specified object: #--------------------------------------------------------------------------- def when_label_changed ( self, object, listener, remove ): """ Sets up or removes a listener for the label being changed on a specified object. """ label = self.label if label[:1] != '=': object.on_trait_change( listener, label, remove = remove, dispatch = 'ui' ) def get_column_labels(self, object): """ Get the labels for any columns that have been defined. """ trait = self.column_labels labels = xgetattr(object, trait, []) formatted = [] for formatter, label in map(None, self.column_formatters, labels): # If the list of column formatters is shorter than the list of # labels, then map(None) will extend it with Nones. Just pass the label # as preformatted. Similarly, explicitly using None in the list will # pass through the item. if formatter is None: formatted.append(label) else: formatted.append(formatter(label)) return formatted def when_column_labels_change(self, object, listener, remove): """ Sets up or removes a listener for the column labels being changed on a specified object. This will fire when either the list is reassigned or when it is modified. I.e., it listens both to the trait change event and the trait_items change event. Implement the listener appropriately to handle either case. """ trait = self.column_labels if trait != '': object.on_trait_change(listener, trait, remove=remove, dispatch='ui') object.on_trait_change(listener, trait+'_items', remove=remove, dispatch='ui') #--------------------------------------------------------------------------- # Gets the tooltip to display for a specified object: #--------------------------------------------------------------------------- def get_tooltip ( self, object ): """ Gets the tooltip to display for a specified object. """ tooltip = self.tooltip if tooltip == '': return tooltip if tooltip[:1] == '=': return tooltip[1:] tooltip = xgetattr( object, tooltip, '' ) if self.tooltip_formatter is None: return tooltip return self.tooltip_formatter( object, tooltip ) #--------------------------------------------------------------------------- # Returns the icon for a specified object: #--------------------------------------------------------------------------- def get_icon ( self, object, is_expanded ): """ Returns the icon for a specified object. """ if not self.allows_children( object ): return self.icon_item if is_expanded: return self.icon_open return self.icon_group #--------------------------------------------------------------------------- # Returns the path used to locate an object's icon: #--------------------------------------------------------------------------- def get_icon_path ( self, object ): """ Returns the path used to locate an object's icon. """ return self.icon_path #--------------------------------------------------------------------------- # Returns the name to use when adding a new object instance (displayed in # the 'New' submenu): #--------------------------------------------------------------------------- def get_name ( self, object ): """ Returns the name to use when adding a new object instance (displayed in the "New" submenu). """ return self.name #--------------------------------------------------------------------------- # Gets the View to use when editing an object: #--------------------------------------------------------------------------- def get_view ( self, object ): """ Gets the view to use when editing an object. """ return self.view #--------------------------------------------------------------------------- # Returns the right-click context menu for an object: #--------------------------------------------------------------------------- def get_menu ( self, object ): """ Returns the right-click context menu for an object. """ return self.menu def get_background(self, object) : background = self.background if isinstance(background, basestring) : background = getattr(object, background, background) return background def get_foreground(self, object) : foreground = self.foreground if isinstance(foreground, basestring) : foreground = getattr(object, foreground, foreground) return foreground #--------------------------------------------------------------------------- # Returns whether or not the object's children can be renamed: #--------------------------------------------------------------------------- def can_rename ( self, object ): """ Returns whether the object's children can be renamed. """ return self.rename #--------------------------------------------------------------------------- # Returns whether or not the object can be renamed: #--------------------------------------------------------------------------- def can_rename_me ( self, object ): """ Returns whether the object can be renamed. """ return self.rename_me #--------------------------------------------------------------------------- # Returns whether or not the object's children can be copied: #--------------------------------------------------------------------------- def can_copy ( self, object ): """ Returns whether the object's children can be copied. """ return self.copy #--------------------------------------------------------------------------- # Returns whether or not the object's children can be deleted: #--------------------------------------------------------------------------- def can_delete ( self, object ): """ Returns whether the object's children can be deleted. """ return self.delete #--------------------------------------------------------------------------- # Returns whether or not the object can be deleted: #--------------------------------------------------------------------------- def can_delete_me ( self, object ): """ Returns whether the object can be deleted. """ return self.delete_me #--------------------------------------------------------------------------- # Returns whether or not the object's children can be inserted (or just # appended): #--------------------------------------------------------------------------- def can_insert ( self, object ): """ Returns whether the object's children can be inserted (vs. appended). """ return self.insert #--------------------------------------------------------------------------- # Returns whether or not the object's children should be auto-opened: #--------------------------------------------------------------------------- def can_auto_open ( self, object ): """ Returns whether the object's children should be automatically opened. """ return self.auto_open #--------------------------------------------------------------------------- # Returns whether or not the object's children should be auto-closed: #--------------------------------------------------------------------------- def can_auto_close ( self, object ): """ Returns whether the object's children should be automatically closed. """ return self.auto_close #--------------------------------------------------------------------------- # Returns whether or not this is the node that should handle a specified # object: #--------------------------------------------------------------------------- def is_node_for ( self, object ): """ Returns whether this is the node that handles a specified object. """ return (isinstance( object, self.node_for_class ) or object.has_traits_interface( *self.node_for_interface )) #--------------------------------------------------------------------------- # Returns whether a given 'add_object' can be added to an object: #--------------------------------------------------------------------------- def can_add ( self, object, add_object ): """ Returns whether a given object is droppable on the node. """ klass = self._class_for( add_object ) if self.is_addable( klass ): return True for item in self.move: if type( item ) in SequenceTypes: item = item[0] if issubclass( klass, item ): return True return False #--------------------------------------------------------------------------- # Returns the list of classes that can be added to the object: #--------------------------------------------------------------------------- def get_add ( self, object ): """ Returns the list of classes that can be added to the object. """ return self.add #--------------------------------------------------------------------------- # Returns the 'draggable' version of a specified object: #--------------------------------------------------------------------------- def get_drag_object ( self, object ): """ Returns a draggable version of a specified object. """ return object #--------------------------------------------------------------------------- # Returns a droppable version of a specified object: #--------------------------------------------------------------------------- def drop_object ( self, object, dropped_object ): """ Returns a droppable version of a specified object. """ klass = self._class_for( dropped_object ) if self.is_addable( klass ): return dropped_object for item in self.move: if type( item ) in SequenceTypes: if issubclass( klass, item[0] ): return item[1]( object, dropped_object ) elif issubclass( klass, item ): return dropped_object return dropped_object #--------------------------------------------------------------------------- # Handles an object being selected: #--------------------------------------------------------------------------- def select ( self, object ): """ Handles an object being selected. """ if self.on_select is not None: self.on_select( object ) return None return True #--------------------------------------------------------------------------- # Handles an object being clicked: #--------------------------------------------------------------------------- def click ( self, object ): """ Handles an object being clicked. """ if self.on_click is not None: self.on_click( object ) return None return True #--------------------------------------------------------------------------- # Handles an object being double-clicked: #--------------------------------------------------------------------------- def dclick ( self, object ): """ Handles an object being double-clicked. """ if self.on_dclick is not None: self.on_dclick( object ) return None return True #--------------------------------------------------------------------------- # Returns whether or not a specified object class can be added to the node: #--------------------------------------------------------------------------- def is_addable ( self, klass ): """ Returns whether a specified object class can be added to the node. """ for item in self.add: if type( item ) in SequenceTypes: item = item[0] if issubclass( klass, item ): return True return False #--------------------------------------------------------------------------- # Returns the class of an object: #--------------------------------------------------------------------------- def _class_for ( self, object ): """ Returns the class of an object. """ if isinstance( object, type ): return object return object.__class__ #------------------------------------------------------------------------------- # 'ITreeNode' class #------------------------------------------------------------------------------- class ITreeNode ( Interface ): def allows_children ( self ): """ Returns whether this object can have children. """ def has_children ( self ): """ Returns whether the object has children. """ def get_children ( self ): """ Gets the object's children. """ def get_children_id ( self ): """ Gets the object's children identifier. """ def append_child ( self, child ): """ Appends a child to the object's children. """ def insert_child ( self, index, child ): """ Inserts a child into the object's children. """ def confirm_delete ( self ): """ Checks whether a specified object can be deleted. Returns ------- * **True** if the object should be deleted with no further prompting. * **False** if the object should not be deleted. * Anything else: Caller should take its default action (which might include prompting the user to confirm deletion). """ def delete_child ( self, index ): """ Deletes a child at a specified index from the object's children. """ def when_children_replaced ( self, listener, remove ): """ Sets up or removes a listener for children being replaced on a specified object. """ def when_children_changed ( self, listener, remove ): """ Sets up or removes a listener for children being changed on a specified object. """ def get_label ( self ): """ Gets the label to display for a specified object. """ def set_label ( self, label ): """ Sets the label for a specified object. """ def when_label_changed ( self, listener, remove ): """ Sets up or removes a listener for the label being changed on a specified object. """ def get_column_labels(self, object): """ Get the labels for any columns that have been defined. """ def when_column_labels_change(self, object, listener, remove): """ Sets up or removes a listener for the column labels being changed on a specified object. This will fire when either the list is reassigned or when it is modified. I.e., it listens both to the trait change event and the trait_items change event. Implement the listener appropriately to handle either case. """ def get_tooltip ( self ): """ Gets the tooltip to display for a specified object. """ def get_icon ( self, is_expanded ): """ Returns the icon for a specified object. """ def get_icon_path ( self ): """ Returns the path used to locate an object's icon. """ def get_name ( self ): """ Returns the name to use when adding a new object instance (displayed in the "New" submenu). """ def get_view ( self ): """ Gets the view to use when editing an object. """ def get_menu ( self ): """ Returns the right-click context menu for an object. """ def can_rename ( self ): """ Returns whether the object's children can be renamed. """ def can_rename_me ( self ): """ Returns whether the object can be renamed. """ def can_copy ( self ): """ Returns whether the object's children can be copied. """ def can_delete ( self ): """ Returns whether the object's children can be deleted. """ def can_delete_me ( self ): """ Returns whether the object can be deleted. """ def can_insert ( self ): """ Returns whether the object's children can be inserted (vs. appended). """ def can_auto_open ( self ): """ Returns whether the object's children should be automatically opened. """ def can_auto_close ( self ): """ Returns whether the object's children should be automatically closed. """ def can_add ( self, add_object ): """ Returns whether a given object is droppable on the node. """ def get_add ( self ): """ Returns the list of classes that can be added to the object. """ def get_drag_object ( self ): """ Returns a draggable version of a specified object. """ def drop_object ( self, dropped_object ): """ Returns a droppable version of a specified object. """ def select ( self ): """ Handles an object being selected. """ def click ( self ): """ Handles an object being clicked. """ def dclick ( self ): """ Handles an object being double-clicked. """ #------------------------------------------------------------------------------- # 'ITreeNodeAdapter' class #------------------------------------------------------------------------------- class ITreeNodeAdapter ( Adapter ): """ Abstract base class for an adapter that implements the ITreeNode interface. Usage: 1. Create a subclass of ITreeNodeAdapter. 2. Add an 'adapts( xxx_class, ITreeNode )' declaration (usually placed right after the 'class' statement) to define what class (or classes) this is an ITreeNode adapter for. 3. Override any of the following methods as necessary, using the 'self.adaptee' trait to access the adapted object if needed. Note: This base class implements all of the ITreeNode interface methods, but does not necessarily provide useful implementations for all of the methods. It allows you to get a new adapter class up and running quickly, but you should carefully review your final adapter implementation class to make sure it behaves correctly in your application. """ def allows_children ( self ): """ Returns whether this object can have children. """ return False def has_children ( self ): """ Returns whether the object has children. """ return False def get_children ( self ): """ Gets the object's children. """ return [] def get_children_id ( self ): """ Gets the object's children identifier. """ return '' def append_child ( self, child ): """ Appends a child to the object's children. """ pass def insert_child ( self, index, child ): """ Inserts a child into the object's children. """ pass def confirm_delete ( self ): """ Checks whether a specified object can be deleted. Returns ------- * **True** if the object should be deleted with no further prompting. * **False** if the object should not be deleted. * Anything else: Caller should take its default action (which might include prompting the user to confirm deletion). """ return False def delete_child ( self, index ): """ Deletes a child at a specified index from the object's children. """ pass def when_children_replaced ( self, listener, remove ): """ Sets up or removes a listener for children being replaced on a specified object. """ pass def when_children_changed ( self, listener, remove ): """ Sets up or removes a listener for children being changed on a specified object. """ pass def get_label ( self ): """ Gets the label to display for a specified object. """ return 'No label specified' def set_label ( self, label ): """ Sets the label for a specified object. """ pass def when_label_changed ( self, listener, remove ): """ Sets up or removes a listener for the label being changed on a specified object. """ pass def get_column_labels(self): """ Get the labels for any columns that have been defined. """ return [] def when_column_labels_change(self, listener, remove): """ Sets up or removes a listener for the column labels being changed on a specified object. This will fire when either the list is reassigned or when it is modified. I.e., it listens both to the trait change event and the trait_items change event. Implement the listener appropriately to handle either case. """ pass def get_tooltip ( self ): """ Gets the tooltip to display for a specified object. """ return '' def get_icon ( self, is_expanded ): """ Returns the icon for a specified object. """ return '' def get_icon_path ( self ): """ Returns the path used to locate an object's icon. """ return '' def get_name ( self ): """ Returns the name to use when adding a new object instance (displayed in the "New" submenu). """ return '' def get_view ( self ): """ Gets the view to use when editing an object. """ return None def get_menu ( self ): """ Returns the right-click context menu for an object. """ return None def get_background ( self ): """ Returns the background for object """ return None def get_foreground ( self ): """ Returns the foreground for object """ return None def can_rename ( self ): """ Returns whether the object's children can be renamed. """ return False def can_rename_me ( self ): """ Returns whether the object can be renamed. """ return False def can_copy ( self ): """ Returns whether the object's children can be copied. """ return False def can_delete ( self ): """ Returns whether the object's children can be deleted. """ return False def can_delete_me ( self ): """ Returns whether the object can be deleted. """ return False def can_insert ( self ): """ Returns whether the object's children can be inserted (vs. appended). """ return False def can_auto_open ( self ): """ Returns whether the object's children should be automatically opened. """ return False def can_auto_close ( self ): """ Returns whether the object's children should be automatically closed. """ return False def can_add ( self, add_object ): """ Returns whether a given object is droppable on the node. """ return False def get_add ( self ): """ Returns the list of classes that can be added to the object. """ return [] def get_drag_object ( self ): """ Returns a draggable version of a specified object. """ return self.adaptee def drop_object ( self, dropped_object ): """ Returns a droppable version of a specified object. """ return dropped_object def select ( self ): """ Handles an object being selected. """ pass def click ( self ): """ Handles an object being clicked. """ pass def dclick ( self ): """ Handles an object being double-clicked. """ pass #------------------------------------------------------------------------------- # 'ITreeNodeAdapterBridge' class #------------------------------------------------------------------------------- class ITreeNodeAdapterBridge ( HasPrivateTraits ): """ Private class for use by a toolkit-specific implementation of the TreeEditor to allow bridging the TreeNode interface used by the editor to the ITreeNode interface used by object adapters. """ # The ITreeNode adapter being bridged: adapter = AdaptedTo( ITreeNode ) #-- TreeNode implementation ------------------------------------------------ def allows_children ( self, object ): """ Returns whether this object can have children. """ return self.adapter.allows_children() def has_children ( self, object ): """ Returns whether the object has children. """ return self.adapter.has_children() def get_children ( self, object ): """ Gets the object's children. """ return self.adapter.get_children() def get_children_id ( self, object ): """ Gets the object's children identifier. """ return self.adapter.get_children_id() def append_child ( self, object, child ): """ Appends a child to the object's children. """ return self.adapter.append_child( child ) def insert_child ( self, object, index, child ): """ Inserts a child into the object's children. """ return self.adapter.insert_child( index, child ) def confirm_delete ( self, object ): """ Checks whether a specified object can be deleted. Returns ------- * **True** if the object should be deleted with no further prompting. * **False** if the object should not be deleted. * Anything else: Caller should take its default action (which might include prompting the user to confirm deletion). """ return self.adapter.confirm_delete() def delete_child ( self, object, index ): """ Deletes a child at a specified index from the object's children. """ return self.adapter.delete_child( index ) def when_children_replaced ( self, object, listener, remove ): """ Sets up or removes a listener for children being replaced on a specified object. """ return self.adapter.when_children_replaced( listener, remove ) def when_children_changed ( self, object, listener, remove ): """ Sets up or removes a listener for children being changed on a specified object. """ return self.adapter.when_children_changed( listener, remove ) def get_label ( self, object ): """ Gets the label to display for a specified object. """ return self.adapter.get_label() def set_label ( self, object, label ): """ Sets the label for a specified object. """ return self.adapter.set_label( label ) def when_label_changed ( self, object, listener, remove ): """ Sets up or removes a listener for the label being changed on a specified object. """ return self.adapter.when_label_changed( listener, remove ) def get_column_labels(self, object): """ Get the labels for any columns that have been defined. """ return self.adapter.get_column_labels() def when_column_labels_change(self, object, listener, remove): """ Sets up or removes a listener for the column labels being changed on a specified object. This will fire when either the list is reassigned or when it is modified. I.e., it listens both to the trait change event and the trait_items change event. Implement the listener appropriately to handle either case. """ return self.adapter.when_column_labels_change(listener, remove) def get_tooltip ( self, object ): """ Gets the tooltip to display for a specified object. """ return self.adapter.get_tooltip() def get_icon ( self, object, is_expanded ): """ Returns the icon for a specified object. """ return self.adapter.get_icon( is_expanded ) def get_icon_path ( self, object ): """ Returns the path used to locate an object's icon. """ return self.adapter.get_icon_path() def get_name ( self, object ): """ Returns the name to use when adding a new object instance (displayed in the "New" submenu). """ return self.adapter.get_name() def get_view ( self, object ): """ Gets the view to use when editing an object. """ return self.adapter.get_view() def get_menu ( self, object ): """ Returns the right-click context menu for an object. """ return self.adapter.get_menu() def get_background ( self, object ): """ Returns the background for object """ return self.adapter.get_background() def get_foreground ( self, object ): """ Returns the foreground for object """ return self.adapter.get_foreground() def can_rename ( self, object ): """ Returns whether the object's children can be renamed. """ return self.adapter.can_rename() def can_rename_me ( self, object ): """ Returns whether the object can be renamed. """ return self.adapter.can_rename_me() def can_copy ( self, object ): """ Returns whether the object's children can be copied. """ return self.adapter.can_copy() def can_delete ( self, object ): """ Returns whether the object's children can be deleted. """ return self.adapter.can_delete() def can_delete_me ( self, object ): """ Returns whether the object can be deleted. """ return self.adapter.can_delete_me() def can_insert ( self, object ): """ Returns whether the object's children can be inserted (vs. appended). """ return self.adapter.can_insert() def can_auto_open ( self, object ): """ Returns whether the object's children should be automatically opened. """ return self.adapter.can_auto_open() def can_auto_close ( self, object ): """ Returns whether the object's children should be automatically closed. """ return self.adapter.can_auto_close() def can_add ( self, object, add_object ): """ Returns whether a given object is droppable on the node. """ return self.adapter.can_add( add_object ) def get_add ( self, object ): """ Returns the list of classes that can be added to the object. """ return self.adapter.get_add() def get_drag_object ( self, object ): """ Returns a draggable version of a specified object. """ return self.adapter.get_drag_object() def drop_object ( self, object, dropped_object ): """ Returns a droppable version of a specified object. """ return self.adapter.drop_object( dropped_object ) def select ( self, object ): """ Handles an object being selected. """ return self.adapter.select() def click ( self, object ): """ Handles an object being clicked. """ return self.adapter.click() def dclick ( self, object ): """ Handles an object being double-clicked. """ return self.adapter.dclick() # FIXME RTK: add the column_labels API to the following TreeNodes, too. #------------------------------------------------------------------------------- # 'ObjectTreeNode' class #------------------------------------------------------------------------------- class ObjectTreeNode ( TreeNode ): #--------------------------------------------------------------------------- # Returns whether chidren of this object are allowed or not: #--------------------------------------------------------------------------- def allows_children ( self, object ): """ Returns whether this object can have children. """ return object.tno_allows_children( self ) #--------------------------------------------------------------------------- # Returns whether or not the object has children: #--------------------------------------------------------------------------- def has_children ( self, object ): """ Returns whether the object has children. """ return object.tno_has_children( self ) #--------------------------------------------------------------------------- # Gets the object's children: #--------------------------------------------------------------------------- def get_children ( self, object ): """ Gets the object's children. """ return object.tno_get_children( self ) #--------------------------------------------------------------------------- # Gets the object's children identifier: #--------------------------------------------------------------------------- def get_children_id ( self, object ): """ Gets the object's children identifier. """ return object.tno_get_children_id( self ) #--------------------------------------------------------------------------- # Appends a child to the object's children: #--------------------------------------------------------------------------- def append_child ( self, object, child ): """ Appends a child to the object's children. """ return object.tno_append_child( self, child ) #--------------------------------------------------------------------------- # Inserts a child into the object's children: #--------------------------------------------------------------------------- def insert_child ( self, object, index, child ): """ Inserts a child into the object's children. """ return object.tno_insert_child( self, index, child ) #--------------------------------------------------------------------------- # Confirms that a specified object can be deleted or not: # Result = True: Delete object with no further prompting # = False: Do not delete object # = other: Take default action (may prompt user to confirm delete) #--------------------------------------------------------------------------- def confirm_delete ( self, object ): """ Checks whether a specified object can be deleted. Returns ------- * **True** if the object should be deleted with no further prompting. * **False** if the object should not be deleted. * Anything else: Caller should take its default action (which might include prompting the user to confirm deletion). """ return object.tno_confirm_delete( self ) #--------------------------------------------------------------------------- # Deletes a child at a specified index from the object's children: #--------------------------------------------------------------------------- def delete_child ( self, object, index ): """ Deletes a child at a specified index from the object's children. """ return object.tno_delete_child( self, index ) #--------------------------------------------------------------------------- # Sets up/Tears down a listener for 'children replaced' on a specified # object: #--------------------------------------------------------------------------- def when_children_replaced ( self, object, listener, remove ): """ Sets up or removes a listener for children being replaced on a specified object. """ return object.tno_when_children_replaced( self, listener, remove ) #--------------------------------------------------------------------------- # Sets up/Tears down a listener for 'children changed' on a specified # object: #--------------------------------------------------------------------------- def when_children_changed ( self, object, listener, remove ): """ Sets up or removes a listener for children being changed on a specified object. """ return object.tno_when_children_changed( self, listener, remove ) #--------------------------------------------------------------------------- # Gets the label to display for a specified object: #--------------------------------------------------------------------------- def get_label ( self, object ): """ Gets the label to display for a specified object. """ return object.tno_get_label( self ) #--------------------------------------------------------------------------- # Sets the label for a specified object: #--------------------------------------------------------------------------- def set_label ( self, object, label ): """ Sets the label for a specified object. """ return object.tno_set_label( self, label ) #--------------------------------------------------------------------------- # Sets up/Tears down a listener for 'label changed' on a specified object: #--------------------------------------------------------------------------- def when_label_changed ( self, object, listener, remove ): """ Sets up or removes a listener for the label being changed on a specified object. """ return object.tno_when_label_changed( self, listener, remove ) #--------------------------------------------------------------------------- # Gets the tooltip to display for a specified object: #--------------------------------------------------------------------------- def get_tooltip ( self, object ): """ Gets the tooltip to display for a specified object. """ return object.tno_get_tooltip( self ) #--------------------------------------------------------------------------- # Returns the icon for a specified object: #--------------------------------------------------------------------------- def get_icon ( self, object, is_expanded ): """ Returns the icon for a specified object. """ return object.tno_get_icon( self, is_expanded ) #--------------------------------------------------------------------------- # Returns the path used to locate an object's icon: #--------------------------------------------------------------------------- def get_icon_path ( self, object ): """ Returns the path used to locate an object's icon. """ return object.tno_get_icon_path( self ) #--------------------------------------------------------------------------- # Returns the name to use when adding a new object instance (displayed in # the 'New' submenu): #--------------------------------------------------------------------------- def get_name ( self, object ): """ Returns the name to use when adding a new object instance (displayed in the "New" submenu). """ return object.tno_get_name( self ) #--------------------------------------------------------------------------- # Gets the View to use when editing an object: #--------------------------------------------------------------------------- def get_view ( self, object ): """ Gets the view to use when editing an object. """ return object.tno_get_view( self ) #--------------------------------------------------------------------------- # Returns the right-click context menu for an object: #--------------------------------------------------------------------------- def get_menu ( self, object ): """ Returns the right-click context menu for an object. """ return object.tno_get_menu( self ) #--------------------------------------------------------------------------- # Returns whether or not the object's children can be renamed: #--------------------------------------------------------------------------- def can_rename ( self, object ): """ Returns whether the object's children can be renamed. """ return object.tno_can_rename( self ) #--------------------------------------------------------------------------- # Returns whether or not the object can be renamed: #--------------------------------------------------------------------------- def can_rename_me ( self, object ): """ Returns whether the object can be renamed. """ return object.tno_can_rename_me( self ) #--------------------------------------------------------------------------- # Returns whether or not the object's children can be copied: #--------------------------------------------------------------------------- def can_copy ( self, object ): """ Returns whether the object's children can be copied. """ return object.tno_can_copy( self ) #--------------------------------------------------------------------------- # Returns whether or not the object's children can be deleted: #--------------------------------------------------------------------------- def can_delete ( self, object ): """ Returns whether the object's children can be deleted. """ return object.tno_can_delete( self ) #--------------------------------------------------------------------------- # Returns whether or not the object can be deleted: #--------------------------------------------------------------------------- def can_delete_me ( self, object ): """ Returns whether the object can be deleted. """ return object.tno_can_delete_me( self ) #--------------------------------------------------------------------------- # Returns whether or not the object's children can be inserted (or just # appended): #--------------------------------------------------------------------------- def can_insert ( self, object ): """ Returns whether the object's children can be inserted (vs. appended). """ return object.tno_can_insert( self ) #--------------------------------------------------------------------------- # Returns whether or not the object's children should be auto-opened: #--------------------------------------------------------------------------- def can_auto_open ( self, object ): """ Returns whether the object's children should be automatically opened. """ return object.tno_can_auto_open( self ) #--------------------------------------------------------------------------- # Returns whether or not the object's children should be auto-closed: #--------------------------------------------------------------------------- def can_auto_close ( self, object ): """ Returns whether the object's children should be automatically closed. """ return object.tno_can_auto_close( self ) #--------------------------------------------------------------------------- # Returns whether or not this is the node that should handle a specified # object: #--------------------------------------------------------------------------- def is_node_for ( self, object ): """ Returns whether this is the node that should handle a specified object. """ if isinstance( object, TreeNodeObject ): return object.tno_is_node_for( self ) return False #--------------------------------------------------------------------------- # Returns whether a given 'add_object' can be added to an object: #--------------------------------------------------------------------------- def can_add ( self, object, add_object ): """ Returns whether a given object is droppable on the node. """ return object.tno_can_add( self, add_object ) #--------------------------------------------------------------------------- # Returns the list of classes that can be added to the object: #--------------------------------------------------------------------------- def get_add ( self, object ): """ Returns the list of classes that can be added to the object. """ return object.tno_get_add( self ) #--------------------------------------------------------------------------- # Returns the 'draggable' version of a specified object: #--------------------------------------------------------------------------- def get_drag_object ( self, object ): """ Returns a draggable version of a specified object. """ return object.tno_get_drag_object( self ) #--------------------------------------------------------------------------- # Returns a droppable version of a specified object: #--------------------------------------------------------------------------- def drop_object ( self, object, dropped_object ): """ Returns a droppable version of a specified object. """ return object.tno_drop_object( self, dropped_object ) #--------------------------------------------------------------------------- # Handles an object being selected: #--------------------------------------------------------------------------- def select ( self, object ): """ Handles an object being selected. """ return object.tno_select( self ) #--------------------------------------------------------------------------- # Handles an object being clicked: #--------------------------------------------------------------------------- def click ( self, object ): """ Handles an object being clicked. """ return object.tno_click( self ) #--------------------------------------------------------------------------- # Handles an object being double-clicked: #--------------------------------------------------------------------------- def dclick ( self, object ): """ Handles an object being double-clicked. """ return object.tno_dclick( self ) #------------------------------------------------------------------------------- # 'TreeNodeObject' class: #------------------------------------------------------------------------------- class TreeNodeObject ( HasPrivateTraits ): """ Represents the object that corresponds to a tree node. """ #--------------------------------------------------------------------------- # Returns whether chidren of this object are allowed or not: #--------------------------------------------------------------------------- def tno_allows_children ( self, node ): """ Returns whether this object allows children. """ return (node.children != '') #--------------------------------------------------------------------------- # Returns whether or not the object has children: #--------------------------------------------------------------------------- def tno_has_children ( self, node ): """ Returns whether this object has children. """ return (len( self.tno_get_children( node ) ) > 0) #--------------------------------------------------------------------------- # Gets the object's children: #--------------------------------------------------------------------------- def tno_get_children ( self, node ): """ Gets the object's children. """ return getattr( self, node.children ) #--------------------------------------------------------------------------- # Gets the object's children identifier: #--------------------------------------------------------------------------- def tno_get_children_id ( self, node ): """ Gets the object's children identifier. """ return node.children #--------------------------------------------------------------------------- # Appends a child to the object's children: #--------------------------------------------------------------------------- def tno_append_child ( self, node, child ): """ Appends a child to the object's children. """ getattr( self, node.children ).append( child ) #--------------------------------------------------------------------------- # Inserts a child into the object's children: #--------------------------------------------------------------------------- def tno_insert_child ( self, node, index, child ): """ Inserts a child into the object's children. """ getattr( self, node.children )[ index: index ] = [ child ] #--------------------------------------------------------------------------- # Confirms that a specified object can be deleted or not: # Result = True: Delete object with no further prompting # = False: Do not delete object # = other: Take default action (may prompt user to confirm delete) #--------------------------------------------------------------------------- def tno_confirm_delete ( self, node ): """ Checks whether a specified object can be deleted. Returns ------- * **True** if the object should be deleted with no further prompting. * **False** if the object should not be deleted. * Anything else: Caller should take its default action (which might include prompting the user to confirm deletion). """ return None #--------------------------------------------------------------------------- # Deletes a child at a specified index from the object's children: #--------------------------------------------------------------------------- def tno_delete_child ( self, node, index ): """ Deletes a child at a specified index from the object's children. """ del getattr( self, node.children )[ index ] #--------------------------------------------------------------------------- # Sets up/Tears down a listener for 'children replaced' on a specified # object: #--------------------------------------------------------------------------- def tno_when_children_replaced ( self, node, listener, remove ): """ Sets up or removes a listener for children being replaced on a specified object. """ self.on_trait_change( listener, node.children, remove = remove, dispatch = 'fast_ui' ) #--------------------------------------------------------------------------- # Sets up/Tears down a listener for 'children changed' on a specified # object: #--------------------------------------------------------------------------- def tno_when_children_changed ( self, node, listener, remove ): """ Sets up or removes a listener for children being changed on a specified object. """ self.on_trait_change( listener, node.children + '_items', remove = remove, dispatch = 'fast_ui' ) #--------------------------------------------------------------------------- # Gets the label to display for a specified object: #--------------------------------------------------------------------------- def tno_get_label ( self, node ): """ Gets the label to display for a specified object. """ label = node.label if label[:1] == '=': return label[1:] label = xgetattr( self, label ) if node.formatter is None: return label return node.formatter( self, label ) #--------------------------------------------------------------------------- # Sets the label for a specified node: #--------------------------------------------------------------------------- def tno_set_label ( self, node, label ): """ Sets the label for a specified object. """ label_name = node.label if label_name[:1] != '=': xsetattr( self, label_name, label ) #--------------------------------------------------------------------------- # Sets up/Tears down a listener for 'label changed' on a specified object: #--------------------------------------------------------------------------- def tno_when_label_changed ( self, node, listener, remove ): """ Sets up or removes a listener for the label being changed on a specified object. """ label = node.label if label[:1] != '=': self.on_trait_change( listener, label, remove = remove, dispatch = 'ui' ) #--------------------------------------------------------------------------- # Gets the tooltip to display for a specified object: #--------------------------------------------------------------------------- def tno_get_tooltip ( self, node ): """ Gets the tooltip to display for a specified object. """ tooltip = node.tooltip if tooltip == '': return tooltip if tooltip[:1] == '=': return tooltip[1:] tooltip = xgetattr( self, tooltip ) if node.tooltip_formatter is None: return tooltip return node.tooltip_formatter( self, tooltip ) #--------------------------------------------------------------------------- # Returns the icon for a specified object: #--------------------------------------------------------------------------- def tno_get_icon ( self, node, is_expanded ): """ Returns the icon for a specified object. """ if not self.tno_allows_children( node ): return node.icon_item if is_expanded: return node.icon_open return node.icon_group #--------------------------------------------------------------------------- # Returns the path used to locate an object's icon: #--------------------------------------------------------------------------- def tno_get_icon_path ( self, node ): """ Returns the path used to locate an object's icon. """ return node.icon_path #--------------------------------------------------------------------------- # Returns the name to use when adding a new object instance (displayed in # the 'New' submenu): #--------------------------------------------------------------------------- def tno_get_name ( self, node ): """ Returns the name to use when adding a new object instance (displayed in the "New" submenu). """ return node.name #--------------------------------------------------------------------------- # Gets the View to use when editing an object: #--------------------------------------------------------------------------- def tno_get_view ( self, node ): """ Gets the view to use when editing an object. """ return node.view #--------------------------------------------------------------------------- # Returns the right-click context menu for an object: #--------------------------------------------------------------------------- def tno_get_menu ( self, node ): """ Returns the right-click context menu for an object. """ return node.menu #--------------------------------------------------------------------------- # Returns whether or not the object's children can be renamed: #--------------------------------------------------------------------------- def tno_can_rename ( self, node ): """ Returns whether the object's children can be renamed. """ return node.rename #--------------------------------------------------------------------------- # Returns whether or not the object can be renamed: #--------------------------------------------------------------------------- def tno_can_rename_me ( self, node ): """ Returns whether the object can be renamed. """ return node.rename_me #--------------------------------------------------------------------------- # Returns whether or not the object's children can be copied: #--------------------------------------------------------------------------- def tno_can_copy ( self, node ): """ Returns whether the object's children can be copied. """ return node.copy #--------------------------------------------------------------------------- # Returns whether or not the object's children can be deleted: #--------------------------------------------------------------------------- def tno_can_delete ( self, node ): """ Returns whether the object's children can be deleted. """ return node.delete #--------------------------------------------------------------------------- # Returns whether or not the object can be deleted: #--------------------------------------------------------------------------- def tno_can_delete_me ( self, node ): """ Returns whether the object can be deleted. """ return node.delete_me #--------------------------------------------------------------------------- # Returns whether or not the object's children can be inserted (or just # appended): #--------------------------------------------------------------------------- def tno_can_insert ( self, node ): """ Returns whether the object's children can be inserted (vs. appended). """ return node.insert #--------------------------------------------------------------------------- # Returns whether or not the object's children should be auto-opened: #--------------------------------------------------------------------------- def tno_can_auto_open ( self, node ): """ Returns whether the object's children should be automatically opened. """ return node.auto_open #--------------------------------------------------------------------------- # Returns whether or not the object's children should be auto-closed: #--------------------------------------------------------------------------- def tno_can_auto_close ( self, node ): """ Returns whether the object's children should be automatically closed. """ return node.auto_close #--------------------------------------------------------------------------- # Returns whether or not this is the node that should handle a specified # object: #--------------------------------------------------------------------------- def tno_is_node_for ( self, node ): """ Returns whether this is the node that should handle a specified object. """ return (isinstance( self, node.node_for_class ) or self.has_traits_interface( *node.node_for_interface )) #--------------------------------------------------------------------------- # Returns whether a given 'add_object' can be added to an object: #--------------------------------------------------------------------------- def tno_can_add ( self, node, add_object ): """ Returns whether a given object is droppable on the node. """ klass = node._class_for( add_object ) if node.is_addable( klass ): return True for item in node.move: if type( item ) in SequenceTypes: item = item[0] if issubclass( klass, item ): return True return False #--------------------------------------------------------------------------- # Returns the list of classes that can be added to the object: #--------------------------------------------------------------------------- def tno_get_add ( self, node ): """ Returns the list of classes that can be added to the object. """ return node.add #--------------------------------------------------------------------------- # Returns the 'draggable' version of a specified object: #--------------------------------------------------------------------------- def tno_get_drag_object ( self, node ): """ Returns a draggable version of a specified object. """ return self #--------------------------------------------------------------------------- # Returns a droppable version of a specified object: #--------------------------------------------------------------------------- def tno_drop_object ( self, node, dropped_object ): """ Returns a droppable version of a specified object. """ if node.is_addable( dropped_object ): return dropped_object for item in node.move: if type( item ) in SequenceTypes: if isinstance( dropped_object, item[0] ): return item[1]( self, dropped_object ) else: if isinstance( dropped_object, item ): return dropped_object #--------------------------------------------------------------------------- # Handles an object being selected: #--------------------------------------------------------------------------- def tno_select ( self, node ): """ Handles an object being selected. """ if node.on_select is not None: node.on_select( self ) return None return True #--------------------------------------------------------------------------- # Handles an object being clicked: #--------------------------------------------------------------------------- def tno_click ( self, node ): """ Handles an object being clicked. """ if node.on_click is not None: node.on_click( self ) return None return True #--------------------------------------------------------------------------- # Handles an object being double-clicked: #--------------------------------------------------------------------------- def tno_dclick ( self, node ): """ Handles an object being double-clicked. """ if node.on_dclick is not None: node.on_dclick( self ) return None return True #------------------------------------------------------------------------------- # 'MultiTreeNode' object: #------------------------------------------------------------------------------- class MultiTreeNode ( TreeNode ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # TreeNode that applies to the base object itself root_node = Instance( TreeNode ) # List of TreeNodes (one for each sub-item list) nodes = List( TreeNode ) #--------------------------------------------------------------------------- # Returns whether chidren of this object are allowed or not: #--------------------------------------------------------------------------- def allows_children ( self, object ): """ Returns whether this object can have children (True for this class). """ return True #--------------------------------------------------------------------------- # Returns whether or not the object has children: #--------------------------------------------------------------------------- def has_children ( self, object ): """ Returns whether this object has children (True for this class). """ return True #--------------------------------------------------------------------------- # Gets the object's children: #--------------------------------------------------------------------------- def get_children ( self, object ): """ Gets the object's children. """ return [ ( object, node ) for node in self.nodes ] #--------------------------------------------------------------------------- # Gets the object's children identifier: #--------------------------------------------------------------------------- def get_children_id ( self, object ): """ Gets the object's children identifier. """ return '' #--------------------------------------------------------------------------- # Sets up/Tears down a listener for 'children replaced' on a specified # object: #--------------------------------------------------------------------------- def when_children_replaced ( self, object, listener, remove ): """ Sets up or removes a listener for children being replaced on a specified object. """ pass #--------------------------------------------------------------------------- # Sets up/Tears down a listener for 'children changed' on a specified # object: #--------------------------------------------------------------------------- def when_children_changed ( self, object, listener, remove ): """ Sets up or removes a listener for children being changed on a specified object. """ pass #--------------------------------------------------------------------------- # Gets the label to display for a specified object: #--------------------------------------------------------------------------- def get_label ( self, object ): """ Gets the label to display for a specified object. """ return self.root_node.get_label( object ) #--------------------------------------------------------------------------- # Sets the label for a specified object: #--------------------------------------------------------------------------- def set_label ( self, object, label ): """ Sets the label for a specified object. """ return self.root_node.set_label( object, label ) #--------------------------------------------------------------------------- # Sets up/Tears down a listener for 'label changed' on a specified object: #--------------------------------------------------------------------------- def when_label_changed ( self, object, listener, remove ): """ Sets up or removes a listener for the label being changed on a specified object. """ return self.root_node.when_label_changed( object, listener, remove ) #--------------------------------------------------------------------------- # Returns the icon for a specified object: #--------------------------------------------------------------------------- def get_icon ( self, object, is_expanded ): """ Returns the icon for a specified object. """ return self.root_node.get_icon( object, is_expanded ) #--------------------------------------------------------------------------- # Returns the path used to locate an object's icon: #--------------------------------------------------------------------------- def get_icon_path ( self, object ): """ Returns the path used to locate an object's icon. """ return self.root_node.get_icon_path( object ) #--------------------------------------------------------------------------- # Returns the name to use when adding a new object instance (displayed in # the 'New' submenu): #--------------------------------------------------------------------------- def get_name ( self, object ): """ Returns the name to use when adding a new object instance (displayed in the "New" submenu). """ return self.root_node.get_name( object ) #--------------------------------------------------------------------------- # Gets the View to use when editing an object: #--------------------------------------------------------------------------- def get_view ( self, object ): """ Gets the view to use when editing an object. """ return self.root_node.get_view( object ) #--------------------------------------------------------------------------- # Returns the right-click context menu for an object: #--------------------------------------------------------------------------- def get_menu ( self, object ): """ Returns the right-click context menu for an object. """ return self.root_node.get_menu( object ) #--------------------------------------------------------------------------- # Returns whether or not the object's children can be renamed: #--------------------------------------------------------------------------- def can_rename ( self, object ): """ Returns whether the object's children can be renamed (False for this class). """ return False #--------------------------------------------------------------------------- # Returns whether or not the object can be renamed: #--------------------------------------------------------------------------- def can_rename_me ( self, object ): """ Returns whether the object can be renamed (False for this class). """ return False #--------------------------------------------------------------------------- # Returns whether or not the object's children can be copied: #--------------------------------------------------------------------------- def can_copy ( self, object ): """ Returns whether the object's children can be copied. """ return self.root_node.can_copy( object ) #--------------------------------------------------------------------------- # Returns whether or not the object's children can be deleted: #--------------------------------------------------------------------------- def can_delete ( self, object ): """ Returns whether the object's children can be deleted (False for this class). """ return False #--------------------------------------------------------------------------- # Returns whether or not the object can be deleted: #--------------------------------------------------------------------------- def can_delete_me ( self, object ): """ Returns whether the object can be deleted (True for this class). """ return True #--------------------------------------------------------------------------- # Returns whether or not the object's children can be inserted (or just # appended): #--------------------------------------------------------------------------- def can_insert ( self, object ): """ Returns whether the object's children can be inserted (False, meaning that children are appended, for this class). """ return False #--------------------------------------------------------------------------- # Returns whether or not the object's children should be auto-opened: #--------------------------------------------------------------------------- def can_auto_open ( self, object ): """ Returns whether the object's children should be automatically opened. """ return self.root_node.can_auto_open( object ) #--------------------------------------------------------------------------- # Returns whether or not the object's children should be auto-closed: #--------------------------------------------------------------------------- def can_auto_close ( self, object ): """ Returns whether the object's children should be automatically closed. """ return self.root_node.can_auto_close( object ) #--------------------------------------------------------------------------- # Returns whether a given 'add_object' can be added to an object: #--------------------------------------------------------------------------- def can_add ( self, object, add_object ): """ Returns whether a given object is droppable on the node (False for this class). """ return False #--------------------------------------------------------------------------- # Returns the list of classes that can be added to the object: #--------------------------------------------------------------------------- def get_add ( self, object ): """ Returns the list of classes that can be added to the object. """ return [] #------------------------------------------------------------------------------- # Returns the 'draggable' version of a specified object: #------------------------------------------------------------------------------- def get_drag_object ( self, object ): """ Returns a draggable version of a specified object. """ return self.root_node.get_drag_object( object ) #--------------------------------------------------------------------------- # Returns a droppable version of a specified object: #--------------------------------------------------------------------------- def drop_object ( self, object, dropped_object ): """ Returns a droppable version of a specified object. """ return self.root_node.drop_object( object, dropped_object ) #--------------------------------------------------------------------------- # Handles an object being selected: #--------------------------------------------------------------------------- def select ( self, object ): """ Handles an object being selected. """ return self.root_node.select( object ) #--------------------------------------------------------------------------- # Handles an object being clicked: #--------------------------------------------------------------------------- def click ( self, object ): """ Handles an object being clicked. """ return self.root_node.click( object ) #--------------------------------------------------------------------------- # Handles an object being double-clicked: #--------------------------------------------------------------------------- def dclick ( self, object ): """ Handles an object being double-clicked. """ return self.root_node.dclick( object ) traitsui-4.1.0/traitsui/list_str_adapter.py0000644000175100001440000002716511674463546022155 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2008, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 02/29/2008 # #------------------------------------------------------------------------------- """ Defines adapter interfaces for use with the ListStrEditor. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import (Any, Bool, Color, Enum, Event, HasPrivateTraits, Int, Interface, List, Str, implements, on_trait_change) #------------------------------------------------------------------------------- # 'IListStrAdapter' interface: #------------------------------------------------------------------------------- class IListStrAdapter ( Interface ): # The index of the current item being adapted: index = Int # Current item being adapted: item = Any # The current value (if any): value = Any # Does the adapter know how to handler the current *item* or not: accepts = Bool # Does the value of *accepts* depend only upon the type of *item*? is_cacheable = Bool #------------------------------------------------------------------------------- # 'AnIListStrAdapter' class: #------------------------------------------------------------------------------- class AnIListStrAdapter ( HasPrivateTraits ): implements( IListStrAdapter ) #-- Implementation of the IListStrAdapter Interface ------------------------ # The index of the current item being adapted: index = Int # Current item being adapted: item = Any # The current value (if any): value = Any # Does the adapter know how to handler the current *item* or not: accepts = Bool( True ) # Does the value of *accepts* depend only upon the type of *item*? is_cacheable = Bool( True ) #------------------------------------------------------------------------------- # 'ListStrAdapter' class: #------------------------------------------------------------------------------- class ListStrAdapter ( HasPrivateTraits ): """ The base class for adapting list items to values that can be edited by a ListStrEditor. """ #-- Trait Definitions ------------------------------------------------------ # Specifies the default value for a new list item: default_value = Any( '' ) # Specifies the default text for a new list item: default_text = Str # The default text color for list items (even, odd, any rows): even_text_color = Color( None, update = True ) odd_text_color = Color( None, update = True ) text_color = Color( None, update = True ) # The default background color for list items (even, odd, any rows): even_bg_color = Color( None, update = True ) odd_bg_color = Color( None, update = True ) bg_color = Color( None, update = True ) # The name of the default image to use for list items: image = Str( None, update = True ) # Can the text value of each list item be edited: can_edit = Bool( True ) # Specifies where a dropped item should be placed in the list relative to # the item it is dropped on: dropped = Enum( 'after', 'before' ) # The index of the current item being adapter: index = Int # The current item being adapted: item = Any # The current value (if any): value = Any # List of optional delegated adapters: adapters = List( IListStrAdapter, update = True ) #-- Private Trait Definitions ---------------------------------------------- # Cache of attribute handlers: cache = Any( {} ) # Event fired when the cache is flushed: cache_flushed = Event( update = True ) #-- Adapter methods that are sensitive to item type ------------------------ def get_can_edit ( self, object, trait, index ): """ Returns whether the user can edit a specified *object.trait[index]* list item. A True result indicates the value can be edited, while a False result indicates that it cannot be edited. """ return self._result_for( 'get_can_edit', object, trait, index ) def get_drag ( self, object, trait, index ): """ Returns the 'drag' value for a specified *object.trait[index]* list item. A result of *None* means that the item cannot be dragged. """ return self._result_for( 'get_drag', object, trait, index ) def get_can_drop ( self, object, trait, index, value ): """ Returns whether the specified *value* can be dropped on the specified *object.trait[index]* list item. A value of **True** means the *value* can be dropped; and a value of **False** indicates that it cannot be dropped. """ return self._result_for( 'get_can_drop', object, trait, index, value ) def get_dropped ( self, object, trait, index, value ): """ Returns how to handle a specified *value* being dropped on a specified *object.trait[index]* list item. The possible return values are: 'before' Insert the specified *value* before the dropped on item. 'after' Insert the specified *value* after the dropped on item. """ return self._result_for( 'get_dropped', object, trait, index, value ) def get_text_color ( self, object, trait, index ): """ Returns the text color for a specified *object.trait[index]* list item. A result of None means use the default list item text color. """ return self._result_for( 'get_text_color', object, trait, index ) def get_bg_color ( self, object, trait, index ): """ Returns the background color for a specified *object.trait[index]* list item. A result of None means use the default list item background color. """ return self._result_for( 'get_bg_color', object, trait, index ) def get_image ( self, object, trait, index ): """ Returns the name of the image to use for a specified *object.trait[index]* list item. A result of None means no image should be used. Otherwise, the result should either be the name of the image, or an ImageResource item specifying the image to use. """ return self._result_for( 'get_image', object, trait, index ) def get_item ( self, object, trait, index ): """ Returns the value of the *object.trait[index]* list item. """ return self._result_for( 'get_item', object, trait, index ) def get_text ( self, object, trait, index ): """ Returns the text to display for a specified *object.trait[index]* list item. """ return self._result_for( 'get_text', object, trait, index ) #-- Adapter methods that are not sensitive to item type -------------------- def len ( self, object, trait ): """ Returns the number of items in the specified *object.trait* list. """ return len( getattr( object, trait ) ) def get_default_value ( self, object, trait ): """ Returns a new default value for the specified *object.trait* list. """ return self.default_value def get_default_text ( self, object, trait ): """ Returns the default text for the specified *object.trait* list. """ return self.default_text def get_default_image ( self, object, trait ): """ Returns the default image for the specified *object.trait* list. """ return self.image def get_default_bg_color ( self, object, trait ): """ Returns the default background color for the specified *object.trait* list. """ return self._get_bg_color() def get_default_text_color ( self, object, trait ): """ Returns the default text color for the specified *object.trait* list. """ return self._get_text_color() def set_text ( self, object, trait, index, text ): """ Sets the text for a specified *object.trait[index]* list item to *text*. """ getattr( object, trait )[ index ] = text def delete ( self, object, trait, index ): """ Deletes the specified *object.trait[index]* list item. """ del getattr( object, trait )[ index ] def insert ( self, object, trait, index, value ): """ Inserts a new value at the specified *object.trait[index]* list index. """ getattr( object, trait ) [ index: index ] = [ value ] #-- Private Adapter Implementation Methods --------------------------------- def _get_can_edit ( self ): return self.can_edit def _get_drag ( self ): return unicode( self.item ) def _get_can_drop ( self ): return isinstance( self.value, basestring ) def _get_dropped ( self ): return self.dropped def _get_text_color ( self ): if (self.index % 2) == 0: return self.even_text_color_ or self.text_color_ return self.odd_text_color or self.text_color_ def _get_bg_color ( self ): if (self.index % 2) == 0: return self.even_bg_color_ or self.bg_color_ return self.odd_bg_color or self.bg_color_ def _get_image ( self ): return self.image def _get_item ( self ): return self.item def _get_text ( self ): return unicode( self.item ) #-- Private Methods -------------------------------------------------------- def _result_for ( self, name, object, trait, index, value = None ): """ Returns/Sets the value of the specified *name* attribute for the specified *object.trait[index]* list item. """ self.index = index self.value = value items = getattr( object, trait ) if index >= len( items ): self.item = item = None else: self.item = item = items[ index ] item_class = item.__class__ key = '%s:%s' % ( item_class.__name__, name ) handler = self.cache.get( key ) if handler is not None: return handler() trait_name = name[4:] for adapter in self.adapters: adapter.index = index adapter.item = item adapter.value = value if adapter.accepts and (adapter.trait( trait_name ) is not None): handler = lambda: getattr( adapter.set( index = self.index, item = self.item, value = self.value ), trait_name ) if adapter.is_cacheable: break return handler() else: for klass in item_class.__mro__: cname = '%s_%s' % ( klass.__name__, trait_name ) if self.trait( cname ) is not None: handler = lambda: getattr( self, cname ) break else: handler = getattr( self, '_' + name ) self.cache[ key ] = handler return handler() @on_trait_change( 'adapters.+update' ) def _flush_cache ( self ): """ Flushes the cache when any trait on any adapter changes. """ self.cache = {} self.cache_flushed = True traitsui-4.1.0/traitsui/view_elements.py0000644000175100001440000002016111674463546021445 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/18/2004 # #------------------------------------------------------------------------------ """ Define the ViewElements class, which is used to define a (typically class-based) hierarchical name space of related ViewElement objects. Normally there is a ViewElements object associated with each Traits-based class, which contains all of the ViewElement objects associated with the class. The ViewElements object is also linked to the ViewElements objects of its associated class's parent classes. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import HasStrictTraits, List, Dict, Str, Int, Any, TraitError from traits.trait_base import enumerate from .view_element import ViewElement #------------------------------------------------------------------------------- # Trait definitions: #------------------------------------------------------------------------------- # Trait for contents of a ViewElements object content_trait = Dict( str, ViewElement ) #------------------------------------------------------------------------------- # 'ViewElements' class: #------------------------------------------------------------------------------- class ViewElements ( HasStrictTraits ): """ Defines a hierarchical name space of related ViewElement objects. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Dictionary containing the named ViewElement items content = content_trait #--------------------------------------------------------------------------- # Finds a specified ViewElement within the specified (optional) search # context: #--------------------------------------------------------------------------- def find ( self, name, stack = None ): """ Finds a specified ViewElement within the specified (optional) search context. """ # Assume search starts from the beginning the of the search order: i = 0 # If a stack was specified, see if there is a matching entry in the # stack already: if stack is not None: for ssi in stack: if name == ssi.id: # Match found, resume search at next ViewElements object # in the search order: i = ssi.context + 1 break # Search for a matching name starting at the specified ViewElements # object in the search order: for j, ves in enumerate( self._get_search_order()[i:] ): result = ves.content.get( name ) if result is not None: # Match found. If there is a stack, push matching name and # ViewElements context onto it: if stack is not None: stack[0:0] = [ SearchStackItem( id = name, context = i + j ) ] # Return the ViewElement object that matched the name: return result # Indicate no match was found: return None #--------------------------------------------------------------------------- # Returns a sorted list of all names accessible from the ViewElements # object that are of a specified (ViewElement) type: #--------------------------------------------------------------------------- def filter_by ( self, klass = None ): """ Returns a sorted list of all names accessible from the ViewElements object that are of a specified (ViewElement) type. """ if klass is None: from . import view klass = view.View result = [] # Add each item in the search order which is of the right class and # which is not already in the result list: for ves in self._get_search_order(): for name, ve in ves.content.items(): if isinstance( ve, klass ) and (name not in result): result.append( name ) # Sort the resulting list of names: result.sort() # Return the result: return result #--------------------------------------------------------------------------- # Handles the 'parents' list being updated: #--------------------------------------------------------------------------- def _parents__changed ( self ): self._search_order = None def _parents_items_changed ( self ): self._search_order = None #--------------------------------------------------------------------------- # Returns the current search order (computing it if necessary): #--------------------------------------------------------------------------- def _get_search_order ( self ): if self._search_order is None: self._search_order = self._mro() return self._search_order #--------------------------------------------------------------------------- # Compute the Python 'C3' algorithm used to determine a class's 'mro' # and apply it to the 'parents' of the ViewElements to determine the # correct search order: #--------------------------------------------------------------------------- def _mro ( self ): return self._merge( [ [ self ] ] + [ parent._get_search_order()[:] for parent in self.parents ] + [ self.parents[:] ] ) def _merge ( self, seqs ): result = [] while True: # Remove any empty sequences from the list: seqs = [ seq for seq in seqs if len( seq ) > 0 ] if len( seqs ) == 0: return result # Find merge candidates among the sequence heads: for seq in seqs: candidate = seq[0] if len( [ s for s in seqs if candidate in s[1:] ] ) == 0: break else: raise TraitError, "Inconsistent ViewElements hierarchy" # Add the candidate to the result: result.append( candidate ) # Then remove the candidate: for seq in seqs: if seq[0] == candidate: del seq[0] #--------------------------------------------------------------------------- # Returns a 'pretty print' version of the ViewElements object: #--------------------------------------------------------------------------- def __repr__ ( self ): """ Returns a "pretty print" version of the ViewElements object. """ return self.content.__repr__() #------------------------------------------------------------------------------- # Define forward reference traits: #------------------------------------------------------------------------------- ViewElements.add_class_trait( 'parents', List( ViewElements ) ) ViewElements.add_class_trait( '_search_order', Any ) #------------------------------------------------------------------------------- # 'SearchStackItem' class: #------------------------------------------------------------------------------- class SearchStackItem ( HasStrictTraits ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Name that was looked up id = Str # Index into the 'mro' list of ViewElements that the ID was found in context = Int traitsui-4.1.0/traitsui/view_element.py0000644000175100001440000002320611674463546021265 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/18/2004 # #------------------------------------------------------------------------------ """ Defines the abstract ViewElement class that all trait view template items (i.e., View, Group, Item, Include) derive from. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import import re from string import rfind from traits.api import HasPrivateTraits, Trait, Bool from .ui_traits import (ATheme, AnObject, DockStyle, EditorStyle, ExportType, HelpId, Image) #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- label_pat = re.compile( r"^(.*)\[(.*)\](.*)$", re.MULTILINE | re.DOTALL ) label_pat2 = re.compile( r"^(.*){(.*)}(.*)$", re.MULTILINE | re.DOTALL ) #------------------------------------------------------------------------------- # 'ViewElement' class (abstract): #------------------------------------------------------------------------------- class ViewElement ( HasPrivateTraits ): """ An element of a view. """ #--------------------------------------------------------------------------- # Replaces any items which have an 'id' with an Include object with the # same 'id', and puts the object with the 'id' into the specified # ViewElements object: #--------------------------------------------------------------------------- def replace_include ( self, view_elements ): """ Searches the current object's **content** attribute for objects that have an **id** attribute, and replaces each one with an Include object with the same **id** value, and puts the replaced object into the specified ViewElements object. Parameters ---------- view_elements : ViewElements object Object containing Group, Item, and Include objects """ pass # Normally overridden in a subclass #--------------------------------------------------------------------------- # Returns whether or not the object is replacable by an Include object: #--------------------------------------------------------------------------- def is_includable ( self ): """ Returns whether the object is replacable by an Include object. """ return False # Normally overridden in a subclass #------------------------------------------------------------------------------- # 'DefaultViewElement' class: #------------------------------------------------------------------------------- class DefaultViewElement ( ViewElement ): """ A view element that can be used as a default value for traits whose value is a view element. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # The default context object to edit: object = AnObject # The default editor style to use: style = EditorStyle # The default dock style to use: dock = DockStyle # The default notebook tab image to use: image = Image # The category of elements dragged out of the view: export = ExportType # Should labels be added to items in a group? show_labels = Bool( True ) # The default theme to use for a contained item: item_theme = ATheme # The default theme to use for a contained item's label: label_theme = ATheme #------------------------------------------------------------------------------- # Trait definitions: #------------------------------------------------------------------------------- # The container trait used by ViewSubElements: Container = Trait( DefaultViewElement(), ViewElement ) #------------------------------------------------------------------------------- # 'ViewSubElement' class (abstract): #------------------------------------------------------------------------------- class ViewSubElement ( ViewElement ): """ Abstract class representing elements that can be contained in a view. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # The object this ViewSubElement is contained in; must be a ViewElement. container = Container # External help context identifier: help_id = HelpId #--------------------------------------------------------------------------- # Splits a string at a specified character: #--------------------------------------------------------------------------- def _split ( self, name, value, char, finder, assign, result ): """ Splits a string at a specified character. """ col = finder( value, char ) if col < 0: return value items = ( value[:col].strip(), value[col+1:].strip() ) if items[ assign ] != '': setattr( self, name, items[ assign ] ) return items[ result ] #--------------------------------------------------------------------------- # Sets an object trait if a specified option string is found: #--------------------------------------------------------------------------- def _option ( self, string, option, name, value ): """ Sets a object trait if a specified option string is found. """ col = string.find( option ) if col >= 0: string = string[ : col ] + string[ col + len( option ): ] setattr( self, name, value ) return string #--------------------------------------------------------------------------- # Parses any of the one character forms of the 'style' trait: #--------------------------------------------------------------------------- def _parse_style ( self, value ): """ Parses any of the one-character forms of the **style** trait. """ value = self._option( value, '$', 'style', 'simple' ) value = self._option( value, '@', 'style', 'custom' ) value = self._option( value, '*', 'style', 'text' ) value = self._option( value, '~', 'style', 'readonly' ) value = self._split( 'style', value, ';', rfind, 1, 0 ) return value #--------------------------------------------------------------------------- # Parses a '[label]' value from the string definition: #--------------------------------------------------------------------------- def _parse_label ( self, value ): """ Parses a '[label]' value from the string definition. """ match = label_pat.match( value ) if match is not None: self._parsed_label() else: match = label_pat2.match( value ) empty = False if match is not None: self.label = match.group( 2 ).strip() empty = (self.label == '') value = match.group( 1 ) + match.group( 3 ) return ( value, empty ) #--------------------------------------------------------------------------- # Handles a label being found in the string definition: #--------------------------------------------------------------------------- def _parsed_label ( self ): """ Handles a label being found in the string definition. """ pass #--------------------------------------------------------------------------- # Returns a 'pretty print' version of a specified trait value: #--------------------------------------------------------------------------- def _repr_value ( self, value, prefix = '', suffix = '', ignore = '' ): """ Returns a "pretty print" version of a specified Item trait value. """ if value == ignore: return '' return '%s%s%s' % ( prefix, value, suffix ) #--------------------------------------------------------------------------- # Returns a 'pretty print' version of a list of traits: #--------------------------------------------------------------------------- def _repr_options ( self, *names ): """ Returns a 'pretty print' version of a list of traits. """ result = [] for name in names: value = getattr( self, name ) if value != self.trait( name ).default_value_for( self, name ): result.append( ( name, repr( value ) ) ) if len( result ) > 0: n = max( [ len( name ) for name, value in result ] ) return ',\n'.join( [ '%s = %s' % ( name.ljust( n ), value ) for name, value in result ] ) return None #--------------------------------------------------------------------------- # Indents each line in a specified string by a specified number of spaces: #--------------------------------------------------------------------------- def _indent ( self, string, indent = ' ' ): """ Indents each line in a specified string by 4 spaces. """ return '\n'.join( [ indent + s for s in string.split( '\n' ) ] ) traitsui-4.1.0/traitsui/tabular_adapter.py0000644000175100001440000005115611674463546021741 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2008, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 02/29/2008 # #------------------------------------------------------------------------------- """ Defines the adapter classes associated with the Traits UI TabularEditor. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import (Any, Bool, Color, Enum, Event, Float, Font, HasPrivateTraits, HasTraits, Instance, Int, Interface, List, Property, Str, cached_property, implements, on_trait_change) #------------------------------------------------------------------------------- # 'ITabularAdapter' interface: #------------------------------------------------------------------------------- class ITabularAdapter ( Interface ): # The row index of the current item being adapted: row = Int # The current column id being adapted (if any): column = Any # Current item being adapted: item = Any # The current value (if any): value = Any # The list of columns the adapter supports. The items in the list have the # same format as the *columns* trait in the *TabularAdapter* class, with the # additional requirement that the *string* values must correspond to a # *string* value in the associated *TabularAdapter* class. columns = List( Str ) # Does the adapter know how to handle the current *item* or not: accepts = Bool # Does the value of *accepts* depend only upon the type of *item*? is_cacheable = Bool #------------------------------------------------------------------------------- # 'AnITabularAdapter' class: #------------------------------------------------------------------------------- class AnITabularAdapter ( HasPrivateTraits ): implements( ITabularAdapter ) #-- Implementation of the ITabularAdapter Interface ------------------------ # The row index of the current item being adapted: row = Int # The current column id being adapted (if any): column = Any # Current item being adapted: item = Any # The current value (if any): value = Any # The list of columns the adapter supports. The items in the list have the # same format as the *columns* trait in the *TabularAdapter* class, with the # additional requirement that the *string* values must correspond to a # *string* value in the associated *TabularAdapter* class. columns = List( Str ) # Does the adapter know how to handle the current *item* or not: accepts = Bool( True ) # Does the value of *accepts* depend only upon the type of *item*? is_cacheable = Bool( True ) #------------------------------------------------------------------------------- # 'TabularAdapter' class: #------------------------------------------------------------------------------- class TabularAdapter ( HasPrivateTraits ): """ The base class for adapting list items to values that can be edited by a TabularEditor. """ #-- Public Trait Definitions ----------------------------------------------- # A list of columns that should appear in the table. Each entry can have one # of two forms: string or ( string, any ), where *string* is the UI name of # the column, and *any* is a value that identifies that column to the # adapter. Normally this value is either a trait name or an index, but it # can be any value that the adapter wants. If only *string* is specified, # then *any* is the index of the *string* within *columns*. columns = List() #Maps UI name of column to value identifying column to the adapter, if different. column_dict = Property() # Specifies the default value for a new row: default_value = Any( '' ) # The default text color for table rows (even, odd, any rows): odd_text_color = Color( None, update = True ) even_text_color = Color( None, update = True ) default_text_color = Color( None, update = True ) # The default background color for table rows (even, odd, any rows): odd_bg_color = Color( None, update = True ) even_bg_color = Color( None, update = True ) default_bg_color = Color( None, update = True ) # Alignment to use for a specified column: alignment = Enum( 'left', 'center', 'right' ) # The Python format string to use for a specified column: format = Str( '%s' ) # Width of a specified column: width = Float( -1 ) # Can the text value of each item be edited: can_edit = Bool( True ) # The value to be dragged for a specified row item: drag = Property # Can any arbitrary value be dropped onto the tabular view: can_drop = Bool( False ) # Specifies where a dropped item should be placed in the table relative to # the item it is dropped on: dropped = Enum( 'after', 'before' ) # The font for a row item: font = Font( None ) # The text color for a row item: text_color = Property # The background color for a row item: bg_color = Property # The name of the default image to use for column items: image = Str( None, update = True ) # The text of a row/column item: text = Property # The content of a row/column item (may be any Python value): content = Property # The tooltip information for a row/column item: tooltip = Str # The context menu for a row/column item: menu = Any # The context menu for column header: column_menu = Any # List of optional delegated adapters: adapters = List( ITabularAdapter, update = True ) #-- Traits Set by the Editor ----------------------------------------------- # The object whose trait is being edited: object = Instance( HasTraits ) # The name of the trait being edited: name = Str # The row index of the current item being adapted: row = Int # The column index of the current item being adapted: column = Int # The current column id being adapted (if any): column_id = Any # Current item being adapted: item = Any # The current value (if any): value = Any #-- Private Trait Definitions ---------------------------------------------- # Cache of attribute handlers: cache = Any( {} ) # Event fired when the cache is flushed: cache_flushed = Event( update = True ) # The mapping from column indices to column identifiers (defined by the # *columns* trait): column_map = Property( depends_on = 'columns' ) # The mapping from column indices to column labels (defined by the *columns* # trait): label_map = Property( depends_on = 'columns' ) # For each adapter, specifies the column indices the adapter handles: adapter_column_indices = Property( depends_on = 'adapters,columns' ) # For each adapter, specifies the mapping from column index to column id: adapter_column_map = Property( depends_on = 'adapters,columns' ) #### TabularAdapter interface #### def cleanup(self): """ Clean up the adapter to remove references to objects. """ self.trait_setq( object=None, item=None, value=None, ) #-- Adapter methods that are sensitive to item type ------------------------ def get_alignment ( self, object, trait, column ): """ Returns the alignment style to use for a specified column. """ return self._result_for( 'get_alignment', object, trait, 0, column ) def get_width ( self, object, trait, column ): """ Returns the width to use for a specified column. """ return self._result_for( 'get_width', object, trait, 0, column ) def get_can_edit ( self, object, trait, row ): """ Returns whether the user can edit a specified *object.trait[row]* item. A True result indicates the value can be edited, while a False result indicates that it cannot be edited. """ return self._result_for( 'get_can_edit', object, trait, row, 0 ) def get_drag ( self, object, trait, row ): """ Returns the 'drag' value for a specified *object.trait[row]* item. A result of *None* means that the item cannot be dragged. """ return self._result_for( 'get_drag', object, trait, row, 0 ) def get_can_drop ( self, object, trait, row, value ): """ Returns whether the specified *value* can be dropped on the specified *object.trait[row]* item. A value of **True** means the *value* can be dropped; and a value of **False** indicates that it cannot be dropped. """ return self._result_for( 'get_can_drop', object, trait, row, 0, value ) def get_dropped ( self, object, trait, row, value ): """ Returns how to handle a specified *value* being dropped on a specified *object.trait[row]* item. The possible return values are: 'before' Insert the specified *value* before the dropped on item. 'after' Insert the specified *value* after the dropped on item. """ return self._result_for( 'get_dropped', object, trait, row, 0, value ) def get_font ( self, object, trait, row, column = 0): """ Returns the font for a specified *object.trait[row]* item. A result of None means use the default font. """ return self._result_for( 'get_font', object, trait, row, column ) def get_text_color ( self, object, trait, row, column = 0): """ Returns the text color for a specified *object.trait[row]* item. A result of None means use the default text color. """ return self._result_for( 'get_text_color', object, trait, row, column ) def get_bg_color ( self, object, trait, row, column = 0): """ Returns the background color for a specified *object.trait[row]* item. A result of None means use the default background color. """ return self._result_for( 'get_bg_color', object, trait, row, column ) def get_image ( self, object, trait, row, column ): """ Returns the name of the image to use for a specified *object.trait[row].column* item. A result of None means no image should be used. Otherwise, the result should either be the name of the image, or an ImageResource item specifying the image to use. """ return self._result_for( 'get_image', object, trait, row, column ) def get_format ( self, object, trait, row, column ): """ Returns the Python format string to use for a specified column. """ return self._result_for( 'get_format', object, trait, row, column ) def get_text ( self, object, trait, row, column ): """ Returns the text to display for a specified *object.trait[row].column* item. """ return self._result_for( 'get_text', object, trait, row, column ) def get_content ( self, object, trait, row, column ): """ Returns the content to display for a specified *object.trait[row].column* item. """ return self._result_for( 'get_content', object, trait, row, column ) def set_text ( self, object, trait, row, column, text ): """ Sets the text for a specified *object.trait[row].column* item to *text*. """ self._result_for( 'set_text', object, trait, row, column, text ) def get_tooltip ( self, object, trait, row, column ): """ Returns the tooltip for a specified row. """ return self._result_for( 'get_tooltip', object, trait, row, column ) def get_menu ( self, object, trait, row, column ): """ Returns the context menu for a specified cell. """ return self._result_for( 'get_menu', object, trait, row, column ) def get_column_menu ( self, object, trait, row, column ): """ Returns the context menu for a specified column. """ return self._result_for( 'get_column_menu', object, trait, row, column ) #-- Adapter methods that are not sensitive to item type -------------------- def get_item ( self, object, trait, row ): """ Returns the value of the *object.trait[row]* item. """ try: return getattr( object, trait )[ row ] except: return None def len ( self, object, trait ): """ Returns the number of items in the specified *object.trait* list. """ # Sometimes, during shutdown, the object has been set to None. if object is None: return 0 else: return len( getattr( object, trait ) ) def get_default_value ( self, object, trait ): """ Returns a new default value for the specified *object.trait* list. """ return self.default_value def delete ( self, object, trait, row ): """ Deletes the specified *object.trait[row]* item. """ del getattr( object, trait )[ row ] def insert ( self, object, trait, row, value ): """ Inserts a new value at the specified *object.trait[row]* index. """ getattr( object, trait ) [ row: row ] = [ value ] def get_column ( self, object, trait, index ): """ Returns the column id corresponding to a specified column index. """ self.object, self.name = object, trait return self.column_map[ index ] #-- Property Implementations ----------------------------------------------- def _get_drag ( self ): return self.item def _get_text_color ( self ): if (self.row % 2) == 1: return self.even_text_color_ or self.default_text_color return self.odd_text_color or self.default_text_color_ def _get_bg_color ( self ): if (self.row % 2) == 1: return self.even_bg_color_ or self.default_bg_color_ return self.odd_bg_color or self.default_bg_color_ def _get_text ( self ): return self.get_format( self.object, self.name, self.row, self.column ) % self.get_content( self.object, self.name, self.row, self.column ) def _set_text ( self, value ): if isinstance( self.column_id, int ): self.item[ self.column_id ] = self.value else: # Convert value to the correct trait type. try: trait_handler = self.item.trait(self.column_id).handler setattr( self.item, self.column_id, trait_handler.evaluate(self.value)) except: setattr( self.item, self.column_id, value ) def _get_content ( self ): if isinstance( self.column_id, int ): return self.item[ self.column_id ] return getattr( self.item, self.column_id ) #-- Property Implementations ----------------------------------------------- @cached_property def _get_column_dict(self): cols = {} for i, value in enumerate(self.columns): if isinstance(value, basestring): cols.update({value: value}) else: cols.update({value[0]: value[1]}) return cols @cached_property def _get_column_map ( self ): map = [] for i, value in enumerate( self.columns ): if isinstance( value, basestring ): map.append( i ) else: map.append( value[1] ) return map def get_label(self, section, obj=None): """Override this method if labels will vary from object to object.""" return self.label_map[section] @cached_property def _get_label_map (self): map = [] for i, value in enumerate( self.columns ): if isinstance( value, basestring ): map.append( value ) else: try: col_name = getattr(self, value[0]) except AttributeError: col_name = value[0] map.append( col_name ) return map @cached_property def _get_adapter_column_indices ( self ): labels = self.label_map map = [] for adapter in self.adapters: indices = [] for label in adapter.columns: if not isinstance( label, basestring ): label = label[0] indices.append( labels.index( label ) ) map.append(indices) return map @cached_property def _get_adapter_column_map ( self ): labels = self.label_map map = [] for adapter in self.adapters: mapping = {} for label in adapter.columns: id = None if not isinstance( label, basestring ): label, id = label key = labels.index( label ) if id is None: id = key mapping[ key ] = id map.append( mapping ) return map #-- Private Methods -------------------------------------------------------- def _result_for ( self, name, object, trait, row, column, value = None ): """ Returns/Sets the value of the specified *name* attribute for the specified *object.trait[row].column* item. """ self.object = object self.name = trait self.row = row self.column = column self.column_id = column_id = self.column_map[ column ] self.value = value self.item = item = self.get_item( object, trait, row ) item_class = item.__class__ key = '%s:%s:%d' % ( item_class.__name__, name, column ) handler = self.cache.get( key ) if handler is not None: return handler() prefix = name[:4] trait_name = name[4:] for i, adapter in enumerate( self.adapters ): if column in self.adapter_column_indices[i]: adapter.row = row adapter.item = item adapter.value = value adapter.column = column_id = self.adapter_column_map[i][column] if adapter.accepts: get_name = '%s_%s' % ( column_id, trait_name ) if adapter.trait( get_name ) is not None: if prefix == 'get_': handler = lambda: getattr( adapter.set( row = self.row, column = column_id, item = self.item ), get_name ) else: handler = lambda: setattr( adapter.set( row = self.row, column = column_id, item = self.item ), get_name, self.value ) if adapter.is_cacheable: break return handler() else: if item is not None and hasattr(item_class, '__mro__'): for klass in item_class.__mro__: handler = (self._get_handler_for( '%s_%s_%s' % ( klass.__name__, column_id, trait_name ), prefix ) or self._get_handler_for( '%s_%s' % ( klass.__name__, trait_name ), prefix )) if handler is not None: break if handler is None: handler = (self._get_handler_for( '%s_%s' % ( column_id, trait_name ), prefix ) or self._get_handler_for( trait_name, prefix )) self.cache[ key ] = handler return handler() def _get_handler_for ( self, name, prefix ): """ Returns the handler for a specified trait name (or None if not found). """ if self.trait( name ) is not None: if prefix == 'get_': return lambda: getattr( self, name ) return lambda: setattr( self, name, self.value ) return None @on_trait_change( 'columns,adapters.+update' ) def _flush_cache ( self ): """ Flushes the cache when the columns or any trait on any adapter changes. """ self.cache = {} self.cache_flushed = True traitsui-4.1.0/traitsui/help_template.py0000644000175100001440000000646211674463546021432 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/25/2004 # #------------------------------------------------------------------------------ """ Defines the HTML help templates used for formatting Traits UI help pages. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import HasStrictTraits, Str #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- # Default HTML for a single Item's help window ItemHTML = """
%s %s
""" # Default HTML for a complete Group's help window GroupHTML = """ %s
%s
""" # Default HTML for a single Item within a Group ItemHelp = """ %s: %s """ # Default HTML for formatting a Group's 'help' trait GroupHelp = """
%s
""" #------------------------------------------------------------------------------- # 'HelpTemplate' class: #------------------------------------------------------------------------------- class HelpTemplate ( HasStrictTraits ): """ Contains HTML templates for displaying help. """ item_html = Str( ItemHTML ) # Item popup help window HTML document group_html = Str( GroupHTML ) # Group help window HTML document item_help = Str( ItemHelp ) # Single group item HTML group_help = Str( GroupHelp ) # Group level help HTML no_group_help = Str( '' ) # Missing group level help HTML #------------------------------------------------------------------------------- # Gets/Sets the current HelpTemplate in use: #------------------------------------------------------------------------------- _help_template = HelpTemplate() def help_template ( template = None ): """ Gets or sets the current HelpTemplate in use. """ global _help_template if template is not None: _help_template = template return _help_template traitsui-4.1.0/traitsui/qt4/0000755000175100001440000000000011674463546016735 5ustar ischnellusers00000000000000traitsui-4.1.0/traitsui/qt4/tuple_editor.py0000644000175100001440000000262711674463546022015 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2007, Riverbank Computing Limited # All rights reserved. # # This software is provided without warranty under the terms of the BSD license. # However, when used with the GPL version of PyQt the additional terms described in the PyQt GPL exception also apply # # Author: Riverbank Computing Limited #------------------------------------------------------------------------------ """ Defines the tuple editor for the PyQt user interface toolkit. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- # FIXME: ToolkitEditorFactory is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.tuple_editor file. from traitsui.editors.tuple_editor \ import SimpleEditor as BaseSimpleEditor, ToolkitEditorFactory from editor \ import Editor #------------------------------------------------------------------------------- # 'SimpleEditor' class: #------------------------------------------------------------------------------- class SimpleEditor ( BaseSimpleEditor, Editor ): """ Simple style of editor for tuples. The editor displays an editor for each of the fields in the tuple, based on the type of each field. """ pass traitsui-4.1.0/traitsui/qt4/array_editor.py0000644000175100001440000000363111674463546021776 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 01/10/2006 # #------------------------------------------------------------------------------ """ Defines array editors for the PyQt user interface toolkit. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- # FIXME: ToolkitEditorFactory is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.array_editor file. from traitsui.editors.array_editor \ import SimpleEditor as BaseSimpleEditor, ToolkitEditorFactory from editor \ import Editor #------------------------------------------------------------------------------- # 'SimpleEditor' class: #------------------------------------------------------------------------------- class SimpleEditor ( BaseSimpleEditor, Editor ): """ Simple style of editor for arrays. """ # FIXME: This class has been re-defined here simply so it inherits from the # PyQt Editor class. pass #------------------------------------------------------------------------------- # 'ReadonlyEditor' class: #------------------------------------------------------------------------------- class ReadonlyEditor(SimpleEditor): # Set the value of the readonly trait. readonly = True ### EOF ####################################################################### traitsui-4.1.0/traitsui/qt4/color_editor.py0000644000175100001440000003262211674463546022000 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2007, Riverbank Computing Limited # All rights reserved. # # This software is provided without warranty under the terms of the BSD license. # However, when used with the GPL version of PyQt the additional terms described in the PyQt GPL exception also apply # # Author: Riverbank Computing Limited #------------------------------------------------------------------------------ """ Defines the various color editors for the PyQt user interface toolkit. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from pyface.qt import QtCore, QtGui from traitsui.editors.color_editor \ import ToolkitEditorFactory as BaseToolkitEditorFactory from editor_factory \ import SimpleEditor as BaseSimpleEditor, \ TextEditor as BaseTextEditor, \ ReadonlyEditor as BaseReadonlyEditor from editor \ import Editor #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- # Standard color samples: color_samples = [] #--------------------------------------------------------------------------- # The PyQt ToolkitEditorFactory class. #--------------------------------------------------------------------------- ## We need to add qt4-specific methods to the editor factory (since all editors ## will be accessing these functions. Making these functions global functions ## in this file does not work quite well, since we want custom editors to ## override these methods easily. class ToolkitEditorFactory(BaseToolkitEditorFactory): """ PyQt editor factory for color editors. """ #--------------------------------------------------------------------------- # Gets the PyQt color equivalent of the object trait: #--------------------------------------------------------------------------- def to_qt4_color ( self, editor ): """ Gets the PyQt color equivalent of the object trait. """ if self.mapped: return getattr( editor.object, editor.name + '_' ) return getattr( editor.object, editor.name ) #--------------------------------------------------------------------------- # Gets the application equivalent of a PyQt value: #--------------------------------------------------------------------------- def from_qt4_color ( self, color ): """ Gets the application equivalent of a PyQt value. """ return color #--------------------------------------------------------------------------- # Returns the text representation of a specified color value: #--------------------------------------------------------------------------- def str_color ( self, color ): """ Returns the text representation of a specified color value. """ if isinstance(color, QtGui.QColor): alpha = color.alpha() if alpha == 255: return "(%d,%d,%d)" % (color.red(), color.green(), color.blue()) return "(%d,%d,%d,%d)" % (color.red(), color.green(), color.blue(), alpha) return color #------------------------------------------------------------------------------- # 'SimpleColorEditor' class: #------------------------------------------------------------------------------- class SimpleColorEditor ( BaseSimpleEditor ): """ Simple style of color editor, which displays a text field whose background color is the color value. Selecting the text field displays a dialog box for selecting a new color value. """ #--------------------------------------------------------------------------- # Invokes the pop-up editor for an object trait: #--------------------------------------------------------------------------- def popup_editor(self): """ Invokes the pop-up editor for an object trait. """ color = self.factory.to_qt4_color(self) color = QtGui.QColorDialog.getColor(color, self.control) if color.isValid(): self.value = self.factory.from_qt4_color(color) self.update_editor() #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ super( SimpleColorEditor, self ).update_editor() set_color( self ) #--------------------------------------------------------------------------- # Returns the text representation of a specified color value: #--------------------------------------------------------------------------- def string_value ( self, color ): """ Returns the text representation of a specified color value. """ return self.factory.str_color( color ) #------------------------------------------------------------------------------- # 'CustomColorEditor' class: #------------------------------------------------------------------------------- class CustomColorEditor ( Editor ): """ Custom style of color editor, which displays a color editor panel. """ #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self.control = color_editor_for(self, parent) #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ pass #--------------------------------------------------------------------------- # Updates the object trait when a color swatch is clicked: #--------------------------------------------------------------------------- def update_object_from_swatch(self, color_text): """ Updates the object trait when a color swatch is clicked. """ color = QtGui.QColor(*[int(part) for part in color_text.split(',')]) self.value = self.factory.from_qt4_color(color) self.update_editor() #--------------------------------------------------------------------------- # Returns the text representation of a specified color value: #--------------------------------------------------------------------------- def string_value ( self, color ): """ Returns the text representation of a specified color value. """ return str_color( color ) #------------------------------------------------------------------------------- # 'TextColorEditor' class: #------------------------------------------------------------------------------- class TextColorEditor ( BaseTextEditor ): """ Text style of color editor, which displays a text field whose background color is the color value. """ #--------------------------------------------------------------------------- # Handles the user changing the contents of the edit control: #--------------------------------------------------------------------------- def update_object(self): """ Handles the user changing the contents of the edit control. """ self.value = unicode(self.control.text()) set_color( self ) #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ super( TextColorEditor, self ).update_editor() set_color( self ) #--------------------------------------------------------------------------- # Returns the text representation of a specified color value: #--------------------------------------------------------------------------- def string_value ( self, color ): """ Returns the text representation of a specified color value. """ return self.factory.str_color( color ) #------------------------------------------------------------------------------- # 'ReadonlyColorEditor' class: #------------------------------------------------------------------------------- class ReadonlyColorEditor ( BaseReadonlyEditor ): """ Read-only style of color editor, which displays a read-only text field whose background color is the color value. """ #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self.control = QtGui.QLineEdit() self.control.setReadOnly(True) #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ super( ReadonlyColorEditor, self ).update_editor() set_color( self ) #--------------------------------------------------------------------------- # Returns the text representation of a specified color value: #--------------------------------------------------------------------------- def string_value ( self, color ): """ Returns the text representation of a specified color value. """ return self.factory.str_color( color ) #------------------------------------------------------------------------------- # Sets the color of the specified editor's color control: #------------------------------------------------------------------------------- def set_color ( editor ): """ Sets the color of the specified color control. """ color = editor.factory.to_qt4_color(editor) pal = QtGui.QPalette(editor.control.palette()) pal.setColor(QtGui.QPalette.Base, color) if (color.red() > 192 or color.blue() > 192 or color.green() > 192): pal.setColor(QtGui.QPalette.Text, QtCore.Qt.black) else: pal.setColor(QtGui.QPalette.Text, QtCore.Qt.white) editor.control.setPalette(pal) #---------------------------------------------------------------------------- # Creates a custom color editor panel for a specified editor: #---------------------------------------------------------------------------- def color_editor_for(editor, parent): """ Creates a custom color editor panel for a specified editor. """ # Create the colour samples if it hasn't already been done. if len(color_samples) == 0: color_choices = (0, 128, 192, 255) for r in color_choices: for g in color_choices: for b in (0, 128, 255): color_samples.append(QtGui.QColor(r, g, b)) root = QtGui.QWidget() panel = QtGui.QHBoxLayout(root) panel.setContentsMargins(0, 0, 0, 0) swatch_editor = editor.factory.simple_editor(editor.ui, editor.object, editor.name, editor.description, None) swatch_editor.prepare(parent) panel.addWidget(swatch_editor.control) # Add all of the color choice buttons: grid = QtGui.QGridLayout() grid.setSpacing(0) mapper = QtCore.QSignalMapper(panel) rows = 4 cols = len(color_samples) / rows i = 0 for r in range(rows): for c in range(cols): control = QtGui.QPushButton() control.setMaximumSize(18, 18) QtCore.QObject.connect(control, QtCore.SIGNAL('clicked()'), mapper, QtCore.SLOT('map()')) color = color_samples[r*cols + c] color_text = '%d,%d,%d,%d' % color.getRgb() mapper.setMapping(control, color_text) pal = QtGui.QPalette(control.palette()) pal.setColor(QtGui.QPalette.Button, color_samples[i]) control.setPalette(pal) grid.addWidget(control, r, c) editor.set_tooltip(control) i += 1 QtCore.QObject.connect(mapper, QtCore.SIGNAL('mapped(const QString &)'), editor.update_object_from_swatch) panel.addLayout(grid) return root # Define the SimpleEditor, CustomEditor, etc. classes which are used by the # editor factory for the color editor. SimpleEditor = SimpleColorEditor CustomEditor = CustomColorEditor TextEditor = TextColorEditor ReadonlyEditor = ReadonlyColorEditor traitsui-4.1.0/traitsui/qt4/text_editor.py0000644000175100001440000002040311674463546021640 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2007, Riverbank Computing Limited # All rights reserved. # # This software is provided without warranty under the terms of the BSD license. # However, when used with the GPL version of PyQt the additional terms described in the PyQt GPL exception also apply # # Author: Riverbank Computing Limited #------------------------------------------------------------------------------ """ Defines the various text editors for the PyQt user interface toolkit. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from pyface.qt import QtCore, QtGui from traits.api \ import TraitError # FIXME: ToolkitEditorFactory is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.text_editor file. from traitsui.editors.text_editor \ import evaluate_trait, ToolkitEditorFactory from editor \ import Editor from editor_factory \ import ReadonlyEditor as BaseReadonlyEditor from constants \ import OKColor #------------------------------------------------------------------------------- # 'SimpleEditor' class: #------------------------------------------------------------------------------- class SimpleEditor ( Editor ): """ Simple style text editor, which displays a text field. """ # Flag for window styles: base_style = QtGui.QLineEdit # Background color when input is OK: ok_color = OKColor #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Function used to evaluate textual user input: evaluate = evaluate_trait #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ factory = self.factory wtype = self.base_style self.evaluate = factory.evaluate self.sync_value(factory.evaluate_name, 'evaluate', 'from') if not factory.multi_line or factory.is_grid_cell or factory.password: wtype = QtGui.QLineEdit multi_line = (wtype is not QtGui.QLineEdit) if multi_line: self.scrollable = True control = wtype(self.str_value) if factory.read_only: control.setReadOnly(True) if factory.password: control.setEchoMode(QtGui.QLineEdit.Password) if factory.auto_set and not factory.is_grid_cell: if wtype == QtGui.QTextEdit: QtCore.QObject.connect(control, QtCore.SIGNAL('textChanged()'), self.update_object) else: QtCore.QObject.connect(control, QtCore.SIGNAL('textEdited(QString)'), self.update_object) else: # Assume enter_set is set, otherwise the value will never get # updated. QtCore.QObject.connect(control, QtCore.SIGNAL('editingFinished()'), self.update_object) self.control = control self.set_error_state( False ) self.set_tooltip() #--------------------------------------------------------------------------- # Handles the user entering input data in the edit control: #--------------------------------------------------------------------------- def update_object ( self ): """ Handles the user entering input data in the edit control. """ if (not self._no_update) and (self.control is not None): try: self.value = self._get_user_value() if self._error is not None: self._error = None self.ui.errors -= 1 self.set_error_state( False ) except TraitError, excp: pass #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ user_value = self._get_user_value() try: unequal = bool(user_value != self.value) except ValueError: # This might be a numpy array. unequal = True if unequal: self._no_update = True self.control.setText(self.str_value) self._no_update = False if self._error is not None: self._error = None self.ui.errors -= 1 self.set_error_state( False ) #--------------------------------------------------------------------------- # Gets the actual value corresponding to what the user typed: #--------------------------------------------------------------------------- def _get_user_value ( self ): """ Gets the actual value corresponding to what the user typed. """ try: value = self.control.text() except AttributeError: value = self.control.toPlainText() value = unicode(value) try: value = self.evaluate( value ) except: pass try: ret = self.factory.mapping.get(value, value) except TypeError: # The value is probably not hashable. ret = value return ret #--------------------------------------------------------------------------- # Handles an error that occurs while setting the object's trait value: #--------------------------------------------------------------------------- def error ( self, excp ): """ Handles an error that occurs while setting the object's trait value. """ if self._error is None: self._error = True self.ui.errors += 1 self.set_error_state( True ) #--------------------------------------------------------------------------- # Returns whether or not the editor is in an error state: #--------------------------------------------------------------------------- def in_error_state ( self ): """ Returns whether or not the editor is in an error state. """ return (self.invalid or self._error) #------------------------------------------------------------------------------- # 'CustomEditor' class: #------------------------------------------------------------------------------- class CustomEditor ( SimpleEditor ): """ Custom style of text editor, which displays a multi-line text field. """ # FIXME: The wx version exposes a wx constant. # Flag for window style. This value overrides the default. base_style = QtGui.QTextEdit #------------------------------------------------------------------------------- # 'ReadonlyEditor' class: #------------------------------------------------------------------------------- class ReadonlyEditor ( BaseReadonlyEditor ): """ Read-only style of text editor, which displays a read-only text field. """ def init(self, parent): super(ReadonlyEditor, self).init(parent) if self.factory.readonly_allow_selection: flags = (self.control.textInteractionFlags() | QtCore.Qt.TextSelectableByMouse) self.control.setTextInteractionFlags(flags) #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ new_value = self.str_value if self.factory.password: new_value = '*' * len(new_value) self.control.setText(new_value) traitsui-4.1.0/traitsui/qt4/file_editor.py0000644000175100001440000003030711674463546021577 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2007, Riverbank Computing Limited # All rights reserved. # # This software is provided without warranty under the terms of the BSD license. # However, when used with the GPL version of PyQt the additional terms described in the PyQt GPL exception also apply # # Author: Riverbank Computing Limited #------------------------------------------------------------------------------ """ Defines file editors for the PyQt user interface toolkit. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from os.path import splitext, isfile, exists from pyface.qt import QtCore, QtGui from traits.api import List, Event, File, Unicode, TraitError # FIXME: ToolkitEditorFactory is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.file_editor file. from traitsui.editors.file_editor import ToolkitEditorFactory from text_editor import SimpleEditor as SimpleTextEditor from helper import IconButton #------------------------------------------------------------------------------- # Trait definitions: #------------------------------------------------------------------------------- # Wildcard filter: filter_trait = List(Unicode) #------------------------------------------------------------------------------- # 'SimpleEditor' class: #------------------------------------------------------------------------------- class SimpleEditor ( SimpleTextEditor ): """ Simple style of file editor, consisting of a text field and a **Browse** button that opens a file-selection dialog box. The user can also drag and drop a file onto this control. """ #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self.control = QtGui.QWidget() layout = QtGui.QHBoxLayout(self.control) layout.setContentsMargins(0, 0, 0, 0) self._file_name = control = QtGui.QLineEdit() layout.addWidget(control) if self.factory.auto_set: signal = QtCore.SIGNAL('textEdited(QString)') else: # Assume enter_set is set, or else the value will never get updated. signal = QtCore.SIGNAL('editingFinished()') QtCore.QObject.connect(control, signal, self.update_object) button = IconButton(QtGui.QStyle.SP_DirIcon, self.show_file_dialog) layout.addWidget(button) self.set_tooltip(control) #--------------------------------------------------------------------------- # Handles the user changing the contents of the edit control: #--------------------------------------------------------------------------- def update_object(self): """ Handles the user changing the contents of the edit control. """ if self.control is not None: file_name = unicode(self._file_name.text()) try: if self.factory.truncate_ext: file_name = splitext( file_name )[0] self.value = file_name except TraitError, excp: self._file_name.setText(self.value) #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ self._file_name.setText(self.str_value) #--------------------------------------------------------------------------- # Displays the pop-up file dialog: #--------------------------------------------------------------------------- def show_file_dialog(self): """ Displays the pop-up file dialog. """ # We don't used the canned functions because we don't know how the # file name is to be used (ie. an existing one to be opened or a new # one to be created). dlg = self._create_file_dialog() if dlg.exec_() == QtGui.QDialog.Accepted: files = dlg.selectedFiles() if len(files) > 0: file_name = unicode(files[0]) if self.factory.truncate_ext: file_name = splitext(file_name)[0] self.value = file_name self.update_editor() #--------------------------------------------------------------------------- # Returns the editor's control for indicating error status: #--------------------------------------------------------------------------- def get_error_control ( self ): """ Returns the editor's control for indicating error status. """ return self._file_name #-- Private Methods -------------------------------------------------------- def _create_file_dialog ( self ): """ Creates the correct type of file dialog. """ dlg = QtGui.QFileDialog(self.control) dlg.selectFile(self._file_name.text()) if len(self.factory.filter) > 0: dlg.setNameFilters(self.factory.filter) return dlg #------------------------------------------------------------------------------- # 'CustomEditor' class: #------------------------------------------------------------------------------- class CustomEditor ( SimpleTextEditor ): """ Custom style of file editor, consisting of a file system tree view. """ # Is the file editor scrollable? This value overrides the default. scrollable = True # Wildcard filter to apply to the file dialog: filter = filter_trait # The root path of the file tree view. root_path = File # Event fired when the file system view should be rebuilt: reload = Event # Event fired when the user double-clicks a file: dclick = Event #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self.control = _TreeView(self) self._model = model = QtGui.QFileSystemModel() self.control.setModel(model) # Don't apply filters to directories and don't show "." and ".." model.setFilter(QtCore.QDir.AllDirs | QtCore.QDir.Files | QtCore.QDir.Drives | QtCore.QDir.NoDotAndDotDot) # Hide filtered out files instead of only disabling them self._model.setNameFilterDisables(False) # Show the full filesystem by default. model.setRootPath(QtCore.QDir.rootPath()) # Hide the labels at the top and only show the column for the file name self.control.header().hide() for column in xrange(1, model.columnCount()): self.control.hideColumn(column) factory = self.factory self.filter = factory.filter self.root_path = factory.root_path self.sync_value(factory.filter_name, 'filter', 'from', is_list=True) self.sync_value(factory.root_path_name, 'root_path', 'from') self.sync_value(factory.reload_name, 'reload', 'from') self.sync_value(factory.dclick_name, 'dclick', 'to') self.set_tooltip() # This is needed to enable horizontal scrollbar. self.control.header().setResizeMode(0, QtGui.QHeaderView.ResizeToContents) self.control.header().setStretchLastSection(False) #--------------------------------------------------------------------------- # Handles the user changing the contents of the edit control: #--------------------------------------------------------------------------- def update_object(self, idx): """ Handles the user changing the contents of the edit control. """ if self.control is not None: path = unicode(self._model.filePath(idx)) if self.factory.allow_dir or isfile(path): if self.factory.truncate_ext: path = splitext( path )[0] self.value = path #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ if exists(self.str_value): index = self._model.index(self.str_value) self.control.expand(index) self.control.setCurrentIndex(index) #--------------------------------------------------------------------------- # Handles the 'filter' trait being changed: #--------------------------------------------------------------------------- def _filter_changed ( self ): """ Handles the 'filter' trait being changed. """ self._model.setNameFilters(self.filter) #--------------------------------------------------------------------------- # Handles the 'root_path' trait being changed: #--------------------------------------------------------------------------- def _root_path_changed ( self ): """ Handles the 'root_path' trait being changed. """ path = self.root_path if not path: path = QtCore.QDir.rootPath() self._model.setRootPath(path) self.control.setRootIndex(self._model.index(path)) #--------------------------------------------------------------------------- # Handles the user double-clicking on a file name: #--------------------------------------------------------------------------- def _on_dclick ( self, idx ): """ Handles the user double-clicking on a file name. """ self.dclick = unicode(self._model.filePath(idx)) #--------------------------------------------------------------------------- # Handles the 'reload' trait being changed: #--------------------------------------------------------------------------- def _reload_changed ( self ): """ Handles the 'reload' trait being changed. """ self._model.refresh() #------------------------------------------------------------------------------- # '_TreeView' class: #------------------------------------------------------------------------------- class _TreeView(QtGui.QTreeView): """ This is an internal class needed because QAbstractItemView doesn't provide a signal for when the current index changes. """ def __init__(self, editor): super(_TreeView, self).__init__() self.doubleClicked.connect(editor._on_dclick) self._editor = editor def event(self, event): if event.type() == QtCore.QEvent.ToolTip: index = self.indexAt(event.pos()) if index and index.isValid(): QtGui.QToolTip.showText(event.globalPos(), index.data(), self) else: QtGui.QToolTip.hideText() event.ignore() return True return super(_TreeView, self).event(event) def keyPressEvent(self, keyevent): key = keyevent.key() if key == QtCore.Qt.Key_Return or key == QtCore.Qt.Key_Enter: self._editor._on_dclick(self.selectedIndexes()[0]) keyevent.accept() QtGui.QTreeView.keyPressEvent(self, keyevent) def currentChanged(self, current, previous): """ Reimplemented to tell the editor when the current index has changed. """ super(_TreeView, self).currentChanged(current, previous) self._editor.update_object(current) traitsui-4.1.0/traitsui/qt4/shell_editor.py0000644000175100001440000000265711674463546021776 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2011, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # #------------------------------------------------------------------------------- """ Editor that displays an interactive Python shell. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- # FIXME: ToolkitEditorFactory is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.shell_editor file. from traitsui.editors.shell_editor import \ _ShellEditor as BaseShellEditor from editor import Editor #------------------------------------------------------------------------------- # 'ShellEditor' class: #------------------------------------------------------------------------------- class _ShellEditor(BaseShellEditor, Editor): """ Editor that displays an interactive Python shell. """ def init(self, parent): super(_ShellEditor, self).init(None) traitsui-4.1.0/traitsui/qt4/table_editor.py0000644000175100001440000013535711674463546021762 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2008, Riverbank Computing Limited # All rights reserved. # # This software is provided without warranty under the terms of the BSD license. # However, when used with the GPL version of PyQt the additional terms described # in the PyQt GPL exception also apply. # # Author: Riverbank Computing Limited #------------------------------------------------------------------------------ """ Defines the table editor for the PyQt user interface toolkit. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from pyface.qt import QtCore, QtGui from pyface.timer.api import do_later from traits.api import Any, Bool, Button, Event, List, HasTraits, \ Instance, Int, Property, Str, cached_property, on_trait_change from traitsui.api import EnumEditor, InstanceEditor, Group, \ Handler, Item, Label, TableColumn, TableFilter, UI, View, default_handler, \ spring from traitsui.editors.table_editor import BaseTableEditor, \ ReversedList, ToolkitEditorFactory, customize_filter from traitsui.ui_traits import SequenceTypes from editor import Editor from table_model import TableModel, SortFilterTableModel #------------------------------------------------------------------------------- # 'TableEditor' class: #------------------------------------------------------------------------------- class TableEditor(Editor, BaseTableEditor): """ Editor that presents data in a table. Optionally, tables can have a set of filters that reduce the set of data displayed, according to their criteria. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # The table view control associated with the editor: table_view = Any def _table_view_default(self): return TableView(editor=self) # A wrapper around the source model which provides filtering and sorting: model = Instance(SortFilterTableModel) def _model_default(self): return SortFilterTableModel(editor=self) # The table model associated with the editor: source_model = Instance(TableModel) def _source_model_default(self): return TableModel(editor=self) # The set of columns currently defined on the editor: columns = List(TableColumn) # The currently selected row(s), column(s), or cell(s). selected = Any # The current selected row selected_row = Property(Any, depends_on='selected') selected_indices = Property(Any, depends_on='selected') # Current filter object (should be a TableFilter or callable or None): filter = Any # The indices of the table items currently passing the table filter: filtered_indices = List(Int) # Current filter summary message filter_summary = Str('All items') # Update the filtered contents. update_filter = Event() # The event fired when a cell is clicked on: click = Event # The event fired when a cell is double-clicked on: dclick = Event # The Traits UI associated with the table editor toolbar: toolbar_ui = Instance(UI) # The context menu associated with empty space in the table empty_menu = Instance(QtGui.QMenu) # The context menu associated with the vertical header header_menu = Instance(QtGui.QMenu) # The context menu actions for moving rows up and down header_menu_up = Instance(QtGui.QAction) header_menu_down = Instance(QtGui.QAction) # The index of the row that was last right clicked on its vertical header header_row = Int # Whether to auto-size the columns or not. auto_size = Bool(False) #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init(self, parent): """Finishes initializing the editor by creating the underlying toolkit widget.""" factory = self.factory self.columns = factory.columns[:] if factory.table_view_factory is not None: self.table_view = factory.table_view_factory(editor=self) if factory.source_model_factory is not None: self.source_model = factory.source_model_factory(editor=self) if factory.model_factory is not None: self.model = factory.model_factory(editor=self) # Create the table view and model self.model.setDynamicSortFilter(True) self.model.setSourceModel(self.source_model) self.table_view.setModel(self.model) # Create the vertical header context menu and connect to its signals self.header_menu = QtGui.QMenu(self.table_view) signal = QtCore.SIGNAL('triggered()') insertable = factory.row_factory is not None and not factory.auto_add if factory.editable: if insertable: action = self.header_menu.addAction('Insert new item') QtCore.QObject.connect(action, signal, self._on_context_insert) if factory.deletable: action = self.header_menu.addAction('Delete item') QtCore.QObject.connect(action, signal, self._on_context_remove) if factory.reorderable: if factory.editable and (insertable or factory.deletable): self.header_menu.addSeparator() self.header_menu_up = self.header_menu.addAction('Move item up') QtCore.QObject.connect(self.header_menu_up, signal, self._on_context_move_up) self.header_menu_down = self.header_menu.addAction('Move item down') QtCore.QObject.connect(self.header_menu_down, signal, self._on_context_move_down) # Create the empty space context menu and connect its signals self.empty_menu = QtGui.QMenu(self.table_view) action = self.empty_menu.addAction('Add new item') QtCore.QObject.connect(action, signal, self._on_context_append) # When sorting is enabled, the first column is initially displayed with # the triangle indicating it is the sort index, even though no sorting # has actually been done. Sort here for UI/model consistency. if self.factory.sortable and not self.factory.reorderable: self.model.sort(0, QtCore.Qt.AscendingOrder) # Connect to the mode specific selection handler and select the first # row/column/cell. Do this before creating the edit_view to make sure # that it has a valid item to use when constructing its view. smodel = self.table_view.selectionModel() signal = QtCore.SIGNAL('selectionChanged(QItemSelection, QItemSelection)') mode_slot = getattr(self, '_on_%s_selection' % factory.selection_mode) QtCore.QObject.connect(smodel, signal, mode_slot) self.table_view.setCurrentIndex(self.model.index(0, 0)) # Create the toolbar if necessary if factory.show_toolbar and len(factory.filters) > 0: main_view = QtGui.QWidget() layout = QtGui.QVBoxLayout(main_view) layout.setContentsMargins(0, 0, 0, 0) self.toolbar_ui = self.edit_traits( parent = parent, kind = 'subpanel', view = View(Group(Item('filter{View}', editor = factory._filter_editor ), Item('filter_summary{Results}', style = 'readonly'), spring, orientation='horizontal'), resizable = True)) self.toolbar_ui.parent = self.ui layout.addWidget(self.toolbar_ui.control) layout.addWidget(self.table_view) else: main_view = self.table_view # Create auxillary editor and encompassing splitter if necessary mode = factory.selection_mode if (factory.edit_view == ' ') or not mode in ('row', 'rows'): self.control = main_view else: self.control = QtGui.QSplitter(QtCore.Qt.Vertical) self.control.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) self.control.addWidget(main_view) self.control.setStretchFactor(0, 2) # Create the row editor below the table view editor = InstanceEditor(view=factory.edit_view, kind='subpanel') self._ui = self.edit_traits( parent = self.control, kind = 'subpanel', view = View(Item('selected_row', style = 'custom', editor = editor, show_label = False, resizable = True, width = factory.edit_view_width, height = factory.edit_view_height), resizable = True, handler = factory.edit_view_handler)) self._ui.parent = self.ui self.control.addWidget(self._ui.control) self.control.setStretchFactor(1, 1) # Connect to the click and double click handlers signal = QtCore.SIGNAL('clicked(QModelIndex)') QtCore.QObject.connect(self.table_view, signal, self._on_click) signal = QtCore.SIGNAL('doubleClicked(QModelIndex)') QtCore.QObject.connect(self.table_view, signal, self._on_dclick) # Make sure we listen for 'items' changes as well as complete list # replacements self.context_object.on_trait_change( self.update_editor, self.extended_name + '_items', dispatch='ui') # Listen for changes to traits on the objects in the list self.context_object.on_trait_change( self.refresh_editor, self.extended_name + '.-', dispatch='ui') # Listen for changes on column definitions self.on_trait_change(self._update_columns, 'columns', dispatch='ui') self.on_trait_change(self._update_columns, 'columns_items', dispatch='ui') # Set up the required externally synchronized traits is_list = (mode in ('rows', 'columns', 'cells')) self.sync_value(factory.click, 'click', 'to') self.sync_value(factory.dclick, 'dclick', 'to') self.sync_value(factory.columns_name, 'columns', is_list=True) self.sync_value(factory.selected, 'selected', is_list=is_list) self.sync_value(factory.selected_indices, 'selected_indices', is_list=is_list) self.sync_value(factory.filter_name, 'filter', 'from') self.sync_value(factory.filtered_indices, 'filtered_indices', 'to') self.sync_value(factory.update_filter_name, 'update_filter', 'from') self.auto_size = self.factory.auto_size # Initialize the ItemDelegates for each column self._update_columns() #--------------------------------------------------------------------------- # Disposes of the contents of an editor: #--------------------------------------------------------------------------- def dispose(self): """ Disposes of the contents of an editor.""" # Disconnect the table view from its model to ensure that they do not # continue to interact (the control won't be deleted until later). self.table_view.setModel(None) # Make sure that the auxillary UIs are properly disposed if self.toolbar_ui is not None: self.toolbar_ui.dispose() if self._ui is not None: self._ui.dispose() # Remove listener for 'items' changes on object trait self.context_object.on_trait_change( self.update_editor, self.extended_name + '_items', remove=True) # Remove listener for changes to traits on the objects in the list self.context_object.on_trait_change( self.refresh_editor, self.extended_name + '.-', remove=True) # Remove listeners for column definition changes self.on_trait_change(self._update_columns, 'columns', remove=True) self.on_trait_change(self._update_columns, 'columns_items', remove=True) super(TableEditor, self).dispose() #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor(self): """Updates the editor when the object trait changes externally to the editor.""" if self._no_notify: return self.table_view.setUpdatesEnabled(False) try: filtering = len(self.factory.filters) > 0 or self.filter is not None if filtering: self._update_filtering() # invalidate the model, but do not reset it. Resetting the model # may cause problems if the selection sync'ed traits are being used # externally to manage the selections self.model.invalidate() self.table_view.resizeColumnsToContents() if self.auto_size: self.table_view.resizeRowsToContents() finally: self.table_view.setUpdatesEnabled(True) def restore_prefs ( self, prefs ): """ Restores any saved user preference information associated with the editor. """ header = self.table_view.horizontalHeader() if header is not None and 'column_state' in prefs: header.restoreState(prefs['column_state']) def save_prefs ( self ): """ Returns any user preference information associated with the editor. """ prefs = {} header = self.table_view.horizontalHeader() if header is not None: prefs['column_state'] = str(header.saveState()) return prefs #--------------------------------------------------------------------------- # Requests that the underlying table widget to redraw itself: #--------------------------------------------------------------------------- def refresh_editor(self): """Requests that the underlying table widget to redraw itself.""" self.table_view.viewport().update() #--------------------------------------------------------------------------- # Creates a new row object using the provided factory: #--------------------------------------------------------------------------- def create_new_row(self): """Creates a new row object using the provided factory.""" factory = self.factory kw = factory.row_factory_kw.copy() if '__table_editor__' in kw: kw[ '__table_editor__' ] = self return self.ui.evaluate(factory.row_factory, *factory.row_factory_args, **kw) #--------------------------------------------------------------------------- # Returns the raw list of model objects: #--------------------------------------------------------------------------- def items(self): """Returns the raw list of model objects.""" items = self.value if not isinstance(items, SequenceTypes): items = [ items ] if self.factory.reverse: items = ReversedList(items) return items #--------------------------------------------------------------------------- # Perform actions without notifying the underlying table view or model: #--------------------------------------------------------------------------- def callx(self, func, *args, **kw): """Call a function without notifying the underlying table view or model.""" old = self._no_notify self._no_notify = True try: func(*args, **kw) finally: self._no_notify = old def setx(self, **keywords): """Set one or more attributes without notifying the underlying table view or model.""" old = self._no_notify self._no_notify = True try: for name, value in keywords.items(): setattr(self, name, value) finally: self._no_notify = old #--------------------------------------------------------------------------- # Sets the current selection to a set of specified objects: #--------------------------------------------------------------------------- def set_selection(self, objects=[], notify=True): """Sets the current selection to a set of specified objects.""" if not isinstance(objects, SequenceTypes): objects = [ objects ] mode = self.factory.selection_mode indexes = [] flags = QtGui.QItemSelectionModel.ClearAndSelect # In the case of row or column selection, we need a dummy value for the # other dimension that has not been filtered. source_index = self.model.mapToSource(self.model.index(0, 0)) source_row, source_column = source_index.row(), source_index.column() # Selection mode is 'row' or 'rows' if mode.startswith('row'): flags |= QtGui.QItemSelectionModel.Rows items = self.items() for obj in objects: try: row = items.index(obj) except ValueError: continue indexes.append(self.source_model.index(row, source_column)) # Selection mode is 'column' or 'columns' elif mode.startswith('column'): flags |= QtGui.QItemSelectionModel.Columns for name in objects: column = self._column_index_from_name(name) if column != -1: indexes.append(self.source_model.index(source_row, column)) # Selection mode is 'cell' or 'cells' else: items = self.items() for obj, name in objects: try: row = items.index(obj) except ValueError: continue column = self._column_index_from_name(name) if column != -1: indexes.append(self.source_model.index(row, column)) # Perform the selection so that only one signal is emitted selection = QtGui.QItemSelection() for index in indexes: index = self.model.mapFromSource(index) if index.isValid(): self.table_view.setCurrentIndex(index) selection.select(index, index) smodel = self.table_view.selectionModel() try: smodel.blockSignals(not notify) if len(selection.indexes()): smodel.select(selection, flags) else: smodel.clear() finally: smodel.blockSignals(False) #--------------------------------------------------------------------------- # Private methods: #--------------------------------------------------------------------------- def _column_index_from_name(self, name): """Returns the index of the column with the given name or -1 if no column exists with that name.""" for i, column in enumerate(self.columns): if name == column.name: return i return -1 def _customize_filters(self, filter): """Allows the user to customize the current set of table filters.""" filter_editor = TableFilterEditor(editor=self) ui = filter_editor.edit_traits(parent=self.control) if ui.result: self.factory.filters = filter_editor.templates self.filter = filter_editor.selected_filter else: self.setx(filter = filter) def _update_filtering(self): """Update the filter summary and the filtered indices.""" items = self.items() num_items = len(items) f = self.filter if f is None: self._filtered_cache = None self.filtered_indices = range(num_items) self.filter_summary = 'All %i items' % num_items else: if not callable(f): f = f.filter self._filtered_cache = fc = [ f(item) for item in items ] self.filtered_indices = fi = [ i for i, ok in enumerate(fc) if ok ] self.filter_summary = '%i of %i items' % (len(fi), num_items) #-- Trait Property getters/setters ----------------------------------------- @cached_property def _get_selected_row(self): """Gets the selected row, or the first row if multiple rows are selected.""" mode = self.factory.selection_mode if mode.startswith('column'): return None elif mode == 'row': return self.selected try: if mode == 'rows': return self.selected[0] elif mode == 'cell': return self.selected[0] elif mode == 'cells': return self.selected[0][0] except IndexError: return None @cached_property def _get_selected_indices(self): """Gets the row,column indices which match the selected trait""" if len(self.selected) == 0: return [] selection_items = self.table_view.selectionModel().selection() indices = self.model.mapSelectionFromSource(selection_items).indexes() return [(index.row(), index.column()) for index in indices] def _set_selected_indices(self, indices): selected = [] for row, col in indices: selected.append((self.value[row], self.columns[col].name)) self.selected = selected self.set_selection(self.selected, False) return #-- Trait Change Handlers -------------------------------------------------- def _filter_changed(self, old_filter, new_filter): """Handles the current filter being changed.""" if not self._no_notify: if new_filter is customize_filter: do_later(self._customize_filters, old_filter) else: self._update_filtering() self.model.invalidate() self.set_selection(self.selected) def _update_columns(self): """Handle the column list being changed.""" self.table_view.setItemDelegate(TableDelegate(self.table_view)) for i, column in enumerate(self.columns): if column.renderer: self.table_view.setItemDelegateForColumn(i, column.renderer) self.model.reset() self.table_view.resizeColumnsToContents() if self.auto_size: self.table_view.resizeRowsToContents() def _selected_changed(self, new): """Handle the selected row/column/cell being changed externally.""" if not self._no_notify: self.set_selection(self.selected, notify=False) def _update_filter_changed(self): """ The filter has changed internally. """ self._filter_changed(self.filter, self.filter) #-- Event Handlers --------------------------------------------------------- def _on_row_selection(self, added, removed): """Handle the row selection being changed.""" items = self.items() indexes = self.table_view.selectionModel().selectedRows() if len(indexes): index = self.model.mapToSource(indexes[0]) selected = items[index.row()] else: selected = None self.setx(selected = selected) self.ui.evaluate(self.factory.on_select, self.selected) def _on_rows_selection(self, added, removed): """Handle the rows selection being changed.""" items = self.items() indexes = self.table_view.selectionModel().selectedRows() selected = [ items[self.model.mapToSource(index).row()] for index in indexes ] self.setx(selected = selected) self.ui.evaluate(self.factory.on_select, self.selected) def _on_column_selection(self, added, removed): """Handle the column selection being changed.""" indexes = self.table_view.selectionModel().selectedColumns() if len(indexes): index = self.model.mapToSource(indexes[0]) selected = self.columns[index.column()].name else: selected = '' self.setx(selected = selected) self.ui.evaluate(self.factory.on_select, self.selected) def _on_columns_selection(self, added, removed): """Handle the columns selection being changed.""" indexes = self.table_view.selectionModel().selectedColumns() selected = [ self.columns[self.model.mapToSource(index).column()].name for index in indexes ] self.setx(selected = selected) self.ui.evaluate(self.factory.on_select, self.selected) def _on_cell_selection(self, added, removed): """Handle the cell selection being changed.""" items = self.items() indexes = self.table_view.selectionModel().selectedIndexes() if len(indexes): index = self.model.mapToSource(indexes[0]) obj = items[index.row()] column_name = self.columns[index.column()].name else: obj = None column_name = '' selected = (obj, column_name) self.setx(selected = selected) self.ui.evaluate(self.factory.on_select, self.selected) def _on_cells_selection(self, added, removed): """Handle the cells selection being changed.""" items = self.items() indexes = self.table_view.selectionModel().selectedIndexes() selected = [] for index in indexes: index = self.model.mapToSource(index) obj = items[index.row()] column_name = self.columns[index.column()].name selected.append((obj, column_name)) self.setx(selected = selected) self.ui.evaluate(self.factory.on_select, self.selected) def _on_click(self, index): """Handle a cell being clicked.""" index = self.model.mapToSource(index) column = self.columns[index.column()] obj = self.items()[index.row()] # Fire the same event on the editor after mapping it to a model object # and column name: self.click = (obj, column) # Invoke the column's click handler: column.on_click(obj) def _on_dclick(self, index): """Handle a cell being double clicked.""" index = self.model.mapToSource(index) column = self.columns[index.column()] obj = self.items()[index.row()] # Fire the same event on the editor after mapping it to a model object # and column name: self.dclick = (obj, column) # Invoke the column's double-click handler: column.on_dclick(obj) def _on_context_insert(self): """Handle 'insert item' being selected from the header context menu.""" self.model.insertRow(self.header_row) def _on_context_append(self): """Handle 'add item' being selected from the empty space context menu.""" self.model.insertRow(self.model.rowCount()) def _on_context_remove(self): """Handle 'remove item' being selected from the header context menu.""" self.model.removeRow(self.header_row) def _on_context_move_up(self): """Handle 'move up' being selected from the header context menu.""" self.model.moveRow(self.header_row, self.header_row - 1) def _on_context_move_down(self): """Handle 'move down' being selected from the header context menu.""" self.model.moveRow(self.header_row, self.header_row + 1) # Define the SimpleEditor class. SimpleEditor = TableEditor # Define the ReadonlyEditor class. ReadonlyEditor = TableEditor #------------------------------------------------------------------------------- # Qt widgets that have been configured to behave as expected by Traits UI: #------------------------------------------------------------------------------- class TableDelegate(QtGui.QStyledItemDelegate): """ A QStyledItemDelegate which fetches Traits UI editors. """ def createEditor(self, parent, option, index): """ Reimplemented to return the editor for a given index.""" model = index.model() index = model.mapToSource(index) table_editor = model._editor column = table_editor.columns[index.column()] obj = table_editor.items()[index.row()] factory = column.get_editor(obj) style = column.get_style(obj) if factory is None: return None target, name = column.target_name(obj) handler = default_handler() if table_editor.ui.context is None: ui = UI(handler=handler) else: context = table_editor.ui.context.copy() context['table_editor_object'] = context['object'] context['object'] = target ui = UI(handler=handler, context=context) # Create and initialize the editor factory_method = getattr(factory, style+'_editor') editor = factory_method(ui, target, name, '', parent) editor.prepare(parent) control = editor.control control.setParent(parent) # Required for QMouseEvents to propagate to the widget control.setFocusPolicy(QtCore.Qt.StrongFocus) # The table view's background will shine through unless the editor # paints its own background control.setAutoFillBackground(True) # Make sure that editors are disposed of correctly # will be disposed in closeEditor of the TableView control._editor = editor return control def updateEditorGeometry(self, editor, option, index): """ Update the editor's geometry. """ editor.setGeometry(option.rect) class TableView(QtGui.QTableView): """A QTableView configured to behave as expected by TraitsUI.""" _SELECTION_MAP = { 'row': (QtGui.QAbstractItemView.SelectRows, QtGui.QAbstractItemView.SingleSelection), 'rows': (QtGui.QAbstractItemView.SelectRows, QtGui.QAbstractItemView.ExtendedSelection), 'column': (QtGui.QAbstractItemView.SelectColumns, QtGui.QAbstractItemView.SingleSelection), 'columns': (QtGui.QAbstractItemView.SelectColumns, QtGui.QAbstractItemView.ExtendedSelection), 'cell': (QtGui.QAbstractItemView.SelectItems, QtGui.QAbstractItemView.SingleSelection), 'cells': (QtGui.QAbstractItemView.SelectItems, QtGui.QAbstractItemView.ExtendedSelection) } def __init__(self, editor): """Initialise the object.""" QtGui.QTableView.__init__(self) self._initial_size = False self._editor = editor factory = editor.factory # Configure the row headings. vheader = self.verticalHeader() insertable = factory.row_factory is not None and not factory.auto_add if ((factory.editable and (insertable or factory.deletable)) or factory.reorderable): vheader.installEventFilter(self) else: vheader.hide() self.setAlternatingRowColors(factory.alternate_bg_color) # Configure the column headings. # We detect if there are any stretchy sections at all; if not, then # we make the last non-fixed-size column stretchy. hheader = self.horizontalHeader() resize_mode_map = dict(interactive = QtGui.QHeaderView.Interactive, fixed = QtGui.QHeaderView.Fixed, stretch = QtGui.QHeaderView.Stretch, resize_to_contents = QtGui.QHeaderView.ResizeToContents) stretchable_columns = [] for i, column in enumerate(editor.columns): hheader.setResizeMode(i, resize_mode_map[column.resize_mode]) if column.resize_mode in ("stretch", "interactive"): stretchable_columns.append(i) if not stretchable_columns: # Use the behavior from before the "resize_mode" trait was added # to TableColumn hheader.setStretchLastSection(True) else: hheader.setResizeMode(stretchable_columns[-1], QtGui.QHeaderView.Stretch) hheader.setStretchLastSection(False) if factory.show_column_labels: hheader.setHighlightSections(False) else: hheader.hide() # Configure the grid lines. self.setShowGrid(factory.show_lines) # Configure the selection behaviour. self.setCornerButtonEnabled(False) behav, mode = self._SELECTION_MAP[factory.selection_mode] self.setSelectionBehavior(behav) self.setSelectionMode(mode) # Configure the editing behavior. triggers = (QtGui.QAbstractItemView.DoubleClicked | QtGui.QAbstractItemView.SelectedClicked) if factory.edit_on_first_click and not factory.reorderable: triggers |= QtGui.QAbstractItemView.CurrentChanged self.setEditTriggers(triggers) # Configure the reordering and sorting behavior. if factory.reorderable: self.setDragEnabled(True) self.setDragDropMode(QtGui.QAbstractItemView.InternalMove) self.setDropIndicatorShown(True) elif factory.sortable: self.setSortingEnabled(True) if factory._qt_stylesheet is not None: self.setStyleSheet(factory._qt_stylesheet) self.resizeColumnsToContents() def contextMenuEvent(self, event): """Reimplemented to create context menus for cells and empty space.""" # Determine the logical indices of the cell where click occured hheader, vheader = self.horizontalHeader(), self.verticalHeader() position = event.globalPos() row = vheader.logicalIndexAt(vheader.mapFromGlobal(position)) column = hheader.logicalIndexAt(hheader.mapFromGlobal(position)) # Map the logical row index to a real index for the source model model = self.model() row = model.mapToSource(model.index(row, 0)).row() # Show a context menu for empty space at bottom of table... editor = self._editor if row == -1: factory = editor.factory if (factory.editable and factory.row_factory is not None and not factory.auto_add): event.accept() editor.empty_menu.exec_(position) # ...or show a context menu for a cell. elif column != -1: obj = editor.items()[row] column = editor.columns[column] menu_manager = column.get_menu(obj) if menu_manager is None: menu_manager = editor.factory.menu if menu_manager is not None: event.accept() selected = editor.selected if not isinstance(selected, SequenceTypes): selected = [ selected ] if obj not in selected: selected = [ obj ] editor.set_menu_context(selected, obj, column) menu = menu_manager.create_menu(self, controller=editor) menu.exec_(position) def eventFilter(self, obj, event): """Reimplemented to create context menu for the vertical header.""" vheader = self.verticalHeader() if (obj is vheader and event.type() == QtCore.QEvent.ContextMenu): event.accept() editor = self._editor row = vheader.logicalIndexAt(event.pos().y()) if row == -1: factory = editor.factory if factory.row_factory is not None and not factory.auto_add: editor.empty_menu.exec_(event.globalPos()) else: editor.header_row = row if editor.factory.reorderable: show_up = row > 0 show_down = row < editor.model.rowCount() - 1 editor.header_menu_up.setVisible(show_up) editor.header_menu_down.setVisible(show_down) self._editor.header_menu.exec_(event.globalPos()) return True else: return QtGui.QTableView.eventFilter(self, obj, event) def resizeEvent(self, event): """Reimplemented to size the table columns when the size of the table changes. Because the layout algorithm requires that the available space be known, we have to wait until the UI that contains this table gives it its initial size.""" QtGui.QTableView.resizeEvent(self, event) if self._editor.auto_size: self.resizeColumnsToContents() self.resizeRowsToContents() else: parent = self.parent() if (not self._initial_size and parent and (self.isVisible() or isinstance(parent, QtGui.QMainWindow))): self._initial_size = True if self._editor.auto_size: self.resizeColumnsToContents() self.resizeRowsToContents() def sizeHint(self): """Reimplemented to define a better size hint for the width of the TableEditor.""" size_hint = QtGui.QTableView.sizeHint(self) # This method is sometimes called by Qt after the editor has been # disposed but before this control has been deleted: if self._editor.factory is None: return size_hint width = self.style().pixelMetric(QtGui.QStyle.PM_ScrollBarExtent, QtGui.QStyleOptionHeader(), self) for column in range(len(self._editor.columns)): width += self.sizeHintForColumn(column) size_hint.setWidth(width) return size_hint def sizeHintForColumn(self, column_index): """Reimplemented to support absolute width specification via TableColumns and to improve the metric for autosizing columns.""" editor = self._editor column = editor.columns[column_index] requested_width = column.get_width() # Autosize based on column contents and label width. Qt's default # implementation of this function does content, we handle the label. if requested_width < 1: base_width = QtGui.QTableView.sizeHintForColumn(self, column_index) # Determine what font to use in the calculation font = column.get_text_font(None) if font is None: font = self.font() font.setBold(True) else: font = QtGui.QFont(font) # Determine the width of the column label text = column.get_label() width = QtGui.QFontMetrics(font).width(text) # Add margin to the calculated width as appropriate style = self.style() option = QtGui.QStyleOptionHeader() width += style.pixelMetric(QtGui.QStyle.PM_HeaderGripMargin, option, self) * 2 if editor.factory.sortable and not editor.factory.reorderable: # Add size of sort indicator width += style.pixelMetric(QtGui.QStyle.PM_HeaderMarkSize, option, self) # Add distance between sort indicator and text width += style.pixelMetric(QtGui.QStyle.PM_HeaderMargin, option, self) return max(base_width, width) # Or else set width absolutely else: return requested_width def resizeColumnsToContents(self): """Reimplemented to support proportional column width specifications.""" # TODO: The proportional size specification approach found in the # TableColumns is not entirely compatible with the ability to # specify the resize_mode. Namely, there are combinations of # specifications that are redundant, and others which are # contradictory. Rework this method so that the various values # for **width** have a well-defined, sensible meaning for each # of the possible values of resize_mode. editor = self._editor available_space = self.viewport().width() hheader = self.horizontalHeader() # Compute sizes for columns with absolute or no size requests proportional = [] for column_index in xrange(len(editor.columns)): column = editor.columns[column_index] requested_width = column.get_width() if column.resize_mode in ("interactive", "stretch") and 0 < requested_width <= 1.0: proportional.append((column_index, requested_width)) else: base_width = hheader.sectionSizeHint(column_index) width = max(base_width, self.sizeHintForColumn(column_index)) hheader.resizeSection(column_index, width) available_space -= width # Now use the remaining space for columns with proportional width # requests for column_index, percent in proportional: base_width = hheader.sectionSizeHint(column_index) width = max(base_width, int(percent * available_space)) hheader.resizeSection(column_index, width) def closeEditor(self, control, hint) : # dispose traits editor associated with control if any editor = getattr(control, "_editor", None) if editor is not None : editor.dispose() delattr(control, "_editor") return super(TableView, self).closeEditor(control, hint) #------------------------------------------------------------------------------- # Editor for configuring the filters available to a TableEditor: #------------------------------------------------------------------------------- class TableFilterEditor(HasTraits): """ An editor that manages table filters. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # TableEditor this editor is associated with editor = Instance(TableEditor) # The list of filters filters = List(TableFilter) # The list of available templates from which filters can be created templates = Property(List(TableFilter), depends_on='filters') # The currently selected filter template selected_template = Instance(TableFilter) # The currently selected filter selected_filter = Instance(TableFilter, allow_none=True) # The view to use for the current filter selected_filter_view = Property(depends_on='selected_filter') # Buttons for add/removing filters add_button = Button('New') remove_button = Button('Delete') # The default view for this editor view = View(Group(Group(Group(Item('add_button', enabled_when='selected_template'), Item('remove_button', enabled_when='len(templates) > 1 and ' \ 'selected_filter is not None'), orientation='horizontal', show_labels=False), Label('Base filter for new filters:'), Item('selected_template', editor=EnumEditor(name='templates')), Item('selected_filter', style='custom', editor=EnumEditor(name='filters', mode='list')), show_labels=False), Item('selected_filter', width=0.75, style='custom', editor=InstanceEditor(view_name='selected_filter_view')), id='TableFilterEditorSplit', show_labels=False, layout='split', orientation='horizontal'), id='traitsui.qt4.table_editor.TableFilterEditor', buttons=[ 'OK', 'Cancel' ], kind='livemodal', resizable=True, width=800, height=400, title='Customize filters') #--------------------------------------------------------------------------- # Private methods: #--------------------------------------------------------------------------- #-- Trait Property getter/setters ------------------------------------------ @cached_property def _get_selected_filter_view(self): view = None if self.selected_filter: model = self.editor.model index = model.mapToSource(model.index(0, 0)) if index.isValid(): obj = self.editor.items()[index.row()] else: obj = None view = self.selected_filter.edit_view(obj) return view @cached_property def _get_templates(self): templates = [ f for f in self.editor.factory.filters if f.template ] templates.extend(self.filters) return templates #-- Trait Change Handlers -------------------------------------------------- def _editor_changed(self): self.filters = [ f.clone_traits() for f in self.editor.factory.filters if not f.template ] self.selected_template = self.templates[0] def _add_button_fired(self): """ Create a new filter based on the selected template and select it. """ new_filter = self.selected_template.clone_traits() new_filter.template = False new_filter.name = new_filter._name = 'New filter' self.filters.append(new_filter) self.selected_filter = new_filter def _remove_button_fired(self): """ Delete the currently selected filter. """ if self.selected_template == self.selected_filter: self.selected_template = self.templates[0] index = self.filters.index(self.selected_filter) del self.filters[index] if index < len(self.filters): self.selected_filter = self.filters[index] else: self.selected_filter = None @on_trait_change('selected_filter:name') def _update_filter_list(self): """ A hack to make the EnumEditor watching the list of filters refresh their text when the name of the selected filter changes. """ filters = self.filters self.filters = [] self.filters = filters traitsui-4.1.0/traitsui/qt4/key_binding_editor.py0000644000175100001440000002003711674463546023141 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2007, Riverbank Computing Limited # All rights reserved. # # This software is provided without warranty under the terms of the BSD license. # However, when used with the GPL version of PyQt the additional terms described in the PyQt GPL exception also apply # # Author: Riverbank Computing Limited #------------------------------------------------------------------------------ """ Defines the key binding editor for use with the KeyBinding class. This is a specialized editor used to associate a particular key with a control (i.e., the key binding editor). """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from pyface.qt import QtCore, QtGui from traits.api \ import Bool, Event # FIXME: ToolkitEditorFactory is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.key_binding_editor file. from traitsui.editors.key_binding_editor \ import KeyBindingEditor as ToolkitEditorFactory from editor \ import Editor from key_event_to_name \ import key_event_to_name #------------------------------------------------------------------------------- # 'KeyBindingEditor' class: #------------------------------------------------------------------------------- class KeyBindingEditor ( Editor ): """ An editor for modifying bindings of keys to controls. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Does the editor's control have focus currently? has_focus = Bool(False) # Keyboard event key = Event # Clear field event clear = Event #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init (self, parent): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self.control = KeyBindingCtrl(self) #--------------------------------------------------------------------------- # Handles the user entering input data in the edit control: #--------------------------------------------------------------------------- def update_object ( self, event ): """ Handles the user entering input data in the edit control. """ try: self.value = value = key_event_to_name( event ) self._binding.text = value except: pass #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ self.control.setText(self.value) #--------------------------------------------------------------------------- # Updates the current focus setting of the control: #--------------------------------------------------------------------------- def update_focus ( self, has_focus ): """ Updates the current focus setting of the control. """ if has_focus: self._binding.border_size = 1 self.object.owner.focus_owner = self._binding #--------------------------------------------------------------------------- # Handles a keyboard event: #--------------------------------------------------------------------------- def _key_changed ( self, event ): """ Handles a keyboard event. """ binding = self.object key_name = key_event_to_name( event ) cur_binding = binding.owner.key_binding_for( binding, key_name ) if cur_binding is not None: if QtGui.QMessageBox.question(self.control, "Duplicate Key Definition", "'%s' has already been assigned to '%s'.\n" "Do you wish to continue?" % (key_name, cur_binding.description), QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No) != QtGui.QMessageBox.Yes: return self.value = key_name #--------------------------------------------------------------------------- # Handles a clear field event: #--------------------------------------------------------------------------- def _clear_changed ( self ): """ Handles a clear field event. """ self.value = '' #------------------------------------------------------------------------------- # 'KeyBindingCtrl' class: #------------------------------------------------------------------------------- class KeyBindingCtrl(QtGui.QLabel): """ PyQt control for editing key bindings. """ #--------------------------------------------------------------------------- # Initialize the object: #--------------------------------------------------------------------------- def __init__(self, editor, parent=None): super(KeyBindingCtrl, self).__init__(parent) self.setFocusPolicy(QtCore.Qt.StrongFocus) self.setIndent(4) self.setMinimumWidth(160) pal = QtGui.QPalette(self.palette()) pal.setColor(QtGui.QPalette.Window, QtCore.Qt.white) self.setPalette(pal) self.setAutoFillBackground(True) # Save the reference to the controlling editor object: self.editor = editor # Indicate we don't have the focus right now: editor.has_focus = False #--------------------------------------------------------------------------- # Handle keyboard keys being pressed: #--------------------------------------------------------------------------- def keyPressEvent(self, event): """ Handle keyboard keys being pressed. """ # Ignore presses of the control and shift keys. if event.key() not in (QtCore.Qt.Key_Control, QtCore.Qt.Key_Shift): self.editor.key = event #--------------------------------------------------------------------------- # Do a GUI toolkit specific screen update: #--------------------------------------------------------------------------- def paintEvent(self, event): """ Updates the screen. """ QtGui.QLabel.paintEvent(self, event) w = self.width() h = self.height() p = QtGui.QPainter(self) if self.editor.has_focus: p.setRenderHint(QtGui.QPainter.Antialiasing, True) pen = QtGui.QPen(QtGui.QColor('tomato')) pen.setWidth(2) p.setPen(pen) p.drawRect(1, 1, w - 2, h - 2) else: p.setPen(self.palette().color(QtGui.QPalette.Mid)) p.drawRect(0, 0, w - 1, h - 1) p.end() #--------------------------------------------------------------------------- # Handles getting/losing the focus: #--------------------------------------------------------------------------- def focusInEvent(self, event): """ Handles getting the focus. """ self.editor.has_focus = True self.update() def focusOutEvent(self, event): """ Handles losing the focus. """ self.editor.has_focus = False self.update() #--------------------------------------------------------------------------- # Handles the user double clicking the control to clear its contents: #--------------------------------------------------------------------------- def mouseDoubleClickEvent(self, event): """ Handles the user double clicking the control to clear its contents. """ self.editor.clear = True traitsui-4.1.0/traitsui/qt4/image_enum_editor.py0000644000175100001440000003010511674463546022762 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2009, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: Evan Patterson # Date: 08/11/2009 # #------------------------------------------------------------------------------ """ Defines the various image enumeration editors for the PyQt user interface toolkit. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from pyface.qt import QtCore, QtGui # FIXME: ToolkitEditorFactory is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.image_enum_editor file. from traitsui.editors.image_enum_editor import ToolkitEditorFactory from editor import Editor from enum_editor import BaseEditor as BaseEnumEditor from enum_editor import SimpleEditor as SimpleEnumEditor from enum_editor import RadioEditor as CustomEnumEditor from helper import pixmap_cache #------------------------------------------------------------------------------- # 'BaseImageEnumEditor' class: #------------------------------------------------------------------------------- class BaseEditor(object): """ The base class for the different styles of ImageEnumEditor. """ def get_pixmap(self, name): """ Get a pixmap representing a possible object traits value. """ factory = self.factory name = ''.join((factory.prefix, name, factory.suffix)) return pixmap_cache(name, factory._image_path) #------------------------------------------------------------------------------- # 'ReadonlyEditor' class: #------------------------------------------------------------------------------- class ReadonlyEditor(BaseEditor, BaseEnumEditor): """ Read-only style of image enumeration editor, which displays a single static image representing the object trait's value. """ #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init(self, parent): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self.control = QtGui.QLabel() self.control.setPixmap(self.get_pixmap(self.str_value)) self.set_tooltip() #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor(self): """ Updates the editor when the object trait changes externally to the editor. """ self.control.setPixmap(self.get_pixmap(self.str_value)) #------------------------------------------------------------------------------- # 'SimpleEditor' class: #------------------------------------------------------------------------------- class SimpleEditor(BaseEditor, SimpleEnumEditor): """ Simple style of image enumeration editor, which displays a combo box. """ #--------------------------------------------------------------------------- # Returns the QComboBox used for the editor control: #--------------------------------------------------------------------------- def create_combo_box(self): """ Returns the QComboBox used for the editor control. """ control = ImageEnumComboBox(self) control.setSizePolicy(QtGui.QSizePolicy.Maximum, QtGui.QSizePolicy.Maximum) return control #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ if self._no_enum_update == 0: self._no_enum_update += 1 try: index = self.names.index(self.inverse_mapping[self.value]) except: self.control.setCurrentIndex(-1) else: cols = self.factory.cols rows = (len(self.names) + cols - 1) / cols row, col = index / cols, index % cols self.control.setModelColumn(col) self.control.setCurrentIndex(row) self._no_enum_update -= 1 #--------------------------------------------------------------------------- # Rebuilds the contents of the editor whenever the original factory # object's 'values' trait changes: #--------------------------------------------------------------------------- def rebuild_editor(self): """ Rebuilds the contents of the editor whenever the original factory object's **values** trait changes. """ self.control.model().reset() #------------------------------------------------------------------------------- # 'CustomEditor' class: #------------------------------------------------------------------------------- class CustomEditor(BaseEditor, CustomEnumEditor): """ Simple style of image enumeration editor, which displays a combo box. """ # Is the button layout row-major or column-major? This value overrides the # default. row_major = True #--------------------------------------------------------------------------- # Returns the QAbstractButton used for the radio button: #--------------------------------------------------------------------------- def create_button(self, name): """ Returns the QAbstractButton used for the radio button. """ button = QtGui.QToolButton() button.setAutoExclusive(True) button.setCheckable(True) pixmap = self.get_pixmap(name) button.setIcon(QtGui.QIcon(pixmap)) button.setIconSize(pixmap.size()) return button #------------------------------------------------------------------------------- # Custom Qt objects used in the SimpleEditor: #------------------------------------------------------------------------------- class ImageEnumComboBox(QtGui.QComboBox): """ A combo box which displays images instead of text. """ def __init__(self, editor, parent=None): """ Reimplemented to store the editor and set a delegate for drawing the items in the popup menu. If there is more than one column, use a TableView instead of ListView for the popup. """ QtGui.QComboBox.__init__(self, parent) self._editor = editor model = ImageEnumModel(editor, self) self.setModel(model) delegate = ImageEnumItemDelegate(editor, self) if editor.factory.cols > 1: view = ImageEnumTablePopupView(self) view.setItemDelegate(delegate) self.setView(view) # Unless we force it, the popup for a combo box will not be wider # than the box itself, so we set a high minimum width. width = 0 for col in xrange(self._editor.factory.cols): width += view.sizeHintForColumn(col) view.setMinimumWidth(width) else: self.setItemDelegate(delegate) def paintEvent(self, event): """ Reimplemented to draw the ComboBox frame and paint the image centered in it. """ painter = QtGui.QStylePainter(self) painter.setPen(self.palette().color(QtGui.QPalette.Text)) option = QtGui.QStyleOptionComboBox() self.initStyleOption(option) painter.drawComplexControl(QtGui.QStyle.CC_ComboBox, option) editor = self._editor pixmap = editor.get_pixmap(editor.inverse_mapping[editor.value]) arrow = self.style().subControlRect(QtGui.QStyle.CC_ComboBox, option, QtGui.QStyle.SC_ComboBoxArrow) option.rect.setWidth(option.rect.width() - arrow.width()) target = QtGui.QStyle.alignedRect(QtCore.Qt.LeftToRight, QtCore.Qt.AlignCenter, pixmap.size(), option.rect) painter.drawPixmap(target, pixmap) def sizeHint(self): """ Reimplemented to set a size hint based on the size of the larget image. """ size = QtCore.QSize() for name in self._editor.names: size = size.expandedTo(self._editor.get_pixmap(name).size()) option = QtGui.QStyleOptionComboBox() self.initStyleOption(option) size = self.style().sizeFromContents(QtGui.QStyle.CT_ComboBox, option, size, self) return size class ImageEnumTablePopupView(QtGui.QTableView): def __init__(self, parent): """ Configure the appearence of the table view. """ QtGui.QTableView.__init__(self, parent) hheader = self.horizontalHeader() hheader.setResizeMode(QtGui.QHeaderView.ResizeToContents) hheader.hide() vheader = self.verticalHeader() vheader.setResizeMode(QtGui.QHeaderView.ResizeToContents) vheader.hide() self.setShowGrid(False) class ImageEnumItemDelegate(QtGui.QStyledItemDelegate): """ An item delegate which draws only images. """ def __init__(self, editor, parent): """ Reimplemented to store the editor. """ QtGui.QStyledItemDelegate.__init__(self, parent) self._editor = editor def displayText(self, value, locale): """ Reimplemented to display nothing. """ return '' def paint(self, painter, option, mi): """ Reimplemented to draw images. """ # Delegate to our superclass to draw the background QtGui.QStyledItemDelegate.paint(self, painter, option, mi) # Now draw the pixmap name = mi.data(QtCore.Qt.DisplayRole) pixmap = self._get_pixmap(name) if pixmap is not None: target = QtGui.QStyle.alignedRect(QtCore.Qt.LeftToRight, QtCore.Qt.AlignCenter, pixmap.size(), option.rect) painter.drawPixmap(target, pixmap) def sizeHint(self, option, mi): """ Reimplemented to define a size hint based on the size of the pixmap. """ name = mi.data(QtCore.Qt.DisplayRole) pixmap = self._get_pixmap(name) if pixmap is None: return QtCore.QSize() return pixmap.size() def _get_pixmap(self, name): return self._editor.get_pixmap(name) class ImageEnumModel(QtCore.QAbstractTableModel): """ A table model for use with the 'simple' style ImageEnumEditor. """ def __init__(self, editor, parent): """ Reimplemented to store the editor. """ super(ImageEnumModel, self).__init__(parent) self._editor = editor def rowCount(self, mi): """ Reimplemented to return the number of rows. """ cols = self._editor.factory.cols result = (len(self._editor.names) + cols - 1) / cols return result def columnCount(self, mi): """ Reimplemented to return the number of columns. """ return self._editor.factory.cols def data(self, mi, role): """ Reimplemented to return the data. """ if role == QtCore.Qt.DisplayRole: index = mi.row() * self._editor.factory.cols + mi.column() if index < len(self._editor.names): return self._editor.names[index] return None traitsui-4.1.0/traitsui/qt4/drop_editor.py0000644000175100001440000001267211674463546021631 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2008, Riverbank Computing Limited # All rights reserved. # # This software is provided without warranty under the terms of the BSD license. # However, when used with the GPL version of PyQt the additional terms described in the PyQt GPL exception also apply # # Author: Riverbank Computing Limited #------------------------------------------------------------------------------ """ Defines a drop target editor for the PyQt user interface toolkit. A drop target editor handles drag and drop operations as a drop target. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from pyface.qt import QtGui # FIXME: ToolkitEditorFactory is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.drop_editor file. from traitsui.editors.drop_editor \ import ToolkitEditorFactory from text_editor \ import SimpleEditor as Editor from constants \ import DropColor from clipboard \ import PyMimeData #------------------------------------------------------------------------------- # 'SimpleEditor' class: #------------------------------------------------------------------------------- class SimpleEditor ( Editor ): """ Simple style of drop editor, which displays a read-only text field that contains the string representation of the object trait's value. """ # Background color when it is OK to drop objects. ok_color = DropColor #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ if self.factory.readonly: self.control = QtGui.QLineEdit(self.str_value) self.control.setReadOnly(True) self.set_tooltip() else: super( SimpleEditor, self ).init( parent ) pal = QtGui.QPalette(self.control.palette()) pal.setColor(QtGui.QPalette.Base, self.ok_color) self.control.setPalette(pal) # Patch the type of the control to insert the DND event handlers. self.control.__class__ = type(_DropWidget.__name__, (type(self.control), ), dict(_DropWidget.__dict__)) self.control._qt4_editor = self #--------------------------------------------------------------------------- # Returns the text representation of a specified object trait value: #--------------------------------------------------------------------------- def string_value ( self, value ): """ Returns the text representation of a specified object trait value. """ if value is None: return '' return str( value ) #--------------------------------------------------------------------------- # Handles an error that occurs while setting the object's trait value: #--------------------------------------------------------------------------- def error ( self, excp ): """ Handles an error that occurs while setting the object's trait value. """ pass class _DropWidget(object): #--------------------------------------------------------------------------- # Handles a Python object being dropped on the control: #--------------------------------------------------------------------------- def dropEvent(self, e): """ Handles a Python object being dropped on the tree. """ editor = self._qt4_editor klass = editor.factory.klass if editor.factory.binding: value = getattr(clipboard, 'node', None) else: value = e.mimeData().instance() if (klass is None) or isinstance(data, klass): editor._no_update = True try: if hasattr( value, 'drop_editor_value' ): editor.value = value.drop_editor_value() else: editor.value = value if hasattr( value, 'drop_editor_update' ): value.drop_editor_update(self) else: self.setText(editor.str_value) finally: editor._no_update = False e.acceptProposedAction() #--------------------------------------------------------------------------- # Handles a Python object being dragged over the control: #--------------------------------------------------------------------------- def dragEnterEvent(self, e): """ Handles a Python object being dragged over the tree. """ editor = self._qt4_editor if editor.factory.binding: data = getattr(clipboard, 'node', None) else: md = e.mimeData() if not isinstance(md, PyMimeData): return data = md.instance() try: editor.object.base_trait(editor.name).validate(editor.object, editor.name, data) e.acceptProposedAction() except: pass # Define the Text and ReadonlyEditor for use by the editor factory. TextEditor = ReadonlyEditor = SimpleEditor traitsui-4.1.0/traitsui/qt4/images/0000755000175100001440000000000011674463546020202 5ustar ischnellusers00000000000000traitsui-4.1.0/traitsui/qt4/images/previous.png0000644000175100001440000000160211674463546022563 0ustar ischnellusers00000000000000PNG  IHDRw=gAMAOX2tEXtSoftwareAdobe ImageReadyqe<IDATH͖kHaǏZ4 n&vS, i%`rf 2B@$dm]RDPT%NM7]1ܲ)ά7ޝFt5>ss "MH%`7Y<nxDC3&%@LI<<ҽ*)$XJ8,8x<^1:U/d "f$C^9(a)vB*I`Yy`cu/&sB| e; {1mPOa ⳛz%1.Nt'9ɒxmѐ@8 ~B+)ԕDcdh>g2(L!uhuoJѴl/fP%B9Lc_= 9U."B}Mc^PvmJyYR{| z0S4S % *ah]Q^; 1]9]%Ai3 UxiZqB̉\1P2XE֑ulF|~7b>Dm*~K`O<J"'4jO sL> <ā &YBK,j!=Öfhj:Ni H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3- cHRMz%u0`:o_FIDATxLOh\U޽o$hKh[-UhTFT(UwZ\UэBԍFEQKfcq!h1ѩf2߻.f8q\.LTbiizd27qFQc.;{|gk9"40 ~8?wVCcs_X5.qsn|=`jjbTwf.e={yCnUA lэG2ˏ1)JT*g|qGg3zS4~';v> Ik0g32:\l6Z.#ʞ7NT1 AhC02Ox^ T{Tkm7fpɧ>[q͉/&h 4(:s5O>?{!>Mk@C& 7+͔qt~ >,,,@–>|pgv= RVi4a8{kӸX_uml,'K$IڝhR:p;p w0>D@IENDB`traitsui-4.1.0/traitsui/qt4/images/closetab.png0000644000175100001440000000056711674463546022514 0ustar ischnellusers00000000000000PNG  IHDR(-SPLTE88,.:x',.~*/023F,M `c8z6H q#s$s%t%@@m Cp!kᩄtRNSWIDATx^mG@xͽ;~@I IŠ5,Y)ϦYX.t)!j/9wD1Ɔ!bSáx<Đ|1Kl{)3*JFjݼMoSAHMڻŊ3jڗWʋZTi#GG57o|>ITD8."ƹw-Ρ'[ۛJr+i|}'m0:6S|7s?G^_\b԰g#Oooti·h + LU$' e$$,U*+ C3_-|Zh2xoy Y8,%3bM'LYuaHoYm"9s0!$:ߏ~PJ]7X+E94jUC9 VVCQT]][?-Q;/0IENDB`traitsui-4.1.0/traitsui/qt4/check_list_editor.py0000644000175100001440000002557011674463546022776 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2007, Riverbank Computing Limited # All rights reserved. # # This software is provided without warranty under the terms of the BSD license. # However, when used with the GPL version of PyQt the additional terms described in the PyQt GPL exception also apply # # Author: Riverbank Computing Limited #------------------------------------------------------------------------------ """ Defines the various editors for multi-selection enumerations, for the PyQt user interface toolkit. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import logging from string import capitalize from pyface.qt import QtCore, QtGui from traits.api \ import List, Unicode, TraitError # FIXME: ToolkitEditorFactory is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.check_list_editor file. from traitsui.editors.check_list_editor \ import ToolkitEditorFactory from editor_factory \ import TextEditor as BaseTextEditor from editor \ import EditorWithList logger = logging.getLogger(__name__) #------------------------------------------------------------------------------- # 'SimpleEditor' class: #------------------------------------------------------------------------------- class SimpleEditor ( EditorWithList ): """ Simple style of editor for checklists, which displays a combo box. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Checklist item names names = List( Unicode ) # Checklist item values values = List #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self.create_control( parent ) super( SimpleEditor, self ).init( parent ) #--------------------------------------------------------------------------- # Creates the initial editor control: #--------------------------------------------------------------------------- def create_control ( self, parent ): """ Creates the initial editor control. """ self.control = QtGui.QComboBox() QtCore.QObject.connect(self.control, QtCore.SIGNAL('activated(QString)'), self.update_object) #--------------------------------------------------------------------------- # Handles the list of legal check list values being updated: #--------------------------------------------------------------------------- def list_updated ( self, values ): """ Handles updates to the list of legal checklist values. """ sv = self.string_value if (len( values ) > 0) and isinstance( values[0], basestring ): values = [ ( x, sv( x, capitalize ) ) for x in values ] self.values = valid_values = [ x[0] for x in values ] self.names = [ x[1] for x in values ] # Make sure the current value is still legal: modified = False cur_value = parse_value( self.value ) for i in range( len( cur_value ) - 1, -1, -1 ): if cur_value[i] not in valid_values: try: del cur_value[i] modified = True except TypeError, e: logger.warn('Unable to remove non-current value [%s] from ' 'values %s', cur_value[i], values) if modified: if isinstance( self.value, basestring ): cur_value = ','.join( cur_value ) self.value = cur_value self.rebuild_editor() #--------------------------------------------------------------------------- # Rebuilds the editor after its definition is modified: #--------------------------------------------------------------------------- def rebuild_editor ( self ): """ Rebuilds the editor after its definition is modified. """ control = self.control control.clear() for name in self.names: control.addItem(name) self.update_editor() #---------------------------------------------------------------------------- # Handles the user selecting a new value from the combo box: #---------------------------------------------------------------------------- def update_object ( self, text ): """ Handles the user selecting a new value from the combo box. """ value = self.values[self.names.index(unicode(text))] if not isinstance(self.value, basestring): value = [value] self.value = value #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ try: self.control.setCurrentIndex( self.values.index(parse_value(self.value)[0])) except: pass #------------------------------------------------------------------------------- # 'CustomEditor' class: #------------------------------------------------------------------------------- class CustomEditor ( SimpleEditor ): """ Custom style of editor for checklists, which displays a set of check boxes. """ #--------------------------------------------------------------------------- # Creates the initial editor control: #--------------------------------------------------------------------------- def create_control ( self, parent ): """ Creates the initial editor control. """ self.control = QtGui.QWidget() layout = QtGui.QGridLayout(self.control) layout.setContentsMargins(0, 0, 0, 0) self._mapper = QtCore.QSignalMapper() QtCore.QObject.connect(self._mapper, QtCore.SIGNAL('mapped(const QString &)'), self.update_object) #--------------------------------------------------------------------------- # Rebuilds the editor after its definition is modified: #--------------------------------------------------------------------------- def rebuild_editor ( self ): """ Rebuilds the editor after its definition is modified. """ # Clear any existing content: self.clear_layout() cur_value = parse_value( self.value ) # Create a sizer to manage the radio buttons: labels = self.names values = self.values n = len( labels ) cols = self.factory.cols rows = (n + cols - 1) / cols incr = [ n / cols ] * cols rem = n % cols for i in range( cols ): incr[i] += (rem > i) incr[-1] = -(reduce( lambda x, y: x + y, incr[:-1], 0 ) - 1) # Add the set of all possible choices: layout = self.control.layout() index = 0 for i in range( rows ): for j in range( cols ): if n > 0: cb = QtGui.QCheckBox(labels[index]) cb.value = values[index] if cb.value in cur_value: cb.setCheckState(QtCore.Qt.Checked) else: cb.setCheckState(QtCore.Qt.Unchecked) QtCore.QObject.connect(cb, QtCore.SIGNAL('clicked()'), self._mapper, QtCore.SLOT('map()')) self._mapper.setMapping(cb, labels[index]) layout.addWidget(cb, i, j) index += incr[j] n -= 1 #--------------------------------------------------------------------------- # Handles the user clicking one of the 'custom' check boxes: #--------------------------------------------------------------------------- def update_object(self, label): """ Handles the user clicking one of the custom check boxes. """ cb = self._mapper.mapping(label) cur_value = parse_value(self.value) if cb.checkState() == QtCore.Qt.Checked: cur_value.append(cb.value) elif cb.value in cur_value: cur_value.remove(cb.value) if isinstance(self.value, basestring): cur_value = ','.join(cur_value) self.value = cur_value #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ new_values = parse_value( self.value ) for cb in self.control.findChildren(QtGui.QCheckBox, None): if cb.value in new_values: cb.setCheckState(QtCore.Qt.Checked) else: cb.setCheckState(QtCore.Qt.Unchecked) #------------------------------------------------------------------------------- # 'TextEditor' class: #------------------------------------------------------------------------------- class TextEditor ( BaseTextEditor ): """ Text style of editor for checklists, which displays a text field. """ #--------------------------------------------------------------------------- # Handles the user changing the contents of the edit control: #--------------------------------------------------------------------------- def update_object ( self, event=None ): """ Handles the user changing the contents of the edit control. """ try: value = unicode(self.control.text()) value = eval( value ) except: pass try: self.value = value except TraitError, excp: pass #------------------------------------------------------------------------------- # Parse a value into a list: #------------------------------------------------------------------------------- def parse_value ( value ): """ Parses a value into a list. """ if value is None: return [] if type( value ) is not str: return value[:] return [ x.strip() for x in value.split( ',' ) ] traitsui-4.1.0/traitsui/qt4/extra/0000755000175100001440000000000011674463546020060 5ustar ischnellusers00000000000000traitsui-4.1.0/traitsui/qt4/extra/table_image_renderer.py0000644000175100001440000000623211674463546024554 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2009, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # Thanks for using Enthought open source! # # Author: Evan Patterson # Date: 06/25/09 #------------------------------------------------------------------------------ """ A renderer which will display a cell-specific image in addition to some text displayed in the same way the default renderer would. """ # System library imports from pyface.qt import QtCore, QtGui # ETS imports from traits.api import Bool from traitsui.qt4.table_editor import TableDelegate class TableImageRenderer(TableDelegate): """ A renderer which will display a cell-specific image in addition to some text displayed in the same way the default renderer would. """ # Should the image be scaled to the size of the cell scale_to_cell = Bool(True) #--------------------------------------------------------------------------- # TableImageRenderer interface #--------------------------------------------------------------------------- def get_image_for_obj(self, value, row, col): """ Return the image for the cell given the raw cell value and the row and column numbers. """ return None #--------------------------------------------------------------------------- # QAbstractItemDelegate interface #--------------------------------------------------------------------------- def paint(self, painter, option, index): """ Overriden to draw images. """ # First draw any text/background by delegating to our superclass QtGui.QStyledItemDelegate.paint(self, painter, option, index) # Now draw the image, if possible value = index.data(QtCore.Qt.UserRole) image = self.get_image_for_obj(value, index.row(), index.column()) if image: image = image.create_bitmap() if self.scale_to_cell: w = min(image.width(), option.rect.width()) h = min(image.height(), option.rect.height()) else: w = image.width() h = image.height() x = option.rect.x() y = option.rect.y() + (option.rect.height()-h)/2 target = QtCore.QRect(x, y, w, h) painter.drawPixmap(target, image) def sizeHint(self, option, index): """ Overriden to take image size into account when providing a size hint. """ size = QtGui.QStyledItemDelegate.sizeHint(self, option, index) value = index.data(QtCore.Qt.UserRole) image = self.get_image_for_obj(value, index.row(), index.column()) if image: image = image.create_bitmap() size.setWidth(max(image.width(), size.width())) size.setHeight(max(image.height(), size.height())) return size traitsui-4.1.0/traitsui/qt4/extra/qt_view.py0000644000175100001440000000573611674463546022123 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2011, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # Thanks for using Enthought open source! # # Author: Evan Patterson #------------------------------------------------------------------------------ """ Defines a Traits UI View that allows for the customization of Qt-specific widget properties. """ # Standard library imports. import logging # System library imports. from pyface.qt import QtGui # Enthought library imports. from traits.api import File, List, Str from traitsui.view import View # Logger. logger = logging.getLogger(__name__) class QtView(View): """ A View that allows the specification of Qt style sheets. """ # An optional string containing a Qt style sheet. style_sheet = Str # An optional file path for a Qt style sheet. style_sheet_path = File # A list of trait names that defines the order for focus switching via # Tab/Shift+Tab. If the view contains multiple items for a specified trait # name, the order is undefined. tab_order = List(Str) #--------------------------------------------------------------------------- # Creates a UI user interface object: #--------------------------------------------------------------------------- def ui(self, context, parent=None, kind=None, view_elements=None, handler=None, id='', scrollable=None, args=None): ui = super(QtView, self).ui(context, parent, kind, view_elements, handler, id, scrollable, args) if self.style_sheet: ui.control.setStyleSheet(self.style_sheet) if self.style_sheet_path: try: with open(self.style_sheet_path, 'r') as f: ui.control.setStyleSheet(f.read()) except IOError: logger.exception("Error loading Qt style sheet") if len(self.tab_order) >= 2: previous = self._get_editor_control(ui, self.tab_order[0]) for i in xrange(1, len(self.tab_order)): current = self._get_editor_control(ui, self.tab_order[i]) QtGui.QWidget.setTabOrder(previous, current) previous = current return ui #--------------------------------------------------------------------------- # Private interface: #--------------------------------------------------------------------------- def _get_editor_control(self, ui, name): control = None editors = ui.get_editors(name) if editors: control = editors[0].control else: logger.warning("No item for '%s' trait" % name) return control traitsui-4.1.0/traitsui/qt4/extra/range_slider.py0000644000175100001440000001424411674463546023075 0ustar ischnellusers00000000000000from pyface.qt import QtGui, QtCore class RangeSlider(QtGui.QSlider): """ A slider for ranges. This class provides a dual-slider for ranges, where there is a defined maximum and minimum, as is a normal slider, but instead of having a single slider value, there are 2 slider values. This class emits the same signals as the QSlider base class, with the exception of valueChanged """ def __init__(self, *args): super(RangeSlider, self).__init__(*args) self._low = self.minimum() self._high = self.maximum() self.pressed_control = QtGui.QStyle.SC_None self.hover_control = QtGui.QStyle.SC_None self.click_offset = 0 # 0 for the low, 1 for the high, -1 for both self.active_slider = 0 def low(self): return self._low def setLow(self, low): self._low = low self.update() def high(self): return self._high def setHigh(self, high): self._high = high self.update() def paintEvent(self, event): # based on http://qt.gitorious.org/qt/qt/blobs/master/src/gui/widgets/qslider.cpp painter = QtGui.QPainter(self) style = QtGui.QApplication.style() for i, value in enumerate([self._low, self._high]): opt = QtGui.QStyleOptionSlider() self.initStyleOption(opt) # Only draw the groove for the first slider so it doesn't get drawn # on top of the existing ones every time if i == 0: opt.subControls = QtGui.QStyle.SC_SliderGroove | QtGui.QStyle.SC_SliderHandle else: opt.subControls = QtGui.QStyle.SC_SliderHandle if self.tickPosition() != self.NoTicks: opt.subControls |= QtGui.QStyle.SC_SliderTickmarks if self.pressed_control: opt.activeSubControls = self.pressed_control opt.state |= QtGui.QStyle.State_Sunken else: opt.activeSubControls = self.hover_control opt.sliderPosition = value opt.sliderValue = value style.drawComplexControl(QtGui.QStyle.CC_Slider, opt, painter, self) def mousePressEvent(self, event): event.accept() style = QtGui.QApplication.style() button = event.button() # In a normal slider control, when the user clicks on a point in the # slider's total range, but not on the slider part of the control the # control would jump the slider value to where the user clicked. # For this control, clicks which are not direct hits will slide both # slider parts if button: opt = QtGui.QStyleOptionSlider() self.initStyleOption(opt) self.active_slider = -1 for i, value in enumerate([self._low, self._high]): opt.sliderPosition = value hit = style.hitTestComplexControl(style.CC_Slider, opt, event.pos(), self) if hit == style.SC_SliderHandle: self.active_slider = i self.pressed_control = hit self.triggerAction(self.SliderMove) self.setRepeatAction(self.SliderNoAction) self.setSliderDown(True) break if self.active_slider < 0: self.pressed_control = QtGui.QStyle.SC_SliderHandle self.click_offset = self.__pixelPosToRangeValue(self.__pick(event.pos())) self.triggerAction(self.SliderMove) self.setRepeatAction(self.SliderNoAction) else: event.ignore() def mouseMoveEvent(self, event): if self.pressed_control != QtGui.QStyle.SC_SliderHandle: event.ignore() return event.accept() new_pos = self.__pixelPosToRangeValue(self.__pick(event.pos())) opt = QtGui.QStyleOptionSlider() self.initStyleOption(opt) if self.active_slider < 0: offset = new_pos - self.click_offset self._high += offset self._low += offset if self._low < self.minimum(): diff = self.minimum() - self._low self._low += diff self._high += diff if self._high > self.maximum(): diff = self.maximum() - self._high self._low += diff self._high += diff elif self.active_slider == 0: if new_pos >= self._high: new_pos = self._high - 1 self._low = new_pos else: if new_pos <= self._low: new_pos = self._low + 1 self._high = new_pos self.click_offset = new_pos self.update() self.emit(QtCore.SIGNAL('sliderMoved(int)'), new_pos) def __pick(self, pt): if self.orientation() == QtCore.Qt.Horizontal: return pt.x() else: return pt.y() def __pixelPosToRangeValue(self, pos): opt = QtGui.QStyleOptionSlider() self.initStyleOption(opt) style = QtGui.QApplication.style() gr = style.subControlRect(style.CC_Slider, opt, style.SC_SliderGroove, self) sr = style.subControlRect(style.CC_Slider, opt, style.SC_SliderHandle, self) if self.orientation() == QtCore.Qt.Horizontal: slider_length = sr.width() slider_min = gr.x() slider_max = gr.right() - slider_length + 1 else: slider_length = sr.height() slider_min = gr.y() slider_max = gr.bottom() - slider_length + 1 return style.sliderValueFromPosition(self.minimum(), self.maximum(), pos-slider_min, slider_max-slider_min, opt.upsideDown) if __name__ == "__main__": import sys def echo(value): print value app = QtGui.QApplication(sys.argv) slider = RangeSlider() slider.setMinimum(0) slider.setMaximum(10000) slider.setLow(0) slider.setHigh(10000) QtCore.QObject.connect(slider, QtCore.SIGNAL('sliderMoved(int)'), echo) slider.show() app.exec_() traitsui-4.1.0/traitsui/qt4/extra/__init__.py0000644000175100001440000000000011674463546022157 0ustar ischnellusers00000000000000traitsui-4.1.0/traitsui/qt4/extra/checkbox_renderer.py0000644000175100001440000001014011674463546024102 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2009, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # Thanks for using Enthought open source! # # Author: Evan Patterson # Date: 06/26/09 #------------------------------------------------------------------------------ """ A renderer which displays a checked-box for a True value and an unchecked box for a false value. """ # System library imports from pyface.qt import QtCore, QtGui # ETS imports from traitsui.qt4.table_editor import TableDelegate class CheckboxRenderer(TableDelegate): """ A renderer which displays a checked-box for a True value and an unchecked box for a false value. """ #--------------------------------------------------------------------------- # QAbstractItemDelegate interface #--------------------------------------------------------------------------- def editorEvent(self, event, model, option, index): """ Reimplemented to handle mouse button clicks. """ if event.type() == QtCore.QEvent.MouseButtonRelease and \ event.button() == QtCore.Qt.LeftButton: column = index.model()._editor.columns[index.column()] obj = index.data(QtCore.Qt.UserRole) checked = bool(column.get_raw_value(obj)) column.set_value(obj, not checked) return True else: return False def paint(self, painter, option, index): """ Reimplemented to paint the checkbox. """ # Determine whether the checkbox is check or unchecked column = index.model()._editor.columns[index.column()] obj = index.data(QtCore.Qt.UserRole) checked = column.get_raw_value(obj) # First draw the background painter.save() row_brushes = [option.palette.base(), option.palette.alternateBase()] if option.state & QtGui.QStyle.State_Selected: bg_brush = option.palette.highlight() else: bg_brush = index.data(QtCore.Qt.BackgroundRole) if bg_brush == NotImplemented or bg_brush is None: if index.model()._editor.factory.alternate_bg_color: bg_brush = row_brushes[index.row() % 2] else: bg_brush = row_brushes[0] painter.fillRect(option.rect, bg_brush) # Then draw the checkbox style = QtGui.QApplication.instance().style() box = QtGui.QStyleOptionButton() box.palette = option.palette # Align the checkbox appropriately. box.rect = option.rect size = style.sizeFromContents(QtGui.QStyle.CT_CheckBox, box, QtCore.QSize()) box.rect.setWidth(size.width()) margin = style.pixelMetric(QtGui.QStyle.PM_ButtonMargin, box) alignment = column.horizontal_alignment if alignment == 'left': box.rect.setLeft(option.rect.left() + margin) elif alignment == 'right': box.rect.setLeft(option.rect.right() - size.width() - margin) else: # FIXME: I don't know why I need the 2 pixels, but I do. box.rect.setLeft(option.rect.left() + option.rect.width() // 2 - size.width() // 2 + margin - 2) box.state = QtGui.QStyle.State_Enabled if checked: box.state |= QtGui.QStyle.State_On else: box.state |= QtGui.QStyle.State_Off style.drawControl(QtGui.QStyle.CE_CheckBox, box, painter) painter.restore() def sizeHint(self, option, index): """ Reimplemented to provide size hint based on a checkbox """ box = QtGui.QStyleOptionButton() style = QtGui.QApplication.instance().style() return style.sizeFromContents(QtGui.QStyle.CT_CheckBox, box, QtCore.QSize()) traitsui-4.1.0/traitsui/qt4/extra/bounds_editor.py0000644000175100001440000001371011674463546023274 0ustar ischnellusers00000000000000from pyface.qt import QtGui, QtCore from traits.api import Float, Any, Str, Trait from traitsui.editors.api import RangeEditor from traitsui.qt4.editor import Editor from traitsui.qt4.extra.range_slider import RangeSlider class _BoundsEditor(Editor): evaluate = Any min = Any max = Any low = Any high = Any format = Str def init(self, parent): """ Finishes initializing the editor by creating the underlying toolkit widget. """ factory = self.factory if not factory.low_name: self.low = factory.low if not factory.high_name: self.high = factory.high self.max = factory.max self.min = factory.min self.format = factory.format self.evaluate = factory.evaluate self.sync_value( factory.evaluate_name, 'evaluate', 'from' ) self.sync_value( factory.low_name, 'low', 'both' ) self.sync_value( factory.high_name, 'high', 'both' ) self.control = QtGui.QWidget() panel = QtGui.QHBoxLayout(self.control) panel.setContentsMargins(0, 0, 0, 0) self._label_lo = QtGui.QLineEdit(self.format % self.low) QtCore.QObject.connect(self._label_lo, QtCore.SIGNAL('editingFinished()'), self.update_low_on_enter) panel.addWidget(self._label_lo) # The default size is a bit too big and probably doesn't need to grow. sh = self._label_lo.sizeHint() sh.setWidth(sh.width() / 2) self._label_lo.setMaximumSize(sh) self.control.slider = slider = RangeSlider(QtCore.Qt.Horizontal) slider.setTracking(factory.auto_set) slider.setMinimum(0) slider.setMaximum(10000) slider.setPageStep(1000) slider.setSingleStep(100) slider.setLow(self._convert_to_slider(self.low)) slider.setHigh(self._convert_to_slider(self.high)) QtCore.QObject.connect(slider, QtCore.SIGNAL('sliderMoved(int)'), self.update_object_on_scroll) panel.addWidget(slider) self._label_hi = QtGui.QLineEdit(self.format % self.high) QtCore.QObject.connect(self._label_hi, QtCore.SIGNAL('editingFinished()'), self.update_high_on_enter) panel.addWidget(self._label_hi) # The default size is a bit too big and probably doesn't need to grow. sh = self._label_hi.sizeHint() sh.setWidth(sh.width() / 2) self._label_hi.setMaximumSize(sh) self.set_tooltip(slider) self.set_tooltip(self._label_lo) self.set_tooltip(self._label_hi) def update_low_on_enter(self): try: try: low = eval(unicode(self._label_lo.text()).strip()) if self.evaluate is not None: low = self.evaluate(low) except Exception, ex: low = self.low self._label_lo.setText(self.format % self.low) if not self.factory.is_float: low = int(low) if low > self.high: low = self.high - self._step_size() self._label_lo.setText(self.format % low) self.control.slider.setLow(self._convert_to_slider(low)) self.low = low except: pass def update_high_on_enter(self): try: try: high = eval(unicode(self._label_hi.text()).strip()) if self.evaluate is not None: high = self.evaluate(high) except: high = self.high self._label_hi.setText(self.format % self.high) if not self.factory.is_float: high = int(high) if high < self.low: high = self.low + self._step_size() self._label_hi.setText(self.format % high) self.control.slider.setHigh(self._convert_to_slider(high)) self.high = high except: pass def update_object_on_scroll(self, pos): low = self._convert_from_slider(self.control.slider.low()) high = self._convert_from_slider(self.control.slider.high()) if self.factory.is_float: self.low = low self.high = high else: self.low = int(low) self.high = int(high) # update the sliders to the int values or the sliders # will jiggle self.control.slider.setLow(self._convert_to_slider(low)) self.control.slider.setHigh(self._convert_to_slider(high)) def update_editor(self): return def _check_max_and_min(self): # check if max & min have been defined: if self.max is None: self.max = self.high if self.min is None: self.min = self.low def _step_size(self): slider_delta = self.control.slider.maximum() - self.control.slider.minimum() range_delta = self.max - self.min return float(range_delta)/slider_delta def _convert_from_slider(self, slider_val): self._check_max_and_min() return self.min + slider_val * self._step_size() def _convert_to_slider(self, value): self._check_max_and_min() return self.control.slider.minimum() + (value-self.min) / self._step_size() def _low_changed(self, low): if self.control is None: return if self._label_lo is not None: self._label_lo.setText(self.format % low) self.control.slider.setLow(self._convert_to_slider(low)) def _high_changed(self, high): if self.control is None: return if self._label_hi is not None: self._label_hi.setText(self.format % high) self.control.slider.setHigh(self._convert_to_slider(self.high)) class BoundsEditor(RangeEditor): min = Trait(None, Float) max = Trait(None, Float) def _get_simple_editor_class(self): return _BoundsEditor def _get_custom_editor_class(self): return _BoundsEditor traitsui-4.1.0/traitsui/qt4/instance_editor.py0000644000175100001440000004776411674463546022503 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2008, Riverbank Computing Limited # All rights reserved. # # This software is provided without warranty under the terms of the BSD license. # However, when used with the GPL version of PyQt the additional terms described in the PyQt GPL exception also apply # # Author: Riverbank Computing Limited #------------------------------------------------------------------------------ """ Defines the various instance editors and the instance editor factory for the PyQt user interface toolkit.. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from pyface.qt import QtCore, QtGui from traits.api \ import HasTraits, Property # FIXME: ToolkitEditorFactory is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.instance_editor file. from traitsui.editors.instance_editor \ import ToolkitEditorFactory from traitsui.ui_traits \ import AView from traitsui.helper \ import user_name_for from traitsui.handler \ import Handler from traitsui.instance_choice \ import InstanceChoiceItem from editor \ import Editor from constants \ import DropColor from helper \ import position_window #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- OrientationMap = { 'default': None, 'horizontal': QtGui.QBoxLayout.LeftToRight, 'vertical': QtGui.QBoxLayout.TopToBottom } #------------------------------------------------------------------------------- # 'CustomEditor' class: #------------------------------------------------------------------------------- class CustomEditor ( Editor ): """ Custom style of editor for instances. If selection among instances is allowed, the editor displays a combo box listing instances that can be selected. If the current instance is editable, the editor displays a panel containing trait editors for all the instance's traits. """ # Background color when an item can be dropped on the editor: ok_color = DropColor # The orientation of the instance editor relative to the instance selector: orientation = QtGui.QBoxLayout.TopToBottom # Class constant: extra = 0 #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # List of InstanceChoiceItem objects used by the editor items = Property # The view to use for displaying the instance view = AView #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ factory = self.factory if factory.name != '': self._object, self._name, self._value = \ self.parse_extended_name( factory.name ) # Create a panel to hold the object trait's view: if factory.editable: self.control = self._panel = parent = QtGui.QWidget() # Build the instance selector if needed: selectable = factory.selectable droppable = factory.droppable items = self.items for item in items: droppable |= item.is_droppable() selectable |= item.is_selectable() if selectable: self._object_cache = {} item = self.item_for( self.value ) if item is not None: self._object_cache[ id( item ) ] = self.value self._choice = QtGui.QComboBox() QtCore.QObject.connect(self._choice, QtCore.SIGNAL('activated(QString)'), self.update_object) self.set_tooltip( self._choice ) if factory.name != '': self._object.on_trait_change( self.rebuild_items, self._name, dispatch = 'ui' ) self._object.on_trait_change( self.rebuild_items, self._name + '_items', dispatch = 'ui' ) factory.on_trait_change( self.rebuild_items, 'values', dispatch = 'ui' ) factory.on_trait_change( self.rebuild_items, 'values_items', dispatch = 'ui' ) self.rebuild_items() elif droppable: self._choice = QtGui.QLineEdit() self._choice.setReadOnly(True) self.set_tooltip( self._choice ) if droppable: self._choice.SetDropTarget( PythonDropTarget( self ) ) orientation = OrientationMap[ factory.orientation ] if orientation is None: orientation = self.orientation if (selectable or droppable) and factory.editable: layout = QtGui.QBoxLayout(orientation, parent) layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(self._choice) if orientation == QtGui.QBoxLayout.TopToBottom: hline = QtGui.QFrame() hline.setFrameShape(QtGui.QFrame.HLine) hline.setFrameShadow(QtGui.QFrame.Sunken) layout.addWidget(hline) self.create_editor(parent, layout) elif self.control is None: if self._choice is None: self._choice = QtGui.QComboBox() QtCore.QObject.connect(self._choice, QtCore.SIGNAL('activated(QString)'), self.update_object) self.control = self._choice else: layout = QtGui.QBoxLayout(orientation, parent) layout.setContentsMargins(0, 0, 0, 0) self.create_editor(parent, layout) # Synchronize the 'view' to use: # fixme: A normal assignment can cause a crash (for unknown reasons) in # some cases, so we make sure that no notifications are generated: self.trait_setq( view = factory.view ) self.sync_value( factory.view_name, 'view', 'from' ) #--------------------------------------------------------------------------- # Creates the editor control: #--------------------------------------------------------------------------- def create_editor(self, parent, layout): """ Creates the editor control. """ self._panel = QtGui.QWidget() layout.addWidget(self._panel) #--------------------------------------------------------------------------- # Gets the current list of InstanceChoiceItem items: #--------------------------------------------------------------------------- def _get_items ( self ): """ Gets the current list of InstanceChoiceItem items. """ if self._items is not None: return self._items factory = self.factory if self._value is not None: values = self._value() + factory.values else: values = factory.values items = [] adapter = factory.adapter for value in values: if not isinstance( value, InstanceChoiceItem ): value = adapter( object = value ) items.append( value ) self._items = items return items #--------------------------------------------------------------------------- # Rebuilds the object selector list: #--------------------------------------------------------------------------- def rebuild_items ( self ): """ Rebuilds the object selector list. """ # Clear the current cached values: self._items = None # Rebuild the contents of the selector list: name = -1 value = self.value choice = self._choice choice.clear() for i, item in enumerate(self.items): if item.is_selectable(): choice.addItem(item.get_name()) if item.is_compatible( value ): name = i # Reselect the current item if possible: if name >= 0: choice.setCurrentIndex(name) else: # Otherwise, current value is no longer valid, try to discard it: try: self.value = None except: pass #--------------------------------------------------------------------------- # Returns the InstanceChoiceItem for a specified object: #--------------------------------------------------------------------------- def item_for ( self, object ): """ Returns the InstanceChoiceItem for a specified object. """ for item in self.items: if item.is_compatible( object ): return item return None #--------------------------------------------------------------------------- # Returns the view to use for a specified object: #--------------------------------------------------------------------------- def view_for ( self, object, item ): """ Returns the view to use for a specified object. """ view = '' if item is not None: view = item.get_view() if view == '': view = self.view return self.ui.handler.trait_view_for( self.ui.info, view, object, self.object_name, self.name ) #--------------------------------------------------------------------------- # Handles the user selecting a new value from the combo box: #--------------------------------------------------------------------------- def update_object(self, text): """ Handles the user selecting a new value from the combo box. """ name = unicode(text) for item in self.items: if name == item.get_name(): id_item = id( item ) object = self._object_cache.get( id_item ) if object is None: object = item.get_object() if (not self.factory.editable) and item.is_factory: view = self.view_for( object, self.item_for( object ) ) view.ui( object, self.control, 'modal' ) if self.factory.cachable: self._object_cache[ id_item ] = object self.value = object self.resynch_editor() break #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ # Synchronize the editor contents: self.resynch_editor() # Update the selector (if any): choice = self._choice item = self.item_for( self.value ) if (choice is not None) and (item is not None): name = item.get_name( self.value ) if self._object_cache is not None: idx = choice.findText(name) if idx < 0: idx = choice.count() choice.addItem(name) choice.setCurrentIndex(idx) else: choice.setText(name) #--------------------------------------------------------------------------- # Resynchronizes the contents of the editor when the object trait changes # external to the editor: #--------------------------------------------------------------------------- def resynch_editor ( self ): """ Resynchronizes the contents of the editor when the object trait changes externally to the editor. """ panel = self._panel if panel is not None: # Dispose of the previous contents of the panel: layout = panel.layout() if layout is None: layout = QtGui.QVBoxLayout(panel) layout.setContentsMargins(0, 0, 0, 0) elif self._ui is not None: self._ui.dispose() self._ui = None else: child = layout.takeAt(0) while child is not None: child = layout.takeAt(0) del child # Create the new content for the panel: stretch = 0 value = self.value if not isinstance( value, HasTraits ): str_value = '' if value is not None: str_value = self.str_value control = QtGui.QLabel(str_value) else: view = self.view_for( value, self.item_for( value ) ) context = value.trait_context() handler = None if isinstance( value, Handler ): handler = value context.setdefault( 'context', self.object ) context.setdefault( 'context_handler', self.ui.handler ) self._ui = ui = view.ui( context, panel, 'subpanel', value.trait_view_elements(), handler, self.factory.id ) control = ui.control self.scrollable = ui._scrollable ui.parent = self.ui if view.resizable or view.scrollable or ui._scrollable: stretch = 1 # FIXME: Handle stretch. layout.addWidget(control) #--------------------------------------------------------------------------- # Disposes of the contents of an editor: #--------------------------------------------------------------------------- def dispose ( self ): """ Disposes of the contents of an editor. """ # Make sure we aren't hanging on to any object refs: self._object_cache = None if self._ui is not None: self._ui.dispose() if self._choice is not None: if self._object is not None: self._object.on_trait_change( self.rebuild_items, self._name, remove = True ) self._object.on_trait_change( self.rebuild_items, self._name + '_items', remove = True ) self.factory.on_trait_change( self.rebuild_items, 'values', remove = True ) self.factory.on_trait_change( self.rebuild_items, 'values_items', remove = True ) super( CustomEditor, self ).dispose() #--------------------------------------------------------------------------- # Handles an error that occurs while setting the object's trait value: #--------------------------------------------------------------------------- def error ( self, excp ): """ Handles an error that occurs while setting the object's trait value. """ pass #--------------------------------------------------------------------------- # Returns the editor's control for indicating error status: #--------------------------------------------------------------------------- def get_error_control ( self ): """ Returns the editor's control for indicating error status. """ return (self._choice or self.control) #-- UI preference save/restore interface ----------------------------------- #--------------------------------------------------------------------------- # Restores any saved user preference information associated with the # editor: #--------------------------------------------------------------------------- def restore_prefs ( self, prefs ): """ Restores any saved user preference information associated with the editor. """ ui = self._ui if (ui is not None) and (prefs.get( 'id' ) == ui.id): ui.set_prefs( prefs.get( 'prefs' ) ) #--------------------------------------------------------------------------- # Returns any user preference information associated with the editor: #--------------------------------------------------------------------------- def save_prefs ( self ): """ Returns any user preference information associated with the editor. """ ui = self._ui if (ui is not None) and (ui.id != ''): return { 'id': ui.id, 'prefs': ui.get_prefs() } return None #-- Traits event handlers -------------------------------------------------- def _view_changed ( self, view ): self.resynch_editor() #------------------------------------------------------------------------------- # 'SimpleEditor' class: #------------------------------------------------------------------------------- class SimpleEditor ( CustomEditor ): """ Simple style of editor for instances, which displays a button. Clicking the button displays a dialog box in which the instance can be edited. """ # Class constants: orientation = QtGui.QBoxLayout.LeftToRight extra = 2 #--------------------------------------------------------------------------- # Creates the editor control: #--------------------------------------------------------------------------- def create_editor(self, parent, layout): """ Creates the editor control (a button). """ self._button = QtGui.QPushButton() layout.addWidget(self._button) QtCore.QObject.connect(self._button, QtCore.SIGNAL('clicked()'), self.edit_instance) #--------------------------------------------------------------------------- # Edit the contents of the object trait when the user clicks the button: #--------------------------------------------------------------------------- def edit_instance(self): """ Edit the contents of the object trait when the user clicks the button. """ # Create the user interface: factory = self.factory view = self.ui.handler.trait_view_for( self.ui.info, factory.view, self.value, self.object_name, self.name ) ui = self.value.edit_traits( view, kind=factory.kind, id=factory.id ) # Make sure the editor is properly disposed QtCore.QObject.connect( self._button, QtCore.SIGNAL( 'destroyed()' ), lambda: ui.dispose() ) # Check to see if the view was 'modal', in which case it will already # have been closed (i.e. is None) by the time we get control back: if ui.control is not None: # Position the window on the display: position_window( ui.control ) # Chain our undo history to the new user interface if it does not # have its own: if ui.history is None: ui.history = self.ui.history #--------------------------------------------------------------------------- # Resynchronizes the contents of the editor when the object trait changes # external to the editor: #--------------------------------------------------------------------------- def resynch_editor ( self ): """ Resynchronizes the contents of the editor when the object trait changes externally to the editor. """ button = self._button if button is not None: label = self.factory.label if label == '': label = user_name_for( self.name ) button.setText(label) button.setEnabled(isinstance(self.value, HasTraits)) traitsui-4.1.0/traitsui/qt4/range_editor.py0000644000175100001440000007206411674463546021762 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2008, Riverbank Computing Limited # All rights reserved. # # This software is provided without warranty under the terms of the BSD license. # However, when used with the GPL version of PyQt the additional terms described in the PyQt GPL exception also apply # # Author: Riverbank Computing Limited #------------------------------------------------------------------------------ """ Defines the various range editors and the range editor factory, for the PyQt user interface toolkit. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from math \ import log10 from pyface.qt import QtCore, QtGui from traits.api \ import TraitError, Str, Float, Any, Bool # FIXME: ToolkitEditorFactory is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.range_editor file. from traitsui.editors.range_editor \ import ToolkitEditorFactory from editor_factory \ import TextEditor from editor \ import Editor from constants \ import OKColor, ErrorColor from helper \ import IconButton #------------------------------------------------------------------------------- # 'BaseRangeEditor' class: #------------------------------------------------------------------------------- class BaseRangeEditor ( Editor ): """ The base class for Range editors. Using an evaluate trait, if specified, when assigning numbers the object trait. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Function to evaluate floats/ints evaluate = Any #--------------------------------------------------------------------------- # Sets the associated object trait's value: #--------------------------------------------------------------------------- def _set_value ( self, value ): if self.evaluate is not None: value = self.evaluate( value ) Editor._set_value( self, value ) #------------------------------------------------------------------------------- # 'SimpleSliderEditor' class: #------------------------------------------------------------------------------- class SimpleSliderEditor ( BaseRangeEditor ): """ Simple style of range editor that displays a slider and a text field. The user can set a value either by moving the slider or by typing a value in the text field. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Low value for the slider range low = Any # High value for the slider range high = Any # Formatting string used to format value and labels format = Str #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ factory = self.factory if not factory.low_name: self.low = factory.low if not factory.high_name: self.high = factory.high self.format = factory.format self.evaluate = factory.evaluate self.sync_value( factory.evaluate_name, 'evaluate', 'from' ) self.sync_value( factory.low_name, 'low', 'from' ) self.sync_value( factory.high_name, 'high', 'from' ) self.control = QtGui.QWidget() panel = QtGui.QHBoxLayout(self.control) panel.setContentsMargins(0, 0, 0, 0) fvalue = self.value try: if not (self.low <= fvalue <= self.high): fvalue = self.low fvalue_text = self.format % fvalue except: fvalue_text = '' fvalue = self.low ivalue = self._convert_to_slider(fvalue) self._label_lo = QtGui.QLabel() self._label_lo.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter) if factory.label_width > 0: self._label_lo.setMinimumWidth(factory.label_width) panel.addWidget(self._label_lo) self.control.slider = slider = QtGui.QSlider(QtCore.Qt.Horizontal) slider.setTracking(factory.auto_set) slider.setMinimum(0) slider.setMaximum(10000) slider.setPageStep(1000) slider.setSingleStep(100) slider.setValue(ivalue) QtCore.QObject.connect(slider, QtCore.SIGNAL('valueChanged(int)'), self.update_object_on_scroll) panel.addWidget(slider) self._label_hi = QtGui.QLabel() panel.addWidget(self._label_hi) if factory.label_width > 0: self._label_hi.setMinimumWidth(factory.label_width) self.control.text = text = QtGui.QLineEdit(fvalue_text) QtCore.QObject.connect(text, QtCore.SIGNAL('editingFinished()'), self.update_object_on_enter) # The default size is a bit too big and probably doesn't need to grow. sh = text.sizeHint() sh.setWidth(sh.width() / 2) text.setMaximumSize(sh) panel.addWidget(text) low_label = factory.low_label if factory.low_name != '': low_label = self.format % self.low high_label = factory.high_label if factory.high_name != '': high_label = self.format % self.high self._label_lo.setText(low_label) self._label_hi.setText(high_label) self.set_tooltip(slider) self.set_tooltip(self._label_lo) self.set_tooltip(self._label_hi) self.set_tooltip(text) #--------------------------------------------------------------------------- # Handles the user changing the current slider value: #--------------------------------------------------------------------------- def update_object_on_scroll(self, pos): """ Handles the user changing the current slider value. """ value = self._convert_from_slider(pos) self.control.text.setText(self.format % value) self.value = value #--------------------------------------------------------------------------- # Handle the user pressing the 'Enter' key in the edit control: #--------------------------------------------------------------------------- def update_object_on_enter (self): """ Handles the user pressing the Enter key in the text field. """ try: try: value = eval(unicode(self.control.text.text()).strip()) except Exception, ex: # The entered something that didn't eval as a number, (e.g., # 'foo') pretend it didn't happen value = self.value self.control.text.setText(unicode(value)) if not self.factory.is_float: value = int(value) self.value = value self.control.slider.setValue(self._convert_to_slider(self.value)) except TraitError, excp: pass #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ value = self.value low = self.low high = self.high try: text = self.format % value 1 / (low <= value <= high) except: text = '' value = low ivalue = self._convert_to_slider(value) self.control.text.setText(text) blocked = self.control.slider.blockSignals(True) self.control.slider.setValue(ivalue) self.control.slider.blockSignals(blocked) #--------------------------------------------------------------------------- # Returns the editor's control for indicating error status: #--------------------------------------------------------------------------- def get_error_control ( self ): """ Returns the editor's control for indicating error status. """ return self.control.text #--------------------------------------------------------------------------- # Handles the 'low'/'high' traits being changed: #--------------------------------------------------------------------------- def _low_changed ( self, low ): if self.value < low: if self.factory.is_float: self.value = float( low ) else: self.value = int( low ) if self._label_lo is not None: self._label_lo.setText(self.format % low) self.update_editor() def _high_changed ( self, high ): if self.value > high: if self.factory.is_float: self.value = float( high ) else: self.value = int( high ) if self._label_hi is not None: self._label_hi.setText(self.format % high) self.update_editor() def _convert_to_slider(self, value): """ Returns the slider setting corresponding to the user-supplied value. """ if self.high > self.low: ivalue = int( (float( value - self.low ) / (self.high - self.low)) * 10000.0 ) else: ivalue = self.low if ivalue is None: ivalue = 0 return ivalue def _convert_from_slider(self, ivalue): """ Returns the float or integer value corresponding to the slider setting. """ value = self.low + ((float( ivalue ) / 10000.0) * (self.high - self.low)) if not self.factory.is_float: value = int(round(value)) return value #------------------------------------------------------------------------------- class LogRangeSliderEditor ( SimpleSliderEditor ): #------------------------------------------------------------------------------- """ A slider editor for log-spaced values """ def _convert_to_slider(self, value): """ Returns the slider setting corresponding to the user-supplied value. """ value = max(value, self.low) ivalue = int( (log10(value) - log10(self.low)) / (log10(self.high) - log10(self.low)) * 10000.0) return ivalue def _convert_from_slider(self, ivalue): """ Returns the float or integer value corresponding to the slider setting. """ value = float( ivalue ) / 10000.0 * (log10(self.high) -log10(self.low)) # Do this to handle floating point errors, where fvalue may exceed # self.high. fvalue = min(self.low*10**(value), self.high) if not self.factory.is_float: fvalue = int(round(fvalue)) return fvalue #------------------------------------------------------------------------------- # 'LargeRangeSliderEditor' class: #------------------------------------------------------------------------------- class LargeRangeSliderEditor ( BaseRangeEditor ): """ A slider editor for large ranges. The editor displays a slider and a text field. A subset of the total range is displayed in the slider; arrow buttons at each end of the slider let the user move the displayed range higher or lower. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Low value for the slider range low = Any(0) # High value for the slider range high = Any(1) # Low end of displayed range cur_low = Float # High end of displayed range cur_high = Float # Flag indicating that the UI is in the process of being updated ui_changing = Bool(False) #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ factory = self.factory # Initialize using the factory range defaults: self.low = factory.low self.high = factory.high self.evaluate = factory.evaluate # Hook up the traits to listen to the object. self.sync_value( factory.low_name, 'low', 'from' ) self.sync_value( factory.high_name, 'high', 'from' ) self.sync_value( factory.evaluate_name, 'evaluate', 'from' ) self.init_range() low = self.cur_low high = self.cur_high self._set_format() self.control = QtGui.QWidget() panel = QtGui.QHBoxLayout(self.control) panel.setContentsMargins(0, 0, 0, 0) fvalue = self.value try: fvalue_text = self._format % fvalue 1 / (low <= fvalue <= high) except: fvalue_text = '' fvalue = low if high > low: ivalue = int( (float( fvalue - low ) / (high - low)) * 10000 ) else: ivalue = low # Lower limit label: self.control.label_lo = label_lo = QtGui.QLabel() label_lo.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter) panel.addWidget(label_lo) # Lower limit button: self.control.button_lo = IconButton(QtGui.QStyle.SP_ArrowLeft, self.reduce_range) panel.addWidget(self.control.button_lo) # Slider: self.control.slider = slider = QtGui.QSlider(QtCore.Qt.Horizontal) slider.setTracking(factory.auto_set) slider.setMinimum(0) slider.setMaximum(10000) slider.setPageStep(1000) slider.setSingleStep(100) slider.setValue(ivalue) QtCore.QObject.connect(slider, QtCore.SIGNAL('valueChanged(int)'), self.update_object_on_scroll) panel.addWidget(slider) # Upper limit button: self.control.button_hi = IconButton(QtGui.QStyle.SP_ArrowRight, self.increase_range) panel.addWidget(self.control.button_hi) # Upper limit label: self.control.label_hi = label_hi = QtGui.QLabel() panel.addWidget(label_hi) # Text entry: self.control.text = text = QtGui.QLineEdit(fvalue_text) QtCore.QObject.connect(text, QtCore.SIGNAL('editingFinished()'), self.update_object_on_enter) # The default size is a bit too big and probably doesn't need to grow. sh = text.sizeHint() sh.setWidth(sh.width() / 2) text.setMaximumSize(sh) panel.addWidget(text) label_lo.setText(str(low)) label_hi.setText(str(high)) self.set_tooltip(slider) self.set_tooltip(label_lo) self.set_tooltip(label_hi) self.set_tooltip(text) # Update the ranges and button just in case. self.update_range_ui() #--------------------------------------------------------------------------- # Handles the user changing the current slider value: #--------------------------------------------------------------------------- def update_object_on_scroll(self, pos): """ Handles the user changing the current slider value. """ value = self.cur_low + ((float(pos) / 10000.0) * (self.cur_high - self.cur_low)) self.control.text.setText(self._format % value) if self.factory.is_float: self.value = value else: self.value = int(value) #--------------------------------------------------------------------------- # Handle the user pressing the 'Enter' key in the edit control: #--------------------------------------------------------------------------- def update_object_on_enter(self): """ Handles the user pressing the Enter key in the text field. """ try: self.value = eval(unicode(self.control.text.text()).strip()) except TraitError, excp: pass #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ value = self.value low = self.low high = self.high try: text = self._format % value 1 / (low <= value <= high) except: value = low self.value = value if not self.ui_changing: self.init_range() self.update_range_ui() def update_range_ui ( self ): """ Updates the slider range controls. """ low, high = self.cur_low, self.cur_high value = self.value self._set_format() self.control.label_lo.setText( self._format % low ) self.control.label_hi.setText( self._format % high ) if high > low: ivalue = int( (float( value - low ) / (high - low)) * 10000.0 ) else: ivalue = low blocked = self.control.slider.blockSignals(True) self.control.slider.setValue( ivalue ) self.control.slider.blockSignals(blocked) text = self._format % self.value self.control.text.setText( text ) self.control.button_lo.setEnabled(low != self.low) self.control.button_hi.setEnabled(high != self.high) def init_range ( self ): """ Initializes the slider range controls. """ value = self.value low, high = self.low, self.high if (high is None) and (low is not None): high = -low mag = abs( value ) if mag <= 10.0: cur_low = max( value - 10, low ) cur_high = min( value + 10, high ) else: d = 0.5 * (10**int( log10( mag ) + 1 )) cur_low = max( low, value - d ) cur_high = min( high, value + d ) self.cur_low, self.cur_high = cur_low, cur_high def reduce_range(self): """ Reduces the extent of the displayed range. """ low, high = self.low, self.high if abs( self.cur_low ) < 10: self.cur_low = max( -10, low ) self.cur_high = min( 10, high ) elif self.cur_low > 0: self.cur_high = self.cur_low self.cur_low = max( low, self.cur_low / 10 ) else: self.cur_high = self.cur_low self.cur_low = max( low, self.cur_low * 10 ) self.ui_changing = True self.value = min( max( self.value, self.cur_low ), self.cur_high ) self.ui_changing = False self.update_range_ui() def increase_range(self): """ Increased the extent of the displayed range. """ low, high = self.low, self.high if abs( self.cur_high ) < 10: self.cur_low = max( -10, low ) self.cur_high = min( 10, high ) elif self.cur_high > 0: self.cur_low = self.cur_high self.cur_high = min( high, self.cur_high * 10 ) else: self.cur_low = self.cur_high self.cur_high = min( high, self.cur_high / 10 ) self.ui_changing = True self.value = min( max( self.value, self.cur_low ), self.cur_high ) self.ui_changing = False self.update_range_ui() def _set_format ( self ): self._format = '%d' factory = self.factory low, high = self.cur_low, self.cur_high diff = high - low if factory.is_float: if diff > 99999: self._format = '%.2g' elif diff > 1: self._format = '%%.%df' % max( 0, 4 - int( log10( high - low ) ) ) else: self._format = '%.3f' #--------------------------------------------------------------------------- # Returns the editor's control for indicating error status: #--------------------------------------------------------------------------- def get_error_control ( self ): """ Returns the editor's control for indicating error status. """ return self.control.text #--------------------------------------------------------------------------- # Handles the 'low'/'high' traits being changed: #--------------------------------------------------------------------------- def _low_changed ( self, low ): if self.control is not None: if self.value < low: if self.factory.is_float: self.value = float( low ) else: self.value = int( low ) self.update_editor() def _high_changed ( self, high ): if self.control is not None: if self.value > high: if self.factory.is_float: self.value = float( high ) else: self.value = int( high ) self.update_editor() #------------------------------------------------------------------------------- # 'SimpleSpinEditor' class: #------------------------------------------------------------------------------- class SimpleSpinEditor ( BaseRangeEditor ): """ A simple style of range editor that displays a spin box control. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Low value for the slider range low = Any # High value for the slider range high = Any #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ factory = self.factory if not factory.low_name: self.low = factory.low if not factory.high_name: self.high = factory.high self.sync_value( factory.low_name, 'low', 'from' ) self.sync_value( factory.high_name, 'high', 'from' ) low = self.low high = self.high self.control = QtGui.QSpinBox() self.control.setMinimum(low) self.control.setMaximum(high) self.control.setValue(self.value) QtCore.QObject.connect(self.control, QtCore.SIGNAL('valueChanged(int)'), self.update_object) self.set_tooltip() #--------------------------------------------------------------------------- # Handle the user selecting a new value from the spin control: #--------------------------------------------------------------------------- def update_object(self, value): """ Handles the user selecting a new value in the spin box. """ self._locked = True try: self.value = value finally: self._locked = False #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ if not self._locked: try: self.control.setValue(int(self.value)) except: pass #--------------------------------------------------------------------------- # Handles the 'low'/'high' traits being changed: #--------------------------------------------------------------------------- def _low_changed ( self, low ): if self.value < low: if self.factory.is_float: self.value = float( low ) else: self.value = int( low ) if self.control: self.control.setMinimum(low) self.control.setValue(int(self.value)) def _high_changed ( self, high ): if self.value > high: if self.factory.is_float: self.value = float( high ) else: self.value = int( high ) if self.control: self.control.setMaximum(high) self.control.setValue(int(self.value)) #------------------------------------------------------------------------------- # 'RangeTextEditor' class: #------------------------------------------------------------------------------- class RangeTextEditor ( TextEditor ): """ Editor for ranges that displays a text field. If the user enters a value that is outside the allowed range, the background of the field changes color to indicate an error. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Function to evaluate floats/ints evaluate = Any #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ TextEditor.init( self, parent ) self.evaluate = self.factory.evaluate self.sync_value( self.factory.evaluate_name, 'evaluate', 'from' ) #--------------------------------------------------------------------------- # Handles the user entering input data in the edit control: #--------------------------------------------------------------------------- def update_object (self): """ Handles the user entering input data in the edit control. """ try: value = eval(unicode(self.control.text())) if self.evaluate is not None: value = self.evaluate(value) self.value = value col = OKColor except: col = ErrorColor pal = QtGui.QPalette(self.control.palette()) pal.setColor(QtGui.QPalette.Base, col) self.control.setPalette(pal) #------------------------------------------------------------------------------- # 'SimpleEnumEditor' factory adaptor: #------------------------------------------------------------------------------- def SimpleEnumEditor ( parent, factory, ui, object, name, description ): return CustomEnumEditor( parent, factory, ui, object, name, description, 'simple' ) #------------------------------------------------------------------------------- # 'CustomEnumEditor' factory adaptor: #------------------------------------------------------------------------------- def CustomEnumEditor ( parent, factory, ui, object, name, description, style = 'custom' ): """ Factory adapter that returns a enumeration editor of the specified style. """ if factory._enum is None: import traitsui.editors.enum_editor as enum_editor factory._enum = enum_editor.ToolkitEditorFactory( values = range( factory.low, factory.high + 1 ), cols = factory.cols ) if style == 'simple': return factory._enum.simple_editor( ui, object, name, description, parent ) return factory._enum.custom_editor( ui, object, name, description, parent ) #------------------------------------------------------------------------------- # Defines the mapping between editor factory 'mode's and Editor classes: #------------------------------------------------------------------------------- # Mapping between editor factory modes and simple editor classes SimpleEditorMap = { 'slider': SimpleSliderEditor, 'xslider': LargeRangeSliderEditor, 'spinner': SimpleSpinEditor, 'enum': SimpleEnumEditor, 'text': RangeTextEditor, 'low': LogRangeSliderEditor } # Mapping between editor factory modes and custom editor classes CustomEditorMap = { 'slider': SimpleSliderEditor, 'xslider': LargeRangeSliderEditor, 'spinner': SimpleSpinEditor, 'enum': CustomEnumEditor, 'text': RangeTextEditor, 'low': LogRangeSliderEditor } traitsui-4.1.0/traitsui/qt4/boolean_editor.py0000644000175100001440000001104511674463546022275 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2007, Riverbank Computing Limited # All rights reserved. # # This software is provided without warranty under the terms of the BSD license. # However, when used with the GPL version of PyQt the additional terms described in the PyQt GPL exception also apply # # Author: Riverbank Computing Limited #------------------------------------------------------------------------------ """ Defines the various Boolean editors for the PyQt user interface toolkit. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from pyface.qt import QtCore, QtGui # FIXME: ToolkitEditorFactory is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.boolean_editor file. from traitsui.editors.boolean_editor \ import ToolkitEditorFactory from editor \ import Editor # This needs to be imported in here for use by the editor factory for boolean # editors (declared in traitsui). The editor factory's text_editor # method will use the TextEditor in the ui. from text_editor \ import SimpleEditor as TextEditor from constants \ import ReadonlyColor #------------------------------------------------------------------------------- # 'SimpleEditor' class: #------------------------------------------------------------------------------- class SimpleEditor ( Editor ): """ Simple style of editor for Boolean values, which displays a check box. """ #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self.control = QtGui.QCheckBox() self.control.connect(self.control, QtCore.SIGNAL('stateChanged(int)'), self.update_object) self.set_tooltip() #--------------------------------------------------------------------------- # Handles the user clicking on the checkbox: #--------------------------------------------------------------------------- def update_object ( self, state ): """ Handles the user clicking the checkbox. """ self.value = bool(state) #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ if self.value: self.control.setCheckState(QtCore.Qt.Checked) else: self.control.setCheckState(QtCore.Qt.Unchecked) #------------------------------------------------------------------------------- # 'ReadonlyEditor' class: #------------------------------------------------------------------------------- class ReadonlyEditor ( Editor ): """ Read-only style of editor for Boolean values, which displays static text of either "True" or "False". """ #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self.control = QtGui.QLineEdit() self.control.setReadOnly(True) pal = QtGui.QPalette(self.control.palette()) pal.setColor(QtGui.QPalette.Base, ReadonlyColor) self.control.setPalette(pal) #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: # # (Should normally be overridden in a subclass) #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ if self.value: self.control.setText('True') else: self.control.setText('False') traitsui-4.1.0/traitsui/qt4/editor.py0000644000175100001440000004431011674463546020577 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2007, Riverbank Computing Limited # All rights reserved. # # This software is provided without warranty under the terms of the BSD license. # However, when used with the GPL version of PyQt the additional terms described in the PyQt GPL exception also apply # # Author: Riverbank Computing Limited #------------------------------------------------------------------------------ """ Defines the base class for PyQt editors. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from pyface.qt import QtGui from traits.api \ import HasTraits, Instance, Str, Callable from traitsui.api \ import Editor as UIEditor from constants \ import OKColor, ErrorColor #------------------------------------------------------------------------------- # 'Editor' class: #------------------------------------------------------------------------------- class Editor ( UIEditor ): """ Base class for PyQt editors for Traits-based UIs. """ def clear_layout(self): """ Delete the contents of a control's layout. """ layout = self.control.layout() while True: itm = layout.takeAt(0) if itm is None: break itm.widget().setParent(None) #--------------------------------------------------------------------------- # Handles the 'control' trait being set: #--------------------------------------------------------------------------- def _control_changed ( self, control ): """ Handles the **control** trait being set. """ # FIXME: Check we actually make use of this. if control is not None: control._editor = self #--------------------------------------------------------------------------- # Assigns focus to the editor's underlying toolkit widget: #--------------------------------------------------------------------------- def set_focus ( self ): """ Assigns focus to the editor's underlying toolkit widget. """ if self.control is not None: self.control.setFocus() #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ new_value = self.str_value if self.control.text() != new_value: self.control.setText( new_value ) #--------------------------------------------------------------------------- # Handles an error that occurs while setting the object's trait value: #--------------------------------------------------------------------------- def error ( self, excp ): """ Handles an error that occurs while setting the object's trait value. """ # Make sure the control is a widget rather than a layout. if isinstance(self.control, QtGui.QLayout): control = self.control.parentWidget() else: control = self.control QtGui.QMessageBox.information(control, self.description + ' value error', str(excp)) #--------------------------------------------------------------------------- # Sets the tooltip for a specified control: #--------------------------------------------------------------------------- def set_tooltip ( self, control = None ): """ Sets the tooltip for a specified control. """ desc = self.description if desc == '': desc = self.object.base_trait( self.name ).desc if desc is None: return False desc = 'Specifies ' + desc if control is None: control = self.control control.setToolTip( desc ) return True #--------------------------------------------------------------------------- # Handles the 'enabled' state of the editor being changed: #--------------------------------------------------------------------------- def _enabled_changed(self, enabled): """Handles the **enabled** state of the editor being changed. """ if self.control is not None: self._enabled_changed_helper(self.control, enabled) def _enabled_changed_helper(self, control, enabled): """A helper that allows the control to be a layout and recursively manages all its widgets. """ if isinstance(control, QtGui.QWidget): control.setEnabled(enabled) else: for i in range(control.count()): itm = control.itemAt(i) self._enabled_changed_helper((itm.widget() or itm.layout()), enabled) #--------------------------------------------------------------------------- # Handles the 'visible' state of the editor being changed: #--------------------------------------------------------------------------- def _visible_changed(self, visible): """Handles the **visible** state of the editor being changed. """ if self.label_control is not None: self.label_control.setVisible(visible) if self.control is None: # We are being called after the editor has already gone away. return self._visible_changed_helper(self.control, visible) page = self.control.parent() if page is None or page.parent() is None or page.parent().parent() is None or page.layout().count() != 1: return # The TabWidget (representing the notebook) has a StackedWidget inside it, # which then contains our parent. # Even after the tab is removed, the parent-child relationship between # our container widget (representing the page) and the enclosing TabWidget, # so the following reference is still valid. stack_widget = page.parent() notebook = stack_widget.parent() is_tabbed_group = notebook.property("traits_tabbed_group") if notebook is None or not isinstance(notebook, QtGui.QTabWidget) or not is_tabbed_group: return if not visible: # Store the page number and name on the parent for i in range(0, notebook.count()): if notebook.widget(i) == page: self._tab_index = i self._tab_text = notebook.tabText(i) page.setVisible(False) notebook.removeTab(i) break else: # Check to see if our parent has previously-stored tab # index and text attributes if (getattr(self, "_tab_index", None) is not None and getattr(self, "_tab_text", None) is not None): page.setVisible(True) notebook.insertTab(self._tab_index, page, self._tab_text) return def _visible_changed_helper(self, control, visible): """A helper that allows the control to be a layout and recursively manages all its widgets. """ if isinstance(control, QtGui.QWidget): control.setVisible(visible) else: for i in range(control.count()): itm = control.itemAt(i) self._visible_changed_helper((itm.widget() or itm.layout()), visible) #--------------------------------------------------------------------------- # Returns the editor's control for indicating error status: #--------------------------------------------------------------------------- def get_error_control ( self ): """ Returns the editor's control for indicating error status. """ return self.control #--------------------------------------------------------------------------- # Returns whether or not the editor is in an error state: #--------------------------------------------------------------------------- def in_error_state ( self ): """ Returns whether or not the editor is in an error state. """ return False #--------------------------------------------------------------------------- # Sets the editor's current error state: #--------------------------------------------------------------------------- def set_error_state ( self, state = None, control = None ): """ Sets the editor's current error state. """ if state is None: state = self.invalid state = state or self.in_error_state() if control is None: control = self.get_error_control() if not isinstance( control, list ): control = [ control ] for item in control: if item is None: continue pal = QtGui.QPalette(item.palette()) if state: color = ErrorColor if getattr( item, '_ok_color', None ) is None: item._ok_color = QtGui.QColor(pal.color(QtGui.QPalette.Base)) else: color = getattr( item, '_ok_color', OKColor ) pal.setColor(QtGui.QPalette.Base, color) item.setPalette(pal) #--------------------------------------------------------------------------- # Handles the editor's invalid state changing: #--------------------------------------------------------------------------- def _invalid_changed ( self, state ): """ Handles the editor's invalid state changing. """ self.set_error_state() #--------------------------------------------------------------------------- # Handles the editor's context menu action #--------------------------------------------------------------------------- def perform (self, action, action_event = None ): """ Performs the action described by a specified Action object. """ self.ui.do_undoable( self._perform, action ) def _perform ( self, action ): method_name = action.action info = self._menu_context['info'] handler = self._menu_context['handler'] object = self._menu_context['object'] selection = self._menu_context['selection'] self._menu_context['action'] = action if method_name.find( '.' ) >= 0: if method_name.find( '(' ) < 0: method_name += '()' try: eval( method_name, globals(), self._menu_context ) except: from traitsui.api import raise_to_debug raise_to_debug() return method = getattr( handler, method_name, None ) if method is not None: method( info, selection ) return if action.on_perform is not None: action.on_perform(selection) action.perform(selection) def eval_when ( self, condition, object, trait ): """ Evaluates a condition within a defined context, and sets a specified object trait based on the result, which is assumed to be a Boolean. """ if condition != '': value = True try: if not eval( condition, globals(), self._menu_context ): value = False except: from traitsui.api import raise_to_debug raise_to_debug() setattr( object, trait, value ) def add_to_menu ( self, menu_item ): """ Adds a menu item to the menu bar being constructed. """ action = menu_item.item.action self.eval_when( action.enabled_when, menu_item, 'enabled' ) self.eval_when( action.checked_when, menu_item, 'checked' ) def can_add_to_menu(self, action) : """ Returns whether the action should be defined in the user interface. """ if action.defined_when != '': try: if not eval( action.defined_when, globals(), self._menu_context ): return False except: from traitsui.api import raise_to_debug raise_to_debug() if action.visible_when != '': try: if not eval( action.visible_when, globals(), self._menu_context ): return False except: from traitsui.api import raise_to_debug raise_to_debug() return True def set_size_policy(self, direction, resizable, springy, stretch) : policy = self.control.sizePolicy() if direction == QtGui.QBoxLayout.LeftToRight: policy.setHorizontalStretch(stretch) if springy: policy.setHorizontalPolicy(QtGui.QSizePolicy.Expanding) if resizable : policy.setVerticalPolicy(QtGui.QSizePolicy.Expanding) else: policy.setVerticalStretch(stretch) if resizable : policy.setHorizontalPolicy(QtGui.QSizePolicy.Expanding) if springy : policy.setVerticalPolicy(QtGui.QSizePolicy.Expanding) self.control.setSizePolicy(policy) #------------------------------------------------------------------------------- # 'EditorWithList' class: #------------------------------------------------------------------------------- class EditorWithList ( Editor ): """ Editor for an object that contains a list. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Object containing the list being monitored list_object = Instance( HasTraits ) # Name of the monitored trait list_name = Str # Function used to evaluate the current list object value: list_value = Callable #--------------------------------------------------------------------------- # Initializes the object: #--------------------------------------------------------------------------- def init ( self, parent ): """ Initializes the object. """ factory = self.factory name = factory.name if name != '': self.list_object, self.list_name, self.list_value = \ self.parse_extended_name( name ) else: self.list_object, self.list_name = factory, 'values' self.list_value = lambda: factory.values self.list_object.on_trait_change( self._list_updated, self.list_name, dispatch = 'ui' ) self.list_object.on_trait_change( self._list_updated, self.list_name+'_items', dispatch = 'ui' ) self._list_updated() #--------------------------------------------------------------------------- # Disconnects the listeners set up by the constructor: #--------------------------------------------------------------------------- def dispose ( self ): """ Disconnects the listeners set up by the constructor. """ self.list_object.on_trait_change( self._list_updated, self.list_name, remove = True ) self.list_object.on_trait_change( self._list_updated, self.list_name+'_items', remove = True ) super( EditorWithList, self ).dispose() #--------------------------------------------------------------------------- # Handles the monitored trait being updated: #--------------------------------------------------------------------------- def _list_updated ( self ): """ Handles the monitored trait being updated. """ self.list_updated( self.list_value() ) #--------------------------------------------------------------------------- # Handles the monitored list being updated: #--------------------------------------------------------------------------- def list_updated ( self, values ): """ Handles the monitored list being updated. """ raise NotImplementedError #------------------------------------------------------------------------------- # 'EditorFromView' class: #------------------------------------------------------------------------------- class EditorFromView ( Editor ): """ An editor generated from a View object. """ #--------------------------------------------------------------------------- # Initializes the object: #--------------------------------------------------------------------------- def init ( self, parent ): """ Initializes the object. """ self._ui = ui = self.init_ui( parent ) if ui.history is None: ui.history = self.ui.history self.control = ui.control #--------------------------------------------------------------------------- # Creates and returns the traits UI defined by this editor: # (Must be overridden by a subclass): #--------------------------------------------------------------------------- def init_ui ( self, parent ): """ Creates and returns the traits UI defined by this editor. (Must be overridden by a subclass). """ raise NotImplementedError #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ # Normally nothing needs to be done here, since it should all be handled # by the editor's internally created traits UI: pass #--------------------------------------------------------------------------- # Dispose of the editor: #--------------------------------------------------------------------------- def dispose ( self ): """ Disposes of the editor. """ self._ui.dispose() super( EditorFromView, self ).dispose() traitsui-4.1.0/traitsui/qt4/title_editor.py0000644000175100001440000000434011674463546021777 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2008, Riverbank Computing Limited # All rights reserved. # # This software is provided without warranty under the terms of the BSD license. # However, when used with the GPL version of PyQt the additional terms described in the PyQt GPL exception also apply # # Author: Riverbank Computing Limited #------------------------------------------------------------------------------ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from pyface.qt import QtCore from .editor import Editor from pyface.heading_text import HeadingText # FIXME: ToolkitEditorFactory is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.title_editor file. from ..editors.title_editor import TitleEditor class SimpleEditor ( Editor ): #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self._control = HeadingText( None ) self.control = self._control.control if self.factory.allow_selection: flags = (self.control.textInteractionFlags() | QtCore.Qt.TextSelectableByMouse) self.control.setTextInteractionFlags(flags) self.set_tooltip() #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes external to the editor. """ self._control.text = self.str_value CustomEditor = SimpleEditor ReadonlyEditor = SimpleEditor TextEditor = SimpleEditor traitsui-4.1.0/traitsui/qt4/table_model.py0000644000175100001440000002712511674463546021565 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2008, Riverbank Computing Limited # All rights reserved. # # This software is provided without warranty under the terms of the BSD license. # However, when used with the GPL version of PyQt the additional terms described # in the PyQt GPL exception also apply. # # Author: Riverbank Computing Limited #------------------------------------------------------------------------------ """ Defines the table model used by the table editor. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from pyface.qt import QtCore, QtGui from traitsui.ui_traits import SequenceTypes #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- # Mapping for trait alignment values to qt4 horizontal alignment constants h_alignment_map = { 'left': QtCore.Qt.AlignLeft, 'center': QtCore.Qt.AlignHCenter, 'right': QtCore.Qt.AlignRight, } # Mapping for trait alignment values to qt4 vertical alignment constants v_alignment_map = { 'top': QtCore.Qt.AlignTop, 'center': QtCore.Qt.AlignVCenter, 'bottom': QtCore.Qt.AlignBottom, } # MIME type for internal table drag/drop operations mime_type = 'traits-ui-table-editor' def as_qcolor(color): """ Convert a color specification (maybe a tuple) into a QColor. """ if isinstance(color, SequenceTypes): return QtGui.QColor(*color) else: return QtGui.QColor(color) #------------------------------------------------------------------------------- # 'TableModel' class: #------------------------------------------------------------------------------- class TableModel(QtCore.QAbstractTableModel): """The model for table data.""" def __init__(self, editor, parent=None): """Initialise the object.""" QtCore.QAbstractTableModel.__init__(self, parent) self._editor = editor #--------------------------------------------------------------------------- # QAbstractTableModel interface: #--------------------------------------------------------------------------- def rowCount(self, mi): """Reimplemented to return the number of rows.""" return len(self._editor.items()) def columnCount(self, mi): """Reimplemented to return the number of columns.""" return len(self._editor.columns) def data(self, mi, role): """Reimplemented to return the data.""" obj = self._editor.items()[mi.row()] column = self._editor.columns[mi.column()] if role == QtCore.Qt.DisplayRole or role == QtCore.Qt.EditRole: text = column.get_value(obj) if text is not None: return text elif role == QtCore.Qt.ToolTipRole: tooltip = column.get_tooltip(obj) if tooltip: return tooltip elif role == QtCore.Qt.FontRole: font = column.get_text_font(obj) if font is not None: return QtGui.QFont(font) elif role == QtCore.Qt.TextAlignmentRole: string = column.get_horizontal_alignment(obj) h_alignment = h_alignment_map.get(string, QtCore.Qt.AlignLeft) string = column.get_vertical_alignment(obj) v_alignment = v_alignment_map.get(string, QtCore.Qt.AlignVCenter) return (h_alignment | v_alignment) elif role == QtCore.Qt.BackgroundRole: color = column.get_cell_color(obj) if color is None: # FIXME: Yes, this is weird. It should work fine to fall through # to the catch-all None at the end, but it doesn't. return None else: q_color = as_qcolor(color) return QtGui.QBrush(q_color) elif role == QtCore.Qt.ForegroundRole: color = column.get_text_color(obj) if color is not None: q_color = as_qcolor(color) return QtGui.QBrush(q_color) elif role == QtCore.Qt.UserRole: return obj elif role == QtCore.Qt.CheckStateRole: if column.get_type(obj) == "bool" and column.show_checkbox: if column.get_raw_value(obj): return QtCore.Qt.Checked else: return QtCore.Qt.Unchecked return None def flags(self, mi): """Reimplemented to set editable and movable status.""" flags = QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled if not mi.isValid(): return flags editor = self._editor obj = editor.items()[mi.row()] column = editor.columns[mi.column()] if editor.factory.editable and column.is_editable(obj): flags |= QtCore.Qt.ItemIsEditable if editor.factory.reorderable: flags |= QtCore.Qt.ItemIsDragEnabled | QtCore.Qt.ItemIsDropEnabled if column.get_type(obj) == "bool" and column.show_checkbox: flags |= QtCore.Qt.ItemIsUserCheckable return flags def headerData(self, section, orientation, role): """Reimplemented to return the header data.""" if orientation == QtCore.Qt.Horizontal: editor = self._editor column = editor.columns[section] if role == QtCore.Qt.DisplayRole: return column.get_label() elif orientation == QtCore.Qt.Vertical: if role == QtCore.Qt.DisplayRole: return str(section + 1) return None def insertRow(self, row, parent=QtCore.QModelIndex(), obj=None): """Reimplemented to allow creation of new rows. Added an optional arg to allow the insertion of an existing row object.""" editor = self._editor if obj is None: obj = editor.create_new_row() self.beginInsertRows(parent, row, row) editor.callx(editor.items().insert, row, obj) self.endInsertRows() return True def insertRows(self, row, count, parent=QtCore.QModelIndex()): """Reimplemented to allow creation of new rows.""" editor = self._editor items = editor.items() self.beginInsertRows(parent, row, row + count - 1) for i in xrange(count): editor.callx(items.insert, row + i, editor.create_new_row()) self.endInsertRows() return True def removeRows(self, row, count, parent=QtCore.QModelIndex()): """Reimplemented to allow row deletion, as well as reordering via drag and drop.""" editor = self._editor items = editor.items() self.beginRemoveRows(parent, row, row + count - 1) for i in xrange(count): editor.callx(items.pop, row + i) self.endRemoveRows() return True def mimeTypes(self): """Reimplemented to expose our internal MIME type for drag and drop operations.""" types = QtCore.QStringList() types.append(mime_type) return types def mimeData(self, indexes): """Reimplemented to generate MIME data containing the rows of the current selection.""" mime_data = QtCore.QMimeData() rows = list(set([ index.row() for index in indexes ])) data = QtCore.QByteArray(str(rows[0])) for row in rows[1:]: data.append(' %i' % row) mime_data.setData(mime_type, data) return mime_data def dropMimeData(self, mime_data, action, row, column, parent): """Reimplemented to allow items to be moved.""" if action == QtCore.Qt.IgnoreAction: return False data = mime_data.data(mime_type) if data.isNull(): return False current_rows = map(int, str(data).split(' ')) self.moveRows(current_rows, parent.row()) return True def supportedDropActions(self): """Reimplemented to allow items to be moved.""" return QtCore.Qt.MoveAction #--------------------------------------------------------------------------- # TableModel interface: #--------------------------------------------------------------------------- def moveRow(self, old_row, new_row): """Convenience method to move a single row.""" return self.moveRows([old_row], new_row) def moveRows(self, current_rows, new_row): """Moves a sequence of rows (provided as a list of row indexes) to a new row.""" # Sort rows in descending order so they can be removed without # invalidating the indices. current_rows.sort() current_rows.reverse() # If the the highest selected row is lower than the destination, do an # insertion before rather than after the destination. if current_rows[-1] < new_row: new_row += 1 # Remove selected rows... items = self._editor.items() objects = [] for row in current_rows: if row <= new_row: new_row -= 1 objects.insert(0, items[row]) self.removeRow(row) # ...and add them at the new location. for i, obj in enumerate(objects): self.insertRow(new_row + i, obj=obj) # Update the selection for the new location. self._editor.set_selection(objects) #------------------------------------------------------------------------------- # 'SortFilterTableModel' class: #------------------------------------------------------------------------------- class SortFilterTableModel(QtGui.QSortFilterProxyModel): """A wrapper for the TableModel which provides sorting and filtering capability.""" def __init__(self, editor, parent=None): """Initialise the object.""" QtGui.QSortFilterProxyModel.__init__(self, parent) self._editor = editor #--------------------------------------------------------------------------- # QSortFilterProxyModel interface: #--------------------------------------------------------------------------- def filterAcceptsRow(self, source_row, source_parent): """"Reimplemented to use a TableFilter for filtering rows.""" if self._editor._filtered_cache is None: return True else: return self._editor._filtered_cache[source_row] def filterAcceptsColumn(self, source_column, source_parent): """Reimplemented to save time, because we always return True.""" return True def lessThan(self, left_mi, right_mi): """Reimplemented to sort according to the 'cmp' method defined for TableColumn.""" editor = self._editor column = editor.columns[left_mi.column()] items = editor.items() left, right = items[left_mi.row()], items[right_mi.row()] return column.cmp(left, right) < 0 #--------------------------------------------------------------------------- # SortFilterTableModel interface: #--------------------------------------------------------------------------- def moveRow(self, old_row, new_row): """Convenience method to move a single row.""" return self.moveRows([old_row], new_row) def moveRows(self, current_rows, new_row): """Delegate to source model with mapped rows.""" source = self.sourceModel() current_rows = [ self.mapToSource(self.index(row, 0)).row() for row in current_rows ] new_row = self.mapToSource(self.index(new_row, 0)).row() source.moveRows(current_rows, new_row) traitsui-4.1.0/traitsui/qt4/toolkit.py0000644000175100001440000005777311674463546021017 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2007, Riverbank Computing Limited # All rights reserved. # # This software is provided without warranty under the terms of the BSD license. # However, when used with the GPL version of PyQt the additional terms described # in the PyQt GPL exception also apply. # # Author: Riverbank Computing Limited #------------------------------------------------------------------------------ """ Defines the concrete implementations of the traits Toolkit interface for the PyQt user interface toolkit. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- # Make sure that importing from this backend is OK: from traitsui.toolkit import assert_toolkit_import assert_toolkit_import('qt4') from pyface.qt import QtCore, QtGui, qt_api if qt_api == 'pyqt': # Check the version numbers are late enough: if QtCore.QT_VERSION < 0x040200: raise RuntimeError, "Need Qt v4.2 or higher, but got v%s" % QtCore.QT_VERSION_STR # Make sure a QApplication object is created early: import sys if QtGui.QApplication.startingUp(): _app = QtGui.QApplication(sys.argv) from traits.trait_notifiers import set_ui_handler from traitsui.toolkit import Toolkit from constants import screen_dx, screen_dy #------------------------------------------------------------------------------- # Handles UI notification handler requests that occur on a thread other than # the UI thread: #------------------------------------------------------------------------------- _QT_TRAITS_EVENT = QtCore.QEvent.Type(QtCore.QEvent.registerEventType()) class _CallAfter(QtCore.QObject): """ This class dispatches a handler so that it executes in the main GUI thread (similar to the wx function). """ # The list of pending calls. _calls = [] # The mutex around the list of pending calls. _calls_mutex = QtCore.QMutex() def __init__(self, handler, *args, **kwds): """ Initialise the call. """ QtCore.QObject.__init__(self) # Save the details of the call. self._handler = handler self._args = args self._kwds = kwds # Add this to the list. self._calls_mutex.lock() self._calls.append(self) self._calls_mutex.unlock() # Move to the main GUI thread. self.moveToThread(QtGui.QApplication.instance().thread()) # Post an event to be dispatched on the main GUI thread. Note that # we do not call QTimer.singleShot, which would be simpler, because # that only works on QThreads. We want regular Python threads to work. event = QtCore.QEvent(_QT_TRAITS_EVENT) QtGui.QApplication.instance().postEvent(self, event) def event(self, event): """ QObject event handler. """ if event.type() == _QT_TRAITS_EVENT: # Invoke the handler self._handler(*self._args, **self._kwds) # We cannot remove from self._calls here. QObjects don't like being # garbage collected during event handlers (there are tracebacks, # plus maybe a memory leak, I think). QtCore.QTimer.singleShot(0, self._finished) return True else: return QtCore.QObject.event(self, event) def _finished(self): """ Remove the call from the list, so it can be garbage collected. """ self._calls_mutex.lock() del self._calls[self._calls.index(self)] self._calls_mutex.unlock() def ui_handler ( handler, *args, **kwds ): """ Handles UI notification handler requests that occur on a thread other than the UI thread. """ _CallAfter(handler, *args, **kwds) # Tell the traits notification handlers to use this UI handler set_ui_handler( ui_handler ) #------------------------------------------------------------------------------- # 'GUIToolkit' class: #------------------------------------------------------------------------------- class GUIToolkit ( Toolkit ): """ Implementation class for PyQt toolkit. """ #--------------------------------------------------------------------------- # Create PyQt specific user interfaces using information from the # specified UI object: #--------------------------------------------------------------------------- def ui_panel ( self, ui, parent ): """ Creates a PyQt panel-based user interface using information from the specified UI object. """ import ui_panel ui_panel.ui_panel( ui, parent ) def ui_subpanel ( self, ui, parent ): """ Creates a PyQt subpanel-based user interface using information from the specified UI object. """ import ui_panel ui_panel.ui_subpanel( ui, parent ) def ui_livemodal ( self, ui, parent ): """ Creates a PyQt modal "live update" dialog user interface using information from the specified UI object. """ import ui_live ui_live.ui_livemodal( ui, parent ) def ui_live ( self, ui, parent ): """ Creates a PyQt non-modal "live update" window user interface using information from the specified UI object. """ import ui_live ui_live.ui_live( ui, parent ) def ui_modal ( self, ui, parent ): """ Creates a PyQt modal dialog user interface using information from the specified UI object. """ import ui_modal ui_modal.ui_modal( ui, parent ) def ui_nonmodal ( self, ui, parent ): """ Creates a PyQt non-modal dialog user interface using information from the specified UI object. """ import ui_modal ui_modal.ui_nonmodal( ui, parent ) def ui_wizard ( self, ui, parent ): """ Creates a PyQt wizard dialog user interface using information from the specified UI object. """ import ui_wizard ui_wizard.ui_wizard( ui, parent ) def view_application ( self, context, view, kind = None, handler = None, id = '', scrollable = None, args = None ): """ Creates a PyQt modal dialog user interface that runs as a complete application, using information from the specified View object. Parameters ---------- context : object or dictionary A single object or a dictionary of string/object pairs, whose trait attributes are to be edited. If not specified, the current object is used. view : view or string A View object that defines a user interface for editing trait attribute values. kind : string The type of user interface window to create. See the **traitsui.view.kind_trait** trait for values and their meanings. If *kind* is unspecified or None, the **kind** attribute of the View object is used. handler : Handler object A handler object used for event handling in the dialog box. If None, the default handler for Traits UI is used. id : string A unique ID for persisting preferences about this user interface, such as size and position. If not specified, no user preferences are saved. scrollable : Boolean Indicates whether the dialog box should be scrollable. When set to True, scroll bars appear on the dialog box if it is not large enough to display all of the items in the view at one time. """ import view_application return view_application.view_application( context, view, kind, handler, id, scrollable, args ) #--------------------------------------------------------------------------- # Positions the associated dialog window on the display: #--------------------------------------------------------------------------- def position ( self, ui ): """ Positions the associated dialog window on the display. """ view = ui.view window = ui.control # Set up the default position of the window: parent = window.parent() if parent is None: px = 0 py = 0 pdx = screen_dx pdy = screen_dy else: pos = parent.pos() if int(parent.windowFlags()) & QtCore.Qt.Window == 0 : pos = parent.mapToGlobal(pos) px = pos.x() py = pos.y() pdx = parent.width() pdy = parent.height() # Get the window's prefered size. size_hint = window.sizeHint() # Calculate the correct width and height for the window: cur_width = size_hint.width() cur_height = size_hint.height() width = view.width height = view.height if width < 0.0: width = cur_width elif width <= 1.0: width = int( width * screen_dx ) else: width = int( width ) if height < 0.0: height = cur_height elif height <= 1.0: height = int( height * screen_dy ) else: height = int( height ) # Calculate the correct position for the window: x = view.x y = view.y if x < -99999.0: x = px + ((pdx - width) / 2) elif x <= -1.0: x = px + pdx - width + int( x ) + 1 elif x < 0.0: x = px + pdx - width + int( x * pdx ) elif x <= 1.0: x = px + int( x * pdx ) else: x = int( x ) if y < -99999.0: y = py + ((pdy - height) / 2) elif y <= -1.0: y = py + pdy - height + int( y ) + 1 elif x < 0.0: y = py + pdy - height + int( y * pdy ) elif y <= 1.0: y = py + int( y * pdy ) else: y = int( y ) # Position and size the window as requested: layout = window.layout() if layout.sizeConstraint() == QtGui.QLayout.SetFixedSize: layout.setSizeConstraint( QtGui.QLayout.SetDefaultConstraint ) window.move( max( 0, x ), max( 0, y ) ) window.setFixedSize( QtCore.QSize ( width, height ) ) else: window.setGeometry( max( 0, x ), max( 0, y ), width, height ) #--------------------------------------------------------------------------- # Shows a 'Help' window for a specified UI and control: #--------------------------------------------------------------------------- def show_help ( self, ui, control ): """ Shows a help window for a specified UI and control. """ import ui_panel ui_panel.show_help(ui, control) #--------------------------------------------------------------------------- # Saves user preference information associated with a UI window: #--------------------------------------------------------------------------- def save_window ( self, ui ): """ Saves user preference information associated with a UI window. """ import helper helper.save_window(ui) #--------------------------------------------------------------------------- # Rebuilds a UI after a change to the content of the UI: #--------------------------------------------------------------------------- def rebuild_ui ( self, ui ): """ Rebuilds a UI after a change to the content of the UI. """ if ui.control is not None: ui.recycle() ui.info.ui = ui ui.rebuild( ui, ui.parent ) #--------------------------------------------------------------------------- # Sets the title for the UI window: #--------------------------------------------------------------------------- def set_title ( self, ui ): """ Sets the title for the UI window. """ ui.control.setWindowTitle(ui.title) #--------------------------------------------------------------------------- # Sets the icon for the UI window: #--------------------------------------------------------------------------- def set_icon ( self, ui ): """ Sets the icon for the UI window. """ from pyface.image_resource import ImageResource if isinstance(ui.icon, ImageResource): ui.control.setWindowIcon(ui.icon.create_icon()) #--------------------------------------------------------------------------- # Converts a keystroke event into a corresponding key name: #--------------------------------------------------------------------------- def key_event_to_name ( self, event ): """ Converts a keystroke event into a corresponding key name. """ import key_event_to_name return key_event_to_name.key_event_to_name( event ) #--------------------------------------------------------------------------- # Hooks all specified events for all controls in a ui so that they can be # routed to the correct event handler: #--------------------------------------------------------------------------- def hook_events ( self, ui, control, events = None, handler = None ): """ Hooks all specified events for all controls in a UI so that they can be routed to the correct event handler. """ if events is None: # FIXME: Implement drag and drop events ala toolkit.py for wx return elif events == 'keys': class KeyEventHook(QtCore.QObject): def eventFilter(self, object, event): if event.type() == QtCore.QEvent.KeyPress: return handler(event) else: return QtCore.QObject.eventFilter(self, object, event) # It's unsafe to parent the event filter with the object it's # filtering, so we store a reference to it here to ensure that it's # not garbage collected prematurely. ui._key_event_hook = KeyEventHook() control.installEventFilter(ui._key_event_hook) #--------------------------------------------------------------------------- # Indicates that an event should continue to be processed by the toolkit #--------------------------------------------------------------------------- def skip_event ( self, event ): """ Indicates that an event should continue to be processed by the toolkit. """ event.ignore() #--------------------------------------------------------------------------- # Destroys a specified GUI toolkit control: #--------------------------------------------------------------------------- def destroy_control ( self, control ): """ Destroys a specified GUI toolkit control. """ # Block signals to prevent any editors from being updated (the control # will not be deleted immediately). control.blockSignals(True) # This may be called from within the finished() signal handler so we # need to do the delete after the handler has returned. control.hide() control.deleteLater() # PyQt v4.3.1 and earlier deleteLater() didn't transfer ownership to # C++, which is necessary for the QObject system to garbage collect it. if qt_api == 'pyqt': if QtCore.PYQT_VERSION < 0x040302: import sip sip.transferto(control, None) #--------------------------------------------------------------------------- # Destroys all of the child controls of a specified GUI toolkit control: #--------------------------------------------------------------------------- def destroy_children ( self, control ): """ Destroys all of the child controls of a specified GUI toolkit control. """ for w in control.children(): # Only destroy widgets. if isinstance(w, QtGui.QWidget): # This may be called from within the finished() signal handler # so we need to do the delete after the handler has returned. w.deleteLater() #--------------------------------------------------------------------------- # Returns a ( width, height ) tuple containing the size of a specified # toolkit image: #--------------------------------------------------------------------------- def image_size ( self, image ): """ Returns a ( width, height ) tuple containing the size of a specified toolkit image. """ return ( image.width(), image.height() ) #--------------------------------------------------------------------------- # Returns a dictionary of useful constants: #--------------------------------------------------------------------------- def constants ( self ): """ Returns a dictionary of useful constants. Currently, the dictionary should have the following key/value pairs: - 'WindowColor': the standard window background color in the toolkit specific color format. """ return { 'WindowColor': QtGui.QApplication.palette().color(QtGui.QPalette.Window), } #--------------------------------------------------------------------------- # GUI toolkit dependent trait definitions: #--------------------------------------------------------------------------- def color_trait ( self, *args, **traits ): import color_trait as ct return ct.PyQtColor( *args, **traits ) def rgb_color_trait ( self, *args, **traits ): import rgb_color_trait as rgbct return rgbct.RGBColor( *args, **traits ) def font_trait ( self, *args, **traits ): import font_trait as ft return ft.PyQtFont( *args, **traits ) #--------------------------------------------------------------------------- # 'Editor' class methods: #--------------------------------------------------------------------------- # Generic UI-base editor: def ui_editor ( self ): import ui_editor return ui_editor.UIEditor #--------------------------------------------------------------------------- # 'EditorFactory' factory methods: #--------------------------------------------------------------------------- # Array: def array_editor ( self, *args, **traits ): import array_editor as ae return ae.ToolkitEditorFactory( *args, **traits ) # Boolean: def boolean_editor ( self, *args, **traits ): import boolean_editor as be return be.ToolkitEditorFactory( *args, **traits ) # Button: def button_editor ( self, *args, **traits ): import button_editor as be return be.ToolkitEditorFactory( *args, **traits ) # Check list: def check_list_editor ( self, *args, **traits ): import check_list_editor as cle return cle.ToolkitEditorFactory( *args, **traits ) # Code: def code_editor ( self, *args, **traits ): import code_editor as ce return ce.ToolkitEditorFactory( *args, **traits ) # Color: def color_editor ( self, *args, **traits ): import color_editor as ce return ce.ToolkitEditorFactory( *args, **traits ) # Compound: def compound_editor ( self, *args, **traits ): import compound_editor as ce return ce.ToolkitEditorFactory( *args, **traits ) def styled_date_editor ( self, *args, **traits ): import styled_date_editor as sde return sde.ToolkitEditorFactory( *args, **traits ) # Custom: def custom_editor ( self, *args, **traits ): import custom_editor as ce return ce.ToolkitEditorFactory( *args, **traits ) # Directory: def directory_editor ( self, *args, **traits ): import directory_editor as de return de.ToolkitEditorFactory( *args, **traits) # Drop (drag and drop target): def drop_editor ( self, *args, **traits ): import drop_editor as de return de.ToolkitEditorFactory( *args, **traits) # Drag and drop: def dnd_editor ( self, *args, **traits ): import dnd_editor as dnd return dnd.ToolkitEditorFactory( *args, **traits) # Enum(eration): def enum_editor ( self, *args, **traits ): import enum_editor as ee return ee.ToolkitEditorFactory( *args, **traits ) # File: def file_editor ( self, *args, **traits ): import file_editor as fe return fe.ToolkitEditorFactory( *args, **traits ) # Font: def font_editor ( self, *args, **traits ): import font_editor as fe return fe.ToolkitEditorFactory( *args, **traits ) # Key Binding: def key_binding_editor ( self, *args, **traits ): import key_binding_editor as kbe return kbe.ToolkitEditorFactory( *args, **traits ) # History: def history_editor ( self, *args, **traits ): import history_editor as he return he.HistoryEditor( *args, **traits ) # HTML: def html_editor ( self, *args, **traits ): import html_editor as he return he.ToolkitEditorFactory( *args, **traits ) # Image: def image_editor ( self, *args, **traits ): import image_editor as ie return ie.ImageEditor( *args, **traits ) # Image enum(eration): def image_enum_editor ( self, *args, **traits ): import image_enum_editor as iee return iee.ToolkitEditorFactory( *args, **traits ) # Instance: def instance_editor ( self, *args, **traits ): import instance_editor as ie return ie.ToolkitEditorFactory( *args, **traits ) # List: def list_editor ( self, *args, **traits ): import list_editor as le return le.ToolkitEditorFactory( *args, **traits ) # ListStr: def list_str_editor ( self, *args, **traits ): import list_str_editor as lse return lse.ListStrEditor( *args, **traits ) # Null: def null_editor ( self, *args, **traits ): import null_editor as ne return ne.ToolkitEditorFactory( *args, **traits ) # Ordered set: def ordered_set_editor ( self, *args, **traits ): import ordered_set_editor as ose return ose.ToolkitEditorFactory( *args, **traits ) # Plot: def plot_editor ( self, *args, **traits ): import plot_editor as pe return pe.ToolkitEditorFactory( *args, **traits ) # Range: def range_editor ( self, *args, **traits ): import range_editor as re return re.ToolkitEditorFactory( *args, **traits ) # RGB Color: def rgb_color_editor ( self, *args, **traits ): import rgb_color_editor as rgbce return rgbce.ToolkitEditorFactory( *args, **traits ) # Set: def set_editor ( self, *args, **traits ): import set_editor as se return se.ToolkitEditorFactory( *args, **traits ) # Shell: def shell_editor ( self, *args, **traits ): import shell_editor as se return se.ToolkitEditorFactory( *args, **traits ) # Table: def table_editor ( self, *args, **traits ): import table_editor as te return te.ToolkitEditorFactory( *args, **traits ) # Tabular: def tabular_editor ( self, *args, **traits ): import tabular_editor as te return te.TabularEditor( *args, **traits ) # Text: def text_editor ( self, *args, **traits ): import text_editor as te return te.ToolkitEditorFactory( *args, **traits ) # Title: def title_editor ( self, *args, **traits ): import title_editor return title_editor.TitleEditor( *args, **traits ) # Tree: def tree_editor ( self, *args, **traits ): import tree_editor as te return te.ToolkitEditorFactory( *args, **traits ) # Tuple: def tuple_editor ( self, *args, **traits ): import tuple_editor as te return te.ToolkitEditorFactory( *args, **traits ) # Value: def value_editor ( self, *args, **traits ): import value_editor as ve return ve.ToolkitEditorFactory( *args, **traits ) traitsui-4.1.0/traitsui/qt4/basic_editor_factory.py0000644000175100001440000000300311674463546023461 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2008, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # #------------------------------------------------------------------------------ ## Deprecated proxy for the BasicEditorFactory class declared in # traitsui, declared here just for backward compatibility. import warnings from traitsui.basic_editor_factory \ import BasicEditorFactory as AbstractBasicEditorFactory #------------------------------------------------------------------------------- # 'BasicEditorFactory' class # Deprecated alias for traitsui.editor_factory.EditorFactory #------------------------------------------------------------------------------- class BasicEditorFactory(AbstractBasicEditorFactory): """ Deprecated alias for traitsui.basic_editor_factory.BasicEditorFactory. """ def __init__(self, *args, **kwds): super(BasicEditorFactory, self).__init__(*args, **kwds) warnings.warn("DEPRECATED: Use traitsui.basic_editor_factory" ".BasicEditorFactory instead.", DeprecationWarning) #---EOF------------------------------------------------------------------------- traitsui-4.1.0/traitsui/qt4/rgb_color_editor.py0000644000175100001440000000620311674463546022626 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2007, Riverbank Computing Limited # All rights reserved. # # This software is provided without warranty under the terms of the BSD license. # However, when used with the GPL version of PyQt the additional terms described in the PyQt GPL exception also apply # # Author: Riverbank Computing Limited #------------------------------------------------------------------------------ """ Defines a subclass of the base PyQt color editor factory, for colors that are represented as tuples of the form ( *red*, *green*, *blue* ), where *red*, *green* and *blue* are floats in the range from 0.0 to 1.0. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from pyface.qt import QtGui from traits.trait_base \ import SequenceTypes # Note: The ToolkitEditorFactory class imported from color_editor is a # subclass of the abstract ToolkitEditorFactory class # (in traitsui.api) with qt4-specific methods defined. # We need to override the implementations of the qt4-specific methods here. from color_editor \ import ToolkitEditorFactory as BaseColorToolkitEditorFactory #------------------------------------------------------------------------------- # The PyQt4 ToolkitEditorFactory class. #------------------------------------------------------------------------------- class ToolkitEditorFactory(BaseColorToolkitEditorFactory): """ PyQt editor factory for color editors. """ #--------------------------------------------------------------------------- # Gets the PyQt color equivalent of the object trait: #--------------------------------------------------------------------------- def to_qt4_color ( self, editor ): """ Gets the PyQt color equivalent of the object trait. """ try: color = getattr( editor.object, editor.name + '_' ) except AttributeError: color = getattr( editor.object, editor.name ) c = QtGui.QColor() c.setRgbF(color[0], color[1], color[2]) return c #--------------------------------------------------------------------------- # Gets the application equivalent of a PyQt value: #--------------------------------------------------------------------------- def from_qt4_color ( self, color ): """ Gets the application equivalent of a PyQt value. """ return (color.redF(), color.greenF(), color.blueF()) #--------------------------------------------------------------------------- # Returns the text representation of a specified color value: #--------------------------------------------------------------------------- def str_color ( self, color ): """ Returns the text representation of a specified color value. """ if type( color ) in SequenceTypes: return "(%d,%d,%d)" % ( int( color[0] * 255.0 ), int( color[1] * 255.0 ), int( color[2] * 255.0 ) ) return color traitsui-4.1.0/traitsui/qt4/custom_editor.py0000644000175100001440000000500211674463546022164 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2007, Riverbank Computing Limited # All rights reserved. # # This software is provided without warranty under the terms of the BSD license. # However, when used with the GPL version of PyQt the additional terms described in the PyQt GPL exception also apply # # Author: Riverbank Computing Limited #------------------------------------------------------------------------------ """ Defines the PyQt implementation of the editor used to wrap a non-Traits based custom control. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from pyface.qt import QtGui # FIXME: ToolkitEditorFactory is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.custom_editor file. from traitsui.editors.custom_editor \ import ToolkitEditorFactory from editor \ import Editor #------------------------------------------------------------------------------- # 'CustomEditor' class: #------------------------------------------------------------------------------- class CustomEditor ( Editor ): """ Wrapper for a custom editor control """ #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ factory = self.factory.factory if factory is not None: self.control = factory( *(( parent, self ) + self.factory.args ) ) if self.control is None: self.control = QtGui.QLabel( 'An error occurred creating a custom editor.\n' 'Please contact the developer.') self.control.setStyleSheet("background-color: red; color: white") self.set_tooltip() #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ pass traitsui-4.1.0/traitsui/qt4/tree_editor.py0000644000175100001440000022150511674463546021621 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2007, Riverbank Computing Limited # All rights reserved. # # This software is provided without warranty under the terms of the BSD license. # However, when used with the GPL version of PyQt the additional terms described in the PyQt GPL exception also apply # # Author: Riverbank Computing Limited #------------------------------------------------------------------------------ """ Defines the tree editor for the PyQt user interface toolkit. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import copy import collections import logging from pyface.qt import QtCore, QtGui from pyface.resource_manager import resource_manager from pyface.timer.api import do_later from traits.api import Any, Event from traits.trait_base import enumerate from traitsui.api import TreeNode, ObjectTreeNode, MultiTreeNode from traitsui.undo import ListUndoItem from traitsui.tree_node import ITreeNodeAdapterBridge from traitsui.menu import Menu, Action, Separator from clipboard import clipboard, PyMimeData from editor import Editor from helper import pixmap_cache logger = logging.getLogger(__name__) #------------------------------------------------------------------------------- # The core tree node menu actions: #------------------------------------------------------------------------------- from traitsui.ui_traits import SequenceTypes NewAction = 'NewAction' CopyAction = Action( name = 'Copy', action = 'editor._menu_copy_node', enabled_when = 'editor._is_copyable(object)' ) CutAction = Action( name = 'Cut', action = 'editor._menu_cut_node', enabled_when = 'editor._is_cutable(object)' ) PasteAction = Action( name = 'Paste', action = 'editor._menu_paste_node', enabled_when = 'editor._is_pasteable(object)' ) DeleteAction = Action( name = 'Delete', action = 'editor._menu_delete_node', enabled_when = 'editor._is_deletable(object)' ) RenameAction = Action( name = 'Rename', action = 'editor._menu_rename_node', enabled_when = 'editor._is_renameable(object)' ) #------------------------------------------------------------------------------- # 'SimpleEditor' class: #------------------------------------------------------------------------------- class SimpleEditor ( Editor ): """ Simple style of tree editor. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Is the tree editor is scrollable? This value overrides the default. scrollable = True # Allows an external agent to set the tree selection selection = Event # The currently selected object selected = Any # The event fired when a tree node is activated by double clicking or # pressing the Enter key on a node. activated = Event # The event fired when a tree node is clicked on: click = Event # The event fired when a tree node is double-clicked on: dclick = Event # The event fired when the application wants to veto an operation: veto = Event # The vent fired when the application wants to refresh the viewport. refresh = Event #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ factory = self.factory self._editor = None if factory.editable: # Check to see if the tree view is based on a shared trait editor: if factory.shared_editor: factory_editor = factory.editor # If this is the editor that defines the trait editor panel: if factory_editor is None: # Remember which editor has the trait editor in the factory: factory._editor = self # Create the trait editor panel: self.control = sa = QtGui.QScrollArea() sa.setFrameShape(QtGui.QFrame.NoFrame) sa.setWidgetResizable(True) self.control._node_ui = self.control._editor_nid = None # Check to see if there are any existing editors that are # waiting to be bound to the trait editor panel: editors = factory._shared_editors if editors is not None: for editor in factory._shared_editors: # If the editor is part of this UI: if editor.ui is self.ui: # Then bind it to the trait editor panel: editor._editor = self.control # Indicate all pending editors have been processed: factory._shared_editors = None # We only needed to build the trait editor panel, so exit: return # Check to see if the matching trait editor panel has been # created yet: editor = factory_editor._editor if (editor is None) or (editor.ui is not self.ui): # If not, add ourselves to the list of pending editors: shared_editors = factory_editor._shared_editors if shared_editors is None: factory_editor._shared_editors = shared_editors = [] shared_editors.append( self ) else: # Otherwise, bind our trait editor panel to the shared one: self._editor = editor.control # Finally, create only the tree control: self.control = self._tree = _TreeWidget(self) else: # If editable, create a tree control and an editor panel: self._tree = _TreeWidget(self) self._editor = sa = QtGui.QScrollArea() sa.setFrameShape(QtGui.QFrame.NoFrame) sa.setWidgetResizable(True) sa._node_ui = sa._editor_nid = None if factory.orientation == 'horizontal': orient = QtCore.Qt.Horizontal else: orient = QtCore.Qt.Vertical self.control = splitter = QtGui.QSplitter(orient) splitter.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) splitter.addWidget(self._tree) splitter.addWidget(sa) else: # Otherwise, just create the tree control: self.control = self._tree = _TreeWidget(self) # Set up the mapping between objects and tree id's: self._map = {} # Initialize the 'undo state' stack: self._undoable = [] # Synchronize external object traits with the editor: self.sync_value( factory.refresh, 'refresh' ) self.sync_value( factory.selected, 'selected' ) self.sync_value( factory.activated,'activated', 'to' ) self.sync_value( factory.click, 'click', 'to' ) self.sync_value( factory.dclick, 'dclick', 'to' ) self.sync_value( factory.veto, 'veto', 'from' ) #--------------------------------------------------------------------------- # Handles the 'selection' trait being changed: #--------------------------------------------------------------------------- def _selection_changed ( self, selection ): """ Handles the **selection** event. """ try: tree = self._tree if (not isinstance(selection, basestring) and isinstance(selection, collections.Iterable)): item_selection = QtGui.QItemSelection() for sel in selection: item = self._object_info(sel)[2] idx = tree.indexFromItem(item) item_selection.append(QtGui.QItemSelectionRange(idx)) tree.selectionModel().select(item_selection, QtGui.QItemSelectionModel.ClearAndSelect) else: tree.setCurrentItem(self._object_info(selection)[2]) except: from traitsui.api import raise_to_debug raise_to_debug() #--------------------------------------------------------------------------- # Handles the 'selected' trait being changed: #--------------------------------------------------------------------------- def _selected_changed ( self, selected ): """ Handles the **selected** trait being changed. """ if not self._no_update_selected: self._selection_changed( selected ) #--------------------------------------------------------------------------- # Handles the 'veto' event being fired: #--------------------------------------------------------------------------- def _veto_changed ( self ): """ Handles the 'veto' event being fired. """ self._veto = True def _refresh_changed ( self ): """ Update the viewport. """ self._tree.viewport().update() #--------------------------------------------------------------------------- # Disposes of the contents of an editor: #--------------------------------------------------------------------------- def dispose ( self ): """ Disposes of the contents of an editor. """ if self._tree is not None: # Stop the chatter (specifically about the changing selection). self._tree.blockSignals(True) self._delete_node(self._tree.invisibleRootItem()) self._tree = None super( SimpleEditor, self ).dispose() #--------------------------------------------------------------------------- # Expands from the specified node the specified number of sub-levels: #--------------------------------------------------------------------------- def expand_levels ( self, nid, levels, expand = True ): """ Expands from the specified node the specified number of sub-levels. """ if levels > 0: expanded, node, object = self._get_node_data( nid ) if self._has_children( node, object ): self._expand_node( nid ) if expand: nid.setExpanded(True) for cnid in self._nodes_for( nid ): self.expand_levels( cnid, levels - 1 ) #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ tree = self._tree if tree is None: return saved_state = {} object, node = self._node_for( self.old_value ) old_nid = self._get_object_nid( object, node.get_children_id(object)) if old_nid: self._delete_node(old_nid) object, node = self._node_for( self.old_value ) old_nid = self._get_object_nid( object, node.get_children_id(object) ) if old_nid: self._delete_node(old_nid) tree.clear() self._map = {} object, node = self._node_for( self.value ) if node is not None: if self.factory.hide_root: nid = tree.invisibleRootItem() else: nid = self._create_item(tree, node, object) self._map[ id( object ) ] = [ ( node.get_children_id(object), nid ) ] self._add_listeners( node, object ) self._set_node_data( nid, ( False, node, object) ) if self.factory.hide_root or self._has_children( node, object ): self._expand_node( nid ) if not self.factory.hide_root: nid.setExpanded(True) tree.setCurrentItem(nid) self.expand_levels( nid, self.factory.auto_open, False ) ncolumns = self._tree.columnCount() if ncolumns > 1: for i in range(ncolumns): self._tree.resizeColumnToContents(i) # FIXME: Clear the current editor (if any)... #--------------------------------------------------------------------------- # Returns the editor's control for indicating error status: #--------------------------------------------------------------------------- def get_error_control ( self ): """ Returns the editor's control for indicating error status. """ return self._tree def _get_brush(self, color) : if isinstance(color, SequenceTypes): q_color = QtGui.QColor(*color) else: q_color = QtGui.QColor(color) return QtGui.QBrush(q_color) def _set_column_labels(self, nid, column_labels): """ Set the column labels. """ for i, (header, label) in enumerate(map(None, self.factory.column_headers[1:], column_labels), 1): if header is not None and label is not None: nid.setText(i, label) #--------------------------------------------------------------------------- color = node.get_background(object) if color : nid.setBackground(0, self._get_brush(color)) color = node.get_foreground(object) if color : nid.setForeground(0, self._get_brush(color)) # Private Delegate class to do drawing in case of wrapped text labels #--------------------------------------------------------------------------- class ItemDelegate(QtGui.QStyledItemDelegate): """ A delegate class to draw wrapped text labels """ # FIXME: sizeHint() should return the size required by the label, # which is dependent on the width available, which is different for # each item due to the nested tree structure. However the option.rect # argument available to the sizeHint() is invalid (width=-1) so as a # hack sizeHintChanged is emitted in paint() and the size of drawn # text is returned, as paint() gets a valid option.rect argument. def __init__(self, *args, **kwargs): self.size_map = collections.defaultdict(lambda:QtCore.QSize(1,21)) QtGui.QStyledItemDelegate.__init__(self, *args, **kwargs) def sizeHint(self, option, index): """ returns area taken by the text. """ return self.size_map[self.editor._tree.itemFromIndex(index)] def paint(self, painter, option, index): """ Do the actual drawing of the text """ # For icon and highlights during selection etc super(self.__class__, self).paint(painter, option, index) item = self.editor._tree.itemFromIndex(index) expanded, node, object = self.editor._get_node_data(item) text = node.get_label(object) textrect = option.rect if self.editor.factory.show_icons: iconwidth = 24 # FIXME: get width from actual else: iconwidth = 0 rect = painter.drawText(option.rect.left() + iconwidth, option.rect.top(), option.rect.width() - iconwidth, option.rect.height(), QtCore.Qt.TextWordWrap, text) # Need to set the appropriate sizeHint of the item. if self.size_map[item] != rect.size(): self.size_map[item] = rect.size() do_later(self.sizeHintChanged.emit, index) #--------------------------------------------------------------------------- # Create a TreeWidgetItem as per word wrap policy and set icon,tooltip #--------------------------------------------------------------------------- def _create_item(self, nid, node, object, index=None): """ Create a new TreeWidgetItem as per word_wrap policy. Index is the index of the new node in the parent: None implies append the child to the end. """ if index is None: cnid = QtGui.QTreeWidgetItem(nid) else: cnid = QtGui.QTreeWidgetItem() nid.insertChild(index, cnid) if self.factory.word_wrap: item = self.ItemDelegate() item.editor = self self._tree.setItemDelegate(item) else: cnid.setText(0, node.get_label(object)) cnid.setIcon(0, self._get_icon(node, object)) cnid.setToolTip(0, node.get_tooltip(object)) return cnid def _set_label(self, nid, text, col=0): """ Set the label of the specified item """ if not self.factory.word_wrap or col!=0: expanded, node, object = self._get_node_data(nid) nid.setText(col, node.get_label(object)) #--------------------------------------------------------------------------- # Appends a new node to the specified node: #--------------------------------------------------------------------------- def _append_node ( self, nid, node, object ): """ Appends a new node to the specified node. """ return self._insert_node( nid, None, node, object ) #--------------------------------------------------------------------------- # Inserts a new node to the specified node: #--------------------------------------------------------------------------- def _insert_node ( self, nid, index, node, object ): """ Inserts a new node before a specified index into the children of the specified node. """ cnid = self._create_item(nid, node, object, index) has_children = self._has_children(node, object) self._set_node_data( cnid, ( False, node, object ) ) self._map.setdefault( id( object ), [] ).append( ( node.get_children_id(object), cnid ) ) self._add_listeners( node, object ) # Automatically expand the new node (if requested): if has_children: if node.can_auto_open( object ): cnid.setExpanded(True) else: # Qt only draws the control that expands the tree if there is a # child. As the tree is being populated lazily we create a # dummy that will be removed when the node is expanded for the # first time. cnid._dummy = QtGui.QTreeWidgetItem(cnid) # Return the newly created node: return cnid #--------------------------------------------------------------------------- # Deletes a specified tree node and all its children: #--------------------------------------------------------------------------- def _delete_node ( self, nid ): """ Deletes a specified tree node and all its children. """ for cnid in self._nodes_for( nid ): self._delete_node( cnid ) if nid is self._tree.invisibleRootItem(): return # See if it is a dummy. pnid = nid.parent() if pnid is not None and getattr(pnid, '_dummy', None) is nid: pnid.removeChild(nid) del pnid._dummy return try: expanded, node, object = self._get_node_data(nid) except AttributeError: # The node has already been deleted. pass else: id_object = id(object) object_info = self._map[id_object] for i, info in enumerate(object_info): # QTreeWidgetItem does not have an equal operator, so use id() if id(nid) == id(info[1]): del object_info[i] break if len( object_info ) == 0: self._remove_listeners( node, object ) del self._map[ id_object ] if pnid is None: self._tree.takeTopLevelItem(self._tree.indexOfTopLevelItem(nid)) else: pnid.removeChild(nid) # If the deleted node had an active editor panel showing, remove it: if (self._editor is not None) and (nid == self._editor._editor_nid): self._clear_editor() #--------------------------------------------------------------------------- # Expands the contents of a specified node (if required): #--------------------------------------------------------------------------- def _expand_node ( self, nid ): """ Expands the contents of a specified node (if required). """ expanded, node, object = self._get_node_data( nid ) # Lazily populate the item's children: if not expanded: # Remove any dummy node. dummy = getattr(nid, '_dummy', None) if dummy is not None: nid.removeChild(dummy) del nid._dummy for child in node.get_children( object ): child, child_node = self._node_for( child ) if child_node is not None: self._append_node( nid, child_node, child ) # Indicate the item is now populated: self._set_node_data( nid, ( True, node, object) ) #--------------------------------------------------------------------------- # Returns each of the child nodes of a specified node id: #--------------------------------------------------------------------------- def _nodes_for ( self, nid ): """ Returns all child node ids of a specified node id. """ return [nid.child(i) for i in range(nid.childCount())] #--------------------------------------------------------------------------- # Return the index of a specified node id within its parent: #--------------------------------------------------------------------------- def _node_index ( self, nid ): pnid = nid.parent() if pnid is None: return ( None, None, None ) for i in range(pnid.childCount()): if pnid.child(i) is nid: _, pnode, pobject = self._get_node_data( pnid ) return ( pnode, pobject, i ) #--------------------------------------------------------------------------- # Returns whether a specified object has any children: #--------------------------------------------------------------------------- def _has_children ( self, node, object ): """ Returns whether a specified object has any children. """ return (node.allows_children( object ) and node.has_children( object )) #--------------------------------------------------------------------------- # Returns the icon index for the specified object: #--------------------------------------------------------------------------- STD_ICON_MAP = { '': QtGui.QStyle.SP_FileIcon, '': QtGui.QStyle.SP_DirClosedIcon, '': QtGui.QStyle.SP_DirOpenIcon } def _get_icon ( self, node, object, is_expanded = False ): """ Returns the index of the specified object icon. """ if not self.factory.show_icons: return QtGui.QIcon() icon_name = node.get_icon(object, is_expanded) if isinstance(icon_name, basestring): icon = self.STD_ICON_MAP.get(icon_name) if icon is not None: return self._tree.style().standardIcon(icon) path = node.get_icon_path( object ) if isinstance( path, basestring ): path = [ path, node ] else: path.append( node ) reference = resource_manager.locate_image( icon_name, path ) if reference is None: return QtGui.QIcon() file_name = reference.filename else: # Assume it is an ImageResource, and get its file name directly: file_name = icon_name.absolute_path return QtGui.QIcon(pixmap_cache(file_name)) #--------------------------------------------------------------------------- # Adds the event listeners for a specified object: #--------------------------------------------------------------------------- def _add_listeners ( self, node, object ): """ Adds the event listeners for a specified object. """ if node.allows_children( object ): node.when_children_replaced( object, self._children_replaced, False) node.when_children_changed( object, self._children_updated, False) node.when_label_changed( object, self._label_updated, False ) node.when_column_labels_change(object, self._column_labels_updated, False) #--------------------------------------------------------------------------- # Removes any event listeners from a specified object: #--------------------------------------------------------------------------- def _remove_listeners ( self, node, object ): """ Removes any event listeners from a specified object. """ if node.allows_children( object ): node.when_children_replaced( object, self._children_replaced, True ) node.when_children_changed( object, self._children_updated, True ) node.when_label_changed( object, self._label_updated, True ) node.when_column_labels_change(object, self._column_labels_updated, False) #--------------------------------------------------------------------------- # Returns the tree node data for a specified object in the form # ( expanded, node, nid ): #--------------------------------------------------------------------------- def _object_info ( self, object, name = '' ): """ Returns the tree node data for a specified object in the form ( expanded, node, nid ). """ info = self._map[ id( object ) ] for name2, nid in info: if name == name2: break else: nid = info[0][1] expanded, node, ignore = self._get_node_data( nid ) return ( expanded, node, nid ) def _object_info_for ( self, object, name = '' ): """ Returns the tree node data for a specified object as a list of the form: [ ( expanded, node, nid ), ... ]. """ result = [] for name2, nid in self._map[ id( object ) ]: if name == name2: expanded, node, ignore = self._get_node_data( nid ) result.append( ( expanded, node, nid ) ) return result #--------------------------------------------------------------------------- # Returns the TreeNode associated with a specified object: #--------------------------------------------------------------------------- def _node_for ( self, object ): """ Returns the TreeNode associated with a specified object. """ if ((type( object ) is tuple) and (len( object ) == 2) and isinstance( object[1], TreeNode )): return object # Select all nodes which understand this object: factory = self.factory nodes = [ node for node in factory.nodes if node.is_node_for( object ) ] # If only one found, we're done, return it: if len( nodes ) == 1: return ( object, nodes[0] ) # If none found, give up: if len( nodes ) == 0: return ( object, ITreeNodeAdapterBridge(adapter=object) ) # Use all selected nodes that have the same 'node_for' list as the # first selected node: base = nodes[0].node_for nodes = [ node for node in nodes if base == node.node_for ] # If only one left, then return that node: if len( nodes ) == 1: return ( object, nodes[0] ) # Otherwise, return a MultiTreeNode based on all selected nodes... # Use the node with no specified children as the root node. If not # found, just use the first selected node as the 'root node': root_node = None for i, node in enumerate( nodes ): if node.children == '': root_node = node del nodes[i] break else: root_node = nodes[0] # If we have a matching MultiTreeNode already cached, return it: key = ( root_node, ) + tuple( nodes ) if key in factory.multi_nodes: return ( object, factory.multi_nodes[ key ] ) # Otherwise create one, cache it, and return it: factory.multi_nodes[ key ] = multi_node = MultiTreeNode( root_node = root_node, nodes = nodes ) return ( object, multi_node ) #--------------------------------------------------------------------------- # Returns the TreeNode associated with a specified class: #--------------------------------------------------------------------------- def _node_for_class ( self, klass ): """ Returns the TreeNode associated with a specified class. """ for node in self.factory.nodes: if issubclass( klass, tuple( node.node_for ) ): return node return None #--------------------------------------------------------------------------- # Returns the node and class associated with a specified class name: #--------------------------------------------------------------------------- def _node_for_class_name ( self, class_name ): """ Returns the node and class associated with a specified class name. """ for node in self.factory.nodes: for klass in node.node_for: if class_name == klass.__name__: return ( node, klass ) return ( None, None ) #--------------------------------------------------------------------------- # Updates the icon for a specified node: #--------------------------------------------------------------------------- def _update_icon(self, nid): """ Updates the icon for a specified node. """ expanded, node, object = self._get_node_data(nid) nid.setIcon(0, self._get_icon(node, object, expanded)) #--------------------------------------------------------------------------- # Begins an 'undoable' transaction: #--------------------------------------------------------------------------- def _begin_undo ( self ): """ Begins an "undoable" transaction. """ ui = self.ui self._undoable.append( ui._undoable ) if (ui._undoable == -1) and (ui.history is not None): ui._undoable = ui.history.now #--------------------------------------------------------------------------- # Ends an 'undoable' transaction: #--------------------------------------------------------------------------- def _end_undo ( self ): if self._undoable.pop() == -1: self.ui._undoable = -1 #--------------------------------------------------------------------------- # Gets an 'undo' item for a change made to a node's children: #--------------------------------------------------------------------------- def _get_undo_item ( self, object, name, event ): return ListUndoItem( object = object, name = name, index = event.index, added = event.added, removed = event.removed ) #--------------------------------------------------------------------------- # Performs an undoable 'append' operation: #--------------------------------------------------------------------------- def _undoable_append ( self, node, object, data, make_copy = True ): """ Performs an undoable append operation. """ try: self._begin_undo() if make_copy: data = copy.deepcopy( data ) node.append_child( object, data ) finally: self._end_undo() #--------------------------------------------------------------------------- # Performs an undoable 'insert' operation: #--------------------------------------------------------------------------- def _undoable_insert ( self, node, object, index, data, make_copy = True ): """ Performs an undoable insert operation. """ try: self._begin_undo() if make_copy: data = copy.deepcopy( data ) node.insert_child( object, index, data ) finally: self._end_undo() #--------------------------------------------------------------------------- # Performs an undoable 'delete' operation: #--------------------------------------------------------------------------- def _undoable_delete ( self, node, object, index ): """ Performs an undoable delete operation. """ try: self._begin_undo() node.delete_child( object, index ) finally: self._end_undo() #--------------------------------------------------------------------------- # Gets the id associated with a specified object (if any): #--------------------------------------------------------------------------- def _get_object_nid ( self, object, name = '' ): """ Gets the ID associated with a specified object (if any). """ info = self._map.get( id( object ) ) if info is None: return None for name2, nid in info: if name == name2: return nid else: return info[0][1] #--------------------------------------------------------------------------- # Clears the current editor pane (if any): #--------------------------------------------------------------------------- def _clear_editor ( self ): """ Clears the current editor pane (if any). """ editor = self._editor if editor._node_ui is not None: editor.setWidget(None) editor._node_ui.dispose() editor._node_ui = editor._editor_nid = None #--------------------------------------------------------------------------- # Gets/Sets the node specific data: #--------------------------------------------------------------------------- @staticmethod def _get_node_data(nid): """ Gets the node specific data. """ return nid._py_data @staticmethod def _set_node_data(nid, data): """ Sets the node specific data. """ nid._py_data = data #----- User callable methods: -------------------------------------------------- #--------------------------------------------------------------------------- # Gets the object associated with a specified node: #--------------------------------------------------------------------------- def get_object ( self, nid ): """ Gets the object associated with a specified node. """ return self._get_node_data( nid )[2] #--------------------------------------------------------------------------- # Returns the object which is the immmediate parent of a specified object # in the tree: #--------------------------------------------------------------------------- def get_parent ( self, object, name = '' ): """ Returns the object that is the immmediate parent of a specified object in the tree. """ nid = self._get_object_nid( object, name ) if nid is not None: pnid = nid.parent() if pnid is not self._tree.invisibleRootItem(): return self.get_object( pnid ) return None #--------------------------------------------------------------------------- # Returns the node associated with a specified object: #--------------------------------------------------------------------------- def get_node ( self, object, name = '' ): """ Returns the node associated with a specified object. """ nid = self._get_object_nid( object, name ) if nid is not None: return self._get_node_data( nid )[1] return None #----- Tree event handlers: ---------------------------------------------------- #--------------------------------------------------------------------------- # Handles a tree node being expanded: #--------------------------------------------------------------------------- def _on_item_expanded(self, nid): """ Handles a tree node being expanded. """ expanded, node, object = self._get_node_data(nid) # If 'auto_close' requested for this node type, close all of the node's # siblings: if node.can_auto_close(object): parent = nid.parent() if parent is not None: for snid in self._nodes_for(parent): if snid is not nid: snid.setExpanded(False) # Expand the node (i.e. populate its children if they are not there # yet): self._expand_node(nid) self._update_icon(nid) #--------------------------------------------------------------------------- # Handles a tree node being collapsed: #--------------------------------------------------------------------------- def _on_item_collapsed(self, nid): """ Handles a tree node being collapsed. """ self._update_icon(nid) #--------------------------------------------------------------------------- # Handles a tree item click: #--------------------------------------------------------------------------- def _on_item_clicked(self, nid, col): """ Handles a tree item being clicked. """ _, node, object = self._get_node_data(nid) if node.click(object) is True and self.factory.on_click is not None: self.ui.evaluate(self.factory.on_click, object) # Fire the 'click' event with the object as its value: self.click = object #--------------------------------------------------------------------------- # Handles a tree item double click: #--------------------------------------------------------------------------- def _on_item_dclicked(self, nid, col): """ Handles a tree item being double-clicked. """ _, node, object = self._get_node_data(nid) if node.dclick(object) is True: if self.factory.on_dclick is not None: self.ui.evaluate(self.factory.on_dclick, object) self._veto = True else: self._veto = True # Fire the 'dclick' event with the clicked on object as value: self.dclick = object #--------------------------------------------------------------------------- # Handles a tree item being activated: #--------------------------------------------------------------------------- def _on_item_activated(self, nid, col): """ Handles a tree item being activated. """ _, node, object = self._get_node_data(nid) # Fire the 'activated' event with the clicked on object as value: self.activated = object #--------------------------------------------------------------------------- # Handles a tree node being selected: #--------------------------------------------------------------------------- def _on_tree_sel_changed(self): """ Handles a tree node being selected. """ # Get the new selection: nids = self._tree.selectedItems() selected = [] if len(nids) > 0: for nid in nids: # If there is a real selection, get the associated object: expanded, node, sel_object = self._get_node_data(nid) selected.append(sel_object) # Try to inform the node specific handler of the selection, if # there are multiple selections, we only care about the first # (or maybe the last makes more sense?) # QTreeWidgetItem does not have an equal operator, so use id() if id(nid) == id(nids[0]): object = sel_object not_handled = node.select(sel_object) else: nid = None object = None not_handled = True # Set the value of the new selection: if self.factory.selection_mode == 'single': self._no_update_selected = True self.selected = object self._no_update_selected = False else: self._no_update_selected = True self.selected = selected self._no_update_selected = False # If no one has been notified of the selection yet, inform the editor's # select handler (if any) of the new selection: if not_handled is True: self.ui.evaluate(self.factory.on_select, object) # Check to see if there is an associated node editor pane: editor = self._editor if editor is not None: # If we already had a node editor, destroy it: editor.setUpdatesEnabled(False) self._clear_editor() # If there is a selected object, create a new editor for it: if object is not None: # Try to chain the undo history to the main undo history: view = node.get_view( object ) if view is None or isinstance(view, str) : view = object.trait_view(view) if (self.ui.history is not None) or (view.kind == 'subpanel'): ui = object.edit_traits( parent = editor, view = view, kind = 'subpanel' ) else: # Otherwise, just set up our own new one: ui = object.edit_traits( parent = editor, view = view, kind = 'panel' ) # Make our UI the parent of the new UI: ui.parent = self.ui # Remember the new editor's UI and node info: editor._node_ui = ui editor._editor_nid = nid # Finish setting up the editor: ui.control.layout().setContentsMargins(0, 0, 0, 0) editor.setWidget(ui.control) # Allow the editor view to show any changes that have occurred: editor.setUpdatesEnabled(True) #--------------------------------------------------------------------------- # Handles the user right clicking on a tree node: #--------------------------------------------------------------------------- def _on_context_menu(self, pos): """ Handles the user requesting a context menuright clicking on a tree node. """ nid = self._tree.itemAt(pos) if nid is None: return _, node, object = self._get_node_data(nid) self._data = (node, object, nid) self._context = {'object': object, 'editor': self, 'node': node, 'info': self.ui.info, 'handler': self.ui.handler} # Try to get the parent node of the node clicked on: pnid = nid.parent() if pnid is None or pnid is self._tree.invisibleRootItem(): parent_node = parent_object = None else: _, parent_node, parent_object = self._get_node_data(pnid) self._menu_node = node self._menu_parent_node = parent_node self._menu_parent_object = parent_object menu = node.get_menu(object) if menu is None: # Use the standard, default menu: menu = self._standard_menu(node, object) elif isinstance(menu, Menu): # Use the menu specified by the node: group = menu.find_group(NewAction) if group is not None: # Only set it the first time: group.id = '' actions = self._new_actions( node, object ) if len( actions ) > 0: group.insert( 0, Menu( name = 'New', *actions ) ) else: # All other values mean no menu should be displayed: menu = None # Only display the menu if a valid menu is defined: if menu is not None: qmenu = menu.create_menu( self._tree, self ) qmenu.exec_(self._tree.mapToGlobal(pos)) # Reset all menu related cached values: self._data = self._context = self._menu_node = \ self._menu_parent_node = self._menu_parent_object = None #--------------------------------------------------------------------------- # Returns the standard contextual pop-up menu: #--------------------------------------------------------------------------- def _standard_menu ( self, node, object ): """ Returns the standard contextual pop-up menu. """ actions = [ CutAction, CopyAction, PasteAction, Separator(), DeleteAction, Separator(), RenameAction ] # See if the 'New' menu section should be added: items = self._new_actions( node, object ) if len( items ) > 0: actions[0:0] = [ Menu( name = 'New', *items ), Separator() ] return Menu( *actions ) #--------------------------------------------------------------------------- # Returns a list of Actions that will create 'new' objects: #--------------------------------------------------------------------------- def _new_actions ( self, node, object ): """ Returns a list of Actions that will create new objects. """ object = self._data[1] items = [] add = node.get_add( object ) if len( add ) > 0: for klass in add: prompt = False if isinstance( klass, tuple ): klass, prompt = klass add_node = self._node_for_class( klass ) if add_node is not None: class_name = klass.__name__ name = add_node.get_name( object ) if name == '': name = class_name items.append( Action( name = name, action = "editor._menu_new_node('%s',%s)" % ( class_name, prompt ) ) ) return items #--------------------------------------------------------------------------- # Menu action helper methods: #--------------------------------------------------------------------------- def _is_copyable ( self, object ): parent = self._menu_parent_node if isinstance( parent, ObjectTreeNode ): return parent.can_copy( self._menu_parent_object ) return ((parent is not None) and parent.can_copy( object )) def _is_cutable ( self, object ): parent = self._menu_parent_node if isinstance( parent, ObjectTreeNode ): can_cut = (parent.can_copy( self._menu_parent_object ) and parent.can_delete( self._menu_parent_object )) else: can_cut = ((parent is not None) and parent.can_copy( object ) and parent.can_delete( object )) return (can_cut and self._menu_node.can_delete_me( object )) def _is_pasteable ( self, object ): return self._menu_node.can_add(object, clipboard.instance_type) def _is_deletable ( self, object ): parent = self._menu_parent_node if isinstance( parent, ObjectTreeNode ): can_delete = parent.can_delete( self._menu_parent_object ) else: can_delete = ((parent is not None) and parent.can_delete( object )) return (can_delete and self._menu_node.can_delete_me( object )) def _is_renameable ( self, object ): parent = self._menu_parent_node if isinstance( parent, ObjectTreeNode ): can_rename = parent.can_rename( self._menu_parent_object ) else: can_rename = ((parent is not None) and parent.can_rename( object )) can_rename = (can_rename and self._menu_node.can_rename_me( object )) # Set the widget item's editable flag appropriately. nid = self._get_object_nid(object) flags = nid.flags() if can_rename: flags |= QtCore.Qt.ItemIsEditable else: flags &= ~QtCore.Qt.ItemIsEditable nid.setFlags(flags) return can_rename def _is_droppable ( self, node, object, add_object, for_insert ): """ Returns whether a given object is droppable on the node. """ if for_insert and (not node.can_insert( object )): return False return node.can_add( object, add_object ) def _drop_object ( self, node, object, dropped_object, make_copy = True ): """ Returns a droppable version of a specified object. """ new_object = node.drop_object( object, dropped_object ) if (new_object is not dropped_object) or (not make_copy): return new_object return copy.deepcopy( new_object ) #----- pyface.action 'controller' interface implementation: -------------------- #--------------------------------------------------------------------------- # Adds a menu item to the menu being constructed: #--------------------------------------------------------------------------- def add_to_menu ( self, menu_item ): """ Adds a menu item to the menu bar being constructed. """ action = menu_item.item.action self.eval_when( action.enabled_when, menu_item, 'enabled' ) self.eval_when( action.checked_when, menu_item, 'checked' ) #--------------------------------------------------------------------------- # Adds a tool bar item to the tool bar being constructed: #--------------------------------------------------------------------------- def add_to_toolbar ( self, toolbar_item ): """ Adds a toolbar item to the toolbar being constructed. """ self.add_to_menu( toolbar_item ) #--------------------------------------------------------------------------- # Returns whether the menu action should be defined in the user interface: #--------------------------------------------------------------------------- def can_add_to_menu ( self, action ): """ Returns whether the action should be defined in the user interface. """ if action.defined_when != '': if not eval( action.defined_when, globals(), self._context ): return False if action.visible_when != '': if not eval( action.visible_when, globals(), self._context ): return False return True #--------------------------------------------------------------------------- # Returns whether the toolbar action should be defined in the user # interface: #--------------------------------------------------------------------------- def can_add_to_toolbar ( self, action ): """ Returns whether the toolbar action should be defined in the user interface. """ return self.can_add_to_menu( action ) #--------------------------------------------------------------------------- # Performs the action described by a specified Action object: #--------------------------------------------------------------------------- def perform ( self, action, action_event = None ): """ Performs the action described by a specified Action object. """ self.ui.do_undoable( self._perform, action ) def _perform ( self, action ): node, object, nid = self._data method_name = action.action info = self.ui.info handler = self.ui.handler if method_name.find( '.' ) >= 0: if method_name.find( '(' ) < 0: method_name += '()' try: eval( method_name, globals(), { 'object': object, 'editor': self, 'node': node, 'info': info, 'handler': handler } ) except: from traitsui.api import raise_to_debug raise_to_debug() return method = getattr( handler, method_name, None ) if method is not None: method( info, object ) return if action.on_perform is not None: action.on_perform( object ) #----- Menu support methods: --------------------------------------------------- #--------------------------------------------------------------------------- # Evaluates a condition within a defined context and sets a specified # object trait based on the (assumed) boolean result: #--------------------------------------------------------------------------- def eval_when ( self, condition, object, trait ): """ Evaluates a condition within a defined context, and sets a specified object trait based on the result, which is assumed to be a Boolean. """ if condition != '': value = True try: if not eval( condition, globals(), self._context ): value = False except Exception as e: logger.warning("Exception (%s) raised when evaluating the " "condition %s. Returning True." % (e,condition)) setattr( object, trait, value ) #----- Menu event handlers: ---------------------------------------------------- #--------------------------------------------------------------------------- # Copies the current tree node object to the paste buffer: #--------------------------------------------------------------------------- def _menu_copy_node ( self ): """ Copies the current tree node object to the paste buffer. """ clipboard.instance = self._data[1] self._data = None #--------------------------------------------------------------------------- # Cuts the current tree node object into the paste buffer: #--------------------------------------------------------------------------- def _menu_cut_node ( self ): """ Cuts the current tree node object into the paste buffer. """ node, object, nid = self._data clipboard.instance = object self._data = None self._undoable_delete(*self._node_index(nid)) #--------------------------------------------------------------------------- # Pastes the current contents of the paste buffer into the current node: #--------------------------------------------------------------------------- def _menu_paste_node ( self ): """ Pastes the current contents of the paste buffer into the current node. """ node, object, nid = self._data self._data = None self._undoable_append(node, object, clipboard.instance, False) #--------------------------------------------------------------------------- # Deletes the current node from the tree: #--------------------------------------------------------------------------- def _menu_delete_node ( self ): """ Deletes the current node from the tree. """ node, object, nid = self._data self._data = None rc = node.confirm_delete( object ) if rc is not False: if rc is not True: if self.ui.history is None: # If no undo history, ask user to confirm the delete: butn = QtGui.QMessageBox.question( self._tree, "Confirm Deletion", "Are you sure you want to delete %s?" % node.get_label( object ), QtGui.QMessageBox.Yes|QtGui.QMessageBox.No) if butn != QtGui.QMessageBox.Yes: return self._undoable_delete( *self._node_index( nid ) ) #--------------------------------------------------------------------------- # Renames the current tree node: #--------------------------------------------------------------------------- def _menu_rename_node ( self ): """ Rename the current node. """ _, _, nid = self._data self._data = None self._tree.editItem(nid) def _on_nid_changed(self, nid, col): """ Handle changes to a widget item. """ # The node data may not have been set up for the nid yet. Ignore it if # it hasn't. try: _, node, object = self._get_node_data(nid) except: return new_label = unicode(nid.text(col)) old_label = node.get_label(object) if new_label != old_label: if new_label != '': node.set_label(object, new_label) else: self._set_label(nid, old_label, col) #--------------------------------------------------------------------------- # Adds a new object to the current node: #--------------------------------------------------------------------------- def _menu_new_node ( self, class_name, prompt = False ): """ Adds a new object to the current node. """ node, object, nid = self._data self._data = None new_node, new_class = self._node_for_class_name( class_name ) new_object = new_class() if (not prompt) or new_object.edit_traits( parent = self.control, kind = 'livemodal' ).result: self._undoable_append( node, object, new_object, False ) # Automatically select the new object if editing is being performed: if self.factory.editable: self._tree.setCurrentItem(nid.child(nid.childCount() - 1)) #----- Model event handlers: --------------------------------------------------- #--------------------------------------------------------------------------- # Handles the children of a node being completely replaced: #--------------------------------------------------------------------------- def _children_replaced ( self, object, name = '', new = None ): """ Handles the children of a node being completely replaced. """ tree = self._tree for expanded, node, nid in self._object_info_for( object, name ): children = node.get_children( object ) # Only add/remove the changes if the node has already been expanded: if expanded: # Delete all current child nodes: for cnid in self._nodes_for( nid ): self._delete_node( cnid ) # Add all of the children back in as new nodes: for child in children: child, child_node = self._node_for( child ) if child_node is not None: self._append_node( nid, child_node, child ) # Try to expand the node (if requested): if node.can_auto_open( object ): nid.setExpanded(True) #--------------------------------------------------------------------------- # Handles the children of a node being changed: #--------------------------------------------------------------------------- def _children_updated ( self, object, name, event ): """ Handles the children of a node being changed. """ # Log the change that was made made (removing '_items' from the end of # the name): name = name[:-6] self.log_change( self._get_undo_item, object, name, event ) # Get information about the node that was changed: start = event.index n = len( event.added ) end = start + len( event.removed ) tree = self._tree for expanded, node, nid in self._object_info_for( object, name ): children = node.get_children( object ) # If the new children aren't all at the end, remove/add them all: #if (n > 0) and ((start + n) != len( children )): # self._children_replaced( object, name, event ) # return # Only add/remove the changes if the node has already been expanded: if expanded: # Remove all of the children that were deleted: for cnid in self._nodes_for( nid )[ start: end ]: self._delete_node( cnid ) remaining = n - len( event.removed ) child_index = 0 # Add all of the children that were added: for child in event.added: child, child_node = self._node_for( child ) if child_node is not None: insert_index = (start + child_index) if \ (start <= remaining) else None self._insert_node( nid, insert_index, child_node, child ) child_index += 1 # Try to expand the node (if requested): if node.can_auto_open( object ): nid.setExpanded(True) #--------------------------------------------------------------------------- # Handles the label of an object being changed: #--------------------------------------------------------------------------- def _label_updated ( self, object, name, label ): """ Handles the label of an object being changed. """ # Prevent the itemChanged() signal from being emitted. blk = self._tree.blockSignals(True) nids = {} for name2, nid in self._map[ id( object ) ]: if nid not in nids: nids[ nid ] = None node = self._get_node_data( nid )[1] self._set_label(nid, node.get_label(object), 0) self._update_icon(nid) self._tree.blockSignals(blk) def _column_labels_updated(self, object, name, new): """ Handles the column labels of an object being changed. """ # Prevent the itemChanged() signal from being emitted. blk = self._tree.blockSignals(True) nids = {} for name2, nid in self._map[ id( object ) ]: if nid not in nids: nids[ nid ] = None node = self._get_node_data( nid )[1] # Just do all of them at once. The number of columns should be # small. self._set_column_labels(nid, node.get_column_labels(object)) self._tree.blockSignals(blk) #-- UI preference save/restore interface --------------------------------------- #--------------------------------------------------------------------------- # Restores any saved user preference information associated with the # editor: #--------------------------------------------------------------------------- def restore_prefs ( self, prefs ): """ Restores any saved user preference information associated with the editor. """ if isinstance(self.control, QtGui.QSplitter): if isinstance(prefs, dict): structure = prefs.get('structure') else: structure = prefs self.control.restoreState(structure) header = self._tree.header() self.setExpandsOnDoubleClick(editor.factory.expands_on_dclick) if header is not None and 'column_state' in prefs: header.restoreState(prefs['column_state']) #--------------------------------------------------------------------------- # Returns any user preference information associated with the editor: #--------------------------------------------------------------------------- def save_prefs ( self ): """ Returns any user preference information associated with the editor. """ prefs = {} if isinstance(self.control, QtGui.QSplitter): prefs['structure'] = str(self.control.saveState()) header = self._tree.header() if header is not None: prefs['column_state'] = str(header.saveState()) return prefs #-- End UI preference save/restore interface ----------------------------------- #------------------------------------------------------------------------------- # '_TreeWidget' class: #------------------------------------------------------------------------------- class _TreeWidget(QtGui.QTreeWidget): """ The _TreeWidget class is a specialised QTreeWidget that reimplements the drag'n'drop support so that it hooks into the provided Traits support. """ def __init__(self, editor, parent=None): """ Initialise the tree widget. """ QtGui.QTreeWidget.__init__(self, parent) self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.setDragEnabled(True) self.setAcceptDrops(True) # Set up headers if necessary. column_count = len(editor.factory.column_headers) if column_count > 0: self.setHeaderHidden(False) self.setColumnCount(column_count) self.setHeaderLabels(editor.factory.column_headers) else: self.setHeaderHidden(True) self.setAlternatingRowColors(editor.factory.alternating_row_colors) padding = editor.factory.vertical_padding if padding > 0: self.setStyleSheet(""" QTreeView::item { padding-top: %spx; padding-bottom: %spx; } """ % (padding, padding)) if editor.factory.selection_mode == 'extended': self.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection) self.itemExpanded.connect(editor._on_item_expanded) self.itemCollapsed.connect(editor._on_item_collapsed) self.itemClicked.connect(editor._on_item_clicked) self.itemDoubleClicked.connect(editor._on_item_dclicked) self.itemActivated.connect(editor._on_item_activated) self.itemSelectionChanged.connect(editor._on_tree_sel_changed) self.customContextMenuRequested.connect(editor._on_context_menu) self.itemChanged.connect(editor._on_nid_changed) self._editor = editor self._dragging = None def resizeEvent(self, event): """ Overridden to emit sizeHintChanged() of items for word wrapping """ if self._editor.factory.word_wrap: for i in range(self.topLevelItemCount()): mi = self.indexFromItem(self.topLevelItem(i)) id = self.itemDelegate(mi) id.sizeHintChanged.emit(mi) super(self.__class__, self).resizeEvent(event) def startDrag(self, actions): """ Reimplemented to start the drag of a tree widget item. """ nid = self.currentItem() if nid is None: return self._dragging = nid _, node, object = self._editor._get_node_data(nid) # Convert the item being dragged to MIME data. md = PyMimeData(node.get_drag_object(object)) # Render the item being dragged as a pixmap. nid_rect = self.visualItemRect(nid) rect = nid_rect.intersected(self.viewport().rect()) pm = QtGui.QPixmap(rect.size()) pm.fill(self.palette().base().color()) painter = QtGui.QPainter(pm) option = self.viewOptions() option.state |= QtGui.QStyle.State_Selected option.rect = QtCore.QRect(nid_rect.topLeft() - rect.topLeft(), nid_rect.size()) self.itemDelegate().paint(painter, option, self.indexFromItem(nid)) painter.end() # Calculate the hotspot so that the pixmap appears on top of the # original item. rect.adjust(self.horizontalOffset(), self.verticalOffset(), 0, 0) hspos = self.mapFromGlobal(QtGui.QCursor.pos()) - rect.topLeft() # Start the drag. drag = QtGui.QDrag(self) drag.setMimeData(md) drag.setPixmap(pm) drag.setHotSpot(hspos) drag.exec_(actions) def dragEnterEvent(self, e): """ Reimplemented to see if the current drag can be handled by the tree. """ # Assume the drag is invalid. e.ignore() # Check what is being dragged. md = PyMimeData.coerce(e.mimeData()) if md is None: return # We might be able to handle it (but it depends on what the final # target is). e.acceptProposedAction() def dragMoveEvent(self, e): """ Reimplemented to see if the current drag can be handled by the particular tree widget item underneath the cursor. """ # Assume the drag is invalid. e.ignore() # Get the tree widget item under the cursor. nid = self.itemAt(e.pos()) if nid is None: return # Check that the target is not the source of a child of the source. if self._dragging is not None: pnid = nid while pnid is not None: if pnid is self._dragging: return pnid = pnid.parent() # A copy action is interpreted as moving the source to a particular # place within the target's parent. A move action is interpreted as # moving the source to be a child of the target. if e.proposedAction() == QtCore.Qt.CopyAction: node, object, _ = self._editor._node_index(nid) insert = True else: _, node, object = self._editor._get_node_data(nid) insert = False # See if the model will accept a drop. data = PyMimeData.coerce(e.mimeData()).instance() if not self._editor._is_droppable(node, object, data, insert): return e.acceptProposedAction() def dropEvent(self, e): """ Reimplemented to update the model and tree. """ # Assume the drop is invalid. e.ignore() dragging = self._dragging self._dragging = None # Get the tree widget item under the cursor. nid = self.itemAt(e.pos()) if nid is None: return # Get the data being dropped. data = PyMimeData.coerce(e.mimeData()).instance() editor = self._editor _, node, object = editor._get_node_data(nid) if e.proposedAction() == QtCore.Qt.MoveAction: if not self._editor._is_droppable(node, object, data, False ): return if dragging is not None: data = self._editor._drop_object( node, object, data, False ) if data is not None: try: editor._begin_undo() editor._undoable_delete( *editor._node_index( dragging ) ) editor._undoable_append( node, object, data, False ) finally: editor._end_undo() else: data = self._editor._drop_object( node, object, data, True ) if data is not None: editor._undoable_append( node, object, data, False ) else: to_node, to_object, to_index = editor._node_index( nid ) if to_node is not None: if dragging is not None: data = self._editor._drop_object( node, to_object, data, False ) if data is not None: from_node, from_object, from_index = \ editor._node_index( dragging ) if ((to_object is from_object) and (to_index > from_index)): to_index -= 1 try: editor._begin_undo() editor._undoable_delete( from_node, from_object, from_index ) editor._undoable_insert( to_node, to_object, to_index, data, False ) finally: editor._end_undo() else: data = self._editor._drop_object( to_node, to_object, data, True ) if data is not None: editor._undoable_insert( to_node, to_object, to_index, data, False ) e.acceptProposedAction() traitsui-4.1.0/traitsui/qt4/code_editor.py0000644000175100001440000003316611674463546021600 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2007, Riverbank Computing Limited # All rights reserved. # # This software is provided without warranty under the terms of the BSD license. # However, when used with the GPL version of PyQt the additional terms described in the PyQt GPL exception also apply # # Author: Riverbank Computing Limited #------------------------------------------------------------------------------ """ Defines a source code editor and code editor factory, for the PyQt user interface toolkit, useful for tools such as debuggers. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from pyface.qt import QtCore, QtGui from pyface.ui.qt4.code_editor.code_widget import AdvancedCodeWidget from traits.api import Str, Unicode, List, Int, Event, Bool, \ TraitError, on_trait_change from traits.trait_base import SequenceTypes # FIXME: ToolkitEditorFactory is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.code_editor file. from traitsui.editors.code_editor import ToolkitEditorFactory from pyface.key_pressed_event import KeyPressedEvent from constants import OKColor, ErrorColor from editor import Editor from helper import pixmap_cache #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- # Marker line constants: MARK_MARKER = 0 # Marks a marked line SEARCH_MARKER = 1 # Marks a line matching the current search SELECTED_MARKER = 2 # Marks the currently selected line class SourceEditor ( Editor ): """ Editor for source code which uses the advanced code widget. """ #--------------------------------------------------------------------------- # PyFace PythonEditor interface: #--------------------------------------------------------------------------- # Event that is fired on keypresses: key_pressed = Event(KeyPressedEvent) #--------------------------------------------------------------------------- # Editor interface: #--------------------------------------------------------------------------- # The code editor is scrollable. This value overrides the default. scrollable = True #--------------------------------------------------------------------------- # SoureEditor interface: #--------------------------------------------------------------------------- # Is the editor read only? readonly = Bool( False ) # The currently selected line selected_line = Int # The start position of the selected selected_start_pos = Int # The end position of the selected selected_end_pos = Int # The currently selected text selected_text = Unicode # The list of line numbers to mark mark_lines = List( Int ) # The current line number line = Event # The current column column = Event # The lines to be dimmed dim_lines = List(Int) dim_color = Str dim_style_number = Int(16) # 0-15 are reserved for the python lexer # The lines to have squiggles drawn under them squiggle_lines = List(Int) squiggle_color = Str # The lexer to use. lexer = Str #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self.control = QtGui.QWidget() layout = QtGui.QVBoxLayout(self.control) layout.setContentsMargins(0, 0, 0, 0) self._widget = control = AdvancedCodeWidget(None, lexer=self.factory.lexer) layout.addWidget(control) factory = self.factory # Set up listeners for the signals we care about code_editor = self._widget.code if not self.readonly: code_editor.textChanged.connect(self.update_object) if factory.auto_set: code_editor.textChanged.connect(self.update_object) if factory.selected_text != '': code_editor.selectionChanged.connect(self._selection_changed) if (factory.line != '') or (factory.column != ''): code_editor.cursorPositionChanged.connect(self._position_changed) # Make sure the editor has been initialized: self.update_editor() # Set up any event listeners: self.sync_value( factory.mark_lines, 'mark_lines', 'from', is_list = True ) self.sync_value( factory.selected_line, 'selected_line', 'from' ) self.sync_value( factory.selected_text, 'selected_text', 'to' ) self.sync_value( factory.line, 'line' ) self.sync_value( factory.column, 'column' ) self.sync_value( factory.selected_start_pos, 'selected_start_pos', 'to') self.sync_value( factory.selected_end_pos, 'selected_end_pos', 'to') self.sync_value(factory.dim_lines, 'dim_lines', 'from', is_list=True) if self.factory.dim_color == '': self.dim_color = 'grey' else: self.sync_value(factory.dim_color, 'dim_color', 'from') self.sync_value(factory.squiggle_lines, 'squiggle_lines', 'from', is_list=True) if factory.squiggle_color == '': self.squiggle_color = 'red' else: self.sync_value(factory.squiggle_color, 'squiggle_color', 'from') # Set the control tooltip: self.set_tooltip() #--------------------------------------------------------------------------- # Disposes of the contents of an editor: #--------------------------------------------------------------------------- def dispose ( self ): """ Disposes of the contents of an editor. """ # Make sure that the editor does not try to update as the control is # being destroyed: QtCore.QObject.disconnect(self._widget, QtCore.SIGNAL('lostFocus'), self.update_object) super( SourceEditor, self ).dispose() #--------------------------------------------------------------------------- # Handles the user entering input data in the edit control: #--------------------------------------------------------------------------- def update_object ( self ): """ Handles the user entering input data in the edit control. """ if not self._locked: try: value = unicode(self._widget.code.toPlainText()) if isinstance( self.value, SequenceTypes ): value = value.split() self.value = value except TraitError, excp: pass #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ self._locked = True new_value = self.value if isinstance( new_value, SequenceTypes ): new_value = '\n'.join( [ line.rstrip() for line in new_value ] ) control = self._widget if control.code.toPlainText() != new_value: control.code.setPlainText(new_value) # TODO: check the readonly flag and make sure the editor # is still readonly when we're done. if self.factory.selected_line: # TODO: update the factory selected line pass # TODO: put the cursor somewhere self._locked = False #--------------------------------------------------------------------------- # Handles an error that occurs while setting the object's trait value: #--------------------------------------------------------------------------- def error ( self, excp ): """ Handles an error that occurs while setting the object's trait value. """ pass #-- UI preference save/restore interface ----------------------------------- #--------------------------------------------------------------------------- # Restores any saved user preference information associated with the # editor: #--------------------------------------------------------------------------- def restore_prefs ( self, prefs ): """ Restores any saved user preference information associated with the editor. """ if self.factory.key_bindings is not None: key_bindings = prefs.get( 'key_bindings' ) if key_bindings is not None: self.factory.key_bindings.merge( key_bindings ) #--------------------------------------------------------------------------- # Returns any user preference information associated with the editor: #--------------------------------------------------------------------------- def save_prefs ( self ): """ Returns any user preference information associated with the editor. """ return { 'key_bindings': self.factory.key_bindings } #--------------------------------------------------------------------------- # Handles the set of 'marked lines' being changed: #--------------------------------------------------------------------------- def _mark_lines_changed ( self ): """ Handles the set of marked lines being changed. """ # FIXME: Not implemented at this time. return def _mark_lines_items_changed ( self ): self._mark_lines_changed() #--------------------------------------------------------------------------- # Handles the currently 'selected line' being changed: #--------------------------------------------------------------------------- def _selection_changed(self): self.selected_text = unicode(self._widget.code.textCursor().selectedText()) start = self._widget.code.textCursor().selectionStart() end = self._widget.code.textCursor().selectionEnd() if start > end: start, end = end, start self.selected_start_pos = start self.selected_end_pos = end def _selected_line_changed ( self ): """ Handles a change in which line is currently selected. """ control = self._widget line = max(1, min(control.lines(), self.selected_line)) _, column = control.get_line_column() control.set_line_column(line, column) if self.factory.auto_scroll: control.centerCursor() #--------------------------------------------------------------------------- # Handles the 'line' trait being changed: #--------------------------------------------------------------------------- def _line_changed ( self, line ): if not self._locked: _, column = self._widget.get_line_column() self._widget.set_line_column(line, column) if self.factory.auto_scroll: self._widget.centerCursor() #--------------------------------------------------------------------------- # Handles the 'column' trait being changed: #--------------------------------------------------------------------------- def _column_changed ( self, column ): if not self._locked: line, _ = self._widget.get_line_column() self._widget.set_line_column(line, column) #--------------------------------------------------------------------------- # Handles the cursor position being changed: #--------------------------------------------------------------------------- def _position_changed(self): """ Handles the cursor position being changed. """ control = self._widget self._locked = True self.line, self.column = control.get_line_column() self._locked = False self.selected_text = control.get_selected_text() if self.factory.auto_scroll: self._widget.centerCursor() #--------------------------------------------------------------------------- # Handles a key being pressed within the editor: #--------------------------------------------------------------------------- def _key_pressed_changed ( self, event ): """ Handles a key being pressed within the editor. """ key_bindings = self.factory.key_bindings if key_bindings: processed = key_bindings.do(event.event, self.ui.handler, self.ui.info) else: processed = False if not processed and event.event.matches(QtGui.QKeySequence.Find): self._find_widget.show() #--------------------------------------------------------------------------- # Handles the styling of the editor: #--------------------------------------------------------------------------- def _dim_color_changed(self): pass def _squiggle_color_changed(self): pass @on_trait_change('dim_lines, squiggle_lines') def _style_document(self): self._widget.set_warn_lines(self.squiggle_lines) # Define the simple, custom, text and readonly editors, which will be accessed # by the editor factory for code editors. CustomEditor = SimpleEditor = TextEditor = SourceEditor class ReadonlyEditor(SourceEditor): # Set the value of the readonly trait. readonly = True traitsui-4.1.0/traitsui/qt4/history_editor.py0000644000175100001440000001065611674463546022366 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright(c) 2009, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: Evan Patterson # Date: 08/21/2009 # #------------------------------------------------------------------------------- """ Defines a text editor which displays a text field and maintains a history of previously entered values. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from pyface.qt import QtCore, QtGui from editor import Editor #------------------------------------------------------------------------------- # '_HistoryEditor' class: #------------------------------------------------------------------------------- class _HistoryEditor(Editor): """ Simple style text editor, which displays a text field and maintains a history of previously entered values, the maximum number of which is specified by the 'entries' trait of the HistoryEditor factory. """ #--------------------------------------------------------------------------- # 'Editor' interface: #--------------------------------------------------------------------------- def init(self, parent): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self.control = control = QtGui.QComboBox() control.setEditable(True) control.setInsertPolicy(QtGui.QComboBox.InsertAtTop) if self.factory.entries > 0: signal = QtCore.SIGNAL('rowsInserted(const QModelIndex&, int, int)') QtCore.QObject.connect(control.model(), signal, self._truncate) if self.factory.auto_set: signal = QtCore.SIGNAL('editTextChanged(QString)') else: signal = QtCore.SIGNAL('activated(QString)') QtCore.QObject.connect(control, signal, self.update_object) self.set_tooltip() def update_object(self, text): """ Handles the user entering input data in the edit control. """ if not self._no_update: self.value = unicode(text) def update_editor(self): """ Updates the editor when the object trait changes externally to the editor. """ self._no_update = True self.control.setEditText(self.str_value) self._no_update = False #-- UI preference save/restore interface ----------------------------------- def restore_prefs(self, prefs): """ Restores any saved user preference information associated with the editor. """ history = prefs.get('history') if history: self._no_update = True self.control.addItems(history[:self.factory.entries]) # Adding items sets the edit text, so we reset it afterwards: self.control.setEditText(self.str_value) self._no_update = False def save_prefs(self): """ Returns any user preference information associated with the editor. """ history = [ str(self.control.itemText(index)) for index in xrange(self.control.count()) ] # If the view closed successfully, update the history with the current # editor value, as long it is different from the current object value: if self.ui.result: current = str(self.control.currentText()) if current != self.str_value: history.insert(0, current) return { 'history': history } #--------------------------------------------------------------------------- # '_HistoryEditor' private interface: #--------------------------------------------------------------------------- def _truncate(self, parent, start, end): """ Handle items being added to the combo box. If there are too many, remove items at the end. """ diff = self.control.count() - self.factory.entries if diff > 0: for i in xrange(diff): self.control.removeItem(self.factory.entries) traitsui-4.1.0/traitsui/qt4/html_editor.py0000644000175100001440000000720611674463546021626 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2009, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # #------------------------------------------------------------------------------ """ Defines the HTML "editor" for the QT4 user interface toolkit. HTML editors interpret and display HTML-formatted text, but do not modify it. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import webbrowser from pyface.qt import QtCore, QtGui, QtWebKit from traits.api import Str from editor import Editor #------------------------------------------------------------------------------- # 'SimpleEditor' class: #------------------------------------------------------------------------------- class SimpleEditor ( Editor ): """ Simple style editor for HTML. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Is the HTML editor scrollable? This values override the default. scrollable = True # External objects referenced in the HTML are relative to this URL base_url = Str #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self.control = QtWebKit.QWebView() self.control.setSizePolicy( QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding ) if self.factory.open_externally: page = self.control.page() page.setLinkDelegationPolicy( QtWebKit.QWebPage.DelegateAllLinks ) signal = QtCore.SIGNAL( 'linkClicked(QUrl)' ) QtCore.QObject.connect( page, signal, self._link_clicked ) self.base_url = self.factory.base_url self.sync_value( self.factory.base_url_name, 'base_url', 'from' ) #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes external to the editor. """ text = self.str_value if self.factory.format_text: text = self.factory.parse_text( text ) if self.base_url: url = self.base_url if not url.endswith("/"): url += "/" self.control.setHtml( text , QtCore.QUrl.fromLocalFile ( url ) ) else: self.control.setHtml( text ) #-- Event Handlers --------------------------------------------------------- def _base_url_changed ( self ): self.update_editor() def _link_clicked ( self, url ): webbrowser.open_new( url.toString() ) #-EOF-------------------------------------------------------------------------- traitsui-4.1.0/traitsui/qt4/list_str_model.py0000644000175100001440000002473011674463546022340 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2009, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: Evan Patterson # Date: 08/05/2009 # #------------------------------------------------------------------------------- """ Defines the table model used by the tabular editor. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from pyface.qt import QtCore, QtGui from traitsui.ui_traits import SequenceTypes #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- # MIME type for internal table drag/drop operations mime_type = 'traits-ui-list-str-editor' #------------------------------------------------------------------------------- # 'ListStrModel' class: #------------------------------------------------------------------------------- class ListStrModel(QtCore.QAbstractListModel): """ A model for lists of strings. """ def __init__(self, editor, parent=None): """ Initialise the object. """ QtCore.QAbstractListModel.__init__(self, parent) self._editor = editor #--------------------------------------------------------------------------- # QAbstractItemModel interface: #--------------------------------------------------------------------------- def rowCount(self, mi): """ Reimplemented to return items in the list. """ editor = self._editor return editor.adapter.len(editor.object, editor.name) def data(self, mi, role): """ Reimplemented to return the data. """ editor = self._editor adapter = editor.adapter index = mi.row() if role == QtCore.Qt.DisplayRole or role == QtCore.Qt.EditRole: if editor.is_auto_add(index): text = adapter.get_default_text(editor.object, editor.name, index) else: text = adapter.get_text(editor.object, editor.name, index) if role == QtCore.Qt.DisplayRole and text == '': # FIXME: This is a hack to make empty strings editable. text = ' ' return text elif role == QtCore.Qt.DecorationRole: if editor.is_auto_add(index): image = adapter.get_default_image(editor.object, editor.name, index) else: image = adapter.get_image(editor.object, editor.name, index) image = editor.get_image(image) if image is not None: return image elif role == QtCore.Qt.BackgroundRole: if editor.is_auto_add(index): color = adapter.get_default_bg_color(editor.object, editor.name) else: color = adapter.get_bg_color(editor.object, editor.name, index) if color is not None: if isinstance(color, SequenceTypes): q_color = QtGui.QColor(*color) else: q_color = QtGui.QColor(color) return QtGui.QBrush(q_color) elif role == QtCore.Qt.ForegroundRole: if editor.is_auto_add(index): color = adapter.get_default_text_color(editor.object, editor.name) else: color = adapter.get_text_color(editor.object, editor.name, index) if color is not None: if isinstance(color, SequenceTypes): q_color = QtGui.QColor(*color) else: q_color = QtGui.QColor(color) return QtGui.QBrush(q_color) return None def setData(self, mi, value, role): """ Reimplmented to allow for modification of the object trait. """ editor = self._editor editor.adapter.set_text(editor.object, editor.name, mi.row(), value) signal = QtCore.SIGNAL('dataChanged(QModelIndex,QModelIndex)') self.emit(signal, mi, mi) return True def setItemData(self, mi, roles): """ Reimplmented to reject all setItemData calls. """ # FIXME: This is a hack to prevent the QListView from clearing out the # old row after a move operation. (The QTableView doesn't do this, for # some reason). This behavior is not overridable so far as I can tell, # but there may be a better way around this issue. Note that we cannot # simply use a CopyAction instead because InternalMove mode is hardcoded # in the Qt source to allow only MoveActions. return False def flags(self, mi): """ Reimplemented to set editable status and movable status. """ editor = self._editor index = mi.row() flags = QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled if (editor.factory.editable and 'edit' in editor.factory.operations and editor.adapter.get_can_edit(editor.object, editor.name, index)): flags |= QtCore.Qt.ItemIsEditable if (editor.factory.editable and 'move' in editor.factory.operations and editor.adapter.get_drag(editor.object, editor.name, index) is not None): flags |= QtCore.Qt.ItemIsDragEnabled | QtCore.Qt.ItemIsDropEnabled return flags def headerData(self, section, orientation, role): """ Reimplemented to return title for vertical header data. """ if orientation != QtCore.Qt.Horizontal or role != QtCore.Qt.DisplayRole: return None return self._editor.title def insertRow(self, row, parent=QtCore.QModelIndex(), obj=None): """ Reimplemented to allow creation of new rows. Added an optional arg to allow the insertion of an existing row object. """ editor = self._editor adapter = editor.adapter if obj is None: obj = adapter.get_default_value(editor.object, editor.name) self.beginInsertRows(parent, row, row) editor.callx( editor.adapter.insert, editor.object, editor.name, row, obj) self.endInsertRows() return True def insertRows(self, row, count, parent=QtCore.QModelIndex()): """ Reimplemented to allow creation of new items. """ editor = self._editor adapter = editor.adapter self.beginInsertRows(parent, row, row + count - 1) for i in xrange(count): value = adapter.get_default_value(editor.object, editor.name) editor.callx(adapter.insert, editor.object, editor.name, row, value) self.endInsertRows() return True def removeRows(self, row, count, parent=QtCore.QModelIndex()): """ Reimplemented to allow row deletion, as well as reordering via drag and drop. """ editor = self._editor adapter = editor.adapter self.beginRemoveRows(parent, row, row + count - 1) for i in xrange(count): editor.callx(adapter.delete, editor.object, editor.name, row) self.endRemoveRows() return True def mimeTypes(self): """ Reimplemented to expose our internal MIME type for drag and drop operations. """ types = QtCore.QStringList() types.append(mime_type) return types def mimeData(self, indexes): """ Reimplemented to generate MIME data containing the rows of the current selection. """ mime_data = QtCore.QMimeData() rows = list(set([ index.row() for index in indexes ])) data = QtCore.QByteArray(str(rows[0])) for row in rows[1:]: data.append(' %i' % row) mime_data.setData(mime_type, data) return mime_data def dropMimeData(self, mime_data, action, row, column, parent): """ Reimplemented to allow items to be moved. """ if action == QtCore.Qt.IgnoreAction: return False data = mime_data.data(mime_type) if data.isNull(): return False current_rows = map(int, str(data).split(' ')) self.moveRows(current_rows, parent.row()) return True def supportedDropActions(self): """ Reimplemented to allow items to be moved. """ return QtCore.Qt.MoveAction #--------------------------------------------------------------------------- # ListStrModel interface: #--------------------------------------------------------------------------- def moveRow(self, old_row, new_row): """ Convenience method to move a single row. """ return self.moveRows([old_row], new_row) def moveRows(self, current_rows, new_row): """ Moves a sequence of rows (provided as a list of row indexes) to a new row. """ editor = self._editor # Sort rows in descending order so they can be removed without # invalidating the indices. current_rows.sort() current_rows.reverse() # If the the highest selected row is lower than the destination, do an # insertion before rather than after the destination. if current_rows[-1] < new_row: new_row += 1 # Remove selected rows... objects = [] for row in current_rows: if row <= new_row: new_row -= 1 obj = editor.adapter.get_item(editor.object, editor.name, row) objects.insert(0, obj) self.removeRow(row) # ...and add them at the new location. for i, obj in enumerate(objects): self.insertRow(new_row + i, obj=obj) # Update the selection for the new location. if editor.factory.multi_select: editor.setx(multi_selected = objects) editor.multi_selected_indices = range(new_row, new_row+len(objects)) else: editor.setx(selected = objects[0]) editor.selected_index = new_row traitsui-4.1.0/traitsui/qt4/null_editor.py0000644000175100001440000000435211674463546021633 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2006, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 07/26/2006 # #------------------------------------------------------------------------------- """ Defines a completely empty editor, intended to be used as a spacer. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from pyface.qt import QtGui # FIXME: ToolkitEditorFactory is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.null_editor file. from traitsui.editors.null_editor \ import NullEditor as ToolkitEditorFactory from editor \ import Editor #------------------------------------------------------------------------------- # 'NullEditor' class: #------------------------------------------------------------------------------- class NullEditor ( Editor ): """ A completely empty editor. """ #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self.control = QtGui.QWidget() #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ pass traitsui-4.1.0/traitsui/qt4/editor_factory.py0000644000175100001440000001602411674463546022327 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2007, Riverbank Computing Limited # All rights reserved. # # This software is provided without warranty under the terms of the BSD license. # However, when used with the GPL version of PyQt the additional terms described in the PyQt GPL exception also apply # # Author: Riverbank Computing Limited #------------------------------------------------------------------------------ """ Defines the base PyQt classes the various styles of editors used in a Traits-based user interface. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from pyface.qt import QtCore, QtGui from traits.api \ import TraitError from traitsui.editor_factory \ import EditorFactory as BaseEditorFactory from editor \ import Editor #------------------------------------------------------------------------------- # 'EditorFactory' class # Deprecated alias for traitsui.editor_factory.EditorFactory #------------------------------------------------------------------------------- class EditorFactory(BaseEditorFactory): """ Deprecated alias for traitsui.editor_factory.EditorFactory. """ def __init__(self, *args, **kwds): super(EditorFactory, self).__init__(*args, **kwds) warnings.warn("DEPRECATED: Use traitsui.editor_factory." ".EditorFactory instead.", DeprecationWarning) #------------------------------------------------------------------------------- # 'SimpleEditor' class: #------------------------------------------------------------------------------- class SimpleEditor ( Editor ): """ Base class for simple style editors, which displays a text field containing the text representation of the object trait value. Clicking in the text field displays an editor-specific dialog box for changing the value. """ #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self.control = _SimpleField(self) self.set_tooltip() #--------------------------------------------------------------------------- # Invokes the pop-up editor for an object trait: # # (Normally overridden in a subclass) #--------------------------------------------------------------------------- def popup_editor(self): """ Invokes the pop-up editor for an object trait. """ pass #------------------------------------------------------------------------------- # 'TextEditor' class: #------------------------------------------------------------------------------- class TextEditor ( Editor ): """ Base class for text style editors, which displays an editable text field, containing a text representation of the object trait value. """ #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self.control = QtGui.QLineEdit(self.str_value) QtCore.QObject.connect(self.control, QtCore.SIGNAL('editingFinished()'), self.update_object) self.set_tooltip() #--------------------------------------------------------------------------- # Handles the user changing the contents of the edit control: #--------------------------------------------------------------------------- def update_object(self): """ Handles the user changing the contents of the edit control. """ try: self.value = unicode(self.control.text()) except TraitError, excp: pass #------------------------------------------------------------------------------- # 'ReadonlyEditor' class: #------------------------------------------------------------------------------- class ReadonlyEditor ( Editor ): """ Base class for read-only style editors, which displays a read-only text field, containing a text representation of the object trait value. """ #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- text_alignment_map = { 'left' : QtCore.Qt.AlignLeft, 'right' : QtCore.Qt.AlignRight, 'just' : QtCore.Qt.AlignJustify, 'top' : QtCore.Qt.AlignLeft, 'bottom' : QtCore.Qt.AlignBottom, 'vcenter' : QtCore.Qt.AlignVCenter, 'hcenter' : QtCore.Qt.AlignHCenter, 'center' : QtCore.Qt.AlignVCenter | QtCore.Qt.AlignHCenter } def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self.control = QtGui.QLabel(self.str_value) if self.item.resizable is True or self.item.height != -1.0: self.control.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) self.control.setWordWrap(True) alignment = None for item in self.factory.text_alignment.split(",") : item_alignment = self.text_alignment_map.get(item, None) if item_alignment : if alignment : alignment = alignment | item_alignment else : alignment = item_alignment if alignment : self.control.setAlignment(alignment) self.set_tooltip() #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ self.control.setText(self.str_value) #------------------------------------------------------------------------------- # '_SimpleField' class: #------------------------------------------------------------------------------- class _SimpleField(QtGui.QLineEdit): def __init__(self, editor): QtGui.QLineEdit.__init__(self, editor.str_value) self.setReadOnly(True) self._editor = editor def mouseReleaseEvent(self, e): QtGui.QLineEdit.mouseReleaseEvent(self, e) if e.button() == QtCore.Qt.LeftButton: self._editor.popup_editor() traitsui-4.1.0/traitsui/qt4/date_editor.py0000644000175100001440000001543011674463546021575 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2009, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: Evan Patterson # Date: 08/03/2009 # #------------------------------------------------------------------------------ """ A Traits UI editor for datetime.date objects. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import datetime from pyface.qt import QtCore, QtGui from editor import Editor from editor_factory import ReadonlyEditor as BaseReadonlyEditor #------------------------------------------------------------------------------- # 'SimpleEditor' class: #------------------------------------------------------------------------------- class SimpleEditor(Editor): """ Simple Traits UI date editor that wraps QDateEdit. """ #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init(self, parent): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self.control = QtGui.QDateEdit() if hasattr(self.factory, 'qt_date_format'): self.control.setDisplayFormat(self.factory.qt_date_format) if not self.factory.allow_future: self.control.setMaximumDate(QtCore.QDate.currentDate()) if getattr(self.factory, 'maximum_date_name', None): obj, extended_name, func = self.parse_extended_name(self.factory.maximum_date_name) self.factory.maximum_date = func() if getattr(self.factory, 'minimum_date_name', None): obj, extended_name, func = self.parse_extended_name(self.factory.minimum_date_name) self.factory.minimum_date = func() if getattr(self.factory, 'minimum_date', None): min_date = QtCore.QDate(self.factory.minimum_date.year, self.factory.minimum_date.month, self.factory.minimum_date.day) self.control.setMinimumDate(min_date) if getattr(self.factory, 'maximum_date', None): max_date = QtCore.QDate(self.factory.maximum_date.year, self.factory.maximum_date.month, self.factory.maximum_date.day) self.control.setMaximumDate(max_date) signal = QtCore.SIGNAL('dateChanged(QDate)') QtCore.QObject.connect(self.control, signal, self.update_object) #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor(self): """ Updates the editor when the object trait changes externally to the editor. """ value = self.value if value: q_date = QtCore.QDate(value.year, value.month, value.day) self.control.setDate(q_date) #--------------------------------------------------------------------------- # Handles the user entering input data in the edit control: #--------------------------------------------------------------------------- def update_object(self, q_date): """ Handles the user entering input data in the edit control. """ year = q_date.year() month = q_date.month() day = q_date.day() try: self.value = datetime.date(year, month, day) except ValueError: print 'Invalid date:', year, month, day raise #------------------------------------------------------------------------------- # 'CustomEditor' class: #------------------------------------------------------------------------------- class CustomEditor(Editor): """ Custom Traits UI date editor that wraps QCalendarWidget. """ #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init(self, parent): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self.control = QtGui.QCalendarWidget() if not self.factory.allow_future: self.control.setMaximumDate(QtCore.QDate.currentDate()) signal = QtCore.SIGNAL('clicked(QDate)') QtCore.QObject.connect(self.control, signal, self.update_object) #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor(self): """ Updates the editor when the object trait changes externally to the editor. """ value = self.value if value: q_date = QtCore.QDate(value.year, value.month, value.day) self.control.setSelectedDate(q_date) #--------------------------------------------------------------------------- # Handles the user entering input data in the edit control: #--------------------------------------------------------------------------- def update_object(self, q_date): """ Handles the user entering input data in the edit control. """ year = q_date.year() month = q_date.month() day = q_date.day() try: self.value = datetime.date(year, month, day) except ValueError: print 'Invalid date:', year, month, day raise #------------------------------------------------------------------------------ # 'ReadonlyEditor' class: #------------------------------------------------------------------------------ class ReadonlyEditor(BaseReadonlyEditor): """ Readonly Traits UI date editor that uses a QLabel for the view. """ def _get_str_value(self): """ Replace the default string value with our own date verision. """ if not self.value: return self.factory.message else: return self.value.strftime(self.factory.strftime) traitsui-4.1.0/traitsui/qt4/constants.py0000644000175100001440000000335411674463546021330 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2007, Riverbank Computing Limited # All rights reserved. # # This software is provided without warranty under the terms of the BSD license. # However, when used with the GPL version of PyQt the additional terms described in the PyQt GPL exception also apply # # Author: Riverbank Computing Limited #------------------------------------------------------------------------------ """ Defines constants used by the PyQt implementation of the various text editors and text editor factories. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from pyface.qt import QtGui #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- _palette = QtGui.QApplication.palette() # Default dialog title DefaultTitle = 'Edit properties' # Color of valid input OKColor = _palette.color(QtGui.QPalette.Base) # Color to highlight input errors ErrorColor = QtGui.QColor( 255, 192, 192 ) # Color for background of read-only fields ReadonlyColor = QtGui.QColor( 244, 243, 238 ) # Color for background of fields where objects can be dropped DropColor = QtGui.QColor( 215, 242, 255 ) # Color for an editable field EditableColor = _palette.color(QtGui.QPalette.Base) # Color for background of windows (like dialog background color) WindowColor = _palette.color(QtGui.QPalette.Window) del _palette # Screen size values: _geom = QtGui.QApplication.desktop().availableGeometry() screen_dx = _geom.width() screen_dy = _geom.height() del _geom traitsui-4.1.0/traitsui/qt4/menu.py0000644000175100001440000002466511674463546020270 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2007, Riverbank Computing Limited # All rights reserved. # # This software is provided without warranty under the terms of the BSD license. # However, when used with the GPL version of PyQt the additional terms described in the PyQt GPL exception also apply # # Author: Riverbank Computing Limited #------------------------------------------------------------------------------ """ Dynamically construct PyQt Menus or MenuBars from a supplied string description of the menu. Menu Description Syntax:: submenu_label {help_string} menuitem_label | accelerator {help_string} [~/-name]: code *submenu_label* Label of a sub menu *menuitem_label* Label of a menu item {*help_string*} Help string to display on the status line (optional) *accelerator* Accelerator key (e.g., Ctrl-C) (The '|' and keyname are optional, but must be used together.) [~] The menu item is checkable, but is not checked initially (optional) [/] The menu item is checkable, and is checked initially (optional) [-] The menu item disabled initially (optional) [*name*] Symbolic name used to refer to menu item (optional) *code* Python code invoked when menu item is selected A line beginning with a hyphen (-) is interpreted as a menu separator. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import re from pyface.qt import QtGui #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- help_pat = re.compile( r'(.*){(.*)}(.*)' ) options_pat = re.compile( r'(.*)\[(.*)\](.*)' ) #------------------------------------------------------------------------------- # 'MakeMenu' class: #------------------------------------------------------------------------------- class MakeMenu: """ Manages creation of menus. """ #--------------------------------------------------------------------------- # Initializes the object: #--------------------------------------------------------------------------- def __init__ ( self, desc, owner, popup = False, window = None ): """ Initializes the object. """ self.owner = owner if window is None: window = owner self.window = window self.indirect = getattr( owner, 'call_menu', None ) self.names = {} self.desc = desc.split( '\n' ) self.index = 0 if popup: self.menu = menu = QtGui.QMenu() self.parse( menu, -1 ) else: self.menu = menu = QtGui.QMenuBar() self.parse( menu, -1 ) window.setMenuBar( menu ) #--------------------------------------------------------------------------- # Recursively parses menu items from the description: #--------------------------------------------------------------------------- def parse ( self, menu, indent ): """ Recursively parses menu items from the description. """ while True: # Make sure we have not reached the end of the menu description yet: if self.index >= len( self.desc ): return # Get the next menu description line and check its indentation: dline = self.desc[ self.index ] line = dline.lstrip() indented = len( dline ) - len( line ) if indented <= indent: return # Indicate that the current line has been processed: self.index += 1 # Check for a blank or comment line: if (line == '') or (line[0:1] == '#'): continue # Check for a menu separator: if line[0:1] == '-': menu.addSeparator() continue # Extract the help string (if any): help = '' match = help_pat.search( line ) if match: help = ' ' + match.group(2).strip() line = match.group(1) + match.group(3) # Check for a menu item: col = line.find( ':' ) if col >= 0: handler = line[ col + 1: ].strip() if handler != '': if self.indirect: self.indirect( cur_id, handler ) handler = self.indirect else: try: exec ('def handler(self=self.owner):\n %s\n' % handler) except: handler = null_handler else: try: exec 'def handler(self=self.owner):\n%s\n' % ( self.get_body( indented ), ) in globals() except: handler = null_handler not_checked = checked = disabled = False name = key = '' line = line[:col] match = options_pat.search(line) if match: line = match.group(1) + match.group(3) not_checked, checked, disabled, name = option_check( '~/-', match.group(2).strip() ) label = line.strip() col = label.find( '|' ) if col >= 0: key = label[col + 1:].strip() label = label[:col].strip() act = menu.addAction(label, handler) act.setCheckable(not_checked or checked) act.setStatusTip(help) if key: act.setShortcut(key) if checked: act.setChecked(True) if disabled: act.setEnabled(False) if name: self.names[name] = act setattr(self.owner, name, MakeMenuItem(self, act)) # Else must be the start of a sub menu: submenu = QtGui.QMenu(line.strip()) # Recursively parse the sub-menu: self.parse(submenu, indented) # Add the menu to its parent: act = menu.addMenu(submenu) act.setStatusTip(help) #--------------------------------------------------------------------------- # Returns the body of an inline method: #--------------------------------------------------------------------------- def get_body ( self, indent ): """ Returns the body of an inline method. """ result = [] while self.index < len( self.desc ): line = self.desc[ self.index ] if (len( line ) - len( line.lstrip() )) <= indent: break result.append( line ) self.index += 1 result = '\n'.join( result ).rstrip() if result != '': return result return ' pass' #--------------------------------------------------------------------------- # Returns the QAction associated with a specified name: #--------------------------------------------------------------------------- def get_action(self, name): """ Returns the QAction associated with a specified name. """ if isinstance(name, basestring): return self.names[name] return name #--------------------------------------------------------------------------- # Checks (or unchecks) a menu item specified by name: #--------------------------------------------------------------------------- def checked(self, name, check=None): """ Checks (or unchecks) a menu item specified by name. """ act = self.get_action(name) if check is None: return act.isChecked() act.setChecked(check) #--------------------------------------------------------------------------- # Enables (or disables) a menu item specified by name: #--------------------------------------------------------------------------- def enabled(self, name, enable=None): """ Enables (or disables) a menu item specified by name. """ act = self.get_action(name) if enable is None: return act.isEnabled() act.setEnabled(enable) #--------------------------------------------------------------------------- # Gets/Sets the label for a menu item: #--------------------------------------------------------------------------- def label(self, name, label=None): """ Gets or sets the label for a menu item. """ act = self.get_action(name) if label is None: return unicode(act.text()) act.setText(label) #------------------------------------------------------------------------------- # 'MakeMenuItem' class: #------------------------------------------------------------------------------- class MakeMenuItem: """ A menu item for a menu managed by MakeMenu. """ def __init__(self, menu, act): self.menu = menu self.act = act def checked(self, check=None): return self.menu.checked(self.act, check) def toggle(self): checked = not self.checked() self.checked(checked) return checked def enabled(self, enable=None): return self.menu.enabled(self.act, enable) def label(self, label=None): return self.menu.label(self.act, label) #------------------------------------------------------------------------------- # Determine whether a string contains any specified option characters, and # remove them if it does: #------------------------------------------------------------------------------- def option_check ( test, string ): """ Determines whether a string contains any specified option characters, and removes them if it does. """ result = [] for char in test: col = string.find( char ) result.append( col >= 0 ) if col >= 0: string = string[ : col ] + string[ col + 1: ] return result + [ string.strip() ] #------------------------------------------------------------------------------- # Null menu option selection handler: #------------------------------------------------------------------------------- def null_handler ( event ): print 'null_handler invoked' traitsui-4.1.0/traitsui/qt4/key_event_to_name.py0000644000175100001440000001341611674463546023007 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2007, Riverbank Computing Limited # All rights reserved. # # This software is provided without warranty under the terms of the BSD license. # However, when used with the GPL version of PyQt the additional terms described in the PyQt GPL exception also apply # # Author: Riverbank Computing Limited #------------------------------------------------------------------------------ """ Converts a QKeyEvent to a standardized "name". """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from pyface.qt import QtCore #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- # Mapping from PyQt keypad key names to Pyface key names. keypad_map = { QtCore.Qt.Key_Enter: 'Enter', QtCore.Qt.Key_0: 'Numpad 0', QtCore.Qt.Key_1: 'Numpad 1', QtCore.Qt.Key_2: 'Numpad 2', QtCore.Qt.Key_3: 'Numpad 3', QtCore.Qt.Key_4: 'Numpad 4', QtCore.Qt.Key_5: 'Numpad 5', QtCore.Qt.Key_6: 'Numpad 6', QtCore.Qt.Key_7: 'Numpad 7', QtCore.Qt.Key_8: 'Numpad 8', QtCore.Qt.Key_9: 'Numpad 9', QtCore.Qt.Key_Asterisk: 'Multiply', QtCore.Qt.Key_Plus: 'Add', QtCore.Qt.Key_Comma: 'Separator', QtCore.Qt.Key_Minus: 'Subtract', QtCore.Qt.Key_Period: 'Decimal', QtCore.Qt.Key_Slash: 'Divide' } # Mapping from PyQt non-keypad key names to Pyface key names. key_map = { QtCore.Qt.Key_0: '0', QtCore.Qt.Key_1: '1', QtCore.Qt.Key_2: '2', QtCore.Qt.Key_3: '3', QtCore.Qt.Key_4: '4', QtCore.Qt.Key_5: '5', QtCore.Qt.Key_6: '6', QtCore.Qt.Key_7: '7', QtCore.Qt.Key_8: '8', QtCore.Qt.Key_9: '9', QtCore.Qt.Key_A: 'A', QtCore.Qt.Key_B: 'B', QtCore.Qt.Key_C: 'C', QtCore.Qt.Key_D: 'D', QtCore.Qt.Key_E: 'E', QtCore.Qt.Key_F: 'F', QtCore.Qt.Key_G: 'G', QtCore.Qt.Key_H: 'H', QtCore.Qt.Key_I: 'I', QtCore.Qt.Key_J: 'J', QtCore.Qt.Key_K: 'K', QtCore.Qt.Key_L: 'L', QtCore.Qt.Key_M: 'M', QtCore.Qt.Key_N: 'N', QtCore.Qt.Key_O: 'O', QtCore.Qt.Key_P: 'P', QtCore.Qt.Key_Q: 'Q', QtCore.Qt.Key_R: 'R', QtCore.Qt.Key_S: 'S', QtCore.Qt.Key_T: 'T', QtCore.Qt.Key_U: 'U', QtCore.Qt.Key_V: 'V', QtCore.Qt.Key_W: 'W', QtCore.Qt.Key_X: 'X', QtCore.Qt.Key_Y: 'Y', QtCore.Qt.Key_Z: 'Z', QtCore.Qt.Key_Space: 'Space', QtCore.Qt.Key_Backspace: 'Backspace', QtCore.Qt.Key_Tab: 'Tab', QtCore.Qt.Key_Enter: 'Enter', QtCore.Qt.Key_Return: 'Return', QtCore.Qt.Key_Escape: 'Esc', QtCore.Qt.Key_Delete: 'Delete', QtCore.Qt.Key_Cancel: 'Cancel', QtCore.Qt.Key_Clear: 'Clear', QtCore.Qt.Key_Shift: 'Shift', QtCore.Qt.Key_Menu: 'Menu', QtCore.Qt.Key_Pause: 'Pause', QtCore.Qt.Key_PageUp: 'Page Up', QtCore.Qt.Key_PageDown: 'Page Down', QtCore.Qt.Key_End: 'End', QtCore.Qt.Key_Home: 'Home', QtCore.Qt.Key_Left: 'Left', QtCore.Qt.Key_Up: 'Up', QtCore.Qt.Key_Right: 'Right', QtCore.Qt.Key_Down: 'Down', QtCore.Qt.Key_Select: 'Select', QtCore.Qt.Key_Print: 'Print', QtCore.Qt.Key_Execute: 'Execute', QtCore.Qt.Key_Insert: 'Insert', QtCore.Qt.Key_Help: 'Help', QtCore.Qt.Key_F1: 'F1', QtCore.Qt.Key_F2: 'F2', QtCore.Qt.Key_F3: 'F3', QtCore.Qt.Key_F4: 'F4', QtCore.Qt.Key_F5: 'F5', QtCore.Qt.Key_F6: 'F6', QtCore.Qt.Key_F7: 'F7', QtCore.Qt.Key_F8: 'F8', QtCore.Qt.Key_F9: 'F9', QtCore.Qt.Key_F10: 'F10', QtCore.Qt.Key_F11: 'F11', QtCore.Qt.Key_F12: 'F12', QtCore.Qt.Key_F13: 'F13', QtCore.Qt.Key_F14: 'F14', QtCore.Qt.Key_F15: 'F15', QtCore.Qt.Key_F16: 'F16', QtCore.Qt.Key_F17: 'F17', QtCore.Qt.Key_F18: 'F18', QtCore.Qt.Key_F19: 'F19', QtCore.Qt.Key_F20: 'F20', QtCore.Qt.Key_F21: 'F21', QtCore.Qt.Key_F22: 'F22', QtCore.Qt.Key_F23: 'F23', QtCore.Qt.Key_F24: 'F24', QtCore.Qt.Key_NumLock: 'Num Lock', QtCore.Qt.Key_ScrollLock:'Scroll Lock' } #------------------------------------------------------------------------------- # Converts a keystroke event into a corresponding key name: #------------------------------------------------------------------------------- def key_event_to_name(event): """ Converts a keystroke event into a corresponding key name. """ key_code = event.key() modifiers = event.modifiers() if modifiers & QtCore.Qt.KeypadModifier: key = keypad_map.get(key_code) else: key = None if key is None: key = key_map.get(key_code) name = '' if modifiers & QtCore.Qt.ControlModifier: name += 'Ctrl' if modifiers & QtCore.Qt.AltModifier: name += '-Alt' if name else 'Alt' if modifiers & QtCore.Qt.MetaModifier: name += '-Meta' if name else 'Meta' if modifiers & QtCore.Qt.ShiftModifier and ((name != '') or (len(key) > 1)): name += '-Shift' if name else 'Shift' if key: if name: name += '-' name += key return name traitsui-4.1.0/traitsui/qt4/helper.py0000644000175100001440000001652711674463546020601 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2007, Riverbank Computing Limited # All rights reserved. # # This software is provided without warranty under the terms of the BSD license. # However, when used with the GPL version of PyQt the additional terms described in the PyQt GPL exception also apply # # Author: Riverbank Computing Limited #------------------------------------------------------------------------------ """ Defines helper functions and classes used to define PyQt-based trait editors and trait editor factories. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import os.path from pyface.qt import QtCore, QtGui from traits.api \ import Enum, CTrait, BaseTraitHandler, TraitError from traitsui.ui_traits \ import convert_image, SequenceTypes #------------------------------------------------------------------------------- # Trait definitions: #------------------------------------------------------------------------------- # Layout orientation for a control and its associated editor Orientation = Enum( 'horizontal', 'vertical' ) #------------------------------------------------------------------------------- # Convert an image file name to a cached QPixmap: #------------------------------------------------------------------------------- def pixmap_cache(name, path=None): """ Return the QPixmap corresponding to a filename. If the filename does not contain a path component, 'path' is used (or if 'path' is not specified, the local 'images' directory is used). """ if name[:1] == '@': image = convert_image(name.replace(' ', '_').lower()) if image is not None: return image.create_image() name_path, name = os.path.split(name) name = name.replace(' ', '_').lower() if name_path: filename = os.path.join(name_path, name) else: if path is None: filename = os.path.join(os.path.dirname(__file__), 'images', name) else: filename = os.path.join(path, name) filename = os.path.abspath(filename) pm = QtGui.QPixmap() if not QtGui.QPixmapCache.find(filename, pm): pm.load(filename) QtGui.QPixmapCache.insert(filename, pm) return pm #------------------------------------------------------------------------------- # Positions a window on the screen with a specified width and height so that # the window completely fits on the screen if possible: #------------------------------------------------------------------------------- def position_window ( window, width = None, height = None, parent = None ): """ Positions a window on the screen with a specified width and height so that the window completely fits on the screen if possible. """ # Get the available geometry of the screen containing the window. sgeom = QtGui.QApplication.desktop().availableGeometry(window) screen_dx = sgeom.width() screen_dy = sgeom.height() # Use the frame geometry even though it is very unlikely that the X11 frame # exists at this point. fgeom = window.frameGeometry() width = width or fgeom.width() height = height or fgeom.height() if parent is None: parent = window._parent if parent is None: # Center the popup on the screen. window.move((screen_dx - width) / 2, (screen_dy - height) / 2) return # Calculate the desired size of the popup control: if isinstance(parent, QtGui.QWidget): gpos = parent.mapToGlobal(QtCore.QPoint()) x = gpos.x() y = gpos.y() cdx = parent.width() cdy = parent.height() # Get the frame height of the parent and assume that the window will # have a similar frame. Note that we would really like the height of # just the top of the frame. pw = parent.window() fheight = pw.frameGeometry().height() - pw.height() else: # Special case of parent being a screen position and size tuple (used # to pop-up a dialog for a table cell): x, y, cdx, cdy = parent fheight = 0 x -= (width - cdx) / 2 y += cdy + fheight # Position the window (making sure it will fit on the screen). window.move(max(0, min(x, screen_dx - width)), max(0, min(y, screen_dy - height))) #------------------------------------------------------------------------------- # Restores the user preference items for a specified UI: #------------------------------------------------------------------------------- def restore_window ( ui ): """ Restores the user preference items for a specified UI. """ prefs = ui.restore_prefs() if prefs is not None: ui.control.setGeometry( *prefs ) #------------------------------------------------------------------------------- # Saves the user preference items for a specified UI: #------------------------------------------------------------------------------- def save_window ( ui ): """ Saves the user preference items for a specified UI. """ geom = ui.control.geometry() ui.save_prefs( (geom.x(), geom.y(), geom.width(), geom.height()) ) #------------------------------------------------------------------------------- # Safely tries to pop up an FBI window if etsdevtools.debug is installed #------------------------------------------------------------------------------- def open_fbi(): try: from etsdevtools.developer.helper.fbi import if_fbi if not if_fbi(): import traceback traceback.print_exc() except ImportError: pass #------------------------------------------------------------------------------- # 'IconButton' class: #------------------------------------------------------------------------------- class IconButton(QtGui.QPushButton): """ The IconButton class is a push button that contains a small image or a standard icon provided by the current style. """ def __init__(self, icon, slot): """ Initialise the button. icon is either the name of an image file or one of the QtGui.QStyle.SP_* values. """ QtGui.QPushButton.__init__(self) # Get the current style. sty = QtGui.QApplication.instance().style() # Get the minimum icon size to use. ico_sz = sty.pixelMetric(QtGui.QStyle.PM_ButtonIconSize) if isinstance(icon, basestring): pm = pixmap_cache(icon) # Increase the icon size to accomodate the image if needed. pm_width = pm.width() pm_height = pm.height() if ico_sz < pm_width: ico_sz = pm_width if ico_sz < pm_height: ico_sz = pm_height ico = QtGui.QIcon(pm) else: ico = sty.standardIcon(icon) # Configure the button. self.setIcon(ico) self.setMaximumSize(ico_sz, ico_sz) self.setFlat(True) self.setFocusPolicy(QtCore.Qt.NoFocus) QtCore.QObject.connect(self, QtCore.SIGNAL('clicked()'), slot) #------------------------------------------------------------------------------- # Dock-related stubs. #------------------------------------------------------------------------------- DockStyle = Enum('horizontal', 'vertical', 'tab', 'fixed') traitsui-4.1.0/traitsui/qt4/styled_date_editor.py0000644000175100001440000001255011674463546023161 0ustar ischnellusers00000000000000 from pyface.qt import QtCore, QtGui from pyface.qt.QtGui import QFont from traits.api import Dict # For a simple editor style, we just punt and use the same simple editor # as in the default date_editor. from date_editor import SimpleEditor from date_editor import CustomEditor as DateCustomEditor class CustomEditor(DateCustomEditor): dates = Dict() styles = Dict() def init(self, parent): self.control = QtGui.QCalendarWidget() if not self.factory.allow_future: self.control.setMaximumDate(QtCore.QDate.currentDate()) if not self.factory.allow_past: self.control.setMinimumDate(QtCore.QDate.currentDate()) if self.factory.dates_trait and self.factory.styles_trait: self.sync_value(self.factory.dates_trait, "dates", "from") self.sync_value(self.factory.styles_trait, "styles", "from") self.control.clicked.connect(self.update_object) return def _dates_changed(self, old, new): # Someone changed out the entire dict. The easiest, most robust # way to handle this is to reset the text formats of all the dates # in the old dict, and then set the dates in the new dict. if old: [map(self._reset_formatting, dates) for dates in old.values()] if new: styles = getattr(self.object, self.factory.styles_trait, None) self._apply_styles(styles, new) def _dates_items_changed(self, event): # Handle the added and changed items groups_to_set = event.added groups_to_set.update(event.changed) styles = getattr(self.object, self.factory.styles_trait, None) self._apply_styles(styles, groups_to_set) # Handle the removed items by resetting them [map(self._reset_formatting, dates) for dates in event.removed.values()] def _styles_changed(self, old, new): groups = getattr(self.object, self.factory.dates_trait, {}) if not new: # If no new styles, then reset all the dates to a default style [map(self._reset_formatting, dates) for dates in groups.values()] else: self._apply_styles(new, groups) return def _styles_items_changed(self, event): groups = getattr(self.object, self.factory.dates_trait) styles = getattr(self.object, self.factory.styles_trait) names_to_update = event.added.keys() + event.changed.keys() modified_groups = dict((name, groups[name]) for name in names_to_update) self._apply_styles(styles, modified_groups) names_to_reset = event.removed.keys() for name in names_to_reset: self._reset_formatting(groups[name]) return #------------------------------------------------------------------------ # Helper functions #------------------------------------------------------------------------ def _apply_style(self, style, dates): """ **style** is a CellFormat, **dates** is a list of datetime.date """ for dt in dates: qdt = QtCore.QDate(dt) textformat = self.control.dateTextFormat(qdt) self._apply_cellformat(style, textformat) self.control.setDateTextFormat(qdt, textformat) return def _apply_styles(self, style_dict, date_dict): """ Applies the proper style out of style_dict to every (name,date_list) in date_dict. """ if not style_dict or not date_dict: return for groupname, dates in date_dict.items(): cellformat = style_dict.get(groupname, None) if not cellformat: continue for dt in dates: qdt = QtCore.QDate(dt) textformat = self.control.dateTextFormat(qdt) self._apply_cellformat(cellformat, textformat) self.control.setDateTextFormat(qdt, textformat) return def _reset_formatting(self, dates): # Resets the text format on the given dates for dt in dates: qdt = QtCore.QDate(dt) self.control.setDateTextFormat(qdt, QtGui.QTextCharFormat()) def _apply_cellformat(self, cf, textformat): """ Applies the formatting in the cellformat cf to the QTextCharFormat object provided. """ if cf.italics is not None: textformat.setFontItalic(cf.italics) if cf.underline is not None: textformat.setFontUnderline(cf.underline) if cf.bold is not None: if cf.bold: weight = QFont.Bold else: weight = QFont.Normal textformat.setFontWeight(weight) if cf.bgcolor is not None: textformat.setBackground(self._color_to_brush(cf.bgcolor)) if cf.fgcolor is not None: textformat.setForeground(self._color_to_brush(cf.fgcolor)) return def _color_to_brush(self, color): """ Returns a QBrush with the color specified in **color** """ brush = QtGui.QBrush() if isinstance(color, basestring) and hasattr(QtCore.Qt, color): col = getattr(QtCore.Qt, color) elif isinstance(color, tuple) and len(color) == 3: col = QtGui.QColor() col.setRgb(*color) else: raise RuntimeError("Invalid color specification '%r'" % color) brush.setColor(col) return brush traitsui-4.1.0/traitsui/qt4/font_editor.py0000644000175100001440000003303511674463546021627 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2007, Riverbank Computing Limited # All rights reserved. # # This software is provided without warranty under the terms of the BSD license. # However, when used with the GPL version of PyQt the additional terms described in the PyQt GPL exception also apply # # Author: Riverbank Computing Limited #------------------------------------------------------------------------------ """ Defines the various font editors and the font editor factory, for the PyQt user interface toolkit.. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from pyface.qt import QtCore, QtGui from traitsui.editors.font_editor \ import ToolkitEditorFactory as BaseToolkitEditorFactory from editor_factory \ import SimpleEditor as BaseSimpleEditor, \ TextEditor as BaseTextEditor, \ ReadonlyEditor as BaseReadonlyEditor from editor \ import Editor #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- # Standard font point sizes PointSizes = [ '8', '9', '10', '11', '12', '14', '16', '18', '20', '22', '24', '26', '28', '36', '48', '72' ] #--------------------------------------------------------------------------- # The PyQtToolkitEditorFactory class. #--------------------------------------------------------------------------- ## We need to add qt4-specific methods to the editor factory, and so we create ## a subclass of the BaseToolkitEditorFactory. class ToolkitEditorFactory(BaseToolkitEditorFactory): """ PyQt editor factory for font editors. """ #--------------------------------------------------------------------------- # Returns a QFont object corresponding to a specified object's font trait: #--------------------------------------------------------------------------- def to_qt4_font ( self, editor ): """ Returns a QFont object corresponding to a specified object's font trait. """ return QtGui.QFont(editor.value) #--------------------------------------------------------------------------- # Gets the application equivalent of a QFont value: #--------------------------------------------------------------------------- def from_qt4_font ( self, font ): """ Gets the application equivalent of a QFont value. """ return font #--------------------------------------------------------------------------- # Returns the text representation of the specified object trait value: #--------------------------------------------------------------------------- def str_font ( self, font ): """ Returns the text representation of the specified object trait value. """ weight = { QtGui.QFont.Light: ' Light', QtGui.QFont.Bold: ' Bold' }.get(font.weight(), '') style = { QtGui.QFont.StyleOblique: ' Slant', QtGui.QFont.StyleItalic: ' Italic' }.get(font.style(), '') return '%s point %s%s%s' % ( font.pointSize(), font.family(), style, weight ) #------------------------------------------------------------------------------- # 'SimpleFontEditor' class: #------------------------------------------------------------------------------- class SimpleFontEditor ( BaseSimpleEditor ): """ Simple style of font editor, which displays a text field that contains a text representation of the font value (using that font if possible). Clicking the field displays a font selection dialog box. """ #--------------------------------------------------------------------------- # Invokes the pop-up editor for an object trait: #--------------------------------------------------------------------------- def popup_editor(self): """ Invokes the pop-up editor for an object trait. """ fnt, ok = QtGui.QFontDialog.getFont(self.factory.to_qt4_font(self), self.control) if ok: self.value = self.factory.from_qt4_font(fnt) self.update_editor() #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ super( SimpleFontEditor, self ).update_editor() set_font( self ) #--------------------------------------------------------------------------- # Returns the text representation of a specified font value: #--------------------------------------------------------------------------- def string_value ( self, font ): """ Returns the text representation of a specified font value. """ return self.factory.str_font( font ) #------------------------------------------------------------------------------- # 'CustomFontEditor' class: #------------------------------------------------------------------------------- class CustomFontEditor ( Editor ): """ Custom style of font editor, which displays the following: * A text field containing the text representation of the font value (using that font if possible). * A combo box containing all available type face names. * A combo box containing the available type sizes. """ #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self.control = QtGui.QWidget() layout = QtGui.QVBoxLayout(self.control) layout.setContentsMargins(0, 0, 0, 0) # Add the standard font control: self._font = font = QtGui.QLineEdit(self.str_value) QtCore.QObject.connect(font, QtCore.SIGNAL('editingFinished()'), self.update_object) layout.addWidget(font) # Add all of the font choice controls: layout2 = QtGui.QHBoxLayout() self._facename = control = QtGui.QFontComboBox() control.setEditable(False) QtCore.QObject.connect(control, QtCore.SIGNAL('currentFontChanged(QFont)'), self.update_object_parts) layout2.addWidget(control) self._point_size = control = QtGui.QComboBox() control.addItems(PointSizes) QtCore.QObject.connect(control, QtCore.SIGNAL('currentIndexChanged(int)'), self.update_object_parts) layout2.addWidget(control) # These don't have explicit controls. self._bold = self._italic = False layout.addLayout(layout2) #--------------------------------------------------------------------------- # Handles the user changing the contents of the font text control: #--------------------------------------------------------------------------- def update_object (self): """ Handles the user changing the contents of the font text control. """ self.value = unicode(self._font.text()) self._set_font(self.factory.to_qt4_font(self)) self.update_editor() #--------------------------------------------------------------------------- # Handles the user modifying one of the font components: #--------------------------------------------------------------------------- def update_object_parts (self): """ Handles the user modifying one of the font components. """ fnt = self._facename.currentFont() fnt.setBold(self._bold) fnt.setItalic(self._italic) psz = int(self._point_size.currentText()) fnt.setPointSize(psz) self.value = self.factory.from_qt4_font(fnt) self._font.setText(self.str_value) self._set_font(fnt) #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ font = self.factory.to_qt4_font( self ) self._bold = font.bold() self._italic = font.italic() self._facename.setCurrentFont(font) try: idx = PointSizes.index(str(font.pointSize())) except ValueError: idx = PointSizes.index('9') self._point_size.setCurrentIndex(idx) #--------------------------------------------------------------------------- # Returns the text representation of a specified font value: #--------------------------------------------------------------------------- def string_value ( self, font ): """ Returns the text representation of a specified font value. """ return self.factory.str_font( font ) #--------------------------------------------------------------------------- # Returns the editor's control for indicating error status: #--------------------------------------------------------------------------- def get_error_control ( self ): """ Returns the editor's control for indicating error status. """ return [ self._font, self._facename, self._point_size ] #-- Private Methods -------------------------------------------------------- def _set_font ( self, font ): """ Sets the font used by the text control to the specified font. """ font.setPointSize( min( 10, font.pointSize() ) ) self._font.setFont( font ) #------------------------------------------------------------------------------- # 'TextFontEditor' class: #------------------------------------------------------------------------------- class TextFontEditor ( BaseTextEditor ): """ Text style of font editor, which displays an editable text field containing a text representation of the font value (using that font if possible). """ #--------------------------------------------------------------------------- # Handles the user changing the contents of the edit control: #--------------------------------------------------------------------------- def update_object(self): """ Handles the user changing the contents of the edit control. """ self.value = unicode(self.control.text()) #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes external to the editor. """ super( TextFontEditor, self ).update_editor() set_font( self ) #--------------------------------------------------------------------------- # Returns the text representation of a specified font value: #--------------------------------------------------------------------------- def string_value ( self, font ): """ Returns the text representation of a specified font value. """ return self.factory.str_font( font ) #------------------------------------------------------------------------------- # 'ReadonlyFontEditor' class: #------------------------------------------------------------------------------- class ReadonlyFontEditor ( BaseReadonlyEditor ): """ Read-only style of font editor, which displays a read-only text field containing a text representation of the font value (using that font if possible). """ #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes external to the editor. """ super( ReadonlyFontEditor, self ).update_editor() set_font( self ) #--------------------------------------------------------------------------- # Returns the text representation of a specified font value: #--------------------------------------------------------------------------- def string_value ( self, font ): """ Returns the text representation of a specified font value. """ return self.factory.str_font( font ) #------------------------------------------------------------------------------- # Set the editor control's font to match a specified font: #------------------------------------------------------------------------------- def set_font ( editor ): """ Sets the editor control's font to match a specified font. """ editor.control.setFont(editor.factory.to_qt4_font(editor)) # Define the names SimpleEditor, CustomEditor, TextEditor and ReadonlyEditor # which are looked up by the editor factory for the font editor. SimpleEditor = SimpleFontEditor CustomEditor = CustomFontEditor TextEditor = TextFontEditor ReadonlyEditor = ReadonlyFontEditor traitsui-4.1.0/traitsui/qt4/ui_live.py0000644000175100001440000001544111674463546020750 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2007, Riverbank Computing Limited # All rights reserved. # # This software is provided without warranty under the terms of the BSD license. # However, when used with the GPL version of PyQt the additional terms described in the PyQt GPL exception also apply # # Author: Riverbank Computing Limited #------------------------------------------------------------------------------ """Creates a PyQt user interface for a specified UI object, where the UI is "live", meaning that it immediately updates its underlying object(s). """ from pyface.qt import QtCore, QtGui from traitsui.undo \ import UndoHistory from traitsui.menu \ import UndoButton, RevertButton, OKButton, CancelButton, HelpButton from ui_base \ import BaseDialog from ui_panel \ import panel #------------------------------------------------------------------------------- # Create the different 'live update' PyQt user interfaces. #------------------------------------------------------------------------------- def ui_live(ui, parent): """Creates a live, non-modal PyQt user interface for a specified UI object. """ _ui_dialog(ui, parent, BaseDialog.NONMODAL) def ui_livemodal(ui, parent): """Creates a live, modal PyQt user interface for a specified UI object. """ _ui_dialog(ui, parent, BaseDialog.MODAL) def ui_popup(ui, parent): """Creates a live, modal popup PyQt user interface for a specified UI object. """ _ui_dialog(ui, parent, BaseDialog.POPUP) def _ui_dialog(ui, parent, style): """Creates a live PyQt user interface for a specified UI object. """ if ui.owner is None: ui.owner = _LiveWindow() BaseDialog.display_ui(ui, parent, style) class _LiveWindow(BaseDialog): """User interface window that immediately updates its underlying object(s). """ def init(self, ui, parent, style): """Initialise the object. FIXME: Note that we treat MODAL and POPUP as equivalent until we have an example that demonstrates how POPUP is supposed to work. """ self.ui = ui self.control = ui.control view = ui.view history = ui.history if self.control is not None: if history is not None: history.on_trait_change(self._on_undoable, 'undoable', remove=True) history.on_trait_change(self._on_redoable, 'redoable', remove=True) history.on_trait_change(self._on_revertable, 'undoable', remove=True) ui.reset() else: self.create_dialog(parent, style) self.set_icon(view.icon) # Convert the buttons to actions. buttons = [self.coerce_button(button) for button in view.buttons] nr_buttons = len(buttons) no_buttons = ((nr_buttons == 1) and self.is_button(buttons[0], '')) has_buttons = ((not no_buttons) and ((nr_buttons > 0) or view.undo or view.revert or view.ok or view.cancel)) if has_buttons or (view.menubar is not None): if history is None: history = UndoHistory() else: history = None ui.history = history if (not no_buttons) and (has_buttons or view.help): bbox = QtGui.QDialogButtonBox() # Create the necessary special function buttons. if nr_buttons == 0: if view.undo: self.check_button(buttons, UndoButton) if view.revert: self.check_button(buttons, RevertButton) if view.ok: self.check_button(buttons, OKButton) if view.cancel: self.check_button(buttons, CancelButton) if view.help: self.check_button(buttons, HelpButton) for raw_button, button in zip(view.buttons, buttons): default = raw_button == view.default_button if self.is_button(button, 'Undo'): self.undo = self.add_button(button, bbox, QtGui.QDialogButtonBox.ActionRole, self._on_undo, False, default=default) history.on_trait_change(self._on_undoable, 'undoable', dispatch='ui') if history.can_undo: self._on_undoable(True) self.redo = self.add_button(button, bbox, QtGui.QDialogButtonBox.ActionRole, self._on_redo, False, 'Redo') history.on_trait_change(self._on_redoable, 'redoable', dispatch='ui') if history.can_redo: self._on_redoable(True) elif self.is_button(button, 'Revert'): self.revert = self.add_button(button, bbox, QtGui.QDialogButtonBox.ResetRole, self._on_revert, False, default=default) history.on_trait_change(self._on_revertable, 'undoable', dispatch='ui') if history.can_undo: self._on_revertable(True) elif self.is_button(button, 'OK'): self.ok = self.add_button(button, bbox, QtGui.QDialogButtonBox.AcceptRole, self.control.accept, default=default) ui.on_trait_change(self._on_error, 'errors', dispatch='ui') elif self.is_button(button, 'Cancel'): self.add_button(button, bbox, QtGui.QDialogButtonBox.RejectRole, self.control.reject, default=default) elif self.is_button(button, 'Help'): self.add_button(button, bbox, QtGui.QDialogButtonBox.HelpRole, self._on_help, default=default) elif not self.is_button(button, ''): self.add_button(button, bbox, QtGui.QDialogButtonBox.ActionRole, default=default) else: bbox = None self.add_contents(panel(ui), bbox) def close(self, rc=True): """Close the dialog and set the given return code. """ super(_LiveWindow, self).close(rc) self.undo = self.redo = self.revert = None def _on_finished(self, result): """Handles the user finishing with the dialog. """ accept = bool(result) if not accept and self.ui.history is not None: self._on_revert() self.close(accept) traitsui-4.1.0/traitsui/qt4/ui_panel.py0000644000175100001440000011712411674463546021111 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2007, Riverbank Computing Limited # All rights reserved. # # This software is provided without warranty under the terms of the BSD license. # However, when used with the GPL version of PyQt the additional terms described # in the PyQt GPL exception also apply. # # Author: Riverbank Computing Limited #------------------------------------------------------------------------------ """Creates a panel-based PyQt user interface for a specified UI object. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import cgi import re from pyface.qt import QtCore, QtGui from traits.api \ import Any, Instance, Undefined from traitsui.api \ import Group from traits.trait_base \ import enumerate from traitsui.undo \ import UndoHistory from traitsui.help_template \ import help_template from traitsui.menu \ import UndoButton, RevertButton, HelpButton from helper \ import position_window from constants \ import screen_dx, screen_dy, WindowColor from ui_base \ import BasePanel from editor \ import Editor #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- # Pattern of all digits all_digits = re.compile(r'\d+') #------------------------------------------------------------------------------- # Create the different panel-based PyQt user interfaces. #------------------------------------------------------------------------------- def ui_panel(ui, parent): """Creates a panel-based PyQt user interface for a specified UI object. """ _ui_panel_for(ui, parent, False) def ui_subpanel(ui, parent): """Creates a subpanel-based PyQt user interface for a specified UI object. A subpanel does not allow control buttons (other than those specified in the UI object) and does not show headers for view titles. """ _ui_panel_for(ui, parent, True) def _ui_panel_for(ui, parent, is_subpanel): """Creates a panel-based PyQt user interface for a specified UI object. """ ui.control = control = _Panel(ui, parent, is_subpanel).control control._parent = parent control._object = ui.context.get('object') control._ui = ui try: ui.prepare_ui() except: control.setParent(None) del control ui.control = None ui.result = False raise ui.restore_prefs() ui.result = True class _Panel(BasePanel): """PyQt user interface panel for Traits-based user interfaces. """ def __init__(self, ui, parent, is_subpanel): """Initialise the object. """ self.ui = ui history = ui.history view = ui.view # Reset any existing history listeners. if history is not None: history.on_trait_change(self._on_undoable, 'undoable', remove=True) history.on_trait_change(self._on_redoable, 'redoable', remove=True) history.on_trait_change(self._on_revertable, 'undoable', remove=True) # Determine if we need any buttons or an 'undo' history. buttons = [self.coerce_button(button) for button in view.buttons] nr_buttons = len(buttons) has_buttons = (not is_subpanel and (nr_buttons != 1 or not self.is_button(buttons[0], ''))) if nr_buttons == 0: if view.undo: self.check_button(buttons, UndoButton) if view.revert: self.check_button(buttons, RevertButton) if view.help: self.check_button(buttons, HelpButton) if not is_subpanel and history is None: for button in buttons: if self.is_button(button, 'Undo') or self.is_button(button, 'Revert'): history = ui.history = UndoHistory() break # Create the panel. self.control = panel(ui) # Suppress the title if this is a subpanel or if we think it should be # superceded by the title of an "outer" widget (eg. a dock widget). title = view.title if (is_subpanel or (isinstance(parent, QtGui.QMainWindow) and not isinstance(parent.parent(), QtGui.QDialog)) or isinstance(parent, QtGui.QTabWidget)): title = "" # Panels must be widgets as it is only the TraitsUI PyQt code that can # handle them being layouts as well. Therefore create a widget if the # panel is not a widget or if we need a title or buttons. if not isinstance(self.control, QtGui.QWidget) or title != "" or has_buttons: w = QtGui.QWidget() layout = QtGui.QVBoxLayout(w) layout.setContentsMargins(0, 0, 0, 0) # Handle any view title. if title != "": layout.addWidget(heading_text(None, text=view.title).control) if isinstance(self.control, QtGui.QWidget): layout.addWidget(self.control) elif isinstance(self.control, QtGui.QLayout): layout.addLayout(self.control) self.control = w # Add any buttons. if has_buttons: # Add the horizontal separator separator = QtGui.QFrame() separator.setFrameStyle(QtGui.QFrame.Sunken | QtGui.QFrame.HLine) separator.setFixedHeight(2) layout.addWidget(separator) # Add the special function buttons bbox = QtGui.QDialogButtonBox(QtCore.Qt.Horizontal) for button in buttons: role = QtGui.QDialogButtonBox.ActionRole if self.is_button(button, 'Undo'): self.undo = self.add_button(button, bbox, role, self._on_undo, False, 'Undo') self.redo = self.add_button(button, bbox, role, self._on_redo, False, 'Redo') history.on_trait_change(self._on_undoable, 'undoable', dispatch = 'ui') history.on_trait_change(self._on_redoable, 'redoable', dispatch = 'ui') elif self.is_button(button, 'Revert'): role = QtGui.QDialogButtonBox.ResetRole self.revert = self.add_button(button, bbox, role, self._on_revert, False) history.on_trait_change(self._on_revertable, 'undoable', dispatch = 'ui') elif self.is_button(button, 'Help'): role = QtGui.QDialogButtonBox.HelpRole self.add_button(button, bbox, role, self._on_help) elif not self.is_button(button, ''): self.add_button(button, bbox, role) layout.addWidget(bbox) # Ensure the control has a size hint reflecting the View specification. # Yes, this is a hack, but it's too late to repair this convoluted # control building process, so we do what we have to... self.control.sizeHint = _size_hint_wrapper(self.control.sizeHint, ui) def panel(ui): """Creates a panel-based PyQt user interface for a specified UI object. This function does not modify the UI object passed to it. The object returned may be either a widget, a layout or None. """ # Bind the context values to the 'info' object: ui.info.bind_context() # Get the content that will be displayed in the user interface: content = ui._groups nr_groups = len(content) if nr_groups == 0: panel = None if nr_groups == 1: panel = _GroupPanel(content[0], ui).control elif nr_groups > 1: panel = QtGui.QTabWidget() # Identify ourselves as being a Tabbed group so we can later # distinguish this from other QTabWidgets. panel.setProperty("traits_tabbed_group", True) _fill_panel(panel, content, ui) panel.ui = ui # If the UI is scrollable then wrap the panel in a scroll area. if ui.scrollable and panel is not None: # Make sure the panel is a widget. if isinstance(panel, QtGui.QLayout): w = QtGui.QWidget() w.setLayout(panel) panel = w sa = QtGui.QScrollArea() sa.setWidget(panel) sa.setWidgetResizable(True) panel = sa return panel def _fill_panel(panel, content, ui, item_handler=None): """Fill a page based container panel with content. """ active = 0 for index, item in enumerate(content): page_name = item.get_label(ui) if page_name == "": page_name = "Page %d" % index if isinstance(item, Group): if item.selected: active = index gp = _GroupPanel(item, ui, suppress_label=True) page = gp.control sub_page = gp.sub_control # If the result is the same type with only one page, collapse it # down into just the page. if type(sub_page) is type(panel) and sub_page.count() == 1: new = sub_page.widget(0) if isinstance(panel, QtGui.QTabWidget): sub_page.removeTab(0) else: sub_page.removeItem(0) elif isinstance(page, QtGui.QWidget): new = page else: new = QtGui.QWidget() new.setLayout(page) layout = new.layout() if layout is not None: layout.setAlignment(QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop) else: new = QtGui.QWidget() layout = QtGui.QVBoxLayout(new) layout.setContentsMargins(0, 0, 0, 0) item_handler(item, layout) # Add the content. if isinstance(panel, QtGui.QTabWidget): panel.addTab(new, page_name) else: panel.addItem(new, page_name) panel.setCurrentIndex(active) def _size_hint_wrapper(f, ui): """Wrap an existing sizeHint method with sizes from a UI object. """ def sizeHint(): size = f() if ui.view.width > 0: size.setWidth(ui.view.width) if ui.view.height > 0: size.setHeight(ui.view.height) return size return sizeHint #------------------------------------------------------------------------------- # Displays a help window for the specified UI's active Group: #------------------------------------------------------------------------------- def show_help ( ui, button ): """ Displays a help window for the specified UI's active Group. """ group = ui._groups[ ui._active_group ] template = help_template() if group.help != '': header = template.group_help % cgi.escape( group.help ) else: header = template.no_group_help fields = [] for item in group.get_content( False ): if not item.is_spacer(): fields.append( template.item_help % ( cgi.escape( item.get_label( ui ) ), cgi.escape( item.get_help( ui ) ) ) ) html = template.group_html % ( header, '\n'.join( fields ) ) HTMLHelpWindow( button, html, .25, .33 ) #------------------------------------------------------------------------------- # Displays a pop-up help window for a single trait: #------------------------------------------------------------------------------- def show_help_popup ( event ): """ Displays a pop-up help window for a single trait. """ control = event.GetEventObject() template = help_template() # Note: The following check is necessary because under Linux, we get back # a control which does not have the 'help' trait defined (it is the parent # of the object with the 'help' trait): help = getattr( control, 'help', None ) if help is not None: html = template.item_html % ( control.GetLabel(), help ) HTMLHelpWindow( control, html, .25, .13 ) class _GroupSplitter(QtGui.QSplitter): """ A splitter for a Traits UI Group with layout='split'. """ def __init__(self, group): """ Store the group. """ QtGui.QSplitter.__init__(self) self._group = group self._initialized = False def resizeEvent(self, event): """ Overridden to position the splitter based on the Group when the application is initializing. Because the splitter layout algorithm requires that the available space be known, we have to wait until the UI that contains this splitter gives it its initial size. """ QtGui.QSplitter.resizeEvent(self, event) parent = self.parent() if (not self._initialized and parent and (self.isVisible() or isinstance(parent, QtGui.QMainWindow))): self._initialized = True self._resize_items() def showEvent(self, event): """ Wait for the show event to resize items if necessary. """ QtGui.QSplitter.showEvent(self, event) if not self._initialized: self._initialized = True self._resize_items() def _resize_items(self): """ Size the splitter based on the 'width' or 'height' attributes of the Traits UI view elements. """ use_widths = (self.orientation() == QtCore.Qt.Horizontal) # Get the requested size for the items. sizes = [] for item in self._group.content: if use_widths: sizes.append(item.width) else: sizes.append(item.height) # Find out how much space is available. if use_widths: total = self.width() else: total = self.height() # Allocate requested space. avail = total remain = 0 for i, sz in enumerate(sizes): if avail <= 0: break if sz >= 0: if sz >= 1: sz = min(sz, avail) else: sz *= total sz = int(sz) sizes[i] = sz avail -= sz else: remain += 1 # Allocate the remainder to those parts that didn't request a width. if remain > 0: remain = int(avail / remain) for i, sz in enumerate(sizes): if sz < 0: sizes[i] = remain # If all requested a width, allocate the remainder to the last item. else: sizes[-1] += avail self.setSizes(sizes) class _GroupPanel(object): """A sub-panel for a single group of items. It may be either a layout or a widget. """ def __init__(self, group, ui, suppress_label=False): """Initialise the object. """ # Get the contents of the group: content = group.get_content() # Save these for other methods. self.group = group self.ui = ui if group.orientation == 'horizontal': self.direction = QtGui.QBoxLayout.LeftToRight else: self.direction = QtGui.QBoxLayout.TopToBottom # outer is the top-level widget or layout that will eventually be # returned. sub is the QTabWidget or QToolBox corresponding to any # 'tabbed' or 'fold' layout. It is only used to collapse nested # widgets. inner is the object (not necessarily a layout) that new # controls should be added to. outer = sub = inner = None # Get the group label. if suppress_label: label = "" else: label = group.label # Create a border if requested. if group.show_border: outer = QtGui.QGroupBox(label) inner = QtGui.QBoxLayout(self.direction, outer) elif label != "": outer = inner = QtGui.QBoxLayout(self.direction) inner.addWidget(heading_text(None, text=label).control) # Add the layout specific content. if len(content) == 0: pass elif group.layout == 'flow': raise NotImplementedError, "'the 'flow' layout isn't implemented" elif group.layout == 'split': # Create the splitter. splitter = _GroupSplitter(group) splitter.setOpaqueResize(False) # Mimic wx backend resize behavior if self.direction == QtGui.QBoxLayout.TopToBottom: splitter.setOrientation(QtCore.Qt.Vertical) # Make sure the splitter will expand to fill available space policy = splitter.sizePolicy() policy.setHorizontalStretch(50) policy.setVerticalStretch(50) if group.orientation == 'horizontal': policy.setVerticalPolicy(QtGui.QSizePolicy.Expanding) else: policy.setHorizontalPolicy(QtGui.QSizePolicy.Expanding) splitter.setSizePolicy(policy) if outer is None: outer = splitter else: inner.addWidget(splitter) # Create an editor. editor = SplitterGroupEditor(control=outer, splitter=splitter,ui=ui) self._setup_editor(group, editor) self._add_splitter_items(content, splitter) elif group.layout in ('tabbed', 'fold'): # Create the TabWidget or ToolBox. if group.layout == 'tabbed': sub = QtGui.QTabWidget() sub.setProperty("traits_tabbed_group", True) else: sub = QtGui.QToolBox() # Give tab/tool widget stretch factor equivalent to default stretch # factory for a resizeable item. See end of '_add_items'. policy = sub.sizePolicy() policy.setHorizontalStretch(50) policy.setVerticalStretch(50) sub.setSizePolicy(policy) _fill_panel(sub, content, self.ui, self._add_page_item) if outer is None: outer = sub else: inner.addWidget(sub) # Create an editor. editor = TabbedFoldGroupEditor(container=sub, control=outer, ui=ui) self._setup_editor(group, editor) else: # See if we need to control the visual appearence of the group. if group.visible_when != '' or group.enabled_when != '': # Make sure that outer is a widget or a layout. if outer is None: outer = inner = QtGui.QBoxLayout(self.direction) # Create an editor. self._setup_editor(group, GroupEditor(control=outer)) if isinstance(content[0], Group): layout = self._add_groups(content, inner) else: layout = self._add_items(content, inner) layout.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop) if outer is None: outer = layout elif layout is not inner: inner.addLayout(layout) if group.style_sheet : if isinstance(outer, QtGui.QLayout) : inner = outer outer = QtGui.QWidget() outer.setLayout(inner) # ensure this is not empty group if isinstance(outer, QtGui.QWidget) : outer.setStyleSheet(group.style_sheet) # Publish the top-level widget, layout or None. self.control = outer # Publish the optional sub-control. self.sub_control = sub def _add_splitter_items(self, content, splitter): """Adds a set of groups or items separated by splitter bars. """ for item in content: # Get a panel for the Item or Group. if isinstance(item, Group): panel = _GroupPanel(item, self.ui, suppress_label=True).control else: panel = self._add_items([item]) # Add the panel to the splitter. if panel is not None: if isinstance(panel, QtGui.QLayout): # A QSplitter needs a widget. w = QtGui.QWidget() panel.setContentsMargins(0, 0, 0, 0) w.setLayout(panel) panel = w layout = panel.layout() if layout is not None: layout.setAlignment(QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop) splitter.addWidget(panel) def _setup_editor(self, group, editor): """Setup the editor for a group. """ if group.id != '': self.ui.info.bind(group.id, editor) if group.visible_when != '': self.ui.add_visible(group.visible_when, editor) if group.enabled_when != '': self.ui.add_enabled(group.enabled_when, editor) def _add_page_item(self, item, layout): """Adds a single Item to a page based panel. """ self._add_items([item], layout) def _add_groups(self, content, outer): """Adds a list of Group objects to the panel, creating a layout if needed. Return the outermost layout. """ # Use the existing layout if there is one. if outer is None: outer = QtGui.QBoxLayout(self.direction) # Process each group. for subgroup in content: panel = _GroupPanel(subgroup, self.ui).control if isinstance(panel, QtGui.QWidget): outer.addWidget(panel) elif isinstance(panel, QtGui.QLayout): outer.addLayout(panel) else: # The sub-group is empty which seems to be used as a way of # providing some whitespace. outer.addWidget(QtGui.QLabel(' ')) return outer def _add_items(self, content, outer=None): """Adds a list of Item objects, creating a layout if needed. Return the outermost layout. """ # Get local references to various objects we need: ui = self.ui info = ui.info handler = ui.handler group = self.group show_left = group.show_left padding = group.padding columns = group.columns # See if a label is needed. show_labels = False for item in content: show_labels |= item.show_label # See if a grid layout is needed. if show_labels or columns > 1: inner = QtGui.QGridLayout() if outer is None: outer = inner else: outer.addLayout(inner) row = 0 if show_left: label_alignment = QtCore.Qt.AlignRight else: label_alignment = QtCore.Qt.AlignLeft else: # Use the existing layout if there is one. if outer is None: outer = QtGui.QBoxLayout(self.direction) inner = outer row = -1 label_alignment = 0 # Process each Item in the list: col = -1 for item in content: # Keep a track of the current logical row and column unless the # layout is not a grid. col += 1 if row >= 0 and col >= columns: col = 0 row += 1 # Get the name in order to determine its type: name = item.name # Check if is a label: if name == '': label = item.label if label != "": # Create the label widget. if item.style == 'simple': label = QtGui.QLabel(label) else: label = heading_text(None, text=label).control self._add_widget(inner, label, row, col, show_labels) if item.emphasized: self._add_emphasis(label) # Continue on to the next Item in the list: continue # Check if it is a separator: if name == '_': cols = columns # See if the layout is a grid. if row >= 0: # Move to the start of the next row if necessary. if col > 0: col = 0 row += 1 # Skip the row we are about to do. row += 1 # Allow for the columns. if show_labels: cols *= 2 for i in range(cols): line = QtGui.QFrame() if self.direction == QtGui.QBoxLayout.LeftToRight: # Add a vertical separator: line.setFrameShape(QtGui.QFrame.VLine) if row < 0: inner.addWidget(line) else: inner.addWidget(line, i, row) else: # Add a horizontal separator: line.setFrameShape(QtGui.QFrame.HLine) if row < 0: inner.addWidget(line) else: inner.addWidget(line, row, i) line.setFrameShadow(QtGui.QFrame.Sunken) # Continue on to the next Item in the list: continue # Convert a blank to a 5 pixel spacer: if name == ' ': name = '5' # Check if it is a spacer: if all_digits.match( name ): # If so, add the appropriate amount of space to the layout: n = int( name ) if self.direction == QtGui.QBoxLayout.LeftToRight: # Add a horizontal spacer: spacer = QtGui.QSpacerItem(n, 1) else: # Add a vertical spacer: spacer = QtGui.QSpacerItem(1, n) self._add_widget(inner, spacer, row, col, show_labels) # Continue on to the next Item in the list: continue # Otherwise, it must be a trait Item: object = eval( item.object_, globals(), ui.context ) trait = object.base_trait( name ) desc = trait.desc or '' fixed_width = False # Handle any label. if item.show_label: label = self._create_label(item, ui, desc) self._add_widget(inner, label, row, col, show_labels, label_alignment) else: label = None # Get the editor factory associated with the Item: editor_factory = item.editor if editor_factory is None: editor_factory = trait.get_editor().set(**item.editor_args) # If still no editor factory found, use a default text editor: if editor_factory is None: from text_editor import ToolkitEditorFactory editor_factory = ToolkitEditorFactory() # If the item has formatting traits set them in the editor # factory: if item.format_func is not None: editor_factory.format_func = item.format_func if item.format_str != '': editor_factory.format_str = item.format_str # If the item has an invalid state extended trait name, set it # in the editor factory: if item.invalid != '': editor_factory.invalid = item.invalid # Create the requested type of editor from the editor factory: factory_method = getattr( editor_factory, item.style + '_editor' ) editor = factory_method( ui, object, name, item.tooltip, None).set( item = item, object_name = item.object ) # Tell the editor to actually build the editing widget. Note that # "inner" is a layout. This shouldn't matter as individual editors # shouldn't be using it as a parent anyway. The important thing is # that it is not None (otherwise the main TraitsUI code can change # the "kind" of the created UI object). editor.prepare(inner) control = editor.control if item.style_sheet : control.setStyleSheet(item.style_sheet) # Set the initial 'enabled' state of the editor from the factory: editor.enabled = editor_factory.enabled # Add emphasis to the editor control if requested: if item.emphasized: self._add_emphasis(control) # Give the editor focus if it requested it: if item.has_focus: control.setFocus() # Set the correct size on the control, as specified by the user: stretch = 0 scrollable = editor.scrollable item_width = item.width item_height = item.height if (item_width != -1) or (item_height != -1): is_horizontal = (self.direction == QtGui.QBoxLayout.LeftToRight) min_size = control.minimumSizeHint() width = min_size.width() height = min_size.height() force_width = False force_height = False if (0.0 < item_width <= 1.0) and is_horizontal: stretch = int(100 * item_width) item_width = int(item_width) if item_width < -1: item_width = -item_width force_width = True else: item_width = max(item_width, width) if (0.0 < item_height <= 1.0) and (not is_horizontal): stretch = int(100 * item_height) item_height = int(item_height) if item_height < -1: item_height = -item_height force_height = True else: item_height = max(item_height, height) control.setMinimumWidth(max(item_width, 0)) control.setMinimumHeight(max(item_height, 0)) if (stretch == 0 or not is_horizontal) and force_width : control.setMaximumWidth(item_width) if (stretch == 0 or is_horizontal) and force_height : control.setMaximumHeight(item_height) # Bind the editor into the UIInfo object name space so it can be # referred to by a Handler while the user interface is active: id = item.id or name info.bind( id, editor, item.id ) # Also, add the editors to the list of editors used to construct # the user interface: ui._editors.append( editor ) # If the handler wants to be notified when the editor is created, # add it to the list of methods to be called when the UI is # complete: defined = getattr( handler, id + '_defined', None ) if defined is not None: ui.add_defined( defined ) # If the editor is conditionally visible, add the visibility # 'expression' and the editor to the UI object's list of monitored # objects: if item.visible_when != '': ui.add_visible( item.visible_when, editor ) # If the editor is conditionally enabled, add the enabling # 'expression' and the editor to the UI object's list of monitored # objects: if item.enabled_when != '': ui.add_enabled( item.enabled_when, editor ) # Add the created editor control to the layout with the appropriate # size and stretch policies: ui._scrollable |= scrollable item_resizable = ((item.resizable is True) or ((item.resizable is Undefined) and scrollable)) if item_resizable: stretch = stretch or 50 self.resizable = True elif item.springy: stretch = stretch or 50 editor.set_size_policy(self.direction, item_resizable, item.springy, stretch) # FIXME: Need to decide what to do about border_size and padding self._add_widget(inner, control, row, col, show_labels) # Save the reference to the label control (if any) in the editor: editor.label_control = label return outer def _add_widget(self, layout, w, row, column, show_labels, label_alignment=QtCore.Qt.AlignmentFlag(0)): """Adds a widget to a layout taking into account the orientation and the position of any labels. """ # If the widget really is a widget then remove any margin so that it # fills the cell. if isinstance(w, QtGui.QWidget): wl = w.layout() if wl is not None: wl.setContentsMargins(0, 0, 0, 0) # See if the layout is a grid. if row < 0: if isinstance(w, QtGui.QWidget): layout.addWidget(w) elif isinstance(w, QtGui.QLayout): layout.addLayout(w) else: layout.addItem(w) else: if self.direction == QtGui.QBoxLayout.LeftToRight: # Flip the row and column. row, column = column, row if show_labels: # Convert the "logical" column to a "physical" one. column *= 2 # Determine whether to place widget on left or right of # "logical" column. if (label_alignment != 0 and not self.group.show_left) or \ (label_alignment == 0 and self.group.show_left): column += 1 if isinstance(w, QtGui.QWidget): layout.addWidget(w, row, column, label_alignment) elif isinstance(w, QtGui.QLayout): layout.addLayout(w, row, column, label_alignment) else: layout.addItem(w, row, column, 1, 1, label_alignment) def _create_label(self, item, ui, desc, suffix = ':'): """Creates an item label. """ label = item.get_label(ui) if (label == '') or (label[-1:] in '?=:;,.<>/\\"\'-+#|'): suffix = '' control = QtGui.QLabel(label + suffix) if item.emphasized: self._add_emphasis(control) # FIXME: Decide what to do about the help. (The non-standard wx way, # What's This style help, both?) #wx.EVT_LEFT_UP( control, show_help_popup ) control.help = item.get_help(ui) if desc != '': control.setToolTip('Specifies ' + desc) return control def _add_emphasis(self, control): """Adds emphasis to a specified control's font. """ # Set the foreground colour. pal = QtGui.QPalette(control.palette()) pal.setColor(QtGui.QPalette.WindowText, QtGui.QColor(0, 0, 127)) control.setPalette(pal) # Set the font. font = QtGui.QFont(control.font()) font.setBold(True) font.setPointSize(font.pointSize()) control.setFont(font) class GroupEditor(Editor): """ A pseudo-editor that allows a group to be managed. """ def __init__(self, **traits): """ Initialise the object. """ self.set(**traits) class SplitterGroupEditor(GroupEditor): """ A pseudo-editor that allows a group with a 'split' layout to be managed. """ # The QSplitter for the group splitter = Instance(_GroupSplitter) #-- UI preference save/restore interface ----------------------------------- def restore_prefs(self, prefs): """ Restores any saved user preference information associated with the editor. """ if isinstance(prefs, dict): structure = prefs.get('structure') else: structure = prefs self.splitter._resized = True self.splitter.restoreState(structure) def save_prefs(self): """ Returns any user preference information associated with the editor. """ return { 'structure': str(self.splitter.saveState()) } class TabbedFoldGroupEditor(GroupEditor): """ A pseudo-editor that allows a group with a 'tabbed' or 'fold' layout to be managed. """ # The QTabWidget or QToolBox for the group container = Any #-- UI preference save/restore interface ----------------------------------- def restore_prefs(self, prefs): """ Restores any saved user preference information associated with the editor. """ if isinstance(prefs, dict): current_index = prefs.get('current_index') else: current_index = prefs self.container.setCurrentIndex(int(current_index)) def save_prefs(self): """ Returns any user preference information associated with the editor. """ return { 'current_index': str(self.container.currentIndex()) } #------------------------------------------------------------------------------- # 'HTMLHelpWindow' class: #------------------------------------------------------------------------------- class HTMLHelpWindow ( QtGui.QDialog ): """ Window for displaying Traits-based help text with HTML formatting. """ #--------------------------------------------------------------------------- # Initializes the object: #--------------------------------------------------------------------------- def __init__ ( self, parent, html, scale_dx, scale_dy ): """ Initializes the object. """ # Local import to avoid a WebKit dependency when one isn't needed. from pyface.qt import QtWebKit QtGui.QDialog.__init__(self, parent) layout = QtGui.QVBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) # Create the html control html_control = QtWebKit.QWebView() html_control.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) html_control.setHtml(html) layout.addWidget(html_control) # Create the OK button bbox = QtGui.QDialogButtonBox(QtGui.QDialogButtonBox.Ok, QtCore.Qt.Horizontal) QtCore.QObject.connect(bbox, QtCore.SIGNAL('accepted()'), self, QtCore.SLOT('accept()')) layout.addWidget(bbox) # Position and show the dialog position_window(self, parent=parent) self.show() #------------------------------------------------------------------------------- # Creates a PyFace HeadingText control: #------------------------------------------------------------------------------- HeadingText = None def heading_text(*args, **kw): """Create a PyFace HeadingText control. """ global HeadingText if HeadingText is None: from pyface.api import HeadingText return HeadingText(*args, **kw) traitsui-4.1.0/traitsui/qt4/list_str_editor.py0000644000175100001440000004741011674463546022526 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2009, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: Evan Patterson # Date: 08/05/2009 # #------------------------------------------------------------------------------- """ Traits UI editor for editing lists of strings. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from pyface.qt import QtCore, QtGui import collections from pyface.image_resource import ImageResource from traits.api import Any, Bool, Event, Int, Instance, List, \ Property, Str, TraitListEvent, NO_COMPARE from traitsui.list_str_adapter import ListStrAdapter from editor import Editor from list_str_model import ListStrModel from traitsui.menu import Menu #------------------------------------------------------------------------------- # '_ListStrEditor' class: #------------------------------------------------------------------------------- class _ListStrEditor(Editor): """ Traits UI editor for editing lists of strings. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # The list view control associated with the editor: list_view = Any # The list model associated the editor: model = Instance(ListStrModel) # The title of the editor: title = Str # The current set of selected items (which one is used depends upon the # initial state of the editor factory 'multi_select' trait): selected = Any multi_selected = List # The current set of selected item indices (which one is used depends upon # the initial state of the editor factory 'multi_select' trait): selected_index = Int(-1) multi_selected_indices = List(Int) # The most recently actived item and its index. # Always trigger change notification. activated = Any(comparison_mode=NO_COMPARE) activated_index = Int(comparison_mode=NO_COMPARE) # The most recently right_clicked item and its index: right_clicked = Event right_clicked_index = Event # Is the list editor scrollable? This value overrides the default. scrollable = True # Should the selected item be edited after rebuilding the editor list: edit = Bool(False) # The adapter from list items to editor values: adapter = Instance( ListStrAdapter ) # Dictionary mapping image names to QIcons images = Any({}) # Dictionary mapping ImageResource objects to QIcons image_resources = Any({}) # The current number of item currently in the list: item_count = Property # The current search string: search = Str #--------------------------------------------------------------------------- # Editor interface: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ factory = self.factory # Set up the adapter to use: self.adapter = factory.adapter self.sync_value(factory.adapter_name, 'adapter', 'from') # Create the list model and accompanying controls: self.model = ListStrModel(editor=self) self.control = QtGui.QWidget() layout = QtGui.QVBoxLayout(self.control) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) if factory.title or factory.title_name: header_view = QtGui.QHeaderView(QtCore.Qt.Horizontal, self.control) header_view.setModel(self.model) header_view.setMaximumHeight(header_view.sizeHint().height()) header_view.setResizeMode(QtGui.QHeaderView.Stretch) layout.addWidget(header_view) self.list_view = _ListView(self) layout.addWidget(self.list_view) # Set up the list control's event handlers: if factory.multi_select: slot = self._on_rows_selection else: slot = self._on_row_selection signal = 'selectionChanged(QItemSelection,QItemSelection)' QtCore.QObject.connect(self.list_view.selectionModel(), QtCore.SIGNAL(signal), slot) signal = QtCore.SIGNAL('activated(QModelIndex)') QtCore.QObject.connect(self.list_view, signal, self._on_activate) signal = QtCore.SIGNAL('customContextMenuRequested(QPoint)') QtCore.QObject.connect(self.list_view, signal, self._on_context_menu) # Initialize the editor title: self.title = factory.title self.sync_value(factory.title_name, 'title', 'from') # Set up the selection listener if factory.multi_select: self.sync_value(factory.selected, 'multi_selected', 'both', is_list=True) self.sync_value(factory.selected_index, 'multi_selected_indices', 'both', is_list=True) else: self.sync_value(factory.selected, 'selected', 'both') self.sync_value(factory.selected_index, 'selected_index', 'both') # Synchronize other interesting traits as necessary: self.sync_value(factory.activated, 'activated', 'to') self.sync_value(factory.activated_index, 'activated_index', 'to') self.sync_value(factory.right_clicked, 'right_clicked', 'to') self.sync_value(factory.right_clicked_index, 'right_clicked_index', 'to') # Make sure we listen for 'items' changes as well as complete list # replacements: self.context_object.on_trait_change( self.update_editor, self.extended_name + '_items', dispatch='ui') # Create the mapping from user supplied images to QIcons: for image_resource in factory.images: self._add_image(image_resource) # Refresh the editor whenever the adapter changes: self.on_trait_change( self.refresh_editor, 'adapter.+update', dispatch='ui') # Set the list control's tooltip: self.set_tooltip() def dispose(self): """ Disposes of the contents of an editor. """ self.context_object.on_trait_change( self.update_editor, self.extended_name + '_items', remove=True) self.on_trait_change( self.refresh_editor, 'adapter.+update', remove=True) def update_editor(self): """ Updates the editor when the object trait changes externally to the editor. """ if not self._no_update: self.model.reset() # restore selection back if self.factory.multi_select : self._multi_selected_changed(self.multi_selected) else : self._selected_changed(self.selected) #--------------------------------------------------------------------------- # ListStrEditor interface: #--------------------------------------------------------------------------- def refresh_editor(self): """ Requests that the underlying list widget to redraw itself. """ self.list_view.viewport().update() def callx(self, func, *args, **kw): """ Call a function without allowing the editor to update. """ old = self._no_update self._no_update = True try: func(*args, **kw) finally: self._no_update = old def setx(self, **keywords): """ Set one or more attributes without allowing the editor to update. """ old = self._no_notify self._no_notify = True try: for name, value in keywords.items(): setattr(self, name, value) finally: self._no_notify = old def get_image(self, image): """ Converts a user specified image to a QIcon. """ if isinstance(image, ImageResource): result = self.image_resources.get(image) if result is not None: return result return self._add_image(image) return self.images.get(image) def is_auto_add(self, index): """ Returns whether or not the index is the special 'auto add' item at the end of the list. """ return (self.factory.auto_add and (index >= self.adapter.len(self.object, self.name))) #--------------------------------------------------------------------------- # Private interface: #--------------------------------------------------------------------------- def _add_image(self, image_resource): """ Adds a new image to the image map. """ image = image_resource.create_icon() self.image_resources[image_resource] = image self.images[image_resource.name] = image return image #-- Property Implementations ----------------------------------------------- def _get_item_count ( self ): return (self.model.rowCount(None) - self.factory.auto_add) #-- Trait Event Handlers --------------------------------------------------- def _selected_changed(self, selected): """ Handles the editor's 'selected' trait being changed. """ if not self._no_update: try: selected_index = self.value.index(selected) except ValueError: pass else: self._selected_index_changed(selected_index) def _selected_index_changed(self, selected_index): """ Handles the editor's 'selected_index' trait being changed. """ if not self._no_update: smodel = self.list_view.selectionModel() if selected_index == -1: smodel.clearSelection() else: mi = self.model.index(selected_index) smodel.select(mi, QtGui.QItemSelectionModel.ClearAndSelect) self.list_view.scrollTo(mi) def _multi_selected_changed(self, selected): """ Handles the editor's 'multi_selected' trait being changed. """ if not self._no_update: indices = [] for item in selected : try: indices.append(self.value.index(item)) except ValueError: pass self._multi_selected_indices_changed(indices) def _multi_selected_items_changed(self, event): """ Handles the editor's 'multi_selected' trait being modified. """ if not self._no_update: try: added = [ values.index(item) for item in event.added ] removed = [ values.index(item) for item in event.removed ] except ValueError: pass else: event = TraitListEvent(0, added, removed) self._multi_selected_indices_items_changed(event) def _multi_selected_indices_changed(self, selected_indices): """ Handles the editor's 'multi_selected_indices' trait being changed. """ if not self._no_update: smodel = self.list_view.selectionModel() smodel.clearSelection() for selected_index in selected_indices: smodel.select(self.model.index(selected_index), QtGui.QItemSelectionModel.Select) if selected_indices: self.list_view.scrollTo(self.model.index(selected_indices[-1])) def _multi_selected_indices_items_changed(self, event): """ Handles the editor's 'multi_selected_indices' trait being modified. """ if not self._no_update: smodel = self.list_view.selectionModel() for selected_index in event.removed: smodel.select(self.model.index(selected_index), QtGui.QItemSelectionModel.Deselect) for selected_index in event.added: smodel.select(self.model.index(selected_index), QtGui.QItemSelectionModel.Select) #-- List Control Event Handlers -------------------------------------------- def _on_activate(self, mi): """ Handle a cell being activated. """ self.activated_index = index = mi.row() self.activated = self.adapter.get_item(self.object, self.name, index) def _on_context_menu(self, point): """ Handle a context menu request. """ mi = self.list_view.indexAt(point) if mi.isValid(): self.right_clicked_index = index = mi.row() self.right_clicked = self.adapter.get_item( self.object, self.name, index) def _on_row_selection(self, added, removed): """ Handle the row selection being changed. """ self._no_update = True try: indices = self.list_view.selectionModel().selectedRows() if len(indices): self.selected_index = indices[0].row() self.selected = self.adapter.get_item(self.object, self.name, self.selected_index) else: self.selected_index = -1 self.selected = None finally: self._no_update = False def _on_rows_selection(self, added, removed): """ Handle the rows selection being changed. """ self._no_update = True try: indices = self.list_view.selectionModel().selectedRows() self.multi_selected_indices = indices = [ i.row() for i in indices ] self.multi_selected = [ self.adapter.get_item(self.object, self.name, i) for i in self.multi_selected_indices ] finally: self._no_update = False def _on_context_menu(self, pos) : menu = self.factory.menu index = self.list_view.indexAt(pos).row() if isinstance(menu, str) : menu = getattr(self.object, menu, None) if isinstance(menu, collections.Callable) : menu = menu(index) if menu is not None : qmenu = menu.create_menu( self.list_view, self ) self._menu_context = {'selection': self.object, 'object': self.object, 'editor': self, 'index': index, 'info': self.ui.info, 'handler': self.ui.handler } qmenu.exec_(self.list_view.mapToGlobal(pos)) self._menu_context = None #------------------------------------------------------------------------------- # Qt widgets that have been configured to behave as expected by Traits UI: #------------------------------------------------------------------------------- class _ItemDelegate(QtGui.QStyledItemDelegate): """ A QStyledItemDelegate which optionally draws horizontal gridlines. (QListView does not support gridlines). """ def __init__(self, editor, parent=None): """ Save the editor """ QtGui.QStyledItemDelegate.__init__(self, parent) self._editor = editor def paint(self, painter, option, index): """ Overrident to draw gridlines. """ QtGui.QStyledItemDelegate.paint(self, painter, option, index) if self._editor.factory.horizontal_lines: painter.save() painter.setPen(option.palette.color(QtGui.QPalette.Dark)) painter.drawLine(option.rect.bottomLeft(),option.rect.bottomRight()) painter.restore() class _ListView(QtGui.QListView): """ A QListView configured to behave as expected by TraitsUI. """ def __init__(self, editor): """ Initialise the object. """ QtGui.QListView.__init__(self) self._editor = editor self.setItemDelegate(_ItemDelegate(editor, self)) self.setModel(editor.model) factory = editor.factory # Configure the selection behavior if factory.multi_select: mode = QtGui.QAbstractItemView.ExtendedSelection else: mode = QtGui.QAbstractItemView.SingleSelection self.setSelectionMode(mode) # Configure drag and drop behavior self.setDragEnabled(True) self.setDragDropOverwriteMode(True) self.setDragDropMode(QtGui.QAbstractItemView.InternalMove) self.setDropIndicatorShown(True) if editor.factory.menu is False : self.setContextMenuPolicy(QtCore.Qt.NoContextMenu) elif editor.factory.menu is not False : self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.connect(self, QtCore.SIGNAL('customContextMenuRequested(QPoint)'), editor._on_context_menu) # Configure context menu behavior self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) def keyPressEvent(self, event): """ Reimplemented to support edit, insert, and delete by keyboard. """ editor = self._editor factory = editor.factory # Note that setting 'EditKeyPressed' as an edit trigger does not work on # most platforms, which is why we do this here. if (event.key() in (QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return) and self.state() != QtGui.QAbstractItemView.EditingState and factory.editable and 'edit' in factory.operations): if factory.multi_select: indices = editor.multi_selected_indices row = indices[0] if len(indices) == 1 else -1 else: row = editor.selected_index if row != -1: event.accept() self.edit(editor.model.index(row)) elif (event.key() in (QtCore.Qt.Key_Backspace, QtCore.Qt.Key_Delete) and factory.editable and 'delete' in factory.operations): event.accept() if factory.multi_select: for row in reversed(sorted(editor.multi_selected_indices)): editor.model.removeRow(row) elif editor.selected_index != -1: # Deleting the selected item will reset cause the ListView's # selection model to select the next item before removing the # originally selected rows. Visually, this looks fine because # the next item is then placed where the deleted item used to # be. However, some internal state is kept which makes the # selected item seem off by one. So we'll reset it manually # here. row = editor.selected_index editor.model.removeRow(row) # Handle the case of deleting the last item in the list. editor.selected_index = min( row, editor.adapter.len(editor.object, editor.name) - 1) elif (event.key() == QtCore.Qt.Key_Insert and factory.editable and 'insert' in factory.operations): event.accept() if factory.multi_select: indices = sorted(editor.multi_selected_indices) row = indices[0] if len(indices) else -1 else: row = editor.selected_index if row == -1: row = editor.adapter.len(editor.object, editor.name) editor.model.insertRow(row) self.setCurrentIndex(editor.model.index(row)) else: QtGui.QListView.keyPressEvent(self, event) traitsui-4.1.0/traitsui/qt4/directory_editor.py0000644000175100001440000000540511674463546022665 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2007, Riverbank Computing Limited # All rights reserved. # # This software is provided without warranty under the terms of the BSD license. # However, when used with the GPL version of PyQt the additional terms described in the PyQt GPL exception also apply # # Author: Riverbank Computing Limited #------------------------------------------------------------------------------ """ Defines various directory editor for the PyQt user interface toolkit. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from pyface.qt import QtGui # FIXME: ToolkitEditorFactory is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.custom_editor file. from traitsui.editors.directory_editor \ import ToolkitEditorFactory from file_editor \ import SimpleEditor as SimpleFileEditor, \ CustomEditor as CustomFileEditor #------------------------------------------------------------------------------- # 'SimpleEditor' class: #------------------------------------------------------------------------------- class SimpleEditor ( SimpleFileEditor ): """ Simple style of editor for directories, which displays a text field and a **Browse** button that opens a directory-selection dialog box. """ #--------------------------------------------------------------------------- # Creates the correct type of file dialog: #--------------------------------------------------------------------------- def _create_file_dialog ( self ): """ Creates the correct type of file dialog. """ dlg = QtGui.QFileDialog(self.control) dlg.selectFile(self._file_name.text()) dlg.setFileMode(QtGui.QFileDialog.Directory) dlg.setOptions(QtGui.QFileDialog.ShowDirsOnly) return dlg #------------------------------------------------------------------------------- # 'CustomEditor' class: #------------------------------------------------------------------------------- class CustomEditor ( CustomFileEditor ): """ Custom style of editor for directories, which displays a tree view of the file system. """ #--------------------------------------------------------------------------- # Handles the user changing the contents of the edit control: #--------------------------------------------------------------------------- def update_object(self, idx): """ Handles the user changing the contents of the edit control. """ if self._model.isDir(idx): self.value = unicode(self._model.filePath(idx)) traitsui-4.1.0/traitsui/qt4/font_trait.py0000644000175100001440000001607111674463546021465 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2007, Riverbank Computing Limited # All rights reserved. # # This software is provided without warranty under the terms of the BSD license. # However, when used with the GPL version of PyQt the additional terms described in the PyQt GPL exception also apply # # Author: Riverbank Computing Limited #------------------------------------------------------------------------------ """ Trait definition for a PyQt-based font. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from pyface.qt import QtGui from traits.api \ import Trait, TraitHandler, TraitError #------------------------------------------------------------------------------- # Convert a string into a valid QFont object (if possible): #------------------------------------------------------------------------------- # Mapping of strings to valid QFont style hints. font_families = { 'default': QtGui.QFont.AnyStyle, 'decorative': QtGui.QFont.Decorative, 'roman': QtGui.QFont.Serif, 'script': QtGui.QFont.SansSerif, 'swiss': QtGui.QFont.SansSerif, 'modern': QtGui.QFont.TypeWriter } # Mapping of strings to QFont styles. font_styles = { 'slant': QtGui.QFont.StyleOblique, 'italic': QtGui.QFont.StyleItalic } # Mapping of strings to QFont weights. font_weights = { 'light': QtGui.QFont.Light, 'bold': QtGui.QFont.Bold } # Strings to ignore in text representations of fonts font_noise = [ 'pt', 'point', 'family' ] #------------------------------------------------------------------------------- # Converts a QFont into a string description of itself: #------------------------------------------------------------------------------- def font_to_str ( font ): """ Converts a QFont into a string description of itself. """ weight = { QtGui.QFont.Light: ' Light', QtGui.QFont.Bold: ' Bold' }.get(font.weight(), '') style = { QtGui.QFont.StyleOblique: ' Slant', QtGui.QFont.StyleItalic: ' Italic' }.get(font.style(), '') underline = '' if font.underline(): underline = ' underline' return '%s point %s%s%s%s' % ( font.pointSize(), unicode(font.family()), style, weight, underline ) #------------------------------------------------------------------------------- # Create a TraitFont object from a string description: #------------------------------------------------------------------------------- def create_traitsfont(value): """ Create a TraitFont object from a string description. """ if isinstance(value, QtGui.QFont): return TraitsFont(value) point_size = None family = '' style = QtGui.QFont.StyleNormal weight = QtGui.QFont.Normal underline = False facename = [] for word in value.split(): lword = word.lower() if font_families.has_key(lword): f = QtGui.QFont() f.setStyleHint(font_families[lword]) family = f.defaultFamily() elif font_styles.has_key(lword): style = font_styles[lword] elif font_weights.has_key(lword): weight = font_weights[lword] elif lword == 'underline': underline = True elif lword not in font_noise: if point_size is None: try: point_size = int(lword) continue except: pass facename.append(word) if facename: family = ' '.join(facename) if family: fnt = TraitsFont(family) else: fnt = TraitsFont() fnt.setStyle(style) fnt.setWeight(weight) fnt.setUnderline(underline) if point_size is None: fnt.setPointSize(QtGui.QApplication.font().pointSize()) else: fnt.setPointSize(point_size) return fnt #------------------------------------------------------------------------------- # 'TraitsFont' class: #------------------------------------------------------------------------------- class TraitsFont(QtGui.QFont): """ A Traits-specific QFont. """ #--------------------------------------------------------------------------- # Returns the pickleable form of a TraitsFont object: #--------------------------------------------------------------------------- def __reduce_ex__(self, protocol): """ Returns the pickleable form of a TraitsFont object. """ return (create_traitsfont, (font_to_str(self), )) #--------------------------------------------------------------------------- # Returns a printable form of the font: #--------------------------------------------------------------------------- def __str__(self): """ Returns a printable form of the font. """ return font_to_str(self) #------------------------------------------------------------------------------- # 'TraitPyQtFont' class' #------------------------------------------------------------------------------- class TraitPyQtFont ( TraitHandler ): """ Ensures that values assigned to a trait attribute are valid font descriptor strings; the value actually assigned is the corresponding TraitsFont. """ #--------------------------------------------------------------------------- # Validates that the value is a valid font: #--------------------------------------------------------------------------- def validate ( self, object, name, value ): """ Validates that the value is a valid font descriptor string. If so, it returns the corresponding TraitsFont; otherwise, it raises a TraitError. """ if value is None: return None try: return create_traitsfont( value ) except: pass raise TraitError, ( object, name, 'a font descriptor string', repr( value ) ) def info ( self ): return ( "a string describing a font (e.g. '12 pt bold italic " "swiss family Arial' or 'default 12')" ) #------------------------------------------------------------------------------- # Callable that returns an instance of the PyQtToolkitEditorFactory for font # editors. #------------------------------------------------------------------------------- ### FIXME: We have declared the 'editor' to be a function instead of the # traitsui.qt4.font_editor.ToolkitEditorFactory class, since the # latter is leading to too many circular imports. In the future, try to see if # there is a better way to do this. def get_font_editor(*args, **traits): from traitsui.qt4.font_editor import ToolkitEditorFactory return ToolkitEditorFactory(*args, **traits) #------------------------------------------------------------------------------- # Define a PyQt specific font trait: #------------------------------------------------------------------------------- PyQtFont = Trait(TraitsFont(), TraitPyQtFont(), editor = get_font_editor) traitsui-4.1.0/traitsui/qt4/rgb_color_trait.py0000644000175100001440000000726511674463546022474 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2009, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # #------------------------------------------------------------------------------ """ Trait definition for an RGB-based color, which is a tuple of the form (*red*, *green*, *blue*), where *red*, *green* and *blue* are floats in the range from 0.0 to 1.0. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from traits.api import Trait, TraitError from traits.trait_base import SequenceTypes from traitsui.qt4.color_trait import standard_colors #------------------------------------------------------------------------------- # Convert a number into an RGB tuple: #------------------------------------------------------------------------------- def range_check(value): """ Checks that *value* can be converted to a value in the range 0.0 to 1.0. If so, it returns the floating point value; otherwise, it raises a TraitError. """ value = float(value) if 0.0 <= value <= 1.0: return value raise TraitError def convert_to_color(object, name, value): """ Converts a tuple or an integer to an RGB color value, or raises a TraitError if that is not possible. """ if isinstance(value, SequenceTypes) and len(value) == 3: return (range_check(value[0]), range_check(value[1]), range_check(value[2])) if isinstance(value, int): return ((value / 0x10000) / 255.0, ((value / 0x100) & 0xFF) / 255.0, (value & 0xFF) / 255.0) raise TraitError convert_to_color.info = ('a tuple of the form (r,g,b), where r, g, and b ' 'are floats in the range from 0.0 to 1.0, or an integer which in hex is of ' 'the form 0xRRGGBB, where RR is red, GG is green, and BB is blue') #------------------------------------------------------------------------------- # Standard colors: #------------------------------------------------------------------------------- # RGB versions of standard colors: rgb_standard_colors = {} for name, color in standard_colors.items(): rgb_standard_colors[name] = (color.redF(), color.greenF(), color.blueF()) #------------------------------------------------------------------------------- # Define wxPython specific color traits: #------------------------------------------------------------------------------- ### Note: Declare the editor to be a function which returns the RGBColorEditor # class from traits ui to avoid circular import issues. For backwards # compatibility with previous Traits versions, the 'editors' folder in Traits # project declares 'from api import *' in its __init__.py. The 'api' in turn # can contain classes that have a RGBColor trait which lead to this file getting # imported. This will lead to a circular import when declaring a RGBColor trait. def get_rgb_color_editor(*args, **traits): from rgb_color_editor import ToolkitEditorFactory return ToolkitEditorFactory(*args, **traits) # Trait whose value must be an RGB color: RGBColor = Trait('white', convert_to_color, rgb_standard_colors, editor=get_rgb_color_editor) traitsui-4.1.0/traitsui/qt4/time_editor.py0000644000175100001440000000676711674463546021633 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2009, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: Evan Patterson # Date: 08/04/2009 # #------------------------------------------------------------------------------ """ A Traits UI editor for datetime.time objects. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import datetime from pyface.qt import QtCore, QtGui from editor import Editor from editor_factory import ReadonlyEditor as BaseReadonlyEditor #------------------------------------------------------------------------------- # 'SimpleEditor' class: #------------------------------------------------------------------------------- class SimpleEditor(Editor): """ Simple Traits UI time editor that wraps QTimeEdit. """ #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init(self, parent): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self.control = QtGui.QTimeEdit() signal = QtCore.SIGNAL('timeChanged(QTime)') QtCore.QObject.connect(self.control, signal, self.update_object) #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor(self): """ Updates the editor when the object trait changes externally to the editor. """ value = self.value if value: q_date = QtCore.QTime(value.hour, value.minute, value.second) self.control.setTime(q_date) #--------------------------------------------------------------------------- # Handles the user entering input data in the edit control: #--------------------------------------------------------------------------- def update_object(self, q_time): """ Handles the user entering input data in the edit control. """ hour = q_time.hour() minute = q_time.minute() second = q_time.second() try: self.value = datetime.time(hour, minute, second) except ValueError: print 'Invalid time:', hour, minute, second raise #------------------------------------------------------------------------------ # 'ReadonlyEditor' class: #------------------------------------------------------------------------------ class ReadonlyEditor(BaseReadonlyEditor): """ Readonly Traits UI time editor that uses a QLabel for the view. """ def _get_str_value(self): """ Replace the default string value with our own time verision. """ if not self.value: return self.factory.message else: return self.value.strftime(self.factory.strftime) traitsui-4.1.0/traitsui/qt4/compound_editor.py0000644000175100001440000001006611674463546022504 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2007, Riverbank Computing Limited # All rights reserved. # # This software is provided without warranty under the terms of the BSD license. # However, when used with the GPL version of PyQt the additional terms described in the PyQt GPL exception also apply # # Author: Riverbank Computing Limited #------------------------------------------------------------------------------ """ Defines the compound editor and the compound editor factory for the PyQt user interface toolkit. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from pyface.qt import QtGui from traits.api \ import Str # FIXME: ToolkitEditorFactory is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.compound_editor file. from traitsui.editors.compound_editor \ import ToolkitEditorFactory from editor \ import Editor #------------------------------------------------------------------------------- # 'CompoundEditor' class: #------------------------------------------------------------------------------- class CompoundEditor ( Editor ): """ Editor for compound traits, which displays editors for each of the combined traits, in the appropriate style. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # The kind of editor to create for each list item kind = Str #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self.control = QtGui.QWidget() layout = QtGui.QVBoxLayout(self.control) layout.setContentsMargins(0, 0, 0, 0) # Add all of the component trait editors: self._editors = editors = [] for factory in self.factory.editors: editor = getattr( factory, self.kind )( self.ui, self.object, self.name, self.description, None ) editor.prepare(self.control) layout.addWidget(editor.control) editors.append(editor) #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ pass #--------------------------------------------------------------------------- # Disposes of the contents of an editor: #--------------------------------------------------------------------------- def dispose ( self ): """ Disposes of the contents of an editor. """ for editor in self._editors: editor.dispose() super( CompoundEditor, self ).dispose() #------------------------------------------------------------------------------- # 'SimpleEditor' class: #------------------------------------------------------------------------------- class SimpleEditor(CompoundEditor): # The kind of editor to create for each list item. This value overrides # the default. kind = 'simple_editor' #------------------------------------------------------------------------------- # 'CustomEditor' class: #------------------------------------------------------------------------------- class CustomEditor(CompoundEditor): # The kind of editor to create for each list item. This value overrides # the default. kind = 'custom_editor' traitsui-4.1.0/traitsui/qt4/color_trait.py0000644000175100001440000000747211674463546021642 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2007, Riverbank Computing Limited # All rights reserved. # # This software is provided without warranty under the terms of the BSD license. # However, when used with the GPL version of PyQt the additional terms described in the PyQt GPL exception also apply # # Author: Riverbank Computing Limited #------------------------------------------------------------------------------ """ Trait definition for a PyQt-based color. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from pyface.qt import QtGui from traits.api \ import Trait, TraitError #------------------------------------------------------------------------------- # Convert a number into a QColor object: #------------------------------------------------------------------------------- def convert_to_color ( object, name, value ): """ Converts a number into a QColor object. """ # Try the toolkit agnostic format. try: tup = eval(value) except: tup = value if isinstance(tup, tuple): if 3 <= len(tup) <= 4: try: color = QtGui.QColor(*tup) except TypeError: raise TraitError else: raise TraitError else: if isinstance(value, basestring): # Allow for spaces in the string value. value = value.replace(' ', '') # Let the standard ctors handle the value. try: color = QtGui.QColor(value) except TypeError: raise TraitError if not color.isValid(): raise TraitError return color convert_to_color.info = ('a string of the form (r,g,b) or (r,g,b,a) where r, ' 'g, b, and a are integers from 0 to 255, a QColor ' 'instance, a Qt.GlobalColor, an integer which in hex ' 'is of the form 0xRRGGBB, a string of the form #RGB, ' '#RRGGBB, #RRRGGGBBB or #RRRRGGGGBBBB') #------------------------------------------------------------------------------- # Standard colors: #------------------------------------------------------------------------------- # Note that this is slightly different from the wx implementation in that the # names do not include spaces and the full set of SVG color keywords is # supported. standard_colors = {} for name in QtGui.QColor.colorNames(): standard_colors[str(name)] = QtGui.QColor(name) #------------------------------------------------------------------------------- # Callable that returns an instance of the PyQtToolkitEditorFactory for color # editors. #------------------------------------------------------------------------------- ### FIXME: We have declared the 'editor' to be a function instead of the # traitsui.qt4.color_editor.ToolkitEditorFactory class, since the # latter is leading to too many circular imports. In the future, try to see if # there is a better way to do this. def get_color_editor(*args, **traits): from traitsui.qt4.color_editor import ToolkitEditorFactory return ToolkitEditorFactory(*args, **traits) #------------------------------------------------------------------------------- # Define PyQt specific color traits: #------------------------------------------------------------------------------- def PyQtColor ( default = 'white', allow_none = False, **metadata ): """ Defines PyQt-specific color traits. """ if allow_none: return Trait( default, None, standard_colors, convert_to_color, editor = get_color_editor, **metadata ) return Trait( default, standard_colors, convert_to_color, editor = get_color_editor, **metadata ) traitsui-4.1.0/traitsui/qt4/button_editor.py0000644000175100001440000001312611674463546022173 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2007, Riverbank Computing Limited # All rights reserved. # # This software is provided without warranty under the terms of the BSD license. # However, when used with the GPL version of PyQt the additional terms described in the PyQt GPL exception also apply # # Author: Riverbank Computing Limited #------------------------------------------------------------------------------ """ Defines the various button editors for the PyQt user interface toolkit. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from pyface.qt import QtCore, QtGui from traits.api import Unicode, List, Str, on_trait_change # FIXME: ToolkitEditorFactory is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.button_editor file. from traitsui.editors.button_editor \ import ToolkitEditorFactory from editor import Editor #------------------------------------------------------------------------------- # 'SimpleEditor' class: #------------------------------------------------------------------------------- class SimpleEditor ( Editor ): """ Simple style editor for a button. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # The button label label = Unicode # The list of items in a drop-down menu, if any #menu_items = List # The selected item in the drop-down menu. selected_item = Str #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ label = self.factory.label or self.item.get_label(self.ui) if self.factory.values_trait: self.control = QtGui.QToolButton() self.control.toolButtonStyle = QtCore.Qt.ToolButtonTextOnly self.control.setText(self.string_value(label)) self.object.on_trait_change(self._update_menu, self.factory.values_trait) self.object.on_trait_change(self._update_menu, self.factory.values_trait + "_items") self._menu = QtGui.QMenu() self._update_menu() self.control.setMenu(self._menu) else: self.control = QtGui.QPushButton(self.string_value(label)) self._menu = None self.control.setAutoDefault(False) self.sync_value(self.factory.label_value, 'label', 'from') self.control.clicked.connect(self.update_object) self.set_tooltip() def _label_changed(self, label): self.control.setText(self.string_value(label)) def _update_menu(self): self._menu.blockSignals(True) self._menu.clear() for item in getattr(self.object, self.factory.values_trait): action = self._menu.addAction(item) action.triggered.connect(lambda event, name=item: self._menu_selected(name)) self.selected_item = "" self._menu.blockSignals(False) def _menu_selected(self, item_name): self.selected_item = item_name self.label = item_name def update_object(self): """ Handles the user clicking the button by setting the factory value on the object. """ if self.selected_item != "": self.value = self.selected_item else: self.value = self.factory.value # If there is an associated view, then display it: if (self.factory is not None) and (self.factory.view is not None): self.object.edit_traits( view = self.factory.view, parent = self.control ) def update_editor(self): """ Updates the editor when the object trait changes externally to the editor. """ pass #------------------------------------------------------------------------------- # 'CustomEditor' class: #------------------------------------------------------------------------------- class CustomEditor ( SimpleEditor ): """ Custom style editor for a button, which can contain an image. """ # The mapping of button styles to Qt classes. _STYLE_MAP = { 'checkbox': QtGui.QCheckBox, 'radio': QtGui.QRadioButton, 'toolbar': QtGui.QToolButton } #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ # FIXME: We ignore orientation, width_padding and height_padding. factory = self.factory btype = self._STYLE_MAP.get(factory.style, QtGui.QPushButton) self.control = btype() self.control.setText(self.string_value(factory.label)) if factory.image is not None: self.control.setIcon(factory.image.create_icon()) QtCore.QObject.connect(self.control, QtCore.SIGNAL('clicked()'), self.update_object ) self.set_tooltip() traitsui-4.1.0/traitsui/qt4/__init__.py0000644000175100001440000000176611674463546021060 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2007, Riverbank Computing Limited # All rights reserved. # # This software is provided without warranty under the terms of the BSD license. # However, when used with the GPL version of PyQt the additional terms described in the PyQt GPL exception also apply # # Author: Riverbank Computing Limited #------------------------------------------------------------------------------ """ Defines the concrete implementations of the traits Toolkit interface for the PyQt user interface toolkit. """ # import pyface.qt before anything else is done so the sipapi # can be set correctly if needed import pyface.qt #---------------------------------------------------------------------------- # Define the reference to the exported GUIToolkit object: #---------------------------------------------------------------------------- import toolkit # Reference to the GUIToolkit object for PyQt. toolkit = toolkit.GUIToolkit() traitsui-4.1.0/traitsui/qt4/search_editor.py0000644000175100001440000000662611674463546022134 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # Copyright (c) 20011, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: Evan Patterson #------------------------------------------------------------------------------- # System library imports from pyface.qt import QtCore, QtGui # ETS imports from editor import Editor class SearchWidget(QtGui.QLineEdit): # FIXME: This widget needs a search button and a cancel button like the # wxWidgets SearchControl. def __init__(self, desc): """ Store the descriptive text for the widget. """ super(SearchWidget, self).__init__() self._desc = unicode(desc) self._set_descriptive_text() def focusInEvent(self, event): """ Handles accepting focus. If the text box contains the default description string, reset the text color and clear the box. """ palette = QtGui.QApplication.instance().palette() self.setPalette(palette) if self.text() == self._desc: self.setText('') self.update() super(SearchWidget, self).focusInEvent(event) def focusOutEvent(self, event): """ Handles losing focus. When focus is lost, if the user had typed something, keep that text, otherwise replace it with the default description string. """ if len(self.text()) == 0: self._set_descriptive_text() super(SearchWidget, self).focusOutEvent(event) def _set_descriptive_text(self): """ Sets the greyed-out descriptive text. """ palette = QtGui.QApplication.instance().palette() palette.setColor(QtGui.QPalette.Text, palette.color(QtGui.QPalette.Dark)) self.setPalette(palette) self.setText(self._desc) self.update() class SearchEditor(Editor): def init(self, parent): """ Finishes initializing the editor by creating the underlying toolkit widget. """ if QtCore.__version_info__ < (4, 7, 0): control = self.control = SearchWidget(self.factory.text) else: control = self.control = QtGui.QLineEdit() control.setPlaceholderText(self.factory.text) if self.factory.auto_set: control.textEdited.connect(self.update_object) if self.factory.enter_set: control.editingFinished.connect(self.update_object) def update_object(self, event=None): """ Handles the user entering input data in the edit control. """ if not self._no_update: self.value = str(self.control.text()) if self.factory.search_event_trait != '': setattr(self.object, self.factory.search_event_trait, True) def update_editor(self): """ Updates the editor when the object trait changes externally to the editor. """ if str(self.control.text()) != self.value: self._no_update = True self.control.setText(self.str_value) self._no_update = False traitsui-4.1.0/traitsui/qt4/enum_editor.py0000644000175100001440000005032611674463546021627 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2008, Riverbank Computing Limited # All rights reserved. # # This software is provided without warranty under the terms of the BSD license. # However, when used with the GPL version of PyQt the additional terms described in the PyQt GPL exception also apply # # Author: Riverbank Computing Limited #------------------------------------------------------------------------------ """ Defines the various editors and the editor factory for single-selection enumerations, for the PyQt user interface toolkit. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from string import capitalize from pyface.qt import QtCore, QtGui from traits.api \ import Bool, Property # FIXME: ToolkitEditorFactory is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.enum_editor file. from traitsui.editors.enum_editor \ import ToolkitEditorFactory from editor \ import Editor from constants \ import OKColor, ErrorColor from traitsui.helper \ import enum_values_changed #------------------------------------------------------------------------------- # 'BaseEditor' class: #------------------------------------------------------------------------------- class BaseEditor ( Editor ): """ Base class for enumeration editors. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Current set of enumeration names: names = Property # Current mapping from names to values: mapping = Property # Current inverse mapping from values to names: inverse_mapping = Property #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ factory = self.factory if factory.name != '': self._object, self._name, self._value = \ self.parse_extended_name( factory.name ) self.values_changed() self._object.on_trait_change( self._values_changed, ' ' + self._name, dispatch = 'ui' ) else: factory.on_trait_change( self.rebuild_editor, 'values_modified', dispatch = 'ui' ) #--------------------------------------------------------------------------- # Gets the current set of enumeration names: #--------------------------------------------------------------------------- def _get_names ( self ): """ Gets the current set of enumeration names. """ if self._object is None: return self.factory._names return self._names #--------------------------------------------------------------------------- # Gets the current mapping: #--------------------------------------------------------------------------- def _get_mapping ( self ): """ Gets the current mapping. """ if self._object is None: return self.factory._mapping return self._mapping #--------------------------------------------------------------------------- # Gets the current inverse mapping: #--------------------------------------------------------------------------- def _get_inverse_mapping ( self ): """ Gets the current inverse mapping. """ if self._object is None: return self.factory._inverse_mapping return self._inverse_mapping #--------------------------------------------------------------------------- # Rebuilds the contents of the editor whenever the original factory # object's 'values' trait changes: #--------------------------------------------------------------------------- def rebuild_editor ( self ): """ Rebuilds the contents of the editor whenever the original factory object's **values** trait changes. """ raise NotImplementedError #--------------------------------------------------------------------------- # Recomputes the cached data based on the underlying enumeration model: #--------------------------------------------------------------------------- def values_changed ( self ): """ Recomputes the cached data based on the underlying enumeration model. """ self._names, self._mapping, self._inverse_mapping = \ enum_values_changed( self._value(), self.string_value ) #--------------------------------------------------------------------------- # Handles the underlying object model's enumeration set being changed: #--------------------------------------------------------------------------- def _values_changed ( self ): """ Handles the underlying object model's enumeration set being changed. """ self.values_changed() self.rebuild_editor() #--------------------------------------------------------------------------- # Disposes of the contents of an editor: #--------------------------------------------------------------------------- def dispose ( self ): """ Disposes of the contents of an editor. """ if self._object is not None: self._object.on_trait_change( self._values_changed, ' ' + self._name, remove = True ) else: self.factory.on_trait_change( self.rebuild_editor, 'values_modified', remove = True ) super( BaseEditor, self ).dispose() #------------------------------------------------------------------------------- # 'SimpleEditor' class: #------------------------------------------------------------------------------- class SimpleEditor ( BaseEditor ): """ Simple style of enumeration editor, which displays a combo box. """ #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ super( SimpleEditor, self ).init( parent ) self.control = control = self.create_combo_box() control.addItems(self.names) QtCore.QObject.connect(control, QtCore.SIGNAL('currentIndexChanged(QString)'), self.update_object) if self.factory.evaluate is not None: control.setEditable(True) if self.factory.auto_set: QtCore.QObject.connect(control, QtCore.SIGNAL('editTextChanged(QString)'), self.update_text_object) else: QtCore.QObject.connect(control.lineEdit(), QtCore.SIGNAL('editingFinished()'), self.update_autoset_text_object) control.setInsertPolicy(QtGui.QComboBox.NoInsert) self._no_enum_update = 0 self.set_tooltip() #--------------------------------------------------------------------------- # Returns the QComboBox used for the editor control: #--------------------------------------------------------------------------- def create_combo_box(self): """ Returns the QComboBox used for the editor control. """ control = QtGui.QComboBox() control.setSizeAdjustPolicy(QtGui.QComboBox.AdjustToContents) control.setSizePolicy(QtGui.QSizePolicy.Maximum, QtGui.QSizePolicy.Fixed) return control #--------------------------------------------------------------------------- # Adjust size polify to behave properly in group #--------------------------------------------------------------------------- def set_size_policy(self, direction, resizable, springy, stretch) : super(SimpleEditor, self).set_size_policy(direction, resizable, springy, stretch) if ((direction == QtGui.QBoxLayout.LeftToRight and springy) or (direction != QtGui.QBoxLayout.LeftToRight and resizable)) : self.control.setSizeAdjustPolicy(QtGui.QComboBox.AdjustToContentsOnFirstShow) #--------------------------------------------------------------------------- # Handles the user selecting a new value from the combo box: #--------------------------------------------------------------------------- def update_object (self, text): """ Handles the user selecting a new value from the combo box. """ if self._no_enum_update == 0: self._no_enum_update += 1 try: self.value = self.mapping[unicode(text)] except: from traitsui.api import raise_to_debug raise_to_debug() self._no_enum_update -= 1 #--------------------------------------------------------------------------- # Handles the user typing text into the combo box text entry field: #--------------------------------------------------------------------------- def update_text_object(self, text): """ Handles the user typing text into the combo box text entry field. """ if self._no_enum_update == 0: value = unicode(text) try: value = self.mapping[value] except: try: value = self.factory.evaluate(value) except Exception, excp: self.error( excp ) return self._no_enum_update += 1 self.value = value self._set_background(OKColor) self._no_enum_update -= 1 def update_autoset_text_object(self): # Don't get the final text with the editingFinished signal if self.control is not None: text = self.control.lineEdit().text() return self.update_text_object(text) #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ if self._no_enum_update == 0: self._no_enum_update += 1 if self.factory.evaluate is None: try: index = self.names.index(self.inverse_mapping[self.value]) self.control.setCurrentIndex(index) except: self.control.setCurrentIndex(-1) else: try: self.control.setEditText(self.str_value) except: self.control.setEditText('') self._no_enum_update -= 1 #--------------------------------------------------------------------------- # Handles an error that occurs while setting the object's trait value: #--------------------------------------------------------------------------- def error ( self, excp ): """ Handles an error that occurs while setting the object's trait value. """ self._set_background(ErrorColor) #--------------------------------------------------------------------------- # Sets the background color of the QLineEdit of the QComboBox. #--------------------------------------------------------------------------- def _set_background(self, col): le = self.control.lineEdit() pal = QtGui.QPalette(le.palette()) pal.setColor(QtGui.QPalette.Base, col) le.setPalette(pal) #--------------------------------------------------------------------------- # Rebuilds the contents of the editor whenever the original factory # object's 'values' trait changes: #--------------------------------------------------------------------------- def rebuild_editor ( self ): """ Rebuilds the contents of the editor whenever the original factory object's **values** trait changes. """ self.control.blockSignals(True) self.control.clear() self.control.addItems(self.names) self.control.blockSignals(False) self.update_editor() #------------------------------------------------------------------------------- # 'RadioEditor' class: #------------------------------------------------------------------------------- class RadioEditor ( BaseEditor ): """ Enumeration editor, used for the "custom" style, that displays radio buttons. """ # Is the button layout row-major or column-major? row_major = Bool( False ) #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ super( RadioEditor, self ).init( parent ) self.control = QtGui.QWidget() layout = QtGui.QGridLayout(self.control) layout.setContentsMargins(0, 0, 0, 0) self._mapper = QtCore.QSignalMapper() QtCore.QObject.connect(self._mapper, QtCore.SIGNAL('mapped(int)'), self.update_object) self.rebuild_editor() #--------------------------------------------------------------------------- # Handles the user clicking one of the 'custom' radio buttons: #--------------------------------------------------------------------------- def update_object ( self, index ): """ Handles the user clicking one of the custom radio buttons. """ try: self.value = self.mapping[self.names[index]] except: pass #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ layout = self.control.layout() value = self.value for i in range(layout.count()): rb = layout.itemAt(i).widget() rb.setChecked(rb.value == value) #--------------------------------------------------------------------------- # Rebuilds the contents of the editor whenever the original factory # object's 'values' trait changes: #--------------------------------------------------------------------------- def rebuild_editor ( self ): """ Rebuilds the contents of the editor whenever the original factory object's **values** trait changes. """ # Clear any existing content: self.clear_layout() # Get the current trait value: cur_name = self.str_value # Create a sizer to manage the radio buttons: names = self.names mapping = self.mapping n = len( names ) cols = self.factory.cols rows = (n + cols - 1) / cols if self.row_major: incr = [ 1 ] * cols else: incr = [ n / cols ] * cols rem = n % cols for i in range( cols ): incr[i] += (rem > i) incr[-1] = -(reduce( lambda x, y: x + y, incr[:-1], 0 ) - 1) # Add the set of all possible choices: layout = self.control.layout() index = 0 for i in range( rows ): for j in range( cols ): if n > 0: name = names[index] rb = self.create_button(name) rb.value = mapping[name] rb.setChecked(name == cur_name) QtCore.QObject.connect(rb, QtCore.SIGNAL('clicked()'), self._mapper, QtCore.SLOT('map()')) self._mapper.setMapping(rb, index) self.set_tooltip(rb) layout.addWidget(rb, i, j) index += incr[j] n -= 1 #--------------------------------------------------------------------------- # Returns the QAbstractButton used for the radio button: #--------------------------------------------------------------------------- def create_button(self, name): """ Returns the QAbstractButton used for the radio button. """ label = self.string_value(name, capitalize) return QtGui.QRadioButton(label) #------------------------------------------------------------------------------- # 'ListEditor' class: #------------------------------------------------------------------------------- class ListEditor ( BaseEditor ): """ Enumeration editor, used for the "custom" style, that displays a list box. """ #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ super( ListEditor, self ).init( parent ) self.control = QtGui.QListWidget() QtCore.QObject.connect(self.control, QtCore.SIGNAL('currentTextChanged(QString)'), self.update_object) self.rebuild_editor() self.set_tooltip() #--------------------------------------------------------------------------- # Handles the user selecting a list box item: #--------------------------------------------------------------------------- def update_object(self, text): """ Handles the user selecting a list box item. """ value = unicode(text) try: value = self.mapping[ value ] except: try: value = self.factory.evaluate( value ) except: pass try: self.value = value except: pass #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ control = self.control try: value = self.inverse_mapping[self.value] for row in range(control.count()): itm = control.item(row) if itm.text() == value: control.setCurrentItem(itm) control.scrollToItem(itm) break except: pass #--------------------------------------------------------------------------- # Rebuilds the contents of the editor whenever the original factory # object's 'values' trait changes: #--------------------------------------------------------------------------- def rebuild_editor ( self ): """ Rebuilds the contents of the editor whenever the original factory object's **values** trait changes. """ self.control.blockSignals(True) self.control.clear() for name in self.names: self.control.addItem(name) self.control.blockSignals(False) self.update_editor() traitsui-4.1.0/traitsui/qt4/ui_base.py0000644000175100001440000004773711674463546020740 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2007, Riverbank Computing Limited # All rights reserved. # # This software is provided without warranty under the terms of the BSD license. # However, when used with the GPL version of PyQt the additional terms described in the PyQt GPL exception also apply # # Author: Riverbank Computing Limited #------------------------------------------------------------------------------ """Defines the base class for the PyQt-based Traits UI modal and non-modal dialogs. """ from pyface.qt import QtCore, QtGui from traits.api \ import HasStrictTraits, HasPrivateTraits, Instance, List, Event from traitsui.api \ import UI from traitsui.menu \ import Action from constants \ import DefaultTitle from editor \ import Editor from helper \ import restore_window, save_window #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- # List of all predefined system button names: SystemButtons = ['Undo', 'Redo', 'Apply', 'Revert', 'OK', 'Cancel', 'Help'] def default_icon(): from pyface.image_resource import ImageResource return ImageResource('frame.png') #------------------------------------------------------------------------------- # 'RadioGroup' class: #------------------------------------------------------------------------------- class RadioGroup ( HasStrictTraits ): """ A group of mutually-exclusive menu or toolbar actions. """ # List of menu or tool bar items items = List #--------------------------------------------------------------------------- # Handles a menu item in the group being checked: #--------------------------------------------------------------------------- def menu_checked ( self, menu_item ): """ Handles a menu item in the group being checked. """ for item in self.items: if item is not menu_item: item.control.Check( False ) item.item.action.checked = False #--------------------------------------------------------------------------- # Handles a tool bar item in the group being checked: #--------------------------------------------------------------------------- def toolbar_checked ( self, toolbar_item ): """ Handles a tool bar item in the group being checked. """ for item in self.items: if item is not toolbar_item: item.tool_bar.ToggleTool( item.control_id, False ) item.item.action.checked = False #------------------------------------------------------------------------------- # 'ButtonEditor' class: #------------------------------------------------------------------------------- class ButtonEditor(Editor): """ Editor for buttons. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Action associated with the button action = Instance(Action) #--------------------------------------------------------------------------- # Initializes the object: #--------------------------------------------------------------------------- def __init__(self, **traits): self.set(**traits) #--------------------------------------------------------------------------- # Handles the associated button being clicked: #--------------------------------------------------------------------------- def perform(self): """Handles the associated button being clicked.""" self.ui.do_undoable(self._perform, None) def _perform(self, event): method_name = self.action.action if method_name == '': method_name = '_%s_clicked' % self.action.name.lower() method = getattr(self.ui.handler, method_name, None) if method is not None: method(self.ui.info) else: self.action.perform(event) class BasePanel(object): """Base class for Traits UI panels. """ #--------------------------------------------------------------------------- # Performs the action described by a specified Action object: #--------------------------------------------------------------------------- def perform ( self, action ): """ Performs the action described by a specified Action object. """ self.ui.do_undoable( self._perform, action ) def _perform ( self, action ): method = getattr( self.ui.handler, action.action, None ) if method is not None: method( self.ui.info ) else: action.perform() #--------------------------------------------------------------------------- # Check to see if a specified 'system' button is in the buttons list, and # add it if it is not: #--------------------------------------------------------------------------- def check_button ( self, buttons, action ): """ Adds *action* to the system buttons list for this dialog, if it is not already in the list. """ name = action.name for button in buttons: if self.is_button( button, name ): return buttons.append( action ) #--------------------------------------------------------------------------- # Check to see if a specified Action button is a 'system' button: #--------------------------------------------------------------------------- def is_button ( self, action, name ): """ Returns whether a specified action button is a system button. """ if isinstance(action, basestring): return (action == name) return (action.name == name) #--------------------------------------------------------------------------- # Coerces a string to an Action if necessary: #--------------------------------------------------------------------------- def coerce_button ( self, action ): """ Coerces a string to an Action if necessary. """ if isinstance(action, basestring): return Action( name = action, action = '?'[ (not action in SystemButtons): ] ) return action #--------------------------------------------------------------------------- # Creates a user specified button: #--------------------------------------------------------------------------- def add_button ( self, action, bbox, role, method=None, enabled=True, name=None, default=False ): """ Creates a button. """ ui = self.ui if ((action.defined_when != '') and (not ui.eval_when( action.defined_when ))): return None if name is None: name = action.name id = action.id button = bbox.addButton(name, role) button.setAutoDefault(False) button.setDefault(default) button.setEnabled(enabled) if (method is None) or (action.enabled_when != '') or (id != ''): editor = ButtonEditor( ui = ui, action = action, control = button ) if id != '': ui.info.bind( id, editor ) if action.visible_when != '': ui.add_visible( action.visible_when, editor ) if action.enabled_when != '': ui.add_enabled( action.enabled_when, editor ) if method is None: method = editor.perform if method is not None: button.connect(button, QtCore.SIGNAL('clicked()'), method) if action.tooltip != '': button.setToolTip(action.tooltip) return button def _on_help(self): """Handles the user clicking the Help button. """ # FIXME: Needs porting to PyQt. self.ui.handler.show_help(self.ui.info, event.GetEventObject()) def _on_undo(self): """Handles a request to undo a change. """ self.ui.history.undo() def _on_undoable(self, state): """Handles a change to the "undoable" state of the undo history """ self.undo.setEnabled(state) def _on_redo(self): """Handles a request to redo a change. """ self.ui.history.redo() def _on_redoable(self, state): """Handles a change to the "redoable" state of the undo history. """ self.redo.setEnabled(state) def _on_revert(self): """Handles a request to revert all changes. """ ui = self.ui if ui.history is not None: ui.history.revert() ui.handler.revert(ui.info) def _on_revertable(self, state): """ Handles a change to the "revert" state. """ self.revert.setEnabled(state) class _StickyDialog(QtGui.QDialog): """A QDialog that will only close if the traits handler allows it.""" def __init__(self, ui, parent): """Initialise the dialog.""" QtGui.QDialog.__init__(self, parent) # Create the main window so we can add toolbars etc. self._mw = QtGui.QMainWindow() layout = QtGui.QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(self._mw) self.setLayout(layout) # Set the dialog's window flags and properties. if ui.view.resizable: flags = QtCore.Qt.Window else: flags = QtCore.Qt.Dialog | QtCore.Qt.WindowSystemMenuHint layout.setSizeConstraint(QtGui.QLayout.SetFixedSize) if ui.view.resizable: flags |= QtCore.Qt.WindowMinimizeButtonHint | QtCore.Qt.WindowMaximizeButtonHint try: flags |= QtCore.Qt.WindowCloseButtonHint if ui.view.resizable: flags |= (QtCore.Qt.WindowMinimizeButtonHint | QtCore.Qt.WindowMaximizeButtonHint) except AttributeError: # Either PyQt or Qt is too old. pass self.setWindowFlags(flags) self._ui = ui self._result = None def closeEvent(self, e): """Reimplemented to check when the clicks the window close button. (Note that QDialog doesn't get a close event when the dialog is closed in any other way.)""" if self._ok_to_close(): QtGui.QDialog.closeEvent(self, e) else: # Ignore the event thereby keeping the dialog open. e.ignore() def keyPressEvent(self, e): """Reimplemented to ignore the Escape key if appropriate, and to ignore the Enter key if no default button has been explicitly set.""" if e.key() in (QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return) and \ not self._ui.view.default_button: return if e.key() == QtCore.Qt.Key_Escape and not self._ok_to_close(): return QtGui.QDialog.keyPressEvent(self, e) def sizeHint(self): """Reimplemented to provide an appropriate size hint for the window. """ size = QtGui.QDialog.sizeHint(self) view = self._ui.view if view.width > 0: size.setWidth(view.width) if view.height > 0: size.setHeight(view.height) return size def done(self, r): """Reimplemented to ignore calls to accept() or reject() if appropriate.""" # If we already have a result then we already know that we are done. if self._result is not None: QtGui.QDialog.done(self, self._result) elif self._ok_to_close(bool(r)): QtGui.QDialog.done(self, r) def _ok_to_close(self, is_ok=None): """Let the handler decide if the dialog should be closed.""" # The is_ok flag is also the dialog result. If we don't know it then # the the user closed the dialog other than by an 'Ok' or 'Cancel' # button. if is_ok is None: # Use the view's default, if there is one. is_ok = self._ui.view.close_result if is_ok is None: # There is no default, so use False for a modal dialog and True # for a non-modal one. is_ok = not self.isModal() ok_to_close = self._ui.handler.close(self._ui.info, is_ok) if ok_to_close: # Save the result now. self._result = is_ok return ok_to_close class BaseDialog(BasePanel): """Base class for Traits UI dialog boxes.""" # The different dialog styles. NONMODAL, MODAL, POPUP = range(3) def init(self, ui, parent, style): """Initialise the dialog by creating the controls.""" raise NotImplementedError def create_dialog(self, parent, style): """Create the dialog control.""" self.control = control = _StickyDialog(self.ui, parent) view = self.ui.view control.setModal(style == BaseDialog.MODAL) control.setWindowTitle(view.title or DefaultTitle) QtCore.QObject.connect(control, QtCore.SIGNAL('finished(int)'), self._on_finished) def add_contents(self, panel, buttons): """Add a panel (either a widget, layout or None) and optional buttons to the dialog.""" # If the panel is a layout then provide a widget for it. if isinstance(panel, QtGui.QLayout): w = QtGui.QWidget() panel.setContentsMargins(0, 0, 0, 0) w.setLayout(panel) panel = w if panel is not None: self.control._mw.setCentralWidget(panel) # Add the optional buttons. if buttons is not None: self.control.layout().addWidget(buttons) # Add the menu bar, tool bar and status bar (if any). self._add_menubar() self._add_toolbar() self._add_statusbar() def close(self, rc=True): """Close the dialog and set the given return code.""" self.ui.dispose(rc) self.ui = self.control = None @staticmethod def display_ui(ui, parent, style): """Display the UI.""" ui.owner.init(ui, parent, style) ui.control = ui.owner.control ui.control._parent = parent try: ui.prepare_ui() except: ui.control.setParent(None) ui.control.ui = None ui.control = None ui.owner = None ui.result = False raise ui.handler.position(ui.info) restore_window(ui) if style == BaseDialog.NONMODAL: ui.control.show() else: ui.control.setWindowModality(QtCore.Qt.WindowModal) ui.control.exec_() def set_icon(self, icon=None): """Sets the dialog's icon.""" from pyface.image_resource import ImageResource if not isinstance(icon, ImageResource): icon = default_icon() self.control.setWindowIcon(icon.create_icon()) def _on_error(self, errors): """Handles editing errors.""" self.ok.setEnabled(errors == 0) #--------------------------------------------------------------------------- # Adds a menu bar to the dialog: #--------------------------------------------------------------------------- def _add_menubar(self): """Adds a menu bar to the dialog. """ menubar = self.ui.view.menubar if menubar is not None: self._last_group = self._last_parent = None self.control.layout().setMenuBar( menubar.create_menu_bar( self.control, self ) ) self._last_group = self._last_parent = None #--------------------------------------------------------------------------- # Adds a tool bar to the dialog: #--------------------------------------------------------------------------- def _add_toolbar ( self ): """ Adds a toolbar to the dialog. """ toolbar = self.ui.view.toolbar if toolbar is not None: self._last_group = self._last_parent = None qt_toolbar = toolbar.create_tool_bar( self.control, self ) qt_toolbar.setMovable( False ) self.control._mw.addToolBar( qt_toolbar ) self._last_group = self._last_parent = None #--------------------------------------------------------------------------- # Adds a status bar to the dialog: #--------------------------------------------------------------------------- def _add_statusbar ( self ): """ Adds a statusbar to the dialog. """ if self.ui.view.statusbar is not None: control = QtGui.QStatusBar() control.setSizeGripEnabled(self.ui.view.resizable) listeners = [] for item in self.ui.view.statusbar: # Create the status widget with initial text name = item.name item_control = QtGui.QLabel() item_control.setText(self.ui.get_extended_value(name)) # Add the widget to the control with correct size width = abs(item.width) stretch = 0 if width <= 1.0: stretch = int(100 * width) else: item_control.setMinimumWidth(width) control.addWidget(item_control, stretch) # Set up event listener for updating the status text col = name.find('.') obj = 'object' if col >= 0: obj = name[:col] name = name[col+1:] obj = self.ui.context[obj] set_text = self._set_status_text(item_control) obj.on_trait_change(set_text, name, dispatch='ui') listeners.append((obj, set_text, name)) self.control._mw.setStatusBar(control) self.ui._statusbar = listeners def _set_status_text(self, control): """ Helper function for _add_statusbar. """ def set_status_text(text): control.setText(text) return set_status_text #--------------------------------------------------------------------------- # Adds a menu item to the menu bar being constructed: #--------------------------------------------------------------------------- def add_to_menu ( self, menu_item ): """ Adds a menu item to the menu bar being constructed. """ item = menu_item.item action = item.action if action.id != '': self.ui.info.bind( action.id, menu_item ) if action.style == 'radio': if ((self._last_group is None) or (self._last_parent is not item.parent)): self._last_group = RadioGroup() self._last_parent = item.parent self._last_group.items.append( menu_item ) menu_item.group = self._last_group if action.visible_when != '': self.ui.add_visible( action.visible_when, menu_item ) if action.enabled_when != '': self.ui.add_enabled( action.enabled_when, menu_item ) if action.checked_when != '': self.ui.add_checked( action.checked_when, menu_item ) #--------------------------------------------------------------------------- # Adds a tool bar item to the tool bar being constructed: #--------------------------------------------------------------------------- def add_to_toolbar ( self, toolbar_item ): """ Adds a toolbar item to the toolbar being constructed. """ self.add_to_menu( toolbar_item ) def can_add_to_menu(self, action, action_event=None): """Returns whether the action should be defined in the user interface. """ if action.defined_when == '': return True return self.ui.eval_when(action.defined_when) def can_add_to_toolbar(self, action): """Returns whether the toolbar action should be defined in the user interface. """ return self.can_add_to_menu(action) traitsui-4.1.0/traitsui/qt4/array_view_editor.py0000644000175100001440000000215611674463546023031 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2009, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # #------------------------------------------------------------------------------ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from traitsui.ui_editors.array_view_editor \ import _ArrayViewEditor as BaseArrayViewEditor from ui_editor import UIEditor #------------------------------------------------------------------------------- # '_ArrayViewEditor' class: #------------------------------------------------------------------------------- class _ArrayViewEditor(BaseArrayViewEditor, UIEditor): pass traitsui-4.1.0/traitsui/qt4/value_editor.py0000644000175100001440000000315711674463546021777 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2006, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 01/05/2006 # #------------------------------------------------------------------------------ """ Defines the tree-based Python value editor and the value editor factory, for the wxPython user interface toolkit. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- # FIXME: ToolkitEditorFactory is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.value_editor file. from traitsui.editors.value_editor \ import _ValueEditor, ToolkitEditorFactory from editor import Editor class SimpleEditor( _ValueEditor, Editor): """ Returns the editor to use for simple style views. """ # Override the value of the readonly trait. readonly = False class ReadonlyEditor( _ValueEditor, Editor): """ Returns the editor to use for readonly style views. """ # Override the value of the readonly trait. readonly = True ### EOF ####################################################################### traitsui-4.1.0/traitsui/qt4/view_application.py0000644000175100001440000001056211674463546022650 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2007, Riverbank Computing Limited # All rights reserved. # # This software is provided without warranty under the terms of the BSD license. # However, when used with the GPL version of PyQt the additional terms described in the PyQt GPL exception also apply # # Author: Riverbank Computing Limited #------------------------------------------------------------------------------ """ Creates a PyQt specific modal dialog user interface that runs as a complete application, using information from the specified UI object. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- # Standard library imports. import os # System library imports. from pyface.qt import QtGui # ETS imports. from pyface.util.guisupport import is_event_loop_running_qt4, \ start_event_loop_qt4 #------------------------------------------------------------------------------- # Creates a 'stand-alone' PyQt application to display a specified traits UI # View: #------------------------------------------------------------------------------- def view_application ( context, view, kind, handler, id, scrollable, args ): """ Creates a stand-alone PyQt application to display a specified traits UI View. Parameters ---------- context : object or dictionary A single object or a dictionary of string/object pairs, whose trait attributes are to be edited. If not specified, the current object is used. view : view object A View object that defines a user interface for editing trait attribute values. kind : string The type of user interface window to create. See the **traitsui.view.kind_trait** trait for values and their meanings. If *kind* is unspecified or None, the **kind** attribute of the View object is used. handler : Handler object A handler object used for event handling in the dialog box. If None, the default handler for Traits UI is used. scrollable : Boolean Indicates whether the dialog box should be scrollable. When set to True, scroll bars appear on the dialog box if it is not large enough to display all of the items in the view at one time. """ if (kind == 'panel') or ((kind is None) and (view.kind == 'panel')): kind = 'modal' app = QtGui.QApplication.instance() if app is None or not is_event_loop_running_qt4(app): return ViewApplication( context, view, kind, handler, id, scrollable, args ).ui.result return view.ui( context, kind = kind, handler = handler, id = id, scrollable = scrollable, args = args ).result #------------------------------------------------------------------------------- # 'ViewApplication' class: #------------------------------------------------------------------------------- class ViewApplication ( object ): """ Modal window that contains a stand-alone application. """ #--------------------------------------------------------------------------- # Initializes the object: #--------------------------------------------------------------------------- def __init__ ( self, context, view, kind, handler, id, scrollable, args ): """ Initializes the object. """ self.context = context self.view = view self.kind = kind self.handler = handler self.id = id self.scrollable = scrollable self.args = args # FIXME: fbi is wx specific at the moment. if os.environ.get( 'ENABLE_FBI' ) is not None: try: from etsdevtools.developer.helper.fbi import enable_fbi enable_fbi() except: pass self.ui = self.view.ui( self.context, kind = self.kind, handler = self.handler, id = self.id, scrollable = self.scrollable, args = self.args ) start_event_loop_qt4() traitsui-4.1.0/traitsui/qt4/image_editor.py0000644000175100001440000000521211674463546021737 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2009, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: Evan Patterson # Date: 07/21/2009 # #------------------------------------------------------------------------------- """ Traits UI 'display only' image editor. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from pyface.qt import QtGui from pyface.image_resource \ import ImageResource from traitsui.ui_traits \ import convert_bitmap # FIXME: ImageEditor is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.image_editor file. from traitsui.editors.image_editor \ import ImageEditor from editor \ import Editor #------------------------------------------------------------------------------- # '_ImageEditor' class: #------------------------------------------------------------------------------- class _ImageEditor ( Editor ): """ Traits UI 'display only' image editor. """ #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ image = self.factory.image if image is None: image = self.value self.control = QtGui.QLabel() self.control.setPixmap( convert_bitmap( image ) ) self.set_tooltip() #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ if self.factory.image is None: value = self.value if isinstance( value, ImageResource ): self.control.setPixmap( convert_bitmap( value ) ) traitsui-4.1.0/traitsui/qt4/list_editor.py0000644000175100001440000010032011674463546021624 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2007, Riverbank Computing Limited # All rights reserved. # # This software is provided without warranty under the terms of the BSD license. # However, when used with the GPL version of PyQt the additional terms described in the PyQt GPL exception also apply # # Author: Riverbank Computing Limited #------------------------------------------------------------------------------ """ Defines the various list editors for the PyQt user interface toolkit. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from pyface.qt import QtCore, QtGui from pyface.api import ImageResource from traits.api import Str, Any, Bool, Dict from traits.trait_base import user_name_for, enumerate, xgetattr # FIXME: ToolkitEditorFactory is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.list_editor file. from traitsui.editors.list_editor import ListItemProxy, \ ToolkitEditorFactory from editor import Editor from helper import IconButton from menu import MakeMenu #------------------------------------------------------------------------------- # 'SimpleEditor' class: #------------------------------------------------------------------------------- class SimpleEditor ( Editor ): """ Simple style of editor for lists, which displays a scrolling list box with only one item visible at a time. A icon next to the list box displays a menu of operations on the list. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # The kind of editor to create for each list item kind = Str # Is the list of items being edited mutable? mutable = Bool( True ) #--------------------------------------------------------------------------- # Class constants: #--------------------------------------------------------------------------- # Whether the list is displayed in a single row single_row = True #--------------------------------------------------------------------------- # Normal list item menu: #--------------------------------------------------------------------------- # Menu for modifying the list list_menu = """ Add &Before [_menu_before]: self.add_before() Add &After [_menu_after]: self.add_after() --- &Delete [_menu_delete]: self.delete_item() --- Move &Up [_menu_up]: self.move_up() Move &Down [_menu_down]: self.move_down() Move to &Top [_menu_top]: self.move_top() Move to &Bottom [_menu_bottom]: self.move_bottom() """ #--------------------------------------------------------------------------- # Empty list item menu: #--------------------------------------------------------------------------- empty_list_menu = """ Add: self.add_empty() """ #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ # Initialize the trait handler to use: trait_handler = self.factory.trait_handler if trait_handler is None: trait_handler = self.object.base_trait( self.name ).handler self._trait_handler = trait_handler # Create a scrolled window to hold all of the list item controls: self.control = QtGui.QScrollArea() self.control.setFrameShape(QtGui.QFrame.NoFrame) self.control.setWidgetResizable(True) # Create a widget with a grid layout as the container. self._list_pane = QtGui.QWidget() self._list_pane.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) layout = QtGui.QGridLayout(self._list_pane) layout.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop) layout.setContentsMargins(0, 0, 0, 0) # Remember the editor to use for each individual list item: editor = self.factory.editor if editor is None: editor = trait_handler.item_trait.get_editor() self._editor = getattr( editor, self.kind ) # Set up the additional 'list items changed' event handler needed for # a list based trait. Note that we want to fire the update_editor_item # only when the items in the list change and not when intermediate # traits change. Therefore, replace "." by ":" in the extended_name # when setting up the listener. extended_name = self.extended_name.replace('.', ':') self.context_object.on_trait_change( self.update_editor_item, extended_name + '_items?', dispatch = 'ui' ) self.set_tooltip() #--------------------------------------------------------------------------- # Disposes of the contents of an editor: #--------------------------------------------------------------------------- def dispose ( self ): """ Disposes of the contents of an editor. """ self._dispose_items() extended_name = self.extended_name.replace('.', ':') self.context_object.on_trait_change( self.update_editor_item, extended_name + '_items?', remove = True ) super( SimpleEditor, self ).dispose() #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ # Disconnect the editor from any control about to be destroyed: self._dispose_items() list_pane = self._list_pane layout = list_pane.layout() # Create all of the list item trait editors: trait_handler = self._trait_handler resizable = ((trait_handler.minlen != trait_handler.maxlen) and self.mutable) item_trait = trait_handler.item_trait is_fake = (resizable and (len( self.value ) == 0)) if is_fake: self.empty_list() editor = self._editor for index, value in enumerate(self.value): row, column = divmod(index, self.factory.columns) # Account for the fact that we have number of # pairs column = column * 2 if resizable: control = IconButton('list_editor.png', self.popup_menu) layout.addWidget(control, row, column) proxy = ListItemProxy( self.object, self.name, index, item_trait, value ) if resizable: control.proxy = proxy peditor = editor( self.ui, proxy, 'value', self.description, list_pane ).set( object_name = '' ) peditor.prepare( list_pane ) pcontrol = peditor.control pcontrol.proxy = proxy if isinstance(pcontrol, QtGui.QWidget): layout.addWidget(pcontrol, row, column+1) else: layout.addLayout(pcontrol, row, column+1) # QScrollArea can have problems if the widget being scrolled is set too # early (ie. before it contains something). if self.control.widget() is None: self.control.setWidget(list_pane) #--------------------------------------------------------------------------- # Updates the editor when an item in the object trait changes external to # the editor: #--------------------------------------------------------------------------- def update_editor_item ( self, event ): """ Updates the editor when an item in the object trait changes externally to the editor. """ # If this is not a simple, single item update, rebuild entire editor: if (len( event.removed ) != 1) or (len( event.added ) != 1): self.update_editor() return # Otherwise, find the proxy for this index and update it with the # changed value: for control in self.control.widget().children(): if isinstance(control, QtGui.QLayout): continue proxy = control.proxy if proxy.index == event.index: proxy.value = event.added[0] break #--------------------------------------------------------------------------- # Creates an empty list entry (so the user can add a new item): #--------------------------------------------------------------------------- def empty_list ( self ): """ Creates an empty list entry (so the user can add a new item). """ control = IconButton('list_editor.png', self.popup_empty_menu) control.is_empty = True self._cur_control = control proxy = ListItemProxy( self.object, self.name, -1, None, None ) pcontrol = QtGui.QLabel(' (Empty List)') pcontrol.proxy = control.proxy = proxy layout = self._list_pane.layout() layout.addWidget(control, 0, 0) layout.addWidget(pcontrol, 0, 1) #--------------------------------------------------------------------------- # Returns the associated object list and current item index: #--------------------------------------------------------------------------- def get_info ( self ): """ Returns the associated object list and current item index. """ proxy = self._cur_control.proxy return ( proxy.list, proxy.index ) #--------------------------------------------------------------------------- # Displays the empty list editor popup menu: #--------------------------------------------------------------------------- def popup_empty_menu ( self ): """ Displays the empty list editor popup menu. """ self._cur_control = control = self.control.sender() menu = MakeMenu( self.empty_list_menu, self, True, control ).menu menu.exec_(control.mapToGlobal(QtCore.QPoint(0, 0))) #--------------------------------------------------------------------------- # Displays the list editor popup menu: #--------------------------------------------------------------------------- def popup_menu ( self ): """ Displays the list editor popup menu. """ layout = self._list_pane.layout() sender = layout.sender() self._cur_control = sender proxy = sender.proxy index = proxy.index menu = MakeMenu( self.list_menu, self, True, sender ).menu len_list = len( proxy.list ) not_full = (len_list < self._trait_handler.maxlen) self._menu_before.enabled( not_full ) self._menu_after.enabled( not_full ) self._menu_delete.enabled( len_list > self._trait_handler.minlen ) self._menu_up.enabled( index > 0 ) self._menu_top.enabled( index > 0 ) self._menu_down.enabled( index < (len_list - 1) ) self._menu_bottom.enabled( index < (len_list - 1) ) menu.exec_(sender.mapToGlobal(QtCore.QPoint(0, 0))) #--------------------------------------------------------------------------- # Adds a new value at the specified list index: #--------------------------------------------------------------------------- def add_item ( self, offset ): """ Adds a new value at the specified list index. """ list, index = self.get_info() index += offset item_trait = self._trait_handler.item_trait value = item_trait.default_value_for( self.object, self.name ) self.value = list[:index] + [ value ] + list[index:] self.update_editor() #--------------------------------------------------------------------------- # Inserts a new item before the current item: #--------------------------------------------------------------------------- def add_before ( self ): """ Inserts a new item before the current item. """ self.add_item( 0 ) #--------------------------------------------------------------------------- # Inserts a new item after the current item: #--------------------------------------------------------------------------- def add_after ( self ): """ Inserts a new item after the current item. """ self.add_item( 1 ) #--------------------------------------------------------------------------- # Adds a new item when the list is empty: #--------------------------------------------------------------------------- def add_empty ( self ): """ Adds a new item when the list is empty. """ list, index = self.get_info() self.add_item( 0 ) #--------------------------------------------------------------------------- # Delete the current item: #--------------------------------------------------------------------------- def delete_item ( self ): """ Delete the current item. """ list, index = self.get_info() self.value = list[:index] + list[index+1:] self.update_editor() #--------------------------------------------------------------------------- # Move the current item up one in the list: #--------------------------------------------------------------------------- def move_up ( self ): """ Move the current item up one in the list. """ list, index = self.get_info() self.value = (list[:index-1] + [ list[index], list[index-1] ] + list[index+1:]) self.update_editor() #--------------------------------------------------------------------------- # Moves the current item down one in the list: #--------------------------------------------------------------------------- def move_down ( self ): """ Moves the current item down one in the list. """ list, index = self.get_info() self.value = (list[:index] + [ list[index+1], list[index] ] + list[index+2:]) self.update_editor() #--------------------------------------------------------------------------- # Moves the current item to the top of the list: #--------------------------------------------------------------------------- def move_top ( self ): """ Moves the current item to the top of the list. """ list, index = self.get_info() self.value = [ list[index] ] + list[:index] + list[index+1:] self.update_editor() #--------------------------------------------------------------------------- # Moves the current item to the bottom of the list: #--------------------------------------------------------------------------- def move_bottom ( self ): """ Moves the current item to the bottom of the list. """ list, index = self.get_info() self.value = list[:index] + list[index+1:] + [ list[index] ] self.update_editor() #-- Private Methods -------------------------------------------------------- def _dispose_items ( self ): """ Disposes of each current list item. """ layout = self._list_pane.layout() child = layout.takeAt(0) while child is not None: control = child.widget() if control is not None: editor = getattr( control, '_editor', None ) if editor is not None: editor.dispose() editor.control = None control.deleteLater() child = layout.takeAt(0) del child #-- Trait initializers ---------------------------------------------------- def _kind_default(self): """ Returns a default value for the 'kind' trait. """ return self.factory.style + '_editor' def _mutable_default(self): """ Trait handler to set the mutable trait from the factory. """ return self.factory.mutable #------------------------------------------------------------------------------- # 'CustomEditor' class: #------------------------------------------------------------------------------- class CustomEditor ( SimpleEditor ): """ Custom style of editor for lists, which displays the items as a series of text fields. If the list is editable, an icon next to each item displays a menu of operations on the list. """ #--------------------------------------------------------------------------- # Class constants: #--------------------------------------------------------------------------- # Whether the list is displayed in a single row. This value overrides the # default. single_row = False #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Is the list editor is scrollable? This values overrides the default. scrollable = True #------------------------------------------------------------------------------- # 'TextEditor' class: #------------------------------------------------------------------------------- class TextEditor(CustomEditor): # The kind of editor to create for each list item. This value overrides the # default. kind = 'text_editor' #------------------------------------------------------------------------------- # 'ReadonlyEditor' class: #------------------------------------------------------------------------------- class ReadonlyEditor(CustomEditor): # Is the list of items being edited mutable? This value overrides the # default. mutable = False #------------------------------------------------------------------------------- # 'NotebookEditor' class: #------------------------------------------------------------------------------- class NotebookEditor ( Editor ): """ An editor for lists that displays the list as a "notebook" of tabbed pages. """ # The "Close Tab" button. close_button = Any() # Maps tab names to QWidgets representing the tab contents # TODO: It would be nice to be able to reuse self._pages for this, but # its keys are not quite what we want. _pagewidgets = Dict # Maps names of tabs to their menu QAction instances; used to toggle # checkboxes _action_dict = Dict #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Is the notebook editor scrollable? This values overrides the default: scrollable = True # The currently selected notebook page object: selected = Any # Maps tab names to QWidgets representing the tab contents # TODO: It would be nice to be able to reuse self._pages for this, but # its keys are not quite what we want. _pagewidgets = Dict # Maps names of tabs to their menu QAction instances; used to toggle # checkboxes _action_dict = Dict #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self._uis = [] # Create a tab widget to hold each separate object's view: self.control = QtGui.QTabWidget() signal = QtCore.SIGNAL( 'currentChanged(int)' ) QtCore.QObject.connect( self.control, signal, self._tab_activated ) # Create the button to close tabs, if necessary: if self.factory.deletable: button = QtGui.QToolButton() button.setAutoRaise( True ) button.setToolTip( 'Remove current tab ') button.setIcon ( ImageResource( 'closetab' ).create_icon() ) self.control.setCornerWidget( button, QtCore.Qt.TopRightCorner ) signal = QtCore.SIGNAL( 'clicked()' ) QtCore.QObject.connect( button, signal, self.close_current ) self.close_button = button if self.factory.show_notebook_menu: # Create the necessary attributes to manage hiding and revealing of # tabs via a context menu self._context_menu = QtGui.QMenu() self.control.customContextMenuRequested.connect(self._context_menu_requested) self.control.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) # Set up the additional 'list items changed' event handler needed for # a list based trait: self.context_object.on_trait_change( self.update_editor_item, self.extended_name + '_items?', dispatch = 'ui' ) # Set of selection synchronization: self.sync_value( self.factory.selected, 'selected' ) #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ # Destroy the views on each current notebook page: self.close_all() # Create a tab page for each object in the trait's value: for object in self.value: ui, view_object, monitoring = self._create_page(object) # Remember the page for later deletion processing: self._uis.append([ui.control, ui, view_object, monitoring]) #--------------------------------------------------------------------------- # Handles some subset of the trait's list being updated: #--------------------------------------------------------------------------- def update_editor_item ( self, event ): """ Handles an update to some subset of the trait's list. """ index = event.index # Delete the page corresponding to each removed item: page_name = self.factory.page_name[1:] for i in event.removed: page, ui, view_object, monitoring = self._uis[index] if monitoring: view_object.on_trait_change(self.update_page_name, page_name, remove=True) ui.dispose() self.control.removeTab(self.control.indexOf(page)) if self.factory.show_notebook_menu: for name, tmp in self._pagewidgets.items(): if tmp is page: del self._pagewidgets[name] self._context_menu.removeAction(self._action_dict[name]) del self._action_dict[name] del self._uis[index] # Add a page for each added object: first_page = None for object in event.added: ui, view_object, monitoring = self._create_page(object) self._uis[index:index] = [[ui.control, ui, view_object, monitoring]] index += 1 if first_page is None: first_page = ui.control if first_page is not None: self.control.setCurrentWidget(first_page) #--------------------------------------------------------------------------- # Closes the currently selected tab: #--------------------------------------------------------------------------- def close_current ( self, force=False ): """ Closes the currently selected tab: """ widget = self.control.currentWidget() for i in xrange( len( self._uis ) ): page, ui, _, _ = self._uis[i] if page is widget: if force or ui.handler.close( ui.info, True ): del self.value[i] break if self.factory.show_notebook_menu: # Find the name associated with this widget, so we can purge its action # from the menu for name, tmp in self._pagewidgets.items(): if tmp is widget: break else: # Hmm... couldn't find the widget, assume that we don't need to do # anything. return action = self._action_dict[name] self._context_menu.removeAction(action) del self._action_dict[name] del self._pagewidgets[name] return #--------------------------------------------------------------------------- # Closes all currently open notebook pages: #--------------------------------------------------------------------------- def close_all ( self ): """ Closes all currently open notebook pages. """ page_name = self.factory.page_name[1:] for _, ui, view_object, monitoring in self._uis: if monitoring: view_object.on_trait_change(self.update_page_name, page_name, remove=True) ui.dispose() # Reset the list of ui's and dictionary of page name counts: self._uis = [] self._pages = {} self.control.clear() #--------------------------------------------------------------------------- # Disposes of the contents of an editor: #--------------------------------------------------------------------------- def dispose ( self ): """ Disposes of the contents of an editor. """ self.context_object.on_trait_change( self.update_editor_item, self.name + '_items?', remove = True ) self.close_all() super( NotebookEditor, self ).dispose() #--------------------------------------------------------------------------- # Handles the trait defining a particular page's name being changed: #--------------------------------------------------------------------------- def update_page_name ( self, object, name, old, new ): """ Handles the trait defining a particular page's name being changed. """ for i, value in enumerate(self._uis): page, ui, _, _ = value if object is ui.info.object: name = None handler = getattr(self.ui.handler, '%s_%s_page_name' % (self.object_name, self.name), None) if handler is not None: name = handler(self.ui.info, object) if name is None: name = str(xgetattr(object, self.factory.page_name[1:], '???')) self.control.setTabText(self.control.indexOf(page), name) break #--------------------------------------------------------------------------- # Creates a page for a specified object and adds it to the tab widget: #--------------------------------------------------------------------------- def _create_page ( self, object ): # Create the view for the object: view_object = object factory = self.factory if factory.factory is not None: view_object = factory.factory(object) ui = view_object.edit_traits( parent = self.control, view = factory.view, kind = factory.ui_kind ).set( parent = self.ui ) # Get the name of the page being added to the notebook: name = '' monitoring = False prefix = '%s_%s_page_' % ( self.object_name, self.name ) page_name = factory.page_name if page_name[0:1] == '.': name = xgetattr( view_object, page_name[1:], None ) monitoring = (name is not None) if monitoring: handler_name = None method = getattr( self.ui.handler, prefix + 'name', None ) if method is not None: handler_name = method( self.ui.info, object ) if handler_name is not None: name = handler_name else: name = str( name ) or '???' view_object.on_trait_change( self.update_page_name, page_name[1:], dispatch = 'ui' ) else: name = '' elif page_name != '': name = page_name if name == '': name = user_name_for( view_object.__class__.__name__ ) # Make sure the name is not a duplicate: if not monitoring: self._pages[ name ] = count = self._pages.get( name, 0 ) + 1 if count > 1: name += (' %d' % count) # Return the control for the ui, and whether or not its name is being # monitored: image = None method = getattr( self.ui.handler, prefix + 'image', None ) if method is not None: image = method( self.ui.info, object ) if image is None: self.control.addTab(ui.control, name) else: self.control.addTab(ui.control, image, name) if self.factory.show_notebook_menu: newaction = self._context_menu.addAction(name) newaction.setText(name) newaction.setCheckable(True) newaction.setChecked(True) newaction.triggered.connect(lambda e,name=name: self._menu_action(e,name=name)) self._action_dict[name] = newaction self._pagewidgets[name] = ui.control return (ui, view_object, monitoring) def _tab_activated(self, idx): """ Handles a notebook tab being "activated" (i.e. clicked on) by the user. """ widget = self.control.widget(idx) for page, ui, _, _ in self._uis: if page is widget: self.selected = ui.info.object break def _selected_changed(self, selected): """ Handles the **selected** trait being changed. """ for page, ui, _, _ in self._uis: if ui.info and selected is ui.info.object: self.control.setCurrentWidget(page) break deletable = self.factory.deletable deletable_trait = self.factory.deletable_trait if deletable and deletable_trait: enabled = xgetattr(selected, deletable_trait, True) self.close_button.setEnabled(enabled) def _context_menu_requested(self, event): self._context_menu.popup(self.control.mapToGlobal(event)) def _menu_action(self, event, name=""): """ Qt signal handler for when a item in a context menu is actually selected. Not that we get this even after the underlying value has already changed. """ action = self._action_dict[name] checked = action.isChecked() if not checked: for ndx in range(self.control.count()): if self.control.tabText(ndx) == name: self.control.removeTab(ndx) else: # TODO: Fix tab order based on the context_object's list self.control.addTab(self._pagewidgets[name], name) def _context_menu_requested(self, event): self._context_menu.popup(self.control.mapToGlobal(event)) def _menu_action(self, event, name=""): """ Qt signal handler for when a item in a context menu is actually selected. Not that we get this even after the underlying value has already changed. """ action = self._action_dict[name] checked = action.isChecked() if not checked: for ndx in range(self.control.count()): if self.control.tabText(ndx) == name: self.control.removeTab(ndx) else: # TODO: Fix tab order based on the context_object's list self.control.addTab(self._pagewidgets[name], name) traitsui-4.1.0/traitsui/qt4/set_editor.py0000644000175100001440000005004611674463546021455 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2007, Riverbank Computing Limited # All rights reserved. # # This software is provided without warranty under the terms of the BSD license. # However, when used with the GPL version of PyQt the additional terms described in the PyQt GPL exception also apply # # Author: Riverbank Computing Limited #------------------------------------------------------------------------------ """ Defines the set editors for the PyQt user interface toolkit. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from pyface.qt import QtCore, QtGui # FIXME: ToolkitEditorFactory is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.set_editor file. from traitsui.editors.set_editor \ import ToolkitEditorFactory from traitsui.helper \ import enum_values_changed from editor \ import Editor from traits.api \ import Instance, Property #------------------------------------------------------------------------------- # 'SimpleEditor' class: #------------------------------------------------------------------------------- class SimpleEditor ( Editor ): """ Simple style of editor for sets. The editor displays two list boxes, with buttons for moving the selected items from left to right, or vice versa. If **can_move_all** on the factory is True, then buttons are displayed for moving all the items to one box or the other. If the set is ordered, buttons are displayed for moving the selected item up or down in right-side list box. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # The top level QLayout for the editor: root_layout = Instance(QtGui.QLayout) # Current set of enumeration names: names = Property # Current mapping from names to values: mapping = Property # Current inverse mapping from values to names: inverse_mapping = Property # Is set editor scrollable? This value overrides the default. scrollable = True #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self.control = QtGui.QWidget() self.root_layout = QtGui.QGridLayout(self.control) self.root_layout.setContentsMargins(0, 0, 0, 0) factory = self.factory if factory.name != '': self._object, self._name, self._value = \ self.parse_extended_name( factory.name ) self.values_changed() self._object.on_trait_change( self._values_changed, self._name, dispatch = 'ui' ) else: factory.on_trait_change( self.update_editor, 'values_modified', dispatch = 'ui' ) blayout = QtGui.QVBoxLayout() self._unused = self._create_listbox(0, self._on_unused, self._on_use, factory.left_column_title) self._use_all = self._unuse_all = self._up = self._down = None if factory.can_move_all: self._use_all = self._create_button('>>', blayout, self._on_use_all) self._use = self._create_button('>', blayout, self._on_use) self._unuse = self._create_button('<', blayout, self._on_unuse) if factory.can_move_all: self._unuse_all = self._create_button('<<', blayout, self._on_unuse_all) if factory.ordered: self._up = self._create_button('Move Up', blayout, self._on_up) self._down = self._create_button('Move Down', blayout, self._on_down) self.root_layout.addLayout(blayout, 1, 1, QtCore.Qt.AlignCenter) self._used = self._create_listbox(2, self._on_value, self._on_unuse, factory.right_column_title) self.context_object.on_trait_change( self.update_editor, self.extended_name + '_items?', dispatch = 'ui' ) #--------------------------------------------------------------------------- # Gets the current set of enumeration names: #--------------------------------------------------------------------------- def _get_names ( self ): """ Gets the current set of enumeration names. """ if self._object is None: return self.factory._names return self._names #--------------------------------------------------------------------------- # Gets the current mapping: #--------------------------------------------------------------------------- def _get_mapping ( self ): """ Gets the current mapping. """ if self._object is None: return self.factory._mapping return self._mapping #--------------------------------------------------------------------------- # Gets the current inverse mapping: #--------------------------------------------------------------------------- def _get_inverse_mapping ( self ): """ Gets the current inverse mapping. """ if self._object is None: return self.factory._inverse_mapping return self._inverse_mapping #--------------------------------------------------------------------------- # Creates a list box: #--------------------------------------------------------------------------- def _create_listbox(self, col, handler1, handler2, title): """Creates a list box. """ # Add the column title in emphasized text: title_widget = QtGui.QLabel(title) font = QtGui.QFont(title_widget.font()) font.setBold(True) font.setPointSize(font.pointSize() + 1) title_widget.setFont(font) self.root_layout.addWidget(title_widget, 0, col, QtCore.Qt.AlignLeft) # Create the list box and add it to the column: list = QtGui.QListWidget() list.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection) self.root_layout.addWidget(list, 1, col) list.connect(list, QtCore.SIGNAL('itemClicked(QListWidgetItem *)'), handler1) list.connect(list, QtCore.SIGNAL('itemDoubleClicked(QListWidgetItem *)'), handler2) return list #--------------------------------------------------------------------------- # Creates a button: #--------------------------------------------------------------------------- def _create_button(self, label, layout, handler): """ Creates a button. """ button = QtGui.QPushButton(label) button.connect(button, QtCore.SIGNAL('clicked()'), handler) layout.addWidget(button) return button #--------------------------------------------------------------------------- # Recomputes the cached data based on the underlying enumeration model: #--------------------------------------------------------------------------- def values_changed ( self ): """ Recomputes the cached data based on the underlying enumeration model. """ self._names, self._mapping, self._inverse_mapping = \ enum_values_changed( self._value(), self.string_value ) #--------------------------------------------------------------------------- # Handles the underlying object model's enumeration set being changed: #--------------------------------------------------------------------------- def _values_changed ( self ): """ Handles the underlying object model's enumeration set being changed. """ self.values_changed() self.update_editor() #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ # Check for any items having been deleted from the enumeration that are # still present in the object value: mapping = self.inverse_mapping.copy() values = [ v for v in self.value if v in mapping ] if len( values ) < len( self.value ): self.value = values # Get a list of the selected items in the right box: used = self._used used_labels = self._get_selected_strings( used ) # Get a list of the selected items in the left box: unused = self._unused unused_labels = self._get_selected_strings( unused ) # Empty list boxes in preparation for rebuilding from current values: used.clear() unused.clear() # Ensure right list box is kept alphabetized unless insertion # order is relevant: if not self.factory.ordered: values = values[:] values.sort() # Rebuild the right listbox: used_selections = [] for i, value in enumerate( values ): label = mapping[ value ] used.addItem(label) del mapping[ value ] if label in used_labels: used_selections.append(i) # Rebuild the left listbox: unused_selections = [] unused_items = mapping.values() unused_items.sort() mapping = self.mapping self._unused_items = [ mapping[ ui ] for ui in unused_items ] for i, unused_item in enumerate( unused_items ): unused.addItem(unused_item) if unused_item in unused_labels: unused_selections.append( i ) # If nothing is selected, default selection should be top of left box, # or of right box if left box is empty: if (len( used_selections ) == 0) and (len( unused_selections ) == 0): if unused.count() == 0: used_selections.append(0) else: unused_selections.append(0) used_count = used.count() for i in used_selections: if i < used_count: used.item(i).setSelected(True) unused_count = unused.count() for i in unused_selections: if i < unused_count: unused.item(i).setSelected(True) self._check_up_down() self._check_left_right() #--------------------------------------------------------------------------- # Disposes of the contents of an editor: #--------------------------------------------------------------------------- def dispose ( self ): """ Disposes of the contents of an editor. """ if self._object is not None: self._object.on_trait_change( self._values_changed, self._name, remove = True ) else: self.factory.on_trait_change( self.update_editor, 'values_modified', remove = True ) self.context_object.on_trait_change( self.update_editor, self.extended_name + '_items?', remove = True ) super( SimpleEditor, self ).dispose() #--------------------------------------------------------------------------- # Returns the editor's control for indicating error status: #--------------------------------------------------------------------------- def get_error_control ( self ): """ Returns the editor's control for indicating error status. """ return [ self._unused, self._used ] #--------------------------------------------------------------------------- # Event handlers: #--------------------------------------------------------------------------- def _on_value(self): if not self.factory.ordered: self._unused.clearSelection() self._check_left_right() self._check_up_down() def _on_unused(self): if not self.factory.ordered: self._used.clearSelection() self._check_left_right() self._check_up_down() def _on_use(self): self._unused_items, self.value = self._transfer_items( self._unused, self._used, self._unused_items, self.value ) def _on_unuse(self): self.value, self._unused_items = self._transfer_items( self._used, self._unused, self.value, self._unused_items ) def _on_use_all(self): self._unused_items, self.value = self._transfer_all( self._unused, self._used, self._unused_items, self.value ) def _on_unuse_all(self): self.value, self._unused_items = self._transfer_all( self._used, self._unused, self.value, self._unused_items ) def _on_up(self): self._move_item(-1) def _on_down(self): self._move_item(1) #--------------------------------------------------------------------------- # Private methods: #--------------------------------------------------------------------------- #--------------------------------------------------------------------------- # Transfers all items from one list to another: #--------------------------------------------------------------------------- def _transfer_all ( self, list_from, list_to, values_from, values_to ): """ Transfers all items from one list to another. """ values_from = values_from[:] values_to = values_to[:] list_from.clearSelection() while list_from.count() > 0: index_to = list_to.count() list_from.item(0).setSelected(True) list_to.insertItems(index_to, self._get_selected_strings(list_from)) list_from.takeItem(0) values_to.append(values_from[0]) del values_from[0] list_to.item(0).setSelected(True) self._check_left_right() self._check_up_down() return ( values_from, values_to ) #--------------------------------------------------------------------------- # Transfers the selected item from one list to another: #--------------------------------------------------------------------------- def _transfer_items ( self, list_from, list_to, values_from, values_to ): """ Transfers the selected item from one list to another. """ values_from = values_from[:] values_to = values_to[:] index_from = max( self._get_first_selection( list_from ), 0 ) index_to = max( self._get_first_selection( list_to ), 0 ) list_to.clearSelection() # Get the list of strings in the "from" box to be moved: selected_list = self._get_selected_strings( list_from ) # fixme: I don't know why I have to reverse the list to get # correct behavior from the ordered list box. Investigate -- LP selected_list.reverse() list_to.insertItems(index_to, selected_list) # Delete the transferred items from the left box: items_from = list_from.selectedItems() for i in range(len(items_from) - 1, -1, -1): list_from.takeItem(list_from.row(items_from[i])) del items_from # Delete the transferred items from the "unused" value list: for item_label in selected_list: val_index_from = values_from.index( self.mapping[ item_label ] ) values_to.insert( index_to, values_from[ val_index_from ] ) del values_from[ val_index_from ] # If right list is ordered, keep moved items selected: if self.factory.ordered: items = list_to.findItems(item_label, QtCore.Qt.MatchFixedString|QtCore.Qt.MatchCaseSensitive) if items: items[0].setSelected(True) # Reset the selection in the left box: count = list_from.count() if count > 0: if index_from >= count: index_from = count - 1 list_from.item(index_from).setSelected(True) self._check_left_right() self._check_up_down() return ( values_from, values_to ) #--------------------------------------------------------------------------- # Moves an item up or down with the 'used' list: #--------------------------------------------------------------------------- def _move_item ( self, direction ): """ Moves an item up or down within the "used" list. """ # Move the item up/down within the list: listbox = self._used index_from = self._get_first_selection(listbox) index_to = index_from + direction label = listbox.takeItem(index_from).text() listbox.insertItem(index_to, label) listbox.item(index_to).setSelected(True) # Enable the up/down buttons appropriately: self._check_up_down() # Move the item up/down within the editor's trait value: value = self.value if direction < 0: index = index_to values = [ value[ index_from ], value[ index_to ] ] else: index = index_from values = [ value[ index_to ], value[ index_from ] ] self.value = value[ : index ] + values + value[ index + 2: ] #--------------------------------------------------------------------------- # Sets the proper enable state for the up and down buttons: #--------------------------------------------------------------------------- def _check_up_down ( self ): """ Sets the proper enabled state for the up and down buttons. """ if self.factory.ordered: selected = self._used.selectedItems() self._up.setEnabled(len(selected) == 1 and selected[0] is not self._used.item(0)) self._down.setEnabled(len(selected) == 1 and selected[0] is not self._used.item(self._used.count() - 1)) #--------------------------------------------------------------------------- # Sets the proper enable state for the left and right buttons: #--------------------------------------------------------------------------- def _check_left_right(self): """ Sets the proper enabled state for the left and right buttons. """ self._use.setEnabled(self._unused.count() > 0 and self._get_first_selection(self._unused) >= 0) self._unuse.setEnabled(self._used.count() > 0 and self._get_first_selection(self._used) >= 0) if self.factory.can_move_all: self._use_all.setEnabled(self._unused.count() > 0 and self._get_first_selection(self._unused) >= 0) self._unuse_all.setEnabled(self._used.count() > 0 and self._get_first_selection(self._used) >= 0) #--------------------------------------------------------------------------- # Returns a list of the selected strings in the listbox #--------------------------------------------------------------------------- def _get_selected_strings(self, listbox): """ Returns a list of the selected strings in the given *listbox*. """ return [unicode(itm.text()) for itm in listbox.selectedItems()] #--------------------------------------------------------------------------- # Returns the index of the first (or only) selected item. #--------------------------------------------------------------------------- def _get_first_selection ( self, listbox ): """ Returns the index of the first (or only) selected item. """ select_list = listbox.selectedItems() if len(select_list) == 0: return -1 return listbox.row(select_list[0]) traitsui-4.1.0/traitsui/qt4/tabular_model.py0000644000175100001440000002546211674463546022132 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2009, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: Evan Patterson # Date: 06/22/2009 # #------------------------------------------------------------------------------- """ Defines the table model used by the tabular editor. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from pyface.qt import QtCore, QtGui from traitsui.ui_traits import SequenceTypes #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- # Mapping for trait alignment values to qt4 alignment values: alignment_map = { 'left': QtCore.Qt.AlignLeft, 'right': QtCore.Qt.AlignRight, 'center': QtCore.Qt.AlignHCenter, 'justify': QtCore.Qt.AlignJustify } # MIME type for internal table drag/drop operations tabular_mime_type = 'traits-ui-tabular-editor' #------------------------------------------------------------------------------- # 'TabularModel' class: #------------------------------------------------------------------------------- class TabularModel(QtCore.QAbstractTableModel): """ The model for tabular data.""" def __init__(self, editor, parent=None): """ Initialise the object. """ QtCore.QAbstractTableModel.__init__(self, parent) self._editor = editor #--------------------------------------------------------------------------- # QAbstractItemModel interface: #--------------------------------------------------------------------------- def data(self, mi, role): """ Reimplemented to return the data. """ editor = self._editor adapter = editor.adapter obj, name = editor.object, editor.name row, column = mi.row(), mi.column() if role == QtCore.Qt.DisplayRole or role == QtCore.Qt.EditRole: return adapter.get_text(obj, name, row, column) elif role == QtCore.Qt.DecorationRole: image = editor._get_image(adapter.get_image(obj, name, row, column)) if image is not None: return image elif role == QtCore.Qt.ToolTipRole: tooltip = adapter.get_tooltip(obj, name, row, column) if tooltip: return tooltip elif role == QtCore.Qt.FontRole: font = adapter.get_font(obj, name, row, column) if font is not None: return QtGui.QFont(font) elif role == QtCore.Qt.TextAlignmentRole: string = adapter.get_alignment(obj, name, column) alignment = alignment_map.get(string, QtCore.Qt.AlignLeft) return (alignment | QtCore.Qt.AlignVCenter) elif role == QtCore.Qt.BackgroundRole: color = adapter.get_bg_color(obj, name, row, column) if color is not None: if isinstance(color, SequenceTypes): q_color = QtGui.QColor(*color) else: q_color = QtGui.QColor(color) return QtGui.QBrush(q_color) elif role == QtCore.Qt.ForegroundRole: color = adapter.get_text_color(obj, name, row, column) if color is not None: if isinstance(color, SequenceTypes): q_color = QtGui.QColor(*color) else: q_color = QtGui.QColor(color) return QtGui.QBrush(q_color) return None def setData(self, mi, value, role): """ Reimplmented to allow for modification for the object trait. """ if role != QtCore.Qt.EditRole: return False editor = self._editor obj, name = editor.object, editor.name row, column = mi.row(), mi.column() editor.adapter.set_text(obj, name, row, column, value) signal = QtCore.SIGNAL('dataChanged(QModelIndex,QModelIndex)') self.emit(signal, mi, mi) return True def flags(self, mi): """ Reimplemented to set editable status and movable status. """ editor = self._editor row = mi.row() column = mi.column() flags = QtCore.Qt.ItemIsEnabled if editor.factory.selectable: flags |= QtCore.Qt.ItemIsSelectable # If the adapter defines get_can_edit_cell(), use it to determine # editability over the row-wise get_can_edit(). if (editor.factory.editable and 'edit' in editor.factory.operations and hasattr(editor.adapter, 'get_can_edit_cell')): if editor.adapter.get_can_edit_cell(editor.object, editor.name, row, column): flags |= QtCore.Qt.ItemIsEditable elif (editor.factory.editable and 'edit' in editor.factory.operations and editor.adapter.get_can_edit(editor.object, editor.name, row)): flags |= QtCore.Qt.ItemIsEditable if (editor.factory.editable and 'move' in editor.factory.operations and editor.adapter.get_drag(editor.object, editor.name, row) is not None): flags |= QtCore.Qt.ItemIsDragEnabled | QtCore.Qt.ItemIsDropEnabled return flags def headerData(self, section, orientation, role): """ Reimplemented to return the header data. """ if orientation != QtCore.Qt.Horizontal or role != QtCore.Qt.DisplayRole: return None editor = self._editor label = editor.adapter.get_label(section, editor.object) return label def rowCount(self, mi): """ Reimplemented to return the number of rows. """ editor = self._editor return editor.adapter.len(editor.object, editor.name) def columnCount(self, mi): """ Reimplemented to return the number of columns. """ editor = self._editor return len(editor.adapter.columns) def insertRow(self, row, parent=QtCore.QModelIndex(), obj=None): """ Reimplemented to allow creation of new rows. Added an optional arg to allow the insertion of an existing row object. """ editor = self._editor adapter = editor.adapter if obj is None: obj = adapter.get_default_value(editor.object, editor.name) self.beginInsertRows(parent, row, row) editor.callx(editor.adapter.insert, editor.object, editor.name, row, obj) self.endInsertRows() return True def insertRows(self, row, count, parent=QtCore.QModelIndex()): """ Reimplemented to allow creation of new items. """ editor = self._editor adapter = editor.adapter self.beginInsertRows(parent, row, row + count - 1) for i in xrange(count): value = adapter.get_default_value(editor.object, editor.name) editor.callx(adapter.insert, editor.object, editor.name, row, value) self.endInsertRows() return True def removeRows(self, row, count, parent=QtCore.QModelIndex()): """ Reimplemented to allow row deletion, as well as reordering via drag and drop. """ editor = self._editor adapter = editor.adapter self.beginRemoveRows(parent, row, row + count - 1) for i in xrange(count): editor.callx(adapter.delete, editor.object, editor.name, row) self.endRemoveRows() n = self.rowCount(None) if not editor.factory.multi_select: editor.selected_row = row if row < n else row-1 else: #FIXME: what should the selection be? editor.multi_selected_rows = [] return True def mimeTypes(self): """ Reimplemented to expose our internal MIME type for drag and drop operations. """ return [ tabular_mime_type ] def mimeData(self, indexes): """ Reimplemented to generate MIME data containing the rows of the current selection. """ mime_data = QtCore.QMimeData() rows = list(set([ index.row() for index in indexes ])) data = QtCore.QByteArray(str(rows[0])) for row in rows[1:]: data.append(' %i' % row) mime_data.setData(tabular_mime_type, data) return mime_data def dropMimeData(self, mime_data, action, row, column, parent): """ Reimplemented to allow items to be moved. """ if action == QtCore.Qt.IgnoreAction: return False data = mime_data.data(tabular_mime_type) if data.isNull(): return False current_rows = map(int, str(data).split(' ')) self.moveRows(current_rows, parent.row()) return True def supportedDropActions(self): """ Reimplemented to allow items to be moved. """ return QtCore.Qt.MoveAction #--------------------------------------------------------------------------- # TabularModel interface: #--------------------------------------------------------------------------- def moveRow(self, old_row, new_row): """ Convenience method to move a single row. """ return self.moveRows([old_row], new_row) def moveRows(self, current_rows, new_row): """ Moves a sequence of rows (provided as a list of row indexes) to a new row. """ editor = self._editor # Sort rows in descending order so they can be removed without # invalidating the indices. current_rows.sort() current_rows.reverse() # If the the highest selected row is lower than the destination, do an # insertion before rather than after the destination. if current_rows[-1] < new_row: new_row += 1 # Remove selected rows... objects = [] for row in current_rows: if row <= new_row: new_row -= 1 obj = editor.adapter.get_item(editor.object, editor.name, row) objects.insert(0, obj) self.removeRow(row) # ...and add them at the new location. for i, obj in enumerate(objects): self.insertRow(new_row + i, obj=obj) # Update the selection for the new location. if editor.factory.multi_select: editor.setx(multi_selected = objects) editor.multi_selected_rows = range(new_row, new_row + len(objects)) else: editor.setx(selected = objects[0]) editor.selected_row = new_row traitsui-4.1.0/traitsui/qt4/clipboard.py0000644000175100001440000001302411674463546021246 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2007, Riverbank Computing Limited # All rights reserved. # # This software is provided without warranty under the terms of the BSD license. # However, when used with the GPL version of PyQt the additional terms described in the PyQt GPL exception also apply # # Author: Riverbank Computing Limited #------------------------------------------------------------------------------ """ Implements a wrapper around the PyQt clipboard that handles Python objects using pickle. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from cPickle import dumps, load, loads from cStringIO import StringIO from pyface.qt import QtCore, QtGui from traits.api import HasTraits, Instance, Property #------------------------------------------------------------------------------- # 'PyMimeData' class: #------------------------------------------------------------------------------- class PyMimeData(QtCore.QMimeData): """ The PyMimeData wraps a Python instance as MIME data. """ # The MIME type for instances. MIME_TYPE = 'application/x-ets-qt4-instance' NOPICKLE_MIME_TYPE = 'application/x-ets-qt4-instance-no-pickle' def __init__(self, data=None, pickle=True): """ Initialise the instance. """ QtCore.QMimeData.__init__(self) # Keep a local reference to be returned if possible. self._local_instance = data if pickle: if data is not None: # We may not be able to pickle the data. try: pdata = dumps(data) except: return # This format (as opposed to using a single sequence) allows the # type to be extracted without unpickling the data itself. self.setData(self.MIME_TYPE, dumps(data.__class__) + pdata) else: self.setData(self.NOPICKLE_MIME_TYPE, str(id(data))) @classmethod def coerce(cls, md): """ Coerce a QMimeData instance to a PyMimeData instance if possible. """ # See if the data is already of the right type. If it is then we know # we are in the same process. if isinstance(md, cls): return md # See if the data type is supported. if not md.hasFormat(cls.MIME_TYPE): return None nmd = cls() nmd.setData(cls.MIME_TYPE, md.data()) return nmd def instance(self): """ Return the instance. """ if self._local_instance is not None: return self._local_instance io = StringIO(str(self.data(self.MIME_TYPE))) try: # Skip the type. load(io) # Recreate the instance. return load(io) except: pass return None def instanceType(self): """ Return the type of the instance. """ if self._local_instance is not None: return self._local_instance.__class__ try: if self.hasFormat(self.MIME_TYPE): return loads(str(self.data(self.MIME_TYPE))) except: pass return None #------------------------------------------------------------------------------- # '_Clipboard' class: #------------------------------------------------------------------------------- class _Clipboard(HasTraits): """ The _Clipboard class provides a wrapper around the PyQt clipboard. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # The instance on the clipboard (if any). instance = Property # Set if the clipboard contains an instance. has_instance = Property # The type of the instance on the clipboard (if any). instance_type = Property # The application clipboard. clipboard = Instance(QtGui.QClipboard) #--------------------------------------------------------------------------- # Instance property methods: #--------------------------------------------------------------------------- def _get_instance(self): """ The instance getter. """ md = PyMimeData.coerce(self.clipboard.mimeData()) if md is None: return None return md.instance() def _set_instance(self, data): """ The instance setter. """ self.clipboard.setMimeData(PyMimeData(data)) def _get_has_instance(self): """ The has_instance getter. """ return self.clipboard.mimeData().hasFormat(PyMimeData.MIME_TYPE) def _get_instance_type(self): """ The instance_type getter. """ md = PyMimeData.coerce(self.clipboard.mimeData()) if md is None: return None return md.instanceType() #--------------------------------------------------------------------------- # Other trait handlers: #--------------------------------------------------------------------------- def _clipboard_default(self): """ Initialise the clipboard. """ return QtGui.QApplication.clipboard() #------------------------------------------------------------------------------- # The singleton clipboard instance. #------------------------------------------------------------------------------- clipboard = _Clipboard() traitsui-4.1.0/traitsui/qt4/ui_editor.py0000644000175100001440000000236511674463546021300 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2009, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # #------------------------------------------------------------------------------ """ Defines the BasicUIEditor class, which allows creating editors that define their function by creating an embedded Traits UI. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from traitsui.ui_editor import UIEditor as BaseUIEditor from editor import Editor #------------------------------------------------------------------------------- # 'UIEditor' base class: #------------------------------------------------------------------------------- class UIEditor(BaseUIEditor, Editor): """ An editor that creates an embedded Traits UI. """ pass traitsui-4.1.0/traitsui/qt4/tabular_editor.py0000644000175100001440000007021711674463546022316 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2009, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: Evan Patterson # Date: 06/22/2009 # #------------------------------------------------------------------------------- """ A traits UI editor for editing tabular data (arrays, list of tuples, lists of objects, etc). """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from pyface.qt import QtCore, QtGui from pyface.image_resource import ImageResource from traits.api import (Any, Bool, Callable, Event, HasStrictTraits, Instance, Int, List, NO_COMPARE, Property, TraitListEvent) from traitsui.tabular_adapter import TabularAdapter from traitsui.ui_traits import Image from editor import Editor from tabular_model import TabularModel class HeaderEventFilter(QtCore.QObject) : def __init__(self, editor) : super(HeaderEventFilter, self).__init__() self.editor = editor def eventFilter(self, obj, event) : if event.type() == QtCore.QEvent.ContextMenu : self.editor._on_column_context_menu(event.pos()) return True return False class TabularEditor(Editor): """ A traits UI editor for editing tabular data (arrays, list of tuples, lists of objects, etc). """ #-- Trait Definitions ------------------------------------------------------ # The event fired when a table update is needed: update = Event # The event fired when a simple repaint is needed: refresh = Event # The current set of selected items (which one is used depends upon the # initial state of the editor factory 'multi_select' trait): selected = Any multi_selected = List # The current set of selected item indices (which one is used depends upon # the initial state of the editor factory 'multi_select' trait): selected_row = Int(-1) multi_selected_rows = List(Int) # The most recently actived item and its index: activated = Any(comparison_mode=NO_COMPARE) activated_row = Int(comparison_mode=NO_COMPARE) # The most recent left click data: clicked = Instance('TabularEditorEvent') # The most recent left double click data: dclicked = Instance('TabularEditorEvent') # The most recent right click data: right_clicked = Instance('TabularEditorEvent') # The most recent right double click data: right_dclicked = Instance('TabularEditorEvent') # The most recent column click data: column_clicked = Instance('TabularEditorEvent') # The most recent column click data: column_right_clicked = Instance('TabularEditorEvent') # The event triggering scrolling. scroll_to_row = Event(Int) # Is the tabular editor scrollable? This value overrides the default. scrollable = True # Row index of item to select after rebuilding editor list: row = Any # Should the selected item be edited after rebuilding the editor list: edit = Bool(False) # The adapter from trait values to editor values: adapter = Instance(TabularAdapter) # The table model associated with the editor: model = Instance(TabularModel) # Dictionary mapping image names to QIcons images = Any({}) # Dictionary mapping ImageResource objects to QIcons image_resources = Any({}) # An image being converted: image = Image header_event_filter = Any() widget_factory = Callable(lambda *args, **kwds: _TableView(*args, **kwds)) #--------------------------------------------------------------------------- # Editor interface: #--------------------------------------------------------------------------- def init (self, parent): """ Finishes initializing the editor by creating the underlying toolkit widget. """ factory = self.factory adapter = self.adapter = factory.adapter self.model = TabularModel(editor=self) # Create the control control = self.control = self.widget_factory(self) # Set up the selection listener if factory.multi_select: self.sync_value(factory.selected, 'multi_selected', 'both', is_list=True) self.sync_value(factory.selected_row, 'multi_selected_rows','both', is_list=True) else: self.sync_value(factory.selected, 'selected', 'both') self.sync_value(factory.selected_row, 'selected_row', 'both') # Connect to the mode specific selection handler if factory.multi_select: slot = self._on_rows_selection else: slot = self._on_row_selection signal = 'selectionChanged(QItemSelection,QItemSelection)' QtCore.QObject.connect(self.control.selectionModel(), QtCore.SIGNAL(signal), slot) # Synchronize other interesting traits as necessary: self.sync_value(factory.update, 'update', 'from') self.sync_value(factory.refresh, 'refresh', 'from') self.sync_value(factory.activated, 'activated', 'to') self.sync_value(factory.activated_row, 'activated_row', 'to') self.sync_value(factory.clicked, 'clicked', 'to') self.sync_value(factory.dclicked, 'dclicked', 'to') self.sync_value(factory.right_clicked, 'right_clicked', 'to') self.sync_value(factory.right_dclicked, 'right_dclicked', 'to') self.sync_value(factory.column_clicked, 'column_clicked', 'to') self.sync_value(factory.column_right_clicked, 'column_right_clicked', 'to') self.sync_value(factory.scroll_to_row, 'scroll_to_row', 'from') # Connect other signals as necessary signal = QtCore.SIGNAL('activated(QModelIndex)') QtCore.QObject.connect(control, signal, self._on_activate) signal = QtCore.SIGNAL('clicked(QModelIndex)') QtCore.QObject.connect(control, signal, self._on_click) signal = QtCore.SIGNAL('clicked(QModelIndex)') QtCore.QObject.connect(control, signal, self._on_right_click) signal = QtCore.SIGNAL('doubleClicked(QModelIndex)') QtCore.QObject.connect(control, signal, self._on_dclick) signal = QtCore.SIGNAL('sectionClicked(int)') QtCore.QObject.connect(control.horizontalHeader(), signal, self._on_column_click) control.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) signal = QtCore.SIGNAL('customContextMenuRequested(QPoint)') QtCore.QObject.connect(control, signal, self._on_context_menu) self.header_event_filter = HeaderEventFilter(self) control.horizontalHeader().installEventFilter(self.header_event_filter) # Make sure we listen for 'items' changes as well as complete list # replacements: try: self.context_object.on_trait_change( self.update_editor, self.extended_name+'_items', dispatch='ui') except: pass # If the user has requested automatic update, attempt to set up the # appropriate listeners: if factory.auto_update: self.context_object.on_trait_change( self.refresh_editor, self.extended_name + '.-', dispatch='ui') # Create the mapping from user supplied images to QImages: for image_resource in factory.images: self._add_image(image_resource) # Refresh the editor whenever the adapter changes: self.on_trait_change(self.refresh_editor, 'adapter.+update', dispatch='ui') # Rebuild the editor columns and headers whenever the adapter's # 'columns' changes: self.on_trait_change(self.update_editor, 'adapter.columns', dispatch='ui') def dispose (self): """ Disposes of the contents of an editor. """ self.context_object.on_trait_change( self.update_editor, self.extended_name + '_items', remove=True) if self.factory.auto_update: self.context_object.on_trait_change( self.refresh_editor, self.extended_name + '.-', remove=True) self.on_trait_change(self.refresh_editor, 'adapter.+update', remove=True) self.on_trait_change(self.update_editor, 'adapter.columns', remove=True) self.adapter.cleanup() super(TabularEditor, self).dispose() def update_editor(self): """ Updates the editor when the object trait changes externally to the editor. """ if not self._no_update: self.model.reset() if self.factory.multi_select: self._multi_selected_changed(self.multi_selected) else : self._selected_changed(self.selected) #--------------------------------------------------------------------------- # TabularEditor interface: #--------------------------------------------------------------------------- def refresh_editor(self): """ Requests the table view to redraw itself. """ self.control.viewport().update() def callx(self, func, *args, **kw): """ Call a function without allowing the editor to update. """ old = self._no_update self._no_update = True try: func(*args, **kw) finally: self._no_update = old def setx(self, **keywords): """ Set one or more attributes without allowing the editor to update. """ old = self._no_notify self._no_notify = True try: for name, value in keywords.items(): setattr(self, name, value) finally: self._no_notify = old #--------------------------------------------------------------------------- # UI preference save/restore interface: #--------------------------------------------------------------------------- def restore_prefs(self, prefs): """ Restores any saved user preference information associated with the editor. """ cws = prefs.get('cached_widths') num_columns = len(self.adapter.columns) if cws is not None and num_columns == len(cws): for column in xrange(num_columns): self.control.setColumnWidth(column, cws[column]) def save_prefs(self): """ Returns any user preference information associated with the editor. """ widths = [ self.control.columnWidth(column) for column in xrange(len(self.adapter.columns)) ] return { 'cached_widths': widths } #--------------------------------------------------------------------------- # Private methods: #--------------------------------------------------------------------------- def _add_image(self, image_resource): """ Adds a new image to the image map. """ image = image_resource.create_icon() self.image_resources[image_resource] = image self.images[image_resource.name] = image return image def _get_image(self, image): """ Converts a user specified image to a QIcon. """ if isinstance(image, basestring): self.image = image image = self.image if isinstance(image, ImageResource): result = self.image_resources.get(image) if result is not None: return result return self._add_image(image) return self.images.get(image) def _mouse_click(self, index, trait): """ Generate a TabularEditorEvent event for a specified model index and editor trait name. """ event = TabularEditorEvent(editor=self, row=index.row(), column=index.column()) setattr(self, trait, event) #-- Trait Event Handlers --------------------------------------------------- def _update_changed(self): self.update_editor() def _refresh_changed(self): self.refresh_editor() def _selected_changed(self, new): if not self._no_update: try: selected_row = self.value.index(new) except: pass else: self._selected_row_changed(selected_row) def _selected_row_changed(self, selected_row): if not self._no_update: smodel = self.control.selectionModel() if selected_row == -1: smodel.clearSelection() else: smodel.select(self.model.index(selected_row, 0), QtGui.QItemSelectionModel.ClearAndSelect | QtGui.QItemSelectionModel.Rows) def _multi_selected_changed(self, new): if not self._no_update: values = self.value try: rows = [ values.index(i) for i in new] except: pass else: self._multi_selected_rows_changed(rows) def _multi_selected_items_changed(self, event): values = self.values try: added = [ values.index(item) for item in event.added ] removed = [ values.index(item) for item in event.removed ] except: pass else: list_event = TraitListEvent(0, added, removed) self._multi_selected_rows_items_changed(list_event) def _multi_selected_rows_changed(self, selected_rows): if not self._no_update: smodel = self.control.selectionModel() selection = QtGui.QItemSelection() for row in selected_rows: selection.select(self.model.index(row, 0), self.model.index(row, 0)) smodel.clearSelection() smodel.select(selection, QtGui.QItemSelectionModel.Select | QtGui.QItemSelectionModel.Rows) def _multi_selected_rows_items_changed(self, event): smodel = self.control.selectionModel() for row in event.removed: smodel.select(self.model.index(row, 0), QtGui.QItemSelectionModel.Deselect | QtGui.QItemSelectionModel.Rows) for row in event.added: smodel.select(self.model.index(row, 0), QtGui.QItemSelectionModel.Select | QtGui.QItemSelectionModel.Rows) scroll_to_row_hint_map = { 'center' : QtGui.QTableView.PositionAtCenter, 'top' : QtGui.QTableView.PositionAtTop, 'bottom' : QtGui.QTableView.PositionAtBottom, 'visible' : QtGui.QTableView.EnsureVisible, } def _scroll_to_row_changed(self, row): """ Scroll to the given row. """ scroll_hint = self.scroll_to_row_hint_map.get(self.factory.scroll_to_row_hint, self.control.PositionAtCenter) self.control.scrollTo(self.model.index(row, 0), scroll_hint) #-- Table Control Event Handlers ------------------------------------------- def _on_activate(self, index): """ Handle a cell being activated. """ self.activated_row = row = index.row() self.activated = self.adapter.get_item(self.object, self.name, row) def _on_click(self, index): """ Handle a cell being clicked. """ self._mouse_click(index, 'clicked') def _on_dclick(self, index): """ Handle a cell being double clicked. """ self._mouse_click(index, 'dclicked') def _on_column_click(self, column): event = TabularEditorEvent(editor=self, row=0, column=column) setattr(self, 'column_clicked', event) def _on_right_click(self, column): event = TabularEditorEvent(editor=self, row=0, column=column) setattr(self, 'right_clicked', event) def _on_column_right_click(self, column): event = TabularEditorEvent(editor=self, row=0, column=column) setattr(self, 'column_right_clicked', event) def _on_row_selection(self, added, removed): """ Handle the row selection being changed. """ self._no_update = True try: indexes = self.control.selectionModel().selectedRows() if len(indexes): self.selected_row = indexes[0].row() self.selected = self.adapter.get_item(self.object, self.name, self.selected_row) else: self.selected_row = -1 self.selected = None finally: self._no_update = False def _on_rows_selection(self, added, removed): """ Handle the rows selection being changed. """ self._no_update = True try: indexes = self.control.selectionModel().selectedRows() selected_rows = [] selected = [] for index in indexes: row = index.row() selected_rows.append(row) selected.append(self.adapter.get_item(self.object, self.name, row)) self.multi_selected_rows = selected_rows self.multi_selected = selected finally: self._no_update = False def _on_context_menu(self, pos) : column, row = self.control.columnAt(pos.x()), self.control.rowAt(pos.y()) menu = self.adapter.get_menu(self.object, self.name, row, column) if menu : qmenu = menu.create_menu( self.control, self ) self._menu_context = {'selection' : self.object, 'object': self.object, 'editor': self, 'column': column, 'row': row, 'item': self.adapter.get_item(self.object, self.name, row), 'info': self.ui.info, 'handler': self.ui.handler } qmenu.exec_(self.control.mapToGlobal(pos)) self._menu_context = None def _on_column_context_menu(self, pos) : column = self.control.columnAt(pos.x()) menu = self.adapter.get_column_menu(self.object, self.name, -1, column) if menu : qmenu = menu.create_menu( self.control, self ) self._menu_context = {'selection' : self.object, 'object': self.object, 'editor': self, 'column': column, 'info': self.ui.info, 'handler': self.ui.handler } qmenu.exec_(self.control.mapToGlobal(pos)) self._menu_context = None else: #If no menu is defined on the adapter, just trigger a click event. self._on_column_right_click(column) #------------------------------------------------------------------------------- # 'TabularEditorEvent' class: #------------------------------------------------------------------------------- class TabularEditorEvent(HasStrictTraits): # The index of the row: row = Int # The id of the column (either a string or an integer): column = Any # The row item: item = Property #-- Private Traits --------------------------------------------------------- # The editor the event is associated with: editor = Instance(TabularEditor) #-- Property Implementations ----------------------------------------------- def _get_item(self): editor = self.editor return editor.adapter.get_item(editor.object, editor.name, self.row) #------------------------------------------------------------------------------- # Qt widgets that have been configured to behave as expected by Traits UI: #------------------------------------------------------------------------------- class _ItemDelegate(QtGui.QStyledItemDelegate): """ A QStyledItemDelegate which draws its owns gridlines so that we can choose to draw only the horizontal or only the vertical gridlines if appropriate. """ def __init__(self, table_view): """ Store which grid lines to draw. """ QtGui.QStyledItemDelegate.__init__(self, table_view) self._horizontal_lines = table_view._editor.factory.horizontal_lines self._vertical_lines = table_view._editor.factory.vertical_lines def paint(self, painter, option, index): """ Overrident to draw gridlines. """ QtGui.QStyledItemDelegate.paint(self, painter, option, index) painter.save() # FIXME: 'styleHint' is returning bogus (negative) values. Why? #style = QtGui.QApplication.instance().style() #color = style.styleHint(QtGui.QStyle.SH_Table_GridLineColor, option) #painter.setPen(QtGui.QColor(color)) painter.setPen(option.palette.color(QtGui.QPalette.Dark)) if self._horizontal_lines: painter.drawLine(option.rect.bottomLeft(),option.rect.bottomRight()) if self._vertical_lines: painter.drawLine(option.rect.topRight(), option.rect.bottomRight()) painter.restore() class _TableView(QtGui.QTableView): """ A QTableView configured to behave as expected by TraitsUI. """ def __init__(self, editor): """ Initialise the object. """ QtGui.QTableView.__init__(self) self._initial_size = False self._editor = editor self.setModel(editor.model) factory = editor.factory # Configure the row headings vheader = self.verticalHeader() vheader.hide() # Set a default height for rows. Although setting the resize mode to # ResizeToContents would provide the best sizes, this is far too # expensive when the TabularEditor has a large amount of data. Instead, # we make a reasonable guess based on the minimum size hint and the font # of the first row. size = vheader.minimumSectionSize() font = editor.adapter.get_font(editor.object, editor.name, 0) if font is not None: size = max(size, QtGui.QFontMetrics(QtGui.QFont(font)).height()) vheader.setDefaultSectionSize(size) # Configure the column headings. hheader = self.horizontalHeader() hheader.setStretchLastSection(factory.stretch_last_section) if factory.show_titles: hheader.setHighlightSections(False) else: hheader.hide() # Turn off the grid lines--we'll draw our own self.setShowGrid(False) self.setItemDelegate(_ItemDelegate(self)) # Configure the selection behaviour. self.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) if factory.multi_select: mode = QtGui.QAbstractItemView.ExtendedSelection else: mode = QtGui.QAbstractItemView.SingleSelection self.setSelectionMode(mode) # Configure drag and drop behavior self.setDragEnabled(True) self.setDragDropMode(QtGui.QAbstractItemView.InternalMove) self.setDropIndicatorShown(True) def keyPressEvent(self, event): """ Reimplemented to support edit, insert, and delete by keyboard. """ editor = self._editor factory = editor.factory # Note that setting 'EditKeyPressed' as an edit trigger does not work on # most platforms, which is why we do this here. if (event.key() in (QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return) and self.state() != QtGui.QAbstractItemView.EditingState and factory.editable and 'edit' in factory.operations): if factory.multi_select: rows = editor.multi_selected_rows row = rows[0] if len(rows) == 1 else -1 else: row = editor.selected_row if row != -1: event.accept() self.edit(editor.model.index(row, 0)) elif (event.key() in (QtCore.Qt.Key_Backspace, QtCore.Qt.Key_Delete) and factory.editable and 'delete' in factory.operations): event.accept() if factory.multi_select: for row in reversed(sorted(editor.multi_selected_rows)): editor.model.removeRow(row) elif editor.selected_row != -1: editor.model.removeRow(editor.selected_row) elif (event.key() == QtCore.Qt.Key_Insert and factory.editable and 'insert' in factory.operations): event.accept() if factory.multi_select: rows = sorted(editor.multi_selected_rows) row = rows[0] if len(rows) else -1 else: row = editor.selected_row if row == -1: row = editor.adapter.len(editor.object, editor.name) editor.model.insertRow(row) self.setCurrentIndex(editor.model.index(row, 0)) else: QtGui.QTableView.keyPressEvent(self, event) def sizeHint(self): """ Reimplemented to define a reasonable size hint. """ sh = QtGui.QTableView.sizeHint(self) width = 0 for column in xrange(len(self._editor.adapter.columns)): width += self.sizeHintForColumn(column) sh.setWidth(width) return sh def resizeEvent(self, event): """ Reimplemented to size the table columns when the size of the table changes. Because the layout algorithm requires that the available space be known, we have to wait until the UI that contains this table gives it its initial size. """ QtGui.QTableView.resizeEvent(self, event) parent = self.parent() if (not self._initial_size and parent and (self.isVisible() or isinstance(parent, QtGui.QMainWindow))): self._initial_size = True self.resizeColumnsToContents() def sizeHintForColumn(self, column): """ Reimplemented to support absolute width specification via TabularAdapters and to avoid scanning all data to determine the size hint. (TabularEditor, unlike TableEditor, is expected to handle very large data sets.) """ editor = self._editor if editor.factory.auto_resize: # Use the default implementation. return super(_TableView, self).sizeHintForColumn(column) width = editor.adapter.get_width(editor.object, editor.name, column) if width > 1: return width else: return self.horizontalHeader().sectionSizeHint(column) def resizeColumnsToContents(self): """ Reimplemented to support proportional column width specifications. For information about the layout algorithm, see https://svn.enthought.com/enthought/wiki/Traits_3_0_tabular_editor. """ editor = self._editor if editor.factory.auto_resize: # Use the default implementation. return super(_TableView, self).resizeColumnsToContents() available_space = self.viewport().width() hheader = self.horizontalHeader() # Assign sizes for columns with absolute size requests percent_vals, percent_cols = [], [] for column in xrange(len(editor.adapter.columns)): width = editor.adapter.get_width(editor.object, editor.name, column) if width > 1: available_space -= width hheader.resizeSection(column, width) else: if width <= 0: width = 0.1 percent_vals.append(width) percent_cols.append(column) # Now use the remaining space for columns with proportional or no width # requests. percent_total = sum(percent_vals) for i, column in enumerate(percent_cols): percent = percent_vals[i] / percent_total width = max(30, int(percent * available_space)) hheader.resizeSection(column, width) traitsui-4.1.0/traitsui/qt4/ui_modal.py0000644000175100001440000001616011674463546021104 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2007, Riverbank Computing Limited # All rights reserved. # # This software is provided without warranty under the terms of the BSD license. # However, when used with the GPL version of PyQt the additional terms described in the PyQt GPL exception also apply # # Author: Riverbank Computing Limited #------------------------------------------------------------------------------ """Creates a PyQt user interface for a specified UI object. """ from pyface.qt import QtCore, QtGui from traitsui.menu \ import ApplyButton, RevertButton, OKButton, CancelButton, HelpButton from ui_base \ import BaseDialog from ui_panel \ import panel #------------------------------------------------------------------------------- # Create the different modal PyQt user interfaces. #------------------------------------------------------------------------------- def ui_modal(ui, parent): """Creates a modal PyQt user interface for a specified UI object. """ _ui_dialog(ui, parent, BaseDialog.MODAL) def ui_nonmodal(ui, parent): """Creates a non-modal PyQt user interface for a specified UI object. """ _ui_dialog(ui, parent, BaseDialog.NONMODAL) def _ui_dialog(ui, parent, style): """Creates a PyQt dialog box for a specified UI object. Changes are not immediately applied to the underlying object. The user must click **Apply** or **OK** to apply changes. The user can revert changes by clicking **Revert** or **Cancel**. """ if ui.owner is None: ui.owner = _ModalDialog() BaseDialog.display_ui(ui, parent, style) class _ModalDialog(BaseDialog): """Modal dialog box for Traits-based user interfaces. """ def init(self, ui, parent, style): """Initialise the object. """ self.ui = ui self.control = ui.control view = ui.view revert = apply = False if self.control is not None: if hasattr(self, 'revert'): revert = self.revert.isEnabled() if hasattr(self, 'apply'): apply = self.apply.isEnabled() ui.reset() else: self.create_dialog(parent, style) # Create the 'context' copies we will need while editing: context = ui.context ui._context = context ui.context = self._copy_context(context) ui._revert = self._copy_context(context) self.set_icon(view.icon) # Convert the buttons to actions. buttons = [self.coerce_button(button) for button in view.buttons] nr_buttons = len(buttons) if (nr_buttons != 1) or (not self.is_button(buttons[0], '')): bbox = QtGui.QDialogButtonBox() # Create the necessary special function buttons. if nr_buttons == 0: if view.apply: self.check_button(buttons, ApplyButton) if view.revert: self.check_button(buttons, RevertButton) if view.ok: self.check_button(buttons, OKButton) if view.cancel: self.check_button(buttons, CancelButton) if view.help: self.check_button(buttons, HelpButton) for raw_button, button in zip(view.buttons, buttons): default = raw_button == view.default_button if self.is_button(button, 'Apply'): self.apply = self.add_button(button, bbox, QtGui.QDialogButtonBox.ApplyRole, self._on_apply, enabled=apply, default=default) ui.on_trait_change(self._on_applyable, 'modified', dispatch='ui') elif self.is_button(button, 'Revert'): self.revert = self.add_button(button, bbox, QtGui.QDialogButtonBox.ResetRole, self._on_revert, enabled=revert, default=default) elif self.is_button(button, 'OK'): self.ok = self.add_button(button, bbox, QtGui.QDialogButtonBox.AcceptRole, self.control.accept, default=default) ui.on_trait_change(self._on_error, 'errors', dispatch='ui') elif self.is_button(button, 'Cancel'): self.add_button(button, bbox, QtGui.QDialogButtonBox.RejectRole, self.control.reject, default=default) elif self.is_button(button, 'Help'): self.add_button(button, bbox, QtGui.QDialogButtonBox.HelpRole, self._on_help, default=default) elif not self.is_button(button, ''): self.add_button(button, bbox, QtGui.QDialogButtonBox.ActionRole, default=default) else: bbox = None self.add_contents(panel(ui), bbox) def close(self, rc): """Close the dialog and set the given return code. """ super(_ModalDialog, self).close(rc) self.apply = self.revert = self.help = None def _copy_context(self, context): """Creates a copy of a *context* dictionary. """ result = {} for name, value in context.items(): if value is not None: result[name] = value.clone_traits() else: result[name] = None return result def _apply_context(self, from_context, to_context): """Applies the traits in the *from_context* to the *to_context*. """ for name, value in from_context.items(): if value is not None: to_context[name].copy_traits(value) else: to_context[name] = None if to_context is self.ui._context: on_apply = self.ui.view.on_apply if on_apply is not None: on_apply() def _on_finished(self, result): """Handles the user finishing with the dialog. """ accept = bool(result) if accept: self._apply_context(self.ui.context, self.ui._context) else: self._apply_context(self.ui._revert, self.ui._context) self.close(accept) def _on_apply(self): """Handles a request to apply changes. """ ui = self.ui self._apply_context(ui.context, ui._context) self.revert.setEnabled(True) ui.handler.apply(ui.info) ui.modified = False def _on_applyable(self, state): """Handles a change to the "modified" state of the user interface . """ self.apply.setEnabled( state ) def _on_revert(self): """Handles a request to revert changes. """ ui = self.ui self._apply_context(ui._revert, ui.context) self._apply_context(ui._revert, ui._context) self.revert.setEnabled(False) ui.handler.revert(ui.info) ui.modified = False traitsui-4.1.0/traitsui/tests/0000755000175100001440000000000011674463546017367 5ustar ischnellusers00000000000000traitsui-4.1.0/traitsui/tests/test_ui.py0000644000175100001440000001254411674463546021423 0ustar ischnellusers00000000000000""" Test cases for the UI object. """ import nose.tools from traits.has_traits import HasTraits from traits.trait_types import Str, Int import traitsui from traitsui.item import Item from traitsui.view import View from traitsui.tests._tools import * class FooDialog(HasTraits): """Test dialog that does nothing useful.""" my_int = Int(2) my_str = Str('hallo') traits_view = View( Item('my_int'), Item('my_str'), buttons = ['OK'] ) @skip_if_not_wx def test_reset_with_destroy_wx(): # Characterization test: # UI.reset(destroy=True) destroys all ui children of the top control foo = FooDialog() ui = foo.edit_traits() ui.reset(destroy=True) # the top control is still there nose.tools.assert_is_not_none(ui.control) # but its children are gone nose.tools.assert_equal(len(ui.control.GetChildren()), 0) @skip_if_not_qt4 def test_reset_with_destroy_qt(): # Characterization test: # UI.reset(destroy=True) destroys all ui children of the top control from pyface import qt foo = FooDialog() ui = foo.edit_traits() # decorate children's `deleteLater` function to check that it is called # on `reset`. check only with the editor parts (only widgets are scheduled, # see traitsui.qt4.toolkit.GUIToolkit.destroy_children) for c in ui.control.children(): c.deleteLater = count_calls(c.deleteLater) ui.reset(destroy=True) # the top control is still there nose.tools.assert_is_not_none(ui.control) # but its children are scheduled for removal for c in ui.control.children(): if isinstance(c, qt.QtGui.QWidget): nose.tools.assert_equal(c.deleteLater._n_calls, 1) @skip_if_not_wx def test_reset_without_destroy_wx(): # Characterization test: # UI.reset(destroy=False) destroys all editor controls, but leaves editors # and ui children intact import wx foo = FooDialog() ui = foo.edit_traits() nose.tools.assert_equal(len(ui._editors), 2) nose.tools.assert_is_instance(ui._editors[0], traitsui.wx.text_editor.SimpleEditor) nose.tools.assert_is_instance(ui._editors[0].control, wx._controls.TextCtrl) ui.reset(destroy=False) nose.tools.assert_equal(len(ui._editors), 2) nose.tools.assert_is_instance(ui._editors[0], traitsui.wx.text_editor.SimpleEditor) nose.tools.assert_is_none(ui._editors[0].control) # children are still there: check first text control text_ctrl = ui.control.FindWindowByName('text') nose.tools.assert_is_not_none(text_ctrl) @skip_if_not_qt4 def test_reset_without_destroy_qt(): # Characterization test: # UI.reset(destroy=False) destroys all editor controls, but leaves editors # and ui children intact from pyface import qt foo = FooDialog() ui = foo.edit_traits() nose.tools.assert_equal(len(ui._editors), 2) nose.tools.assert_is_instance(ui._editors[0], traitsui.qt4.text_editor.SimpleEditor) nose.tools.assert_is_instance(ui._editors[0].control, qt.QtGui.QLineEdit) ui.reset(destroy=False) nose.tools.assert_equal(len(ui._editors), 2) nose.tools.assert_is_instance(ui._editors[0], traitsui.qt4.text_editor.SimpleEditor) nose.tools.assert_is_none(ui._editors[0].control) # children are still there: check first text control text_ctrl = ui.control.findChild(qt.QtGui.QLineEdit) nose.tools.assert_is_not_none(text_ctrl) @skip_if_not_wx def test_destroy_after_ok_wx(): # Behavior: after pressing 'OK' in a dialog, the method UI.finish is # called and the view control and its children are destroyed import wx foo = FooDialog() ui = foo.edit_traits() # keep references to the children of the ui to check that they were deleted ui_children = [] for c in ui.control.GetChildren(): ui_children.append(c) # press the OK button and close the dialog okbutton = ui.control.FindWindowByName('button') click_event = wx.CommandEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, okbutton.GetId()) okbutton.ProcessEvent(click_event) nose.tools.assert_is_none(ui.control) # and its children have been destroyed for c in ui_children: with nose.tools.assert_raises(wx._core.PyDeadObjectError): c.GetName() @skip_if_not_qt4 def test_destroy_after_ok_qt(): # Behavior: after pressing 'OK' in a dialog, the method UI.finish is # called and the view control and its children are destroyed from pyface import qt foo = FooDialog() ui = foo.edit_traits() # decorate children's `deleteLater` function to check that it is called for c in ui.control.children(): c.deleteLater = count_calls(c.deleteLater) # keep references to the children of the ui to check that they were deleted ui_children = [] for c in ui.control.children(): ui_children.append(c) # press the OK button and close the dialog okb = ui.control.findChild(qt.QtGui.QPushButton) okb.click() nose.tools.assert_is_none(ui.control) # children are scheduled for removal for c in ui_children: if isinstance(c, qt.QtGui.QWidget): nose.tools.assert_equal(c.deleteLater._n_calls, 1) traitsui-4.1.0/traitsui/tests/test_range_editor_text.py0000644000175100001440000000336711674463546024517 0ustar ischnellusers00000000000000""" Test case for bug (wx, Max OS X) A RangeEditor in mode 'text' for an Int allows values out of range. """ from traits.has_traits import HasTraits from traits.trait_types import Int from traitsui.item import Item from traitsui.view import View from traitsui.editors.range_editor import RangeEditor from _tools import * class NumberWithTextEditor(HasTraits): """Dialog containing a RangeEditor in 'spinner' mode for an Int. """ number = Int traits_view = View( Item(label="Range should be 3 to 8. Enter 1, then press OK"), Item('number', editor=RangeEditor(low=3, high=8, mode='text')), buttons = ['OK'] ) @skip_if_not_wx def test_wx_spin_control_editing(): # behavior: when editing the text part of a spin control box, pressing # the OK button should update the value of the HasTraits class # (tests a bug where this fails with an AttributeError) import wx with store_exceptions_on_all_threads(): num = NumberWithTextEditor() ui = num.edit_traits() # the following is equivalent to setting the text in the text control, # then pressing OK textctrl = ui.control.FindWindowByName('text') textctrl.SetValue('1') # press the OK button and close the dialog okbutton = ui.control.FindWindowByName('button') click_event = wx.CommandEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, okbutton.GetId()) okbutton.ProcessEvent(click_event) # the number traits should be between 3 and 8 assert num.number >= 3 and num.number <=8 if __name__ == '__main__': # Executing the file opens the dialog for manual testing num = NumberWithTextEditor() num.configure_traits() print num.number traitsui-4.1.0/traitsui/tests/test_range_editor_spinner.py0000644000175100001440000001130011674463546025173 0ustar ischnellusers00000000000000""" Test case for bug (wx, Max OS X) Editing the text part of a spin control box and pressing the OK button without de-focusing raises an AttributeError Traceback (most recent call last): File "ETS/traitsui/traitsui/wx/range_editor.py", line 783, in update_object self.value = self.control.GetValue() AttributeError: 'NoneType' object has no attribute 'GetValue' """ from traits.has_traits import HasTraits from traits.trait_types import Int from traitsui.item import Item from traitsui.view import View from traitsui.editors.range_editor import RangeEditor from _tools import * class NumberWithSpinnerEditor(HasTraits): """Dialog containing a RangeEditor in 'spinner' mode for an Int. """ number = Int traits_view = View( Item(label="Enter 4, then press OK without defocusing"), Item('number', editor=RangeEditor(low=3, high=8, mode='spinner')), buttons = ['OK'] ) @skip_if_not_wx def test_wx_spin_control_editing_should_not_crash(): # Bug: when editing the text part of a spin control box, pressing # the OK button raises an AttributeError on Mac OS X import wx try: with store_exceptions_on_all_threads(): num = NumberWithSpinnerEditor() ui = num.edit_traits() # the following is equivalent to clicking in the text control of the # range editor, enter a number, and clicking ok without defocusing # SpinCtrl object spin = ui.control.FindWindowByName('wxSpinCtrl') spin.SetFocusFromKbd() # on Windows, a wxSpinCtrl does not have children, and we cannot do # the more fine-grained testing below if len(spin.GetChildren()) == 0: spin.SetValueString('4') else: # TextCtrl object of the spin control spintxt = spin.FindWindowByName('text') spintxt.SetValue('4') # press the OK button and close the dialog okbutton = ui.control.FindWindowByName('button') click_event = wx.CommandEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, okbutton.GetId()) okbutton.ProcessEvent(click_event) except AttributeError: # if all went well, we should not be here assert False, "AttributeError raised" @skip_if_not_wx def test_wx_spin_control_editing_does_not_update(): # Bug: when editing the text part of a spin control box, pressing # the OK button does not update the value of the HasTraits class # on Mac OS X import wx with store_exceptions_on_all_threads(): num = NumberWithSpinnerEditor() ui = num.edit_traits() # the following is equivalent to clicking in the text control of the # range editor, enter a number, and clicking ok without defocusing # SpinCtrl object spin = ui.control.FindWindowByName('wxSpinCtrl') spin.SetFocusFromKbd() # on Windows, a wxSpinCtrl does not have children, and we cannot do # the more fine-grained testing below if len(spin.GetChildren()) == 0: spin.SetValueString('4') else: # TextCtrl object of the spin control spintxt = spin.FindWindowByName('text') spintxt.SetValue('4') # press the OK button and close the dialog okbutton = ui.control.FindWindowByName('button') click_event = wx.CommandEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, okbutton.GetId()) okbutton.ProcessEvent(click_event) # if all went well, the number traits has been updated and its value is 4 assert num.number == 4 @skip_if_not_qt4 def test_qt_spin_control_editing(): # Behavior: when editing the text part of a spin control box, pressing # the OK button updates the value of the HasTraits class from pyface import qt with store_exceptions_on_all_threads(): num = NumberWithSpinnerEditor() ui = num.edit_traits() # the following is equivalent to clicking in the text control of the # range editor, enter a number, and clicking ok without defocusing # text element inside the spin control lineedit = ui.control.findChild(qt.QtGui.QLineEdit) lineedit.setFocus() lineedit.setText('4') # press the OK button and close the dialog okb = ui.control.findChild(qt.QtGui.QPushButton) okb.click() # if all went well, the number traits has been updated and its value is 4 assert num.number == 4 if __name__ == '__main__': # Executing the file opens the dialog for manual testing num = NumberWithSpinnerEditor() num.configure_traits() print num.number traitsui-4.1.0/traitsui/tests/__init__.py0000644000175100001440000000000011674463546021466 0ustar ischnellusers00000000000000traitsui-4.1.0/traitsui/tests/_tools.py0000644000175100001440000000661111674463546021244 0ustar ischnellusers00000000000000from functools import partial from contextlib import contextmanager import nose import sys import traceback from traits.etsconfig.api import ETSConfig # ######### Testing tools @contextmanager def store_exceptions_on_all_threads(): """Context manager that captures all exceptions, even those coming from the UI thread. On exit, the first exception is raised (if any). """ exceptions = [] def excepthook(type, value, tb): exceptions.append(value) message = 'Uncaught exception:\n' message += ''.join(traceback.format_exception(type, value, tb)) print message try: sys.excepthook = excepthook yield finally: if len(exceptions) > 0: raise exceptions[0] sys.excepthook = sys.__excepthook__ def skip_if_not_backend(test_func, backend_name=''): """Decorator that skip tests if the backend is not the desired one.""" if ETSConfig.toolkit != backend_name: # preserve original name so that it appears in the report orig_name = test_func.__name__ def test_func(): raise nose.SkipTest test_func.__name__ = orig_name return test_func #: Test decorator: Skip test if backend is not 'wx' skip_if_not_wx = partial(skip_if_not_backend, backend_name='wx') #: Test decorator: Skip test if backend is not 'qt4' skip_if_not_qt4 = partial(skip_if_not_backend, backend_name='qt4') def count_calls(func): """Decorator that stores the number of times a function is called. The counter is stored in func._n_counts. """ def wrapped(*args, **kwargs): wrapped._n_calls += 1 return func(*args, **kwargs) wrapped._n_calls = 0 return wrapped # ######### Utility tools to test on both qt4 and wx def get_children(node): if ETSConfig.toolkit == 'wx': return node.GetChildren() else: return node.children() # ######### Debug tools def apply_on_children(func, node, _level=0): """Print the result of applying a function on `node` and its children. """ print '-'*_level + str(node) print ' '*_level + str(func(node)) + '\n' for child in get_children(node): apply_on_children(func, child, _level+1) def wx_print_names(node): """Print the name and id of `node` and its children. """ apply_on_children(lambda n: (n.GetName(), n.GetId()), node) def qt_print_names(node): """Print the name of `node` and its children. """ apply_on_children(lambda n: n.objectName(), node) def wx_announce_when_destroyed(node): """Prints a message when `node` is destroyed. Use as: >>> ui = xxx.edit_traits() >>> apply_on_children(wx_announce_when_destroyed, ui.control) """ _destroy_method = node.Destroy def destroy_wrapped(): print 'Destroying:', node #print 'Stack is' #traceback.print_stack() _destroy_method() print 'Destroyed:', node node.Destroy = destroy_wrapped return 'Node {} decorated'.format(node.GetName()) def wx_find_event_by_number(evt_num): """Find all wx event names that correspond to a ceratin event number. Example: >>> wx_find_event_by_number(10010) ['wxEVT_COMMAND_MENU_SELECTED', 'wxEVT_COMMAND_TOOL_CLICKED'] """ import wx possible = [attr for attr in dir(wx) if attr.startswith('wxEVT') and getattr(wx, attr) == evt_num] return possible traitsui-4.1.0/traitsui/undo.py0000644000175100001440000004404211674463546017550 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/07/2004 # #------------------------------------------------------------------------------ """ Defines the manager for Undo and Redo history for Traits user interface support. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from operator import isSequenceType from traits.api import (Event, HasPrivateTraits, HasStrictTraits, HasTraits, Instance, Int, List, Property, Str, Trait) from traits.trait_base import enumerate #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- NumericTypes = ( int, long, float, complex ) SimpleTypes = ( str, unicode, int, long, float, complex ) #------------------------------------------------------------------------------- # 'AbstractUndoItem' class: #------------------------------------------------------------------------------- class AbstractUndoItem ( HasPrivateTraits ): """ Abstract base class for undo items. """ #--------------------------------------------------------------------------- # Undoes the change: #--------------------------------------------------------------------------- def undo ( self ): """ Undoes the change. """ raise NotImplementedError #--------------------------------------------------------------------------- # Re-does the change: #--------------------------------------------------------------------------- def redo ( self ): """ Re-does the change. """ raise NotImplementedError #--------------------------------------------------------------------------- # Merges two undo items if possible: #--------------------------------------------------------------------------- def merge_undo ( self, undo_item ): """ Merges two undo items if possible. """ return False #------------------------------------------------------------------------------- # 'UndoItem' class: #------------------------------------------------------------------------------- class UndoItem ( AbstractUndoItem ): """ A change to an object trait, which can be undone. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Object the change occurred on object = Trait( HasTraits ) # Name of the trait that changed name = Str # Old value of the changed trait old_value = Property # New value of the changed trait new_value = Property #--------------------------------------------------------------------------- # Implementation of the 'old_value' and 'new_value' properties: #--------------------------------------------------------------------------- def _get_old_value ( self ): return self._old_value def _set_old_value ( self, value ): if isinstance( value, list ): value = value[:] self._old_value = value def _get_new_value ( self ): return self._new_value def _set_new_value ( self, value ): if isinstance( value, list ): value = value[:] self._new_value = value #--------------------------------------------------------------------------- # Undoes the change: #--------------------------------------------------------------------------- def undo ( self ): """ Undoes the change. """ try: setattr( self.object, self.name, self.old_value ) except: pass #--------------------------------------------------------------------------- # Re-does the change: #--------------------------------------------------------------------------- def redo ( self ): """ Re-does the change. """ try: setattr( self.object, self.name, self.new_value ) except: pass #--------------------------------------------------------------------------- # Merges two undo items if possible: #--------------------------------------------------------------------------- def merge_undo ( self, undo_item ): """ Merges two undo items if possible. """ # Undo items are potentially mergeable only if they are of the same # class and refer to the same object trait, so check that first: if (isinstance( undo_item, self.__class__ ) and (self.object is undo_item.object) and (self.name == undo_item.name)): v1 = self.new_value v2 = undo_item.new_value t1 = type( v1 ) if t1 is type( v2 ): if isinstance(t1, basestring): # Merge two undo items if they have new values which are # strings which only differ by one character (corresponding # to a single character insertion, deletion or replacement # operation in a text editor): n1 = len( v1 ) n2 = len( v2 ) n = min( n1, n2 ) i = 0 while (i < n) and (v1[i] == v2[i]): i += 1 if v1[i + (n2 <= n1):] == v2[i + (n2 >= n1):]: self.new_value = v2 return True elif isSequenceType( v1 ): # Merge sequence types only if a single element has changed # from the 'original' value, and the element type is a # simple Python type: v1 = self.old_value if isSequenceType( v1 ): # Note: wxColour says it's a sequence type, but it # doesn't support 'len', so we handle the exception # just in case other classes have similar behavior: try: if len( v1 ) == len( v2 ): diffs = 0 for i, item in enumerate( v1 ): titem = type( item ) item2 = v2[i] if ((titem not in SimpleTypes) or (titem is not type( item2 )) or (item != item2)): diffs += 1 if diffs >= 2: return False if diffs == 0: return False self.new_value = v2 return True except: pass elif t1 in NumericTypes: # Always merge simple numeric trait changes: self.new_value = v2 return True return False #--------------------------------------------------------------------------- # Returns a 'pretty print' form of the object: #--------------------------------------------------------------------------- def __repr__ ( self ): """ Returns a "pretty print" form of the object. """ n = self.name cn = self.object.__class__.__name__ return 'undo( %s.%s = %s )\nredo( %s.%s = %s )' % ( cn, n, self.old_value, cn, n, self.new_value ) #------------------------------------------------------------------------------- # 'ListUndoItem' class: #------------------------------------------------------------------------------- class ListUndoItem ( AbstractUndoItem ): """ A change to a list, which can be undone. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Object that the change occurred on object = Trait( HasTraits ) # Name of the trait that changed name = Str # Starting index index = Int # Items added to the list added = List # Items removed from the list removed = List #--------------------------------------------------------------------------- # Undoes the change: #--------------------------------------------------------------------------- def undo ( self ): """ Undoes the change. """ try: list = getattr( self.object, self.name ) list[ self.index: (self.index + len( self.added )) ] = self.removed except: pass #--------------------------------------------------------------------------- # Re-does the change: #--------------------------------------------------------------------------- def redo ( self ): """ Re-does the change. """ try: list = getattr( self.object, self.name ) list[ self.index: (self.index + len( self.removed )) ] = self.added except: pass #--------------------------------------------------------------------------- # Merges two undo items if possible: #--------------------------------------------------------------------------- def merge_undo ( self, undo_item ): """ Merges two undo items if possible. """ # Discard undo items that are identical to us. This is to eliminate # the same undo item being created by multiple listeners monitoring the # same list for changes: if (isinstance( undo_item, self.__class__ ) and (self.object is undo_item.object) and (self.name == undo_item.name) and (self.index == undo_item.index)): added = undo_item.added removed = undo_item.removed if ((len( self.added ) == len( added )) and (len( self.removed ) == len( removed ))): for i, item in enumerate( self.added ): if item is not added[i]: break else: for i, item in enumerate( self.removed ): if item is not removed[i]: break else: return True return False #--------------------------------------------------------------------------- # Returns a 'pretty print' form of the object: #--------------------------------------------------------------------------- def __repr__ ( self ): """ Returns a 'pretty print' form of the object. """ return 'undo( %s.%s[%d:%d] = %s )' % ( self.object.__class__.__name__, self.name, self.index, self.index + len( self.removed ), self.added ) #------------------------------------------------------------------------------- # 'UndoHistory' class: #------------------------------------------------------------------------------- class UndoHistory ( HasStrictTraits ): """ Manages a list of undoable changes. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # List of accumulated undo changes history = List # The current position in the list now = Int # Fired when state changes to undoable undoable = Event( False ) # Fired when state changes to redoable redoable = Event( False ) # Can an action be undone? can_undo = Property # Can an action be redone? can_redo = Property #--------------------------------------------------------------------------- # Adds an UndoItem to the history: #--------------------------------------------------------------------------- def add ( self, undo_item, extend = False ): """ Adds an UndoItem to the history. """ if extend: self.extend( undo_item ) return # Try to merge the new undo item with the previous item if allowed: now = self.now if now > 0: previous = self.history[ now - 1 ] if (len( previous ) == 1) and previous[0].merge_undo( undo_item ): self.history[ now: ] = [] return old_len = len( self.history ) self.history[ now: ] = [ [ undo_item ] ] self.now += 1 if self.now == 1: self.undoable = True if self.now <= old_len: self.redoable = False #--------------------------------------------------------------------------- # Extends the most recent 'undo' item: #--------------------------------------------------------------------------- def extend ( self, undo_item ): """ Extends the undo history. If possible the method merges the new UndoItem with the last item in the history; otherwise, it appends the new item. """ if self.now > 0: undo_list = self.history[ self.now - 1 ] if not undo_list[-1].merge_undo( undo_item ): undo_list.append( undo_item ) #--------------------------------------------------------------------------- # Undo an operation: #--------------------------------------------------------------------------- def undo ( self ): """ Undoes an operation. """ if self.can_undo: self.now -= 1 items = self.history[ self.now ] for i in range( len( items ) - 1, -1, -1 ): items[i].undo() if self.now == 0: self.undoable = False if self.now == (len( self.history ) - 1): self.redoable = True #--------------------------------------------------------------------------- # Redo an operation: #--------------------------------------------------------------------------- def redo ( self ): """ Redoes an operation. """ if self.can_redo: self.now += 1 for item in self.history[ self.now - 1 ]: item.redo() if self.now == 1: self.undoable = True if self.now == len( self.history ): self.redoable = False #--------------------------------------------------------------------------- # Reverts all changes made so far and clears the history: #--------------------------------------------------------------------------- def revert ( self ): """ Reverts all changes made so far and clears the history. """ history = self.history[ : self.now ] self.clear() for i in range( len( history ) - 1, -1, -1 ): items = history[i] for j in range( len( items ) - 1, -1, -1 ): items[j].undo() #--------------------------------------------------------------------------- # Clears the undo history #--------------------------------------------------------------------------- def clear ( self ): """ Clears the undo history. """ old_len = len( self.history ) old_now = self.now self.now = 0 del self.history[:] if old_now > 0: self.undoable = False if old_now < old_len: self.redoable = False #--------------------------------------------------------------------------- # Are there any undoable operations? #--------------------------------------------------------------------------- def _get_can_undo ( self ): """ Are there any undoable operations? """ return self.now > 0 #--------------------------------------------------------------------------- # Are there any redoable operations? #--------------------------------------------------------------------------- def _get_can_redo ( self ): """ Are there any redoable operations? """ return self.now < len( self.history ) #------------------------------------------------------------------------------- # 'UndoHistoryUndoItem' class: #------------------------------------------------------------------------------- class UndoHistoryUndoItem ( AbstractUndoItem ): """ An undo item for the undo history. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # The undo history to undo or redo history = Instance( UndoHistory ) #--------------------------------------------------------------------------- # Undoes the change: #--------------------------------------------------------------------------- def undo ( self ): """ Undoes the change. """ history = self.history for i in range( history.now - 1, -1, -1 ): items = history.history[i] for j in range( len( items ) - 1, -1, -1 ): items[j].undo() #--------------------------------------------------------------------------- # Re-does the change: #--------------------------------------------------------------------------- def redo ( self ): """ Re-does the change. """ history = self.history for i in range( 0, history.now ): for item in history.history[i]: item.redo() traitsui-4.1.0/traitsui/wx/0000755000175100001440000000000011674463546016663 5ustar ischnellusers00000000000000traitsui-4.1.0/traitsui/wx/themed_vertical_notebook_editor.py0000644000175100001440000002060611674463546025646 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2007, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 07/07/2007 # #------------------------------------------------------------------------------- """ Traits UI vertical notebook editor for editing lists of objects with traits. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from traits.api \ import Instance, Str, Any, List, Bool, Undefined, on_trait_change from traits.trait_base \ import user_name_for from traitsui.wx.editor \ import Editor from traitsui.basic_editor_factory \ import BasicEditorFactory from traitsui.ui_traits \ import AView, ATheme from themed_vertical_notebook \ import ThemedVerticalNotebook #------------------------------------------------------------------------------- # '_ThemedVerticalNotebookEditor' class: #------------------------------------------------------------------------------- class _ThemedVerticalNotebookEditor ( Editor ): """ Traits UI vertical notebook editor for editing lists of objects with traits. """ #-- Trait Definitions ------------------------------------------------------ # Is the notebook editor scrollable? This values overrides the default: scrollable = True #-- Private Traits --------------------------------------------------------- # The currently selected notebook page object (or objects): selected_item = Any selected_list = List # The ThemedVerticalNotebook we use to manager the notebook: notebook = Instance( ThemedVerticalNotebook ) # Dictionary of page counts for all unique names: pages = Any( {} ) #-- Editor Methods --------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ factory = self.factory self.notebook = ThemedVerticalNotebook( **factory.get( 'closed_theme', 'open_theme', 'multiple_open', 'scrollable', 'double_click' ) ).set( editor = self ) self.control = self.notebook.create_control( parent ) # Set up the additional 'list items changed' event handler needed for # a list based trait: self.context_object.on_trait_change( self.update_editor_item, self.extended_name + '_items?', dispatch = 'ui' ) # Synchronize the editor selection with the user selection: if factory.multiple_open: self.sync_value( factory.selected, 'selected_list', 'both', is_list = True ) else: self.sync_value( factory.selected, 'selected_item', 'both' ) self.set_tooltip() def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ # Replace all of the current notebook pages: self.notebook.pages = [ self._create_page( object ) for object in self.value ] def update_editor_item ( self, event ): """ Handles an update to some subset of the trait's list. """ # Replace the updated notebook pages: self.notebook.pages[ event.index: event.index + len( event.removed ) ] \ = [ self._create_page( object ) for object in event.added ] def dispose ( self ): """ Disposes of the contents of an editor. """ self.context_object.on_trait_change( self.update_editor_item, self.name + '_items?', remove = True ) del self.notebook.pages[:] super( _ThemedVerticalNotebookEditor, self ).dispose() #-- Trait Event Handlers --------------------------------------------------- def _selected_item_changed ( self, old, new ): """ Handles the selected item being changed. """ if new is not None: self.notebook.open( self._find_page( new ) ) elif old is not None: self.notebook.close( self._find_page( old ) ) def _selected_list_changed ( self, old, new ): """ Handles the selected list being changed. """ notebook = self.notebook for object in old: notebook.close( self._find_page( object ) ) for object in new: notebook.open( self._find_page( object ) ) def _selected_list_items_changed ( self, event ): self._selected_list_changed( event.removed, event.added ) @on_trait_change( 'notebook:pages:is_open' ) def _page_state_modified ( self, page, name, old, is_open ): if self.factory.multiple_open: object = page.data if is_open: if object not in self.selected_list: self.selected_list.append( object ) elif object in self.selected_list: self.selected_list.remove( object ) elif is_open: self.selected_item = page.data else: self.selected_item = None #-- Private Methods -------------------------------------------------------- def _create_page ( self, object ): """ Creates and returns a notebook page for a specified object with traits. """ # Create a new notebook page: page = self.notebook.create_page().set( data = object ) # Create the Traits UI for the object to put in the notebook page: ui = object.edit_traits( parent = page.parent, view = self.factory.view, kind = 'subpanel' ).set( parent = self.ui ) # Get the name of the page being added to the notebook: name = '' page_name = self.factory.page_name if page_name[0:1] == '.': if getattr( object, page_name[1:], Undefined ) is not Undefined: page.register_name_listener( object, page_name[1:] ) else: name = page_name if name == '': name = user_name_for( object.__class__.__name__ ) # Make sure the name is not a duplicate, then save it in the page: if page.name == '': self.pages[ name ] = count = self.pages.get( name, 0 ) + 1 if count > 1: name += (' %d' % count) page.name = name # Save the Traits UI in the page so it can dispose of it later: page.ui = ui # Return the new notebook page return page def _find_page ( self, object ): """ Find the notebook page corresponding to a specified object. Returns the page if found, and **None** otherwise. """ for page in self.notebook.pages: if object is page.data: return page return None #------------------------------------------------------------------------------- # Create the editor factory object: #------------------------------------------------------------------------------- # wxPython editor factory for themed slider editors: class ThemedVerticalNotebookEditor ( BasicEditorFactory ): # The editor class to be created: klass = _ThemedVerticalNotebookEditor # The theme to use for closed notebook pages: closed_theme = ATheme # The theme to use for open notebook pages: open_theme = ATheme # Allow multiple open pages at once? multiple_open = Bool( False ) # Should the notebook be scrollable? scrollable = Bool( False ) # Use double clicks (True) or single clicks (False) to open/close pages: double_click = Bool( True ) # Extended name to use for each notebook page. It can be either the actual # name or the name of an attribute on the object in the form: # '.name[.name...]' page_name = Str # Name of the view to use for each page: view = AView # Name of the [object.]trait[.trait...] to synchronize notebook page # selection with: selected = Str traitsui-4.1.0/traitsui/wx/tuple_editor.py0000644000175100001440000000321211674463546021732 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 12/13/2004 # #------------------------------------------------------------------------------ """ Defines the tuple editor for the wxPython user interface toolkit. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- # FIXME: ToolkitEditorFactory is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.tuple_editor file. from traitsui.editors.tuple_editor \ import SimpleEditor as BaseSimpleEditor, ToolkitEditorFactory from editor \ import Editor #------------------------------------------------------------------------------- # 'SimpleEditor' class: #------------------------------------------------------------------------------- class SimpleEditor ( BaseSimpleEditor, Editor ): """ Simple style of editor for tuples. The editor displays an editor for each of the fields in the tuple, based on the type of each field. """ pass ### EOF ####################################################################### traitsui-4.1.0/traitsui/wx/array_editor.py0000644000175100001440000000362511674463546021727 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 01/10/2006 # #------------------------------------------------------------------------------ """ Defines array editors for the WX user interface toolkit. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- # FIXME: ToolkitEditorFactory is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.array_editor file. from traitsui.editors.array_editor \ import SimpleEditor as BaseSimpleEditor, ToolkitEditorFactory from editor \ import Editor #------------------------------------------------------------------------------- # 'SimpleEditor' class: #------------------------------------------------------------------------------- class SimpleEditor ( BaseSimpleEditor, Editor ): """ Simple style of editor for arrays. """ # FIXME: This class has been re-defined here simply so it inherits from the # wx Editor class. pass #------------------------------------------------------------------------------- # 'ReadonlyEditor' class: #------------------------------------------------------------------------------- class ReadonlyEditor(SimpleEditor): # Set the value of the readonly trait. readonly = True ### EOF ####################################################################### traitsui-4.1.0/traitsui/wx/animated_gif_editor_26.py0000644000175100001440000001051211674463546023520 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2007, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 03/02/2007 # #------------------------------------------------------------------------------- """ Defines an editor for playing animated GIF files. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from wx.animate \ import GIFAnimationCtrl from traits.api \ import Bool, Str from traitsui.wx.editor \ import Editor from traitsui.basic_editor_factory \ import BasicEditorFactory from pyface.timer.api \ import do_after #------------------------------------------------------------------------------- # '_AnimatedGIFEditor' class: #------------------------------------------------------------------------------- class _AnimatedGIFEditor ( Editor ): """ Editor that displays an animated GIF file. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Is the animated GIF file currently playing? playing = Bool( True ) #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self.control = GIFAnimationCtrl( parent, -1 ) self.control.GetPlayer().UseBackgroundColour( True ) self.sync_value( self.factory.playing, 'playing', 'from' ) self.set_tooltip() #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ control = self.control if self.playing: control.Stop() control.LoadFile( self.value ) self._file_loaded = True # Note: It seems to be necessary to Play/Stop the control to avoid a # hard wx crash when 'PlayNextFrame' is called the first time (must be # some kind of internal initialization issue): control.Play() control.Stop() if self.playing or self._not_first: self._playing_changed() else: do_after( 300, self._frame_changed ) self._not_first = True #--------------------------------------------------------------------------- # Handles the editor 'playing' trait being changed: #--------------------------------------------------------------------------- def _playing_changed ( self ): """ Handles the editor 'playing' trait being changed. """ if self._file_loaded: try: if self.playing: self.control.Play() else: player = self.control.GetPlayer() player.SetCurrentFrame( 0 ) player.PlayNextFrame() player.Stop() except: pass #------------------------------------------------------------------------------- # Create the editor factory object: #------------------------------------------------------------------------------- # wxPython editor factory for animated GIF editors: class AnimatedGIFEditor ( BasicEditorFactory ): # The editor class to be created: klass = _AnimatedGIFEditor # The optional trait used to control whether the animated GIF file is # playing or not: playing = Str traitsui-4.1.0/traitsui/wx/themed_vertical_notebook.py0000644000175100001440000004056011674463546024301 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2007, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 07/05/2007 # #------------------------------------------------------------------------------- """ Defines a ThemedVerticalNotebook class for displaying a series of pages organized vertically, as opposed to horizontally like a standard notebook. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx from traits.api \ import HasTraits, HasPrivateTraits, Instance, List, Str, Bool, Property, \ Event, Any, on_trait_change, cached_property from traitsui.api \ import UI, Theme from traitsui.ui_traits \ import ATheme from traitsui.editor \ import Editor from constants \ import WindowColor, screen_dy from image_slice \ import paint_parent from image_panel \ import ImagePanel from themed_control \ import ThemedControl from helper \ import TraitsUIPanel, TraitsUIScrolledPanel #------------------------------------------------------------------------------- # 'ThemedPage' class: #------------------------------------------------------------------------------- class ThemedPage ( HasPrivateTraits ): """ A class representing a themed page within a notebook. """ #-- Public Traits ---------------------------------------------------------- # The name of the page (displayed on its 'tab') [Set by client]: name = Str # The optional Traits UI associated with this page [Set by client]: ui = Instance( UI ) # The wxPython window the page represents [Set by client]: control = Instance( wx.Window ) # Optional client data associated with the page [Set/Get by client]: data = Any # The optional object defining the page name [Set by client]: object = Instance( HasTraits ) # The name of the object trait that signals a page name change [Set by # client]: trait_name = Str # The parent window for the client page [Get by client]: parent = Property #-- Traits for use by the Notebook/Sizer ----------------------------------- # The current open status of the notebook page: is_open = Bool( False ) # The minimum size for the page: min_size = Property # The open size property for the page: open_size = Property # The closed size property for the page: closed_size = Property #-- Private Traits --------------------------------------------------------- # The notebook this page is associated with: notebook = Instance( 'ThemedVerticalNotebook' ) # The theme used to display a closed page: closed_theme = ATheme # The theme use to display an open page: open_theme = ATheme # The control representing the closed page: closed_page = Property( depends_on = 'closed_theme' ) # The control representing the open page: open_page = Property( depends_on = 'open_theme' ) #-- Public Methods --------------------------------------------------------- def close ( self ): """ Closes the notebook page. """ if self.object is not None: self.object.on_trait_change( self._name_updated, self.trait_name, remove = True ) self.object = None if self.ui is not None: self.ui.dispose() self.ui = None if self.closed_page is not None: self.closed_page.control.Destroy() self.open_page.control.Destroy() self.control = None def set_size ( self, x, y, dx, dy ): """ Sets the size of the current active page. """ if self.is_open: self.open_page.control.SetDimensions( x, y, dx, dy ) else: self.closed_page.control.SetDimensions( x, y, dx, dy ) def register_name_listener ( self, object, trait_name ): """ Registers a listener on the specified object trait for a page name change. """ # Save the information, so we can unregister it later: self.object, self.trait_name = object, trait_name # Register the listener: object.on_trait_change( self._name_updated, trait_name ) # Make sure the name gets initialized: self._name_updated() #-- Property Implementations ----------------------------------------------- def _get_min_size ( self ): """ Returns the minimum size for the page. """ dxo, dyo = self.open_page.best_size dxc, dyc = self.closed_page.best_size if self.is_open: return wx.Size( max( dxo, dxc ), dyo ) return wx.Size( max( dxo, dxc ), dyc ) def _get_open_size ( self ): """ Returns the open size for the page. """ return self.open_page.best_size def _get_closed_size ( self ): """ Returns the closed size for the page. """ return self.closed_page.best_size @cached_property def _get_closed_page ( self ): """ Returns the 'closed' form of the notebook page. """ result = ThemedControl( theme = self.closed_theme, text = self.name, controller = self, default_alignment = 'center', state = 'closed' ) result.create_control( self.notebook.control ) return result @cached_property def _get_open_page ( self ): """ Returns the 'open' form of the notebook page. """ result = ImagePanel( theme = self.open_theme, text = self.name, controller = self, default_alignment = 'center', state = 'open' ) result.create_control( self.notebook.control ) return result def _get_parent ( self ): """ Returns the parent window for the client's window. """ return self.open_page.control #-- Trait Event Handlers --------------------------------------------------- def _ui_changed ( self, ui ): """ Handles the ui trait being changed. """ if ui is not None: self.control = ui.control def _control_changed ( self, control ): """ Handles the control for the page being changed. """ if control is not None: self.open_page.control.GetSizer().Add( control, 1, wx.EXPAND ) self._is_open_changed( self.is_open ) def _is_open_changed ( self, is_open ): """ Handles the 'is_open' state of the page being changed. """ self.closed_page.control.Show( not is_open ) self.open_page.control.Show( is_open ) if is_open: self.closed_page.control.SetSize( wx.Size( 0, 0 ) ) else: self.open_page.control.SetSize( wx.Size( 0, 0 ) ) def _name_changed ( self, name ): """ Handles the name trait being changed. """ self.closed_page.text = self.open_page.text = name def _name_updated ( self ): """ Handles a signal that the associated object's page name has changed. """ nb = self.notebook handler_name = None method = None editor = nb.editor if editor is not None: method = getattr( editor.ui.handler, '%s_%s_page_name' % ( editor.object_name, editor.name ), None ) if method is not None: handler_name = method( editor.ui.info, self.object ) if handler_name is not None: self.name = handler_name else: self.name = getattr( self.object, self.trait_name ) or '???' #-- ThemedControl Mouse Event Handlers ------------------------------------- def open_left_down ( self, x, y, event ): """ Handles the user clicking on an open notebook page to close it. """ if not self.notebook.double_click: self.notebook.close( self ) def open_left_dclick ( self, x, y, event ): """ Handles the user double clicking on an open notebook page to close it. """ if self.notebook.double_click: self.notebook.close( self ) def closed_left_down ( self, x, y, event ): """ Handles the user clicking on a closed notebook page to open it. """ if not self.notebook.double_click: self.notebook.open( self ) def closed_left_dclick ( self, x, y, event ): """ Handles the user double clicking on a closed notebook page to open it. """ if self.notebook.double_click: self.notebook.open( self ) #------------------------------------------------------------------------------- # 'ThemedVerticalNotebook' class: #------------------------------------------------------------------------------- class ThemedVerticalNotebook ( HasPrivateTraits ): """ Defines a ThemedVerticalNotebook class for displaying a series of pages organized vertically, as opposed to horizontally like a standard notebook. """ #-- Public Traits ---------------------------------------------------------- # The theme to use for 'closed' notebook pages: closed_theme = ATheme( Theme( '@std:notebook_close', content = 0 ) ) # The theme to use for 'open' notebook pages: open_theme = ATheme( Theme( '@std:notebook_open', content = 0 ) ) # Allow multiple open pages at once? multiple_open = Bool( False ) # Should the notebook be scrollable? scrollable = Bool( False ) # Use double clicks (True) or single clicks (False) to open/close pages: double_click = Bool( False ) # The pages contained in the notebook: pages = List( ThemedPage ) # The traits UI editor this notebook is associated with (if any): editor = Instance( Editor ) #-- Private Traits --------------------------------------------------------- # The wxPython control used to represent the notebook: control = Instance( wx.Window ) #-- Public Methods --------------------------------------------------------- def create_control ( self, parent ): """ Creates the underlying wxPython window used for the notebook. """ # Create the correct type of window based on whether or not it should # be scrollable: if self.scrollable: self.control = control = TraitsUIScrolledPanel( parent ) control.SetScrollRate( 6, 6 ) control.SetSize( wx.Size( 0, 0 ) ) else: self.control = control = TraitsUIPanel( parent, -1 ) control._image_slice = getattr( parent, '_image_slice', None ) control.SetSizer( ThemedVerticalNotebookSizer( self ) ) # Set up the painting event handlers: wx.EVT_ERASE_BACKGROUND( control, self._erase_background ) wx.EVT_PAINT( control, self._paint ) return control def create_page ( self ): """ Creates a new **ThemedPage** object representing a notebook page and returns it as the result. """ return ThemedPage( notebook = self ).set( closed_theme = self.closed_theme, open_theme = self.open_theme ) def open ( self, page ): """ Handles opening a specified **ThemedPage** notebook page. """ if (page is not None) and (not page.is_open): if not self.multiple_open: for a_page in self.pages: a_page.is_open = False page.is_open = True self._refresh() def close ( self, page ): """ Handles closing a specified **ThemedPage** notebook page. """ if (page is not None) and page.is_open: page.is_open = False self._refresh() #-- Trait Event Handlers --------------------------------------------------- def _pages_changed ( self, old, new ): """ Handles the notebook's pages being changed. """ for page in old: page.close() self._refresh() def _pages_items_changed ( self, event ): """ Handles some of the notebook's pages being changed. """ for page in event.removed: page.close() self._refresh() def _multiple_open_changed ( self, multiple_open ): """ Handles the 'multiple_open' flag being changed. """ if not multiple_open: first = True for page in self.pages: if first and page.is_open: first = False else: page.is_open = False self._refresh() #-- wx.Python Event Handlers ----------------------------------------------- def _erase_background ( self, event ): """ Do not erase the background here (do it in the 'on_paint' handler). """ pass def _paint ( self, event ): """ Paint the background using the associated ImageSlice object. """ paint_parent( wx.PaintDC( self.control ), self.control ) #-- Private Methods -------------------------------------------------------- def _refresh ( self ): """ Refresh the layout and contents of the notebook. """ control = self.control if control is not None: # Set the virtual size of the canvas (so scroll bars work right): sizer = control.GetSizer() if control.GetSize()[0] == 0: control.SetSize( sizer.CalcInit() ) control.SetVirtualSize( sizer.CalcMin() ) control.Layout() control.Refresh() #------------------------------------------------------------------------------- # 'ThemedVerticalNotebookSizer' class: #------------------------------------------------------------------------------- class ThemedVerticalNotebookSizer ( wx.PySizer ): """ Defines a sizer that correctly sizes a themed vertical notebook's children to implement the vertical notebook UI model. """ def __init__ ( self, notebook ): """ Initializes the object. """ super( ThemedVerticalNotebookSizer, self ).__init__() # Save the notebook reference: self._notebook = notebook def CalcMin ( self ): """ Calculates the minimum size of the control by aggregating the sizes of the open and closed pages. """ tdx, tdy = 0, 0 for page in self._notebook.pages: dx, dy = page.min_size tdx = max( tdx, dx ) tdy += dy return wx.Size( tdx, tdy ) def CalcInit ( self ): """ Calculates a reasonable initial size of the control by aggregating the sizes of the open and closed pages. """ tdx, tdy = 0, 0 open_dy = closed_dy = 0 for page in self._notebook.pages: dxo, dyo = page.open_size dxc, dyc = page.closed_size tdx = max( tdx, dxo, dxc ) if dyo > open_dy: tdy += (dyo - open_dy + closed_dy) open_dy, closed_dy = dyo, dyc else: tdy += dyc return wx.Size( tdx, min( tdy, screen_dy / 2 ) ) def RecalcSizes ( self ): """ Layout the contents of the sizer based on the sizer's current size and position. """ x, y = self.GetPositionTuple() tdx, tdy = self.GetSizeTuple() cdy = ody = 0 for page in self._notebook.pages: dx, dy = page.min_size if page.is_open: ody += dy else: cdy += dy ady = max( 0, tdy - cdy ) for page in self._notebook.pages: dx, dy = page.min_size if page.is_open: ndy = (ady * dy) / ody ady -= ndy ody -= dy dy = ndy page.set_size( x, y, tdx, dy ) y += dy traitsui-4.1.0/traitsui/wx/color_editor.py0000644000175100001440000003622211674463546021726 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! #------------------------------------------------------------------------------ """ Defines the various color editors for the Wx user interface toolkit. """ #------------------------------------------------------------------------------ # Imports: #------------------------------------------------------------------------------ import wx import wx.combo from traits.api import List, TraitError from traitsui.editors.color_editor \ import ToolkitEditorFactory as BaseToolkitEditorFactory from editor_factory import SimpleEditor as BaseSimpleEditor from editor_factory import ReadonlyEditor as BaseReadonlyEditor from editor_factory import TextEditor as BaseTextEditor from color_trait import w3c_color_database from helper import TraitsUIPanel # Version dependent imports (ColourPtr not defined in wxPython 2.5): try: ColorTypes = (wx.Colour, wx.ColourPtr) except: ColorTypes = wx.Colour #--------------------------------------------------------------------------- # The Wx ToolkitEditorFactory class. #--------------------------------------------------------------------------- class ToolkitEditorFactory(BaseToolkitEditorFactory): """ Wx editor factory for color editors. """ def to_wx_color(self, editor, color=None): """ Gets the wxPython color equivalent of the object trait. """ if color is None: if self.mapped: color = getattr(editor.object, editor.name + '_') else: color = getattr(editor.object, editor.name) if isinstance(color, tuple): color = wx.Colour(*[int(round(c * 255.0)) for c in color]) return color #-------------------------------------------------------------------------- # Gets the application equivalent of a wxPython value: #-------------------------------------------------------------------------- def from_wx_color(self, color): """ Gets the application equivalent of a wxPython value. """ return color.Red(), color.Green(), color.Blue() #-------------------------------------------------------------------------- # Returns the text representation of a specified color value: #-------------------------------------------------------------------------- def str_color(self, color): """ Returns the text representation of a specified color value. """ if isinstance(color, ColorTypes): alpha = color.Alpha() if alpha == 255: return "rgb(%d,%d,%d)" % ( color.Red(), color.Green(), color.Blue()) return "rgb(%d,%d,%d,%d)" % ( color.Red(), color.Green(), color.Blue(), alpha) return str(color) #------------------------------------------------------------------------------ # 'ColorComboBox' class: #------------------------------------------------------------------------------ class ColorComboBox(wx.combo.OwnerDrawnComboBox): def OnDrawItem(self, dc, rect, item, flags): r = wx.Rect(rect.x, rect.y, rect.width, rect.height) r.Deflate(3, 0) swatch_size = r.height - 2 color_name = self.GetString(item) dc.DrawText(color_name, r.x + 3, r.y + (r.height - dc.GetCharHeight()) / 2) if color_name == 'custom': swatch = wx.Rect(r.x + r.width - swatch_size, r.y + 1, swatch_size, swatch_size) dc.GradientFillLinear(swatch, wx.Colour(255, 255, 0), wx.Colour(0, 0, 255)) else: color = w3c_color_database.Find(color_name) brush = wx.Brush(color) dc.SetBrush(brush) dc.DrawRectangle(r.x + r.width - swatch_size, r.y + 1, swatch_size, swatch_size) #------------------------------------------------------------------------------ # 'SimpleColorEditor' class: #------------------------------------------------------------------------------ class SimpleColorEditor(BaseSimpleEditor): """ Simple style of color editor, which displays a text field whose background color is the color value. Selecting the text field displays a dialog box for selecting a new color value. """ #-------------------------------------------------------------------------- # Invokes the pop-up editor for an object trait: #-------------------------------------------------------------------------- choices = List() def _choices_default(self): """ by default, uses the W3C 16 color names. """ return ['aqua', 'black', 'blue', 'fuchsia', 'gray', 'green', 'lime', 'maroon', 'navy', 'olive', 'purple', 'red', 'silver', 'teal', 'white', 'yellow', 'custom'] def init(self, parent): """ Finishes initializing the editor by creating the underlying widget. """ current_color = self.factory.to_wx_color(self) current_color_name = current_color.GetAsString() self.control = ColorComboBox(parent, -1, current_color_name, wx.Point(0, 0), wx.Size(40, -1), self.choices, style=wx.wx.CB_READONLY) self.control.Bind(wx.EVT_COMBOBOX, self.color_selected) return #-------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #-------------------------------------------------------------------------- def update_editor(self): """ Updates the editor when the object trait changes externally to the editor. """ current_color = self.factory.to_wx_color(self) self.control.SetValue(self.string_value(current_color)) def color_selected(self, event): """ Event for when color is selected """ color_name = self.choices[event.Selection] if color_name == 'custom': color_dialog = wx.ColourDialog(self.control) result = color_dialog.ShowModal() if result == wx.ID_CANCEL: return color = color_dialog.GetColourData().GetColour() self.value = self.factory.from_wx_color(color) else: try: color = w3c_color_database.Find(color_name) self.value = self.factory.from_wx_color(color) except ValueError: pass return def string_value(self, color): """ Returns the text representation of a specified color value. """ color_name = w3c_color_database.FindName(color) if color_name != '': return color_name return color.GetAsString() #------------------------------------------------------------------------------ # 'CustomColorEditor' class: #------------------------------------------------------------------------------ class CustomColorEditor(BaseSimpleEditor): """ Simple style of color editor, which displays a text field whose background color is the color value. Selecting the text field displays a dialog box for selecting a new color value. """ #-------------------------------------------------------------------------- # Invokes the pop-up editor for an object trait: #-------------------------------------------------------------------------- def init(self, parent): """ Finishes initializing the editor by creating the underlying widget. """ self.control = self._panel = parent = TraitsUIPanel(parent, -1) sizer = wx.BoxSizer(wx.HORIZONTAL) # 'text_control' is the text display of the color. text_control = wx.TextCtrl(parent, -1, self.str_value, style=wx.TE_PROCESS_ENTER) wx.EVT_KILL_FOCUS(text_control, self.update_object) wx.EVT_TEXT_ENTER(parent, text_control.GetId(), self.update_object) # 'button_control' shows the 'Edit' button. button_control = wx.Button(parent, label='Edit', style=wx.BU_EXACTFIT) wx.EVT_BUTTON(button_control, button_control.GetId(), self.open_color_dialog) sizer.Add(text_control, wx.ALIGN_LEFT) sizer.AddSpacer(8) sizer.Add(button_control, wx.ALIGN_RIGHT) self.control.SetSizer(sizer) self._text_control = text_control self._button_control = button_control self.set_tooltip() return def update_object(self, event): """ Handles the user changing the contents of the edit control. """ if not isinstance(event, wx._core.CommandEvent): return try: # The TextCtrl object was saved as self._text_control in init(). value = self._text_control.GetValue() self.value = w3c_color_database.Find(value) self.set_color() except TraitError: pass def set_color(self): # The CustomColorEditor uses this method instead of the global # set_color function. color = self.factory.to_wx_color(self) self._text_control.SetBackgroundColour(color) self.control.SetBackgroundColour(color) self._text_control.SetValue(self.string_value(color)) #-------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #-------------------------------------------------------------------------- def update_editor(self): """ Updates the editor when the object trait changes externally to the editor. """ self.set_color() def open_color_dialog(self, event): """ Opens the color dialog and sets the value upon return """ color_data = wx.ColourData() color_data.SetColour(self.value) color_dialog = wx.ColourDialog(self.control, color_data) result = color_dialog.ShowModal() if result == wx.ID_CANCEL: return color = color_dialog.GetColourData().GetColour() self.value = color self.set_color() def color_selected(self, event): """ Event for when color is selected """ color = event.GetColour() try: self.value = self.factory.from_wx_color(color) except ValueError: pass return def string_value(self, color): """ Returns the text representation of a specified color value. """ color_name = w3c_color_database.FindName(color) if color_name != '': return color_name return self.factory.str_color(color) #------------------------------------------------------------------------------ # 'ReadonlyColorEditor' class: #------------------------------------------------------------------------------ class ReadonlyColorEditor(BaseReadonlyEditor): """ Read-only style of color editor, which displays a read-only text field whose background color is the color value. """ #-------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #-------------------------------------------------------------------------- def init(self, parent): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self.control = wx.TextCtrl(parent, style=wx.TE_READONLY) #-------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #-------------------------------------------------------------------------- def update_editor(self): """ Updates the editor when the object trait changes externally to the editor. """ #super(ReadonlyColorEditor, self).update_editor() self.control.SetValue(self.string_value(self.value)) set_color(self) #-------------------------------------------------------------------------- # Returns the text representation of a specified color value: #-------------------------------------------------------------------------- def string_value(self, color): """ Returns the text representation of a specified color value. """ color_name = w3c_color_database.FindName(color) if color_name != '': return color_name return self.factory.str_color(color) #------------------------------------------------------------------------------ # 'ReadonlyColorEditor' class: #------------------------------------------------------------------------------ class TextColorEditor(BaseTextEditor): """ Text style of color editor, which displays a text field whose background color is the color value. """ #-------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #-------------------------------------------------------------------------- def update_editor(self): """ Updates the editor when the object trait changes externally to the editor. """ self.control.SetValue(self.string_value(self.value)) set_color(self) def update_object(self, event): """ Handles the user changing the contents of the edit control. """ if not isinstance(event, wx._core.CommandEvent): return try: self.value = w3c_color_database.Find(self.control.GetValue()) set_color(self) except TraitError: pass #-------------------------------------------------------------------------- # Returns the text representation of a specified color value: #-------------------------------------------------------------------------- def string_value(self, color): """ Returns the text representation of a specified color value. """ color_name = w3c_color_database.FindName(color) if color_name != '': return color_name return self.factory.str_color(color) #------------------------------------------------------------------------------ # Sets the color of the specified editor's color control: #------------------------------------------------------------------------------ def set_color(editor): """ Sets the color of the specified color control. """ color = editor.factory.to_wx_color(editor) editor.control.SetBackgroundColour(color) # Define the SimpleEditor, CustomEditor, etc. classes which are used by the # editor factory for the color editor. SimpleEditor = SimpleColorEditor CustomEditor = CustomColorEditor TextEditor = TextColorEditor ReadonlyEditor = ReadonlyColorEditor traitsui-4.1.0/traitsui/wx/text_editor.py0000644000175100001440000002550311674463546021574 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/21/2004 # #------------------------------------------------------------------------------ """ Defines the various text editors for the wxPython user interface toolkit. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------ import wx from traits.api \ import TraitError # FIXME: ToolkitEditorFactory is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.text_editor file. from traitsui.editors.text_editor \ import ToolkitEditorFactory, evaluate_trait from editor \ import Editor from editor_factory \ import ReadonlyEditor as BaseReadonlyEditor from constants \ import OKColor #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- # Readonly text editor with view state colors: HoverColor = wx.LIGHT_GREY DownColor = wx.WHITE #------------------------------------------------------------------------------- # 'SimpleEditor' class: #------------------------------------------------------------------------------- class SimpleEditor ( Editor ): """ Simple style text editor, which displays a text field. """ # Flag for window styles: base_style = 0 # Background color when input is OK: ok_color = OKColor #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Function used to evaluate textual user input: evaluate = evaluate_trait #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ factory = self.factory style = self.base_style self.evaluate = factory.evaluate self.sync_value( factory.evaluate_name, 'evaluate', 'from' ) if (not factory.multi_line) or factory.password: style &= ~wx.TE_MULTILINE if factory.password: style |= wx.TE_PASSWORD multi_line = ((style & wx.TE_MULTILINE) != 0) if multi_line: self.scrollable = True if factory.enter_set and (not multi_line): control = wx.TextCtrl( parent, -1, self.str_value, style = style | wx.TE_PROCESS_ENTER ) wx.EVT_TEXT_ENTER( parent, control.GetId(), self.update_object ) else: control = wx.TextCtrl( parent, -1, self.str_value, style = style ) wx.EVT_KILL_FOCUS( control, self.update_object ) if factory.auto_set: wx.EVT_TEXT( parent, control.GetId(), self.update_object ) self.control = control self.set_error_state( False ) self.set_tooltip() #--------------------------------------------------------------------------- # Handles the user entering input data in the edit control: #--------------------------------------------------------------------------- def update_object ( self, event ): """ Handles the user entering input data in the edit control. """ if (not self._no_update) and (self.control is not None): try: self.value = self._get_user_value() if self._error is not None: self._error = None self.ui.errors -= 1 self.set_error_state( False ) except TraitError, excp: pass #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ user_value = self._get_user_value() try: unequal = bool( user_value != self.value ) except ValueError: # This might be a numpy array. unequal = True if unequal: self._no_update = True self.control.SetValue( self.str_value ) self._no_update = False if self._error is not None: self._error = None self.ui.errors -= 1 self.set_error_state( False ) #--------------------------------------------------------------------------- # Gets the actual value corresponding to what the user typed: #--------------------------------------------------------------------------- def _get_user_value ( self ): """ Gets the actual value corresponding to what the user typed. """ value = self.control.GetValue() try: value = self.evaluate( value ) except: pass try: ret = self.factory.mapping.get( value, value ) except TypeError: # The value is probably not hashable: ret = value return ret #--------------------------------------------------------------------------- # Handles an error that occurs while setting the object's trait value: #--------------------------------------------------------------------------- def error ( self, excp ): """ Handles an error that occurs while setting the object's trait value. """ if self._error is None: self._error = True self.ui.errors += 1 self.set_error_state( True ) #--------------------------------------------------------------------------- # Returns whether or not the editor is in an error state: #--------------------------------------------------------------------------- def in_error_state ( self ): """ Returns whether or not the editor is in an error state. """ return (self.invalid or self._error) #------------------------------------------------------------------------------- # 'CustomEditor' class: #------------------------------------------------------------------------------- class CustomEditor ( SimpleEditor ): """ Custom style of text editor, which displays a multi-line text field. """ # Flag for window style. This value overrides the default. base_style = wx.TE_MULTILINE #------------------------------------------------------------------------------- # 'ReadonlyEditor' class: #------------------------------------------------------------------------------- class ReadonlyEditor ( BaseReadonlyEditor ): """ Read-only style of text editor, which displays a read-only text field. """ #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ super( ReadonlyEditor, self ).init( parent ) if self.factory.view is not None: control = self.control wx.EVT_ENTER_WINDOW( control, self._enter_window ) wx.EVT_LEAVE_WINDOW( control, self._leave_window ) wx.EVT_LEFT_DOWN( control, self._left_down ) wx.EVT_LEFT_UP( control, self._left_up ) #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ control = self.control new_value = self.str_value if hasattr(self.factory, 'password') and self.factory.password: new_value = '*' * len( new_value ) if (self.item.resizable is True) or (self.item.height != -1.0): if control.GetValue() != new_value: control.SetValue( new_value ) control.SetInsertionPointEnd() elif control.GetLabel() != new_value: control.SetLabel( new_value ) #--------------------------------------------------------------------------- # Disposes of the contents of an editor: #--------------------------------------------------------------------------- def dispose ( self ): """ Disposes of the contents of an editor. """ if self.factory.view is not None: control = self.control wx.EVT_ENTER_WINDOW( control, None ) wx.EVT_LEAVE_WINDOW( control, None ) wx.EVT_LEFT_DOWN( control, None ) wx.EVT_LEFT_UP( control, None ) super( ReadonlyEditor, self ).dispose() #-- Private Methods -------------------------------------------------------- def _set_color ( self ): control = self.control if not self._in_window: color = control.GetParent().GetBackgroundColour() elif self._down: color = DownColor else: color = HoverColor control.SetBackgroundColour( color ) control.Refresh() #-- wxPython Event Handlers ------------------------------------------------ def _enter_window ( self, event ): self._in_window = True self._set_color() def _leave_window ( self, event ): self._in_window = False self._set_color() def _left_down ( self, event ): self.control.CaptureMouse() self._down = True self._set_color() def _left_up ( self, event ): self._set_color() if not self._down: return self.control.ReleaseMouse() self._down = False if self._in_window: self.object.edit_traits( view = self.factory.view, parent = self.control ) TextEditor = SimpleEditor traitsui-4.1.0/traitsui/wx/ui_window.py0000644000175100001440000000667411674463546021256 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2008, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 08/23/2008 # #------------------------------------------------------------------------------ """ A base class for creating custom Traits UI windows. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx from traits.api \ import HasPrivateTraits, Instance, Property from helper \ import init_wx_handlers, BufferDC #------------------------------------------------------------------------------- # 'UIWindow' class: #------------------------------------------------------------------------------- class UIWindow ( HasPrivateTraits ): """ A base class for creating custom Traits UI windows. """ # The wx.Window associated with this custom window: control = Instance( wx.Window ) # The initial size of the window: size = Instance( wx.Size, ( -1, -1 ) ) # The current width of the window: width = Property # The current height of the window: height = Property #-- Public Methods --------------------------------------------------------- def __init__ ( self, parent, **traits ): """ Creates and initializes the window. """ super( UIWindow, self ).__init__( **traits ) self.control = wx.Window( parent, -1, size = self.size, style = wx.FULL_REPAINT_ON_RESIZE ) init_wx_handlers( self.control, self ) def refresh ( self, x = None, y = None, dx = None, dy = None ): """ Refreshes the contents of the window. """ if self.control is not None: if x is None: self.control.Refresh() else: self.control.Refresh( x, y, dx, dy ) def capture ( self ): """ Capture the mouse. """ self.control.CaptureMouse() def release ( self ): """ Release the mouse. """ self.control.ReleaseMouse() #-- wxPython Event Handlers ------------------------------------------------ def _erase_background ( self, event ): """ Never, ever, do anything in this handler. """ pass def _paint ( self, event ): """ Paints the contents of the window. """ dc = BufferDC( self.control ) self._paint_dc( dc ) dc.copy() def _paint_dc ( self, dc ): """ This method should be overridden by sub-classes to do the actual window painting. """ pass #-- Property Implementations ----------------------------------------------- def _get_width ( self ): return self.control.GetClientSize()[0] def _set_width ( self, width ): self.control.SetSize( width, self.height ) def _get_height ( self ): return self.control.GetClientSize()[1] def _set_height ( self, height ): self.control.SetSize( self.width, height ) traitsui-4.1.0/traitsui/wx/themed_text_editor.py0000644000175100001440000004305611674463546023125 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2007, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 06/13/2007 # #------------------------------------------------------------------------------- """ Traits UI simple, read-only single line text editor with a themed (i.e. image) background. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx from traits.api \ import Enum, Instance, Bool, Dict, Str, Any, Property, TraitError, \ cached_property from traitsui.ui_traits \ import ATheme from traitsui.wx.editor \ import Editor from traitsui.wx.editor_factory \ import EditorFactory from pyface.image_resource \ import ImageResource from image_slice import paint_parent, ImageSlice from constants \ import OKColor, ErrorColor from helper \ import disconnect_no_id, BufferDC from themed_control \ import ThemedControl # Define a reusable, default ImageSlice object: default_image_slice = ImageSlice() #------------------------------------------------------------------------------- # Define a simple identity mapping: #------------------------------------------------------------------------------- class _Identity ( object ): """ A simple indentity mapping. """ def __call__ ( self, value ): return value #------------------------------------------------------------------------------- # 'ThemedTextEditor' class: #------------------------------------------------------------------------------- class ThemedTextEditor ( EditorFactory ): """ Traits UI simple, single line text editor with a themed (i.e. image) background. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # The background theme image to display: theme = ATheme # Dictionary that maps user input to other values: mapping = Dict( Str, Any ) # Is user input set on every keystroke? auto_set = Bool( True ) # Is user input set when the Enter key is pressed? enter_set = Bool( False ) # Is user input unreadable? (e.g., for a password) password = Bool( False ) # Function to evaluate textual user input: evaluate = Any # The object trait containing the function used to evaluate user input: evaluate_name = Str #--------------------------------------------------------------------------- # 'Editor' factory methods: #--------------------------------------------------------------------------- def simple_editor ( self, ui, object, name, description, parent ): return _ThemedTextEditor( parent, factory = self, ui = ui, object = object, name = name, description = description ) def custom_editor ( self, ui, object, name, description, parent ): return _ThemedTextEditor( parent, factory = self, ui = ui, object = object, name = name, description = description ) def text_editor ( self, ui, object, name, description, parent ): return _ThemedTextEditor( parent, factory = self, ui = ui, object = object, name = name, description = description ) def readonly_editor ( self, ui, object, name, description, parent ): return _ReadonlyTextEditor( parent, factory = self, ui = ui, object = object, name = name, description = description ) #------------------------------------------------------------------------------- # '_ThemedTextEditor' class: #------------------------------------------------------------------------------- class _ThemedTextEditor ( Editor ): """ Traits UI simple, single line text editor with a themed (i.e. image background). """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Function used to evaluate textual user input: evaluate = Any # The text alignment to use: alignment = Property # The image slice to use: image_slice = Property #-- Class Variables -------------------------------------------------------- text_styles = { 'default': wx.TE_LEFT, 'left': wx.TE_LEFT, 'center': wx.TE_CENTRE, 'right': wx.TE_RIGHT } #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ factory = self.factory evaluate = factory.evaluate if evaluate is None: handler = self.object.trait( self.name ).handler evaluate = getattr( handler, 'evaluate', None ) if evaluate is None: evaluate = _Identity() self.evaluate = evaluate self.sync_value( factory.evaluate_name, 'evaluate', 'from' ) padding_x = padding_y = 0 if factory.theme is not None: slice = self.image_slice padding_x = slice.xleft + slice.xright padding_y = slice.xtop + slice.xbottom self.control = control = wx.Window( parent, -1, size = wx.Size( padding_x + 70, padding_y + 20 ), style = wx.FULL_REPAINT_ON_RESIZE | wx.WANTS_CHARS ) self._text_size = None # Set up the painting event handlers: wx.EVT_ERASE_BACKGROUND( control, self._erase_background ) wx.EVT_PAINT( control, self._on_paint ) wx.EVT_CHAR( control, self._inactive_key_entered ) # Handle 'focus' events: wx.EVT_SET_FOCUS( control, self._set_focus ) wx.EVT_LEFT_UP( control, self._set_focus ) # Handle 'resize' events: wx.EVT_SIZE( control, self._resize ) self.set_tooltip() #--------------------------------------------------------------------------- # Disposes of the contents of an editor: #--------------------------------------------------------------------------- def dispose ( self ): """ Disposes of the contents of an editor. """ # Remove all of the wx event listeners: disconnect_no_id( self.control, wx.EVT_ERASE_BACKGROUND, wx.EVT_PAINT, wx.EVT_CHAR, wx.EVT_SET_FOCUS, wx.EVT_LEFT_UP, wx.EVT_SIZE ) super( _ThemedTextEditor, self ).dispose() #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ if self._text is None: self._refresh() return if self._get_user_value() != self.value: self._no_update = True self._text.SetValue( self.str_value ) self._no_update = False if self._error is not None: self._error = None self.ui.errors -= 1 self._text.SetBackgroundColour( self.ok_color ) self._text.Refresh() #--------------------------------------------------------------------------- # Handles the user entering input data in the edit control: #--------------------------------------------------------------------------- def update_object ( self, event ): """ Handles the user entering input data in the edit control. """ if not self._no_update: try: self.value = self._get_user_value() self._text.SetBackgroundColour( OKColor ) self._text.Refresh() if self._error is not None: self._error = None self.ui.errors -= 1 return True except TraitError, excp: return False #--------------------------------------------------------------------------- # Gets the actual value corresponding to what the user typed: #--------------------------------------------------------------------------- def _get_user_value ( self ): """ Gets the actual value corresponding to what the user typed. """ value = self._text.GetValue() try: value = self.evaluate( value ) except: pass return self.factory.mapping.get( value, value ) #--------------------------------------------------------------------------- # Handles an error that occurs while setting the object's trait value: #--------------------------------------------------------------------------- def error ( self, excp ): """ Handles an error that occurs while setting the object's trait value. """ self._text.SetBackgroundColour( ErrorColor ) self._text.Refresh() wx.Bell() if self._error is None: self._error = True self.ui.errors += 1 #-- Private Methods -------------------------------------------------------- def _pop_up_text ( self ): """ Pop-up a text control to allow the user to enter a value using the keyboard. """ control = self.control factory = self.factory style = (self.text_styles[ self.alignment ] | wx.TE_PROCESS_ENTER) if factory.password: style |= wx.TE_PASSWORD self._text = text = wx.TextCtrl( control, -1, self.str_value, style = style ) slice = self.image_slice wdx, wdy = control.GetClientSize() tdx, tdy = text.GetSize() text.SetPosition( wx.Point( slice.xleft, ((wdy + slice.xtop - slice.xbottom - tdy) / 2) + 1 ) ) text.SetSize( wx.Size( wdx - slice.xleft - slice.xright, tdy ) ) text.SetSelection( -1, -1 ) text.SetFocus() wx.EVT_KILL_FOCUS( text, self._text_completed ) wx.EVT_CHAR( text, self._key_entered ) wx.EVT_TEXT_ENTER( control, text.GetId(), self.update_object ) if factory.auto_set and (not factory.is_grid_cell): wx.EVT_TEXT( control, text.GetId(), self.update_object ) def _destroy_text ( self ): """ Destroys the current text control. """ self.control.DestroyChildren() self._text = None def _refresh ( self ): """ Refreshes the contents of the control. """ if self._text_size is not None: self.control.RefreshRect( wx.Rect( *self._get_text_bounds() ), False ) self._text_size = None self.control.RefreshRect( wx.Rect( *self._get_text_bounds() ), False ) def _get_text_size ( self ): """ Returns the text size information for the window. """ if self._text_size is None: self._text_size = self.control.GetFullTextExtent( self._get_text() or 'M' ) return self._text_size def _get_text_bounds ( self ): """ Get the window bounds of where the current text should be displayed. """ tdx, tdy, descent, leading = self._get_text_size() wdx, wdy = self.control.GetClientSizeTuple() slice = self.image_slice ady = wdy - slice.xtop - slice.xbottom ty = slice.xtop + ((ady - (tdy - descent)) / 2) - 1 alignment = self.alignment if alignment == 'center': adx = wdx - slice.xleft - slice.xright tx = slice.xleft + (adx - tdx) / 2 elif alignment == 'right': tx = wdx - tdx - slice.xright - 4 else: tx = slice.xleft + 4 return ( tx, ty, tdx, tdy ) def _get_text ( self ): """ Returns the current text to display. """ if self.factory.password: return '*' * len( self.str_value ) return self.str_value #-- Property Implementations ----------------------------------------------- @cached_property def _get_alignment ( self ): theme = self.factory.theme if theme is not None: return theme.alignment return 'left' @cached_property def _get_image_slice ( self ): theme = self.factory.theme if theme is not None: return theme.image_slice or default_image_slice return default_image_slice #-- wxPython Event Handlers ------------------------------------------------ def _erase_background ( self, event ): """ Do not erase the background here (do it in the 'on_paint' handler). """ pass def _on_paint ( self, event ): """ Paint the background using the associated ImageSlice object. """ control = self.control dc = BufferDC( control ) slice = paint_parent( dc, control ) slice2 = self.image_slice if slice2 is not default_image_slice: wdx, wdy = control.GetClientSizeTuple() slice2.fill( dc, 0, 0, wdx, wdy, True ) slice = slice2 elif slice is None: slice = slice2 dc.SetBackgroundMode( wx.TRANSPARENT ) dc.SetTextForeground( slice.content_color ) dc.SetFont( control.GetFont() ) tx, ty, tdx, tdy = self._get_text_bounds() dc.DrawText( self._get_text(), tx, ty ) dc.copy() def _resize ( self, event ): """ Handles the control being resized. """ if self._text is not None: self._text.SetSize( self.control.GetSize() ) def _set_focus ( self, event ): """ Handle the control getting the keyboard focus. """ if self._text is None: self._pop_up_text() event.Skip() def _text_completed ( self, event ): """ Handles the user transferring focus out of the text control. """ if self.update_object( event ): self._destroy_text() def _key_entered ( self, event ): """ Handles individual key strokes while the text control is active. """ key_code = event.GetKeyCode() if key_code == wx.WXK_ESCAPE: self._destroy_text() return if key_code == wx.WXK_TAB: if self.update_object( event ): if event.ShiftDown(): self.control.Navigate( 0 ) else: self.control.Navigate() return event.Skip() def _inactive_key_entered ( self, event ): """ Handles individual key strokes while the text control is inactive. """ if event.GetKeyCode() == wx.WXK_RETURN: if self._text is None: self._pop_up_text() return event.Skip() #------------------------------------------------------------------------------- # '_ReadonlyTextEditor' class: #------------------------------------------------------------------------------- class _ReadonlyTextEditor ( Editor ): """ Traits UI simple, read-only single line text view with a themed (i.e. image background). """ #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self._control = ThemedControl( theme = self.factory.theme ) self.control = self._control.create_control( parent ) self.set_tooltip() #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ self._control.text = self.value # Make sure the control is sized correctly: self.control.SetMinSize( self._control.best_size ) traitsui-4.1.0/traitsui/wx/file_editor.py0000644000175100001440000004547111674463546021535 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/21/2004 # #------------------------------------------------------------------------------ """ Defines file editors for the wxPython user interface toolkit. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx from os.path \ import abspath, splitext, isfile, exists from traits.api \ import List, Str, Event, Any, on_trait_change, TraitError # FIXME: ToolkitEditorFactory is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.file_editor file. from traitsui.editors.file_editor \ import ToolkitEditorFactory from text_editor \ import SimpleEditor as SimpleTextEditor from helper \ import TraitsUIPanel, PopupControl #------------------------------------------------------------------------------- # Trait definitions: #------------------------------------------------------------------------------- # Wildcard filter: filter_trait = List( Str ) #------------------------------------------------------------------------------- # 'SimpleEditor' class: #------------------------------------------------------------------------------- class SimpleEditor ( SimpleTextEditor ): """ Simple style of file editor, consisting of a text field and a **Browse** button that opens a file-selection dialog box. The user can also drag and drop a file onto this control. """ # The history control (used if the factory 'entries' > 0): history = Any # The popup file control (an Instance( PopupFile )): popup = Any #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self.control = panel = TraitsUIPanel( parent, -1 ) sizer = wx.BoxSizer( wx.HORIZONTAL ) factory = self.factory if factory.entries > 0: from history_control import HistoryControl self.history = HistoryControl( entries = factory.entries, auto_set = factory.auto_set ) control = self.history.create_control( panel ) pad = 3 button = wx.Button( panel, -1, '...', size = wx.Size( 28, -1 ) ) else: if factory.enter_set: control = wx.TextCtrl( panel, -1, '', style = wx.TE_PROCESS_ENTER ) wx.EVT_TEXT_ENTER( panel, control.GetId(), self.update_object ) else: control = wx.TextCtrl( panel, -1, '' ) wx.EVT_KILL_FOCUS( control, self.update_object ) if factory.auto_set: wx.EVT_TEXT( panel, control.GetId(), self.update_object ) bmp = wx.ArtProvider.GetBitmap( wx.ART_FOLDER_OPEN, size = ( 15, 15 ) ) button = wx.BitmapButton( panel, -1, bitmap = bmp ) pad = 8 self._file_name = control sizer.Add( control, 1, wx.EXPAND | wx.ALIGN_CENTER ) sizer.Add( button, 0, wx.LEFT | wx.ALIGN_CENTER, pad ) wx.EVT_BUTTON( panel, button.GetId(), self.show_file_dialog ) panel.SetDropTarget( FileDropTarget( self ) ) panel.SetSizerAndFit( sizer ) self._button = button self.set_tooltip( control ) def dispose ( self ): """ Disposes of the contents of an editor. """ panel = self.control wx.EVT_BUTTON( panel, self._button.GetId(), None ) self._button = None if self.history is not None: self.history.dispose() self.history = None else: factory = self.factory control, self._file_name = self._file_name, None wx.EVT_KILL_FOCUS( control, None ) wx.EVT_TEXT_ENTER( panel, control.GetId(), None ) wx.EVT_TEXT( panel, control.GetId(), None ) super( SimpleEditor, self ).dispose() #--------------------------------------------------------------------------- # Handles the history 'value' trait being changed: #--------------------------------------------------------------------------- @on_trait_change( 'history:value' ) def _history_value_changed ( self, value ): """ Handles the history 'value' trait being changed. """ if not self._no_update: self._update( value ) #--------------------------------------------------------------------------- # Handles the user changing the contents of the edit control: #--------------------------------------------------------------------------- def update_object ( self, event ): """ Handles the user changing the contents of the edit control. """ self._update( self._file_name.GetValue() ) #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ if self.history is not None: self._no_update = True self.history.value = self.str_value self._no_update = False else: self._file_name.SetValue( self.str_value ) #--------------------------------------------------------------------------- # Displays the pop-up file dialog: #--------------------------------------------------------------------------- def show_file_dialog ( self, event ): """ Displays the pop-up file dialog. """ if self.history is not None: self.popup = self._create_file_popup() else: dlg = self._create_file_dialog() rc = (dlg.ShowModal() == wx.ID_OK) file_name = abspath( dlg.GetPath() ) dlg.Destroy() if rc: if self.factory.truncate_ext: file_name = splitext( file_name )[0] self.value = file_name self.update_editor() #--------------------------------------------------------------------------- # Returns the editor's control for indicating error status: #--------------------------------------------------------------------------- def get_error_control ( self ): """ Returns the editor's control for indicating error status. """ return self._file_name #-- Traits Event Handlers -------------------------------------------------- @on_trait_change( 'popup:value' ) def _popup_value_changed ( self, file_name ): """ Handles the popup value being changed. """ if self.factory.truncate_ext: file_name = splitext( file_name )[0] self.value = file_name self._no_update = True self.history.set_value( self.str_value ) self._no_update = False @on_trait_change( 'popup:closed' ) def _popup_closed_changed ( self ): """ Handles the popup control being closed. """ self.popup = None #-- UI preference save/restore interface ----------------------------------- def restore_prefs ( self, prefs ): """ Restores any saved user preference information associated with the editor. """ if self.history is not None: self.history.history = \ prefs.get( 'history', [] )[ : self.factory.entries ] def save_prefs ( self ): """ Returns any user preference information associated with the editor. """ if self.history is not None: return { 'history': self.history.history[:] } return None #-- Private Methods -------------------------------------------------------- def _create_file_dialog ( self ): """ Creates the correct type of file dialog. """ if len( self.factory.filter ) > 0: wildcard = '|'.join( self.factory.filter[:] ) else: wildcard = 'All Files (*.*)|*.*' if self.factory.dialog_style == 'save': style = wx.FD_SAVE elif self.factory.dialog_style == 'open': style = wx.FD_OPEN else: style = wx.FD_DEFAULT_STYLE dlg = wx.FileDialog( self.control, message = 'Select a File', wildcard = wildcard, style=style) dlg.SetFilename( self._get_value() ) return dlg def _create_file_popup ( self ): """ Creates the correct type of file popup. """ return PopupFile( control = self.control, file_name = self.str_value, filter = self.factory.filter, height = 300 ) def _update ( self, file_name ): """ Updates the editor value with a specified file name. """ try: if self.factory.truncate_ext: file_name = splitext( file_name )[0] self.value = file_name except TraitError, excp: pass def _get_value ( self ): """ Returns the current file name from the edit control. """ if self.history is not None: return self.history.value return self._file_name.GetValue() #------------------------------------------------------------------------------- # 'CustomEditor' class: #------------------------------------------------------------------------------- class CustomEditor ( SimpleTextEditor ): """ Custom style of file editor, consisting of a file system tree view. """ # Is the file editor scrollable? This value overrides the default. scrollable = True # Wildcard filter to apply to the file dialog: filter = filter_trait # Event fired when the file system view should be rebuilt: reload = Event # Event fired when the user double-clicks a file: dclick = Event #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ style = self.get_style() factory = self.factory if (len( factory.filter ) > 0) or (factory.filter_name != ''): style |= wx.DIRCTRL_SHOW_FILTERS self.control = wx.GenericDirCtrl( parent, style = style ) self._tree = tree = self.control.GetTreeCtrl() id = tree.GetId() wx.EVT_TREE_SEL_CHANGED( tree, id, self.update_object ) wx.EVT_TREE_ITEM_ACTIVATED( tree, id, self._on_dclick ) wx.EVT_TREE_ITEM_GETTOOLTIP( tree, id, self._on_tooltip ) self.filter = factory.filter self.sync_value( factory.filter_name, 'filter', 'from', is_list = True ) self.sync_value( factory.reload_name, 'reload', 'from' ) self.sync_value( factory.dclick_name, 'dclick', 'to' ) self.set_tooltip() def dispose ( self ): """ Disposes of the contents of an editor. """ tree, self._tree = self._tree, None id = tree.GetId() wx.EVT_TREE_SEL_CHANGED( tree, id, None ) wx.EVT_TREE_ITEM_ACTIVATED( tree, id, None ) super( CustomEditor, self ).dispose() #--------------------------------------------------------------------------- # Handles the user changing the contents of the edit control: #--------------------------------------------------------------------------- def update_object ( self, event ): """ Handles the user changing the contents of the edit control. """ if self.control is not None: path = self.control.GetPath() if self.factory.allow_dir or isfile( path ): if self.factory.truncate_ext: path = splitext( path )[0] self.value = path #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ if exists( self.str_value ): self.control.SetPath( self.str_value ) #--------------------------------------------------------------------------- # Returns the basic style to use for the control: #--------------------------------------------------------------------------- def get_style ( self ): """ Returns the basic style to use for the control. """ return wx.DIRCTRL_EDIT_LABELS #--------------------------------------------------------------------------- # Returns the editor's control for indicating error status: #--------------------------------------------------------------------------- def get_error_control ( self ): """ Returns the editor's control for indicating error status. """ return self._tree #--------------------------------------------------------------------------- # Handles the 'filter' trait being changed: #--------------------------------------------------------------------------- def _filter_changed ( self ): """ Handles the 'filter' trait being changed. """ self.control.SetFilter( '|'.join( self.filter[:] ) ) #--------------------------------------------------------------------------- # Handles the user double-clicking on a file name: #--------------------------------------------------------------------------- def _on_dclick ( self, event ): """ Handles the user double-clicking on a file name. """ self.dclick = self.control.GetPath() #--------------------------------------------------------------------------- # Handles the user hovering on a file name for a tooltip: #--------------------------------------------------------------------------- def _on_tooltip ( self, event ): """ Handles the user hovering on a file name for a tooltip. """ text = self._tree.GetItemText(event.GetItem()) event.SetToolTip(text) #--------------------------------------------------------------------------- # Handles the 'reload' trait being changed: #--------------------------------------------------------------------------- def _reload_changed ( self ): """ Handles the 'reload' trait being changed. """ self.control.ReCreateTree() #------------------------------------------------------------------------------- # 'PopupFile' class: #------------------------------------------------------------------------------- class PopupFile ( PopupControl ): # The initially specified file name: file_name = Str # The file name filter to support: filter = filter_trait # Override of PopupControl trait to make the popup resizable: resizable = True #-- PopupControl Method Overrides ------------------------------------------ def create_control ( self, parent ): """ Creates the file control and gets it ready for use. """ style = self.get_style() if len( self.filter ) > 0: style |= wx.DIRCTRL_SHOW_FILTERS self._files = files = wx.GenericDirCtrl( parent, style = style, filter = '|'.join( self.filter ) ) files.SetPath( self.file_name ) self._tree = tree = files.GetTreeCtrl() wx.EVT_TREE_SEL_CHANGED( tree, tree.GetId(), self._select_file ) def dispose ( self ): wx.EVT_TREE_SEL_CHANGED( self._tree, self._tree.GetId(), None ) self._tree = self._files = None def get_style ( self ): """ Returns the base style for this type of popup. """ return wx.DIRCTRL_EDIT_LABELS def is_valid ( self, path ): """ Returns whether or not the path is valid. """ return isfile( path ) #-- Private Methods -------------------------------------------------------- def _select_file ( self, event ): """ Handles a file being selected in the file control. """ path = self._files.GetPath() # We have to make sure the selected path is different than the original # path because when a filter is changed we get called with the currently # selected path, even though no file was actually selected by the user. # So we only count it if it is a different path. # # We also check the last character of the path, because under Windows # we get a call when the filter is changed for each drive letter. If the # drive is not available, it can take the 'isfile' call a long time to # time out, so we attempt to ignore them by doing a quick test to see # if it could be a valid file name, and ignore it if it is not: if ((path != abspath( self.file_name )) and (path[-1:] not in ( '/\\' )) and self.is_valid( path )): self.value = path #------------------------------------------------------------------------------- # 'FileDropTarget' class: #------------------------------------------------------------------------------- class FileDropTarget ( wx.FileDropTarget ): """ A target for a drag and drop operation, which accepts a file. """ def __init__ ( self, editor ): wx.FileDropTarget.__init__( self ) self.editor = editor def OnDropFiles ( self, x, y, file_names ): self.editor.value = file_names[-1] self.editor.update_editor() return True ### EOF ####################################################################### traitsui-4.1.0/traitsui/wx/shell_editor.py0000644000175100001440000000270111674463546021712 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 09/27/2005 # #------------------------------------------------------------------------------- """ Editor that displays an interactive Python shell. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- # FIXME: ToolkitEditorFactory is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.shell_editor file. from traitsui.editors.shell_editor \ import _ShellEditor as BaseShellEditor, ToolkitEditorFactory from editor \ import Editor #------------------------------------------------------------------------------- # 'ShellEditor' class: #------------------------------------------------------------------------------- class _ShellEditor ( BaseShellEditor, Editor ): """ Editor that displays an interactive Python shell. """ pass traitsui-4.1.0/traitsui/wx/table_editor.py0000644000175100001440000017735011674463546021707 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 07/01/2005 # #------------------------------------------------------------------------------ """ Defines the table editor for the wxPython user interface toolkit. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx from traits.api \ import Int, List, Instance, Str, Any, Button, Tuple, \ HasPrivateTraits, Bool, Event, Property from traitsui.api \ import View, Item, UI, InstanceEditor, EnumEditor, Handler, SetEditor, \ ListUndoItem from traitsui.editors.table_editor \ import BaseTableEditor, customize_filter from traitsui.menu \ import Action, ToolBar from traitsui.table_column \ import TableColumn, ObjectColumn from traitsui.table_filter \ import TableFilter from traitsui.ui_traits \ import SequenceTypes from pyface.ui.wx.grid.api \ import Grid from pyface.dock.api \ import DockWindow, DockSizer, DockSection, DockRegion, DockControl from pyface.image_resource \ import ImageResource from pyface.timer.api \ import do_later from editor \ import Editor from table_model \ import TableModel, TraitGridSelection from helper import TraitsUIPanel #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- # Mapping from TableEditor selection modes to Grid selection modes: GridModes = { 'row': 'rows', 'rows': 'rows', 'column': 'cols', 'columns': 'cols', 'cell': 'cell', 'cells': 'cell' } #------------------------------------------------------------------------------- # 'TableEditor' class: #------------------------------------------------------------------------------- class TableEditor ( Editor, BaseTableEditor ): """ Editor that presents data in a table. Optionally, tables can have a set of filters that reduce the set of data displayed, according to their criteria. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # The set of columns currently defined on the editor: columns = List( TableColumn ) # Index of currently edited (i.e., selected) table item(s): selected_row_index = Int( -1 ) selected_row_indices = List( Int ) selected_indices = Property selected_column_index = Int( -1 ) selected_column_indices = List( Int ) selected_cell_index = Tuple( Int, Int ) selected_cell_indices = List( Tuple( Int, Int ) ) # The currently selected table item(s): selected_row = Any selected_rows = List selected_items = Property selected_column = Any selected_columns = List selected_cell = Tuple( Any, Str ) selected_cells = List( Tuple( Any, Str ) ) selected_values = Property # The indices of the table items currently passing the table filter: filtered_indices = List( Int ) # The event fired when a cell is clicked on: click = Event # The event fired when a cell is double-clicked on: dclick = Event # Is the editor in row mode (i.e. not column or cell mode)? in_row_mode = Property # Is the editor in column mode (i.e. not row or cell mode)? in_column_mode = Property # Current filter object (should be a TableFilter or callable or None): filter = Any # The grid widget associated with the editor: grid = Instance( Grid ) # The table model associated with the editor: model = Instance( TableModel ) # TableEditorToolbar associated with the editor: toolbar = Any # The Traits UI associated with the table editor toolbar: toolbar_ui = Instance( UI ) # Is the table editor scrollable? This value overrides the default. scrollable = True # Is 'auto_add' mode in effect? (I.e., new rows are automatically added to # the end of the table when the user modifies current last row.) auto_add = Bool( False ) #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ factory = self.factory self.filter = factory.filter self.auto_add = (factory.auto_add and (factory.row_factory is not None)) columns = factory.columns[:] if (len( columns ) == 0) and (len( self.value ) > 0): columns = [ ObjectColumn( name = name ) for name in self.value[0].editable_traits() ] self.columns = columns self.model = model = TableModel( editor = self, reverse = factory.reverse ) model.on_trait_change( self._model_sorted, 'sorted', dispatch = 'ui' ) mode = factory.selection_mode row_mode = mode in ( 'row', 'rows' ) selected = None items = model.get_filtered_items() if factory.editable and (len( items ) > 0): selected = items[0] if (factory.edit_view == ' ') or (not row_mode): self.control = panel = TraitsUIPanel( parent, -1 ) sizer = wx.BoxSizer( wx.VERTICAL ) self._create_toolbar( panel, sizer ) # Create the table (i.e. grid) control: hsizer = wx.BoxSizer( wx.HORIZONTAL ) self._create_grid( panel, hsizer ) sizer.Add( hsizer, 1, wx.EXPAND ) else: item = self.item name = item.get_label( self.ui ) theme = factory.dock_theme or item.container.dock_theme self.control = dw = DockWindow( parent, theme = theme ).control panel = TraitsUIPanel( dw, -1, size = ( 300, 300 ) ) sizer = wx.BoxSizer( wx.VERTICAL ) dc = DockControl( name = name + ' Table', id = 'table', control = panel, style = 'fixed' ) contents = [ DockRegion( contents = [ dc ] ) ] self._create_toolbar( panel, sizer ) selected = None items = model.get_filtered_items() if factory.editable and (len( items ) > 0): selected = items[0] # Create the table (i.e. grid) control: hsizer = wx.BoxSizer( wx.HORIZONTAL ) self._create_grid( panel, hsizer ) sizer.Add( hsizer, 1, wx.EXPAND ) # Assign the initial object here, so a valid editor will be built # when the 'edit_traits' call is made: self.selected_row = selected self._ui = ui = self.edit_traits( parent = dw, kind = 'subpanel', view = View( [ Item( 'selected_row', style = 'custom', editor = InstanceEditor( view = factory.edit_view, kind = 'subpanel' ), resizable = True, width = factory.edit_view_width, height = factory.edit_view_height ), '|<>' ], resizable = True, handler = factory.edit_view_handler ) ) # Set the parent UI of the new UI to our own UI: ui.parent = self.ui # Reset the object so that the sub-sub-view will pick up the # correct history also: self.selected_row = None self.selected_row = selected dc.style = item.dock contents.append( DockRegion( contents = [ DockControl( name = name + ' Editor', id = 'editor', control = ui.control, style = item.dock ) ] ) ) # Finish setting up the DockWindow: dw.SetSizer( DockSizer( contents = DockSection( contents = contents, is_row = (factory.orientation == 'horizontal') ) ) ) # Set up the required externally synchronized traits (if any): sv = self.sync_value is_list = (mode[-1] == 's') sv( factory.click, 'click', 'to' ) sv( factory.dclick, 'dclick', 'to' ) sv( factory.filter_name, 'filter', 'from' ) sv( factory.columns_name, 'columns', is_list = True ) sv( factory.filtered_indices, 'filtered_indices', 'to' ) sv( factory.selected, 'selected_%s' % mode, is_list = is_list ) if is_list: sv( factory.selected_indices, 'selected_%s_indices' % mode[:-1], is_list = True ) else: sv( factory.selected_indices, 'selected_%s_index' % mode ) # Listen for the selection changing on the grid: self.grid.on_trait_change( getattr( self, '_selection_%s_updated' % mode ), 'selection_changed', dispatch = 'ui' ) # Make sure the selection is initialized: if row_mode: self.set_selection( items[0:1] ) else: self.set_selection() # Set the min height of the grid panel to 0, this will provide # a scrollbar if the window is resized such that only the first row # is visible panel.SetMinSize((-1, 0)) # Finish the panel layout setup: panel.SetSizer( sizer ) #--------------------------------------------------------------------------- # Creates the associated grid control used to implement the table: #--------------------------------------------------------------------------- def _create_grid ( self, parent, sizer ): """ Creates the associated grid control used to implement the table. """ factory = self.factory selection_mode = GridModes[ factory.selection_mode ] if factory.selection_bg_color is None: selection_mode = '' self.grid = grid = Grid( parent, model = self.model, enable_lines = factory.show_lines, grid_line_color = factory.line_color, show_row_headers = factory.show_row_labels, show_column_headers = factory.show_column_labels, default_cell_font = factory.cell_font, default_cell_text_color = factory.cell_color, default_cell_bg_color = factory.cell_bg_color, default_cell_read_only_color = factory.cell_read_only_bg_color, default_label_font = factory.label_font, default_label_text_color = factory.label_color, default_label_bg_color = factory.label_bg_color, selection_bg_color = factory.selection_bg_color, selection_text_color = factory.selection_color, autosize = factory.auto_size, read_only = not factory.editable, edit_on_first_click = factory.edit_on_first_click, selection_mode = selection_mode, allow_column_sort = factory.sortable, allow_row_sort = False, column_label_height = factory.column_label_height, row_label_width = factory.row_label_width ) _grid = grid._grid _grid.SetScrollLineY( factory.scroll_dy ) # Set the default size for each table row: height = factory.row_height if height <= 0: height = _grid.GetTextExtent( 'My' )[1] + 9 _grid.SetDefaultRowSize( height ) # Allow the table to be resizable if the user did not explicitly # specify a number of rows to display: self.scrollable = (factory.rows == 0) # Calculate a reasonable default size for the table: if len( self.model.get_filtered_items() ) > 0: height = _grid.GetRowSize( 0 ) max_rows = factory.rows or 15 min_width = max( 150, 80 * len( self.columns ) ) if factory.show_column_labels: min_height = _grid.GetColLabelSize() + (max_rows * height) else: min_height = (max_rows * height) _grid.SetMinSize(wx.Size(min_width, min_height)) # On Linux, there is what appears to be a bug in wx in which the # vertical scrollbar will not be sized properly if the TableEditor is # sized to be shorter than the minimum height specified above. Since # this height is only set to ensure that the TableEditor is sized # correctly during the initial UI layout, we un-set it after this takes # place (addresses ticket 1810) def clear_minimum_height ( info ): min_size = _grid.GetMinSize() min_size.height = 0 _grid.SetMinSize ( min_size ) self.ui.add_defined ( clear_minimum_height ) sizer.Add( grid.control, 1, wx.EXPAND ) return grid.control #--------------------------------------------------------------------------- # Creates the table editing tool bar: #--------------------------------------------------------------------------- def _create_toolbar ( self, parent, sizer ): """ Creates the table editing toolbar. """ factory = self.factory if not factory.show_toolbar: return toolbar = TableEditorToolbar( parent = parent, editor = self ) if (toolbar.control is not None) or (len( factory.filters ) > 0): tb_sizer = wx.BoxSizer( wx.HORIZONTAL ) if len( factory.filters ) > 0: view = View( [ Item( 'filter<250>{View}', editor = factory._filter_editor ), '_', Item( 'filter_summary<100>{Results}~', object = 'model', resizable = False ), '_', '-' ], resizable = True ) self.toolbar_ui = ui = view.ui( context = { 'object': self, 'model': self.model }, parent = parent, kind = 'subpanel' ).set( parent = self.ui ) tb_sizer.Add( ui.control, 0 ) if toolbar.control is not None: self.toolbar = toolbar # add padding so the toolbar is right aligned tb_sizer.Add( ( 1, 1 ), 1, wx.EXPAND ) tb_sizer.Add( toolbar.control, 0 ) sizer.Add( tb_sizer, 0, wx.ALIGN_RIGHT | wx.EXPAND ) #--------------------------------------------------------------------------- # Disposes of the contents of an editor: #--------------------------------------------------------------------------- def dispose ( self ): """ Disposes of the contents of an editor. """ if self.toolbar_ui is not None: self.toolbar_ui.dispose() if self._ui is not None: self._ui.dispose() self.grid.on_trait_change( getattr( self, '_selection_%s_updated' % self.factory.selection_mode ), 'selection_changed', remove = True ) self.model.on_trait_change( self._model_sorted, 'sorted', remove = True ) self.grid.dispose() self.model.dispose() # Break any links needed to allow garbage collection: self.grid = self.model = self.toolbar = None super( TableEditor, self ).dispose() #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ # fixme: Do we need to override this method? pass #--------------------------------------------------------------------------- # Refreshes the editor control: #--------------------------------------------------------------------------- def refresh ( self ): """ Refreshes the editor control. """ self.grid._grid.Refresh() #--------------------------------------------------------------------------- # Sets the current selection to a set of specified objects: #--------------------------------------------------------------------------- def set_selection ( self, objects = [], notify = True ): """ Sets the current selection to a set of specified objects. """ if not isinstance( objects, SequenceTypes ): objects = [ objects ] self.grid.set_selection( [ TraitGridSelection( obj = object ) for object in objects ], notify = notify ) #--------------------------------------------------------------------------- # Sets the current selection to a set of specified object/column pairs: #--------------------------------------------------------------------------- def set_extended_selection ( self, *pairs ): """ Sets the current selection to a set of specified object/column pairs. """ if (len( pairs ) == 1) and isinstance( pairs[0], list ): pairs = pairs[0] grid_selections = [TraitGridSelection(obj = object, name = name) for object, name in pairs] self.grid.set_selection(grid_selections) #--------------------------------------------------------------------------- # Creates a new row object using the provided factory: #--------------------------------------------------------------------------- def create_new_row ( self ): """ Creates a new row object using the provided factory. """ factory = self.factory kw = factory.row_factory_kw.copy() if '__table_editor__' in kw: kw[ '__table_editor__' ] = self return self.ui.evaluate( factory.row_factory, *factory.row_factory_args, **kw ) #--------------------------------------------------------------------------- # Adds a new object as a new row after the currently selected indices: #--------------------------------------------------------------------------- def add_row ( self, object = None, index = None ): """ Adds a specified object as a new row after the specified index. """ filtered_items = self.model.get_filtered_items if index is None: indices = self.selected_indices if len( indices ) == 0: indices = [ len( filtered_items() ) - 1 ] indices.reverse() else: indices = [ index ] if object is None: objects = [] for index in indices: object = self.create_new_row() if object is None: if self.in_row_mode: self.set_selection() return objects.append( object ) else: objects = [ object ] items = [] insert_item_after = self.model.insert_filtered_item_after in_row_mode = self.in_row_mode for i, index in enumerate( indices ): object = objects[i] index, extend = insert_item_after( index, object ) if in_row_mode and (object in filtered_items()): items.append( object ) self._add_undo( ListUndoItem( object = self.object, name = self.name, index = index, added = [ object ] ), extend ) if in_row_mode: self.set_selection( items ) #--------------------------------------------------------------------------- # Moves a column from one place to another: #--------------------------------------------------------------------------- def move_column ( self, from_column, to_column ): """ Moves the specified **from_column** from its current position to just preceding the specified **to_column**. """ columns = self.columns frm = columns.index( from_column ) if to_column is None: to = len( columns ) else: to = columns.index( to_column ) del columns[ frm ] columns.insert( to - (frm < to), from_column ) return True #-- Property Implementations ----------------------------------------------- def _get_selected_indices ( self ): sm = self.factory.selection_mode if sm == 'rows': return self.selected_row_indices elif sm == 'row': index = self.selected_row_index if index >= 0: return [ index ] elif sm == 'cells': return list( set( [ row_col[0] for row_col in self.selected_cell_indices ] ) ) elif sm == 'cell': index = self.selected_cell_index[0] if index >= 0: return [ index ] return [] def _get_selected_items ( self ): sm = self.factory.selection_mode if sm == 'rows': return self.selected_rows elif sm == 'row': item = self.selected_row if item is not None: return [ item ] elif sm == 'cells': return list( set( [ item_name[0] for item_name in self.selected_cells ] ) ) elif sm == 'cell': item = self.selected_cell[0] if item is not None: return [ item ] return [] def _get_selected_values ( self ): if self.in_row_mode: return [ ( item, '' ) for item in self.selected_items ] if self.in_column_mode: if self.factory.selection_mode == 'columns': return [ ( None, column ) for column in self.selected_columns ] column = self.selected_column if column != '': return [ ( None, column ) ] return [] if self.factory.selection_mode == 'cells': return self.selected_cells item = self.selected_cell if item[0] is not None: return [ item ] return [] def _get_in_row_mode ( self ): return (self.factory.selection_mode in ( 'row', 'rows' )) def _get_in_column_mode ( self ): return (self.factory.selection_mode in ( 'column', 'columns' )) #-- UI preference save/restore interface ----------------------------------- #--------------------------------------------------------------------------- # Restores any saved user preference information associated with the # editor: #--------------------------------------------------------------------------- def restore_prefs ( self, prefs ): """ Restores any saved user preference information associated with the editor. """ factory = self.factory try: filters = prefs.get( 'filters', None ) if filters is not None: factory.filters = ([ f for f in factory.filters if f.template ] + [ f for f in filters if not f.template ]) columns = prefs.get( 'columns' ) if columns is not None: new_columns = [] all_columns = self.columns + factory.other_columns for column in columns: for column2 in all_columns: if column == column2.get_label(): new_columns.append( column2 ) break self.columns = new_columns # Restore the column sizes if possible: if not factory.auto_size: widths = prefs.get( 'widths' ) if widths is not None: # fixme: Talk to Jason about a better way to do this: self.grid._user_col_size = True set_col_size = self.grid._grid.SetColSize for i, width in enumerate( widths ): if width >= 0: set_col_size( i, width ) structure = prefs.get( 'structure' ) if (structure is not None) and (factory.edit_view != ' '): self.control.GetSizer().SetStructure( self.control, structure ) except: pass #--------------------------------------------------------------------------- # Returns any user preference information associated with the editor: #--------------------------------------------------------------------------- def save_prefs ( self ): """ Returns any user preference information associated with the editor. """ get_col_size = self.grid._grid.GetColSize result = { 'filters': [ f for f in self.factory.filters if not f.template ], 'columns': [ c.get_label() for c in self.columns ], 'widths': [ get_col_size( i ) for i in range( len( self.columns ) ) ] } if self.factory.edit_view != ' ': result[ 'structure' ] = self.control.GetSizer().GetStructure() return result #-- Public Methods --------------------------------------------------------- def filter_modified ( self ): """ Handles updating the selection when some aspect of the current filter has changed. """ values = self.selected_values if len( values ) > 0: if self.in_column_mode: self.set_extended_selection( values ) else: items = self.model.get_filtered_items() self.set_extended_selection( [ item for item in values if item[0] in items ] ) #-- Event Handlers --------------------------------------------------------- #--------------------------------------------------------------------------- # Handles the user selecting items (rows, columns, cells) in the table: #--------------------------------------------------------------------------- def _selection_row_updated ( self, event ): """ Handles the user selecting items (rows, columns, cells) in the table. """ gfi = self.model.get_filtered_item rio = self.model.raw_index_of tl = self.grid._grid.GetSelectionBlockTopLeft() br = iter( self.grid._grid.GetSelectionBlockBottomRight() ) rows = len( self.model.get_filtered_items() ) if self.auto_add: rows -= 1 # Get the row items and indices in the selection: values = [] for row0, col0 in tl: row1, col1 = br.next() for row in xrange( row0, row1 + 1 ): if row < rows: values.append( ( rio( row ), gfi( row ) ) ) if len( values ) > 0: # Sort by increasing row index: values.sort( lambda l, r: cmp( l[0], r[0] ) ) index, row = values[0] else: index, row = -1, None # Save the new selection information: self.set( selected_row_index = index, trait_change_notify = False ) self.setx( selected_row = row ) # Update the toolbar status: self._update_toolbar( row is not None ) # Invoke the user 'on_select' handler: self.ui.evaluate( self.factory.on_select, row ) def _selection_rows_updated ( self, event ): """ Handles multiple row selection changes. """ gfi = self.model.get_filtered_item rio = self.model.raw_index_of tl = self.grid._grid.GetSelectionBlockTopLeft() br = iter( self.grid._grid.GetSelectionBlockBottomRight() ) rows = len( self.model.get_filtered_items() ) if self.auto_add: rows -= 1 # Get the row items and indices in the selection: values = [] for row0, col0 in tl: row1, col1 = br.next() for row in xrange( row0, row1 + 1 ): if row < rows: values.append( ( rio( row ), gfi( row ) ) ) # Sort by increasing row index: values.sort( lambda l, r: cmp( l[0], r[0] ) ) # Save the new selection information: self.trait_set( selected_row_indices = [ v[0] for v in values ], trait_change_notify = False ) rows = [ v[1] for v in values ] self.setx( selected_rows = rows ) # Update the toolbar status: self._update_toolbar( len( values ) > 0 ) # Invoke the user 'on_select' handler: self.ui.evaluate( self.factory.on_select, rows ) def _selection_column_updated ( self, event ): """ Handles single column selection changes. """ cols = self.columns tl = self.grid._grid.GetSelectionBlockTopLeft() br = iter( self.grid._grid.GetSelectionBlockBottomRight() ) # Get the column items and indices in the selection: values = [] for row0, col0 in tl: row1, col1 = br.next() for col in xrange( col0, col1 + 1 ): values.append( ( col, cols[ col ].name ) ) if len( values ) > 0: # Sort by increasing column index: values.sort( lambda l, r: cmp( l[0], r[0] ) ) index, column = values[0] else: index, column = -1, '' # Save the new selection information: self.set( selected_column_index = index, trait_change_notify = False ) self.setx( selected_column = column ) # Invoke the user 'on_select' handler: self.ui.evaluate( self.factory.on_select, column ) def _selection_columns_updated ( self, event ): """ Handles multiple column selection changes. """ cols = self.columns tl = self.grid._grid.GetSelectionBlockTopLeft() br = iter( self.grid._grid.GetSelectionBlockBottomRight() ) # Get the column items and indices in the selection: values = [] for row0, col0 in tl: row1, col1 = br.next() for col in xrange( col0, col1 + 1 ): values.append( ( col, cols[ col ].name ) ) # Sort by increasing row index: values.sort( lambda l, r: cmp( l[0], r[0] ) ) # Save the new selection information: self.set( selected_column_indices = [ v[0] for v in values ], trait_change_notify = False ) columns = [ v[1] for v in values ] self.setx( selected_columns = columns ) # Invoke the user 'on_select' handler: self.ui.evaluate( self.factory.on_select, columns ) def _selection_cell_updated ( self, event ): """ Handles single cell selection changes. """ tl = self.grid._grid.GetSelectionBlockTopLeft() if len( tl ) == 0: return gfi = self.model.get_filtered_item rio = self.model.raw_index_of cols = self.columns br = iter( self.grid._grid.GetSelectionBlockBottomRight() ) # Get the column items and indices in the selection: values = [] for row0, col0 in tl: row1, col1 = br.next() for row in xrange( row0, row1 + 1 ): item = gfi( row ) for col in xrange( col0, col1 + 1 ): values.append( ( ( rio( row ), col ), ( item, cols[ col ].name ) ) ) if len( values ) > 0: # Sort by increasing row, column index: values.sort( lambda l, r: cmp( l[0], r[0] ) ) index, cell = values[0] else: index, cell = ( -1, -1 ), ( None, '' ) # Save the new selection information: self.set( selected_cell_index = index, trait_change_notify = False ) self.setx( selected_cell = cell ) # Update the toolbar status: self._update_toolbar( len( values ) > 0 ) # Invoke the user 'on_select' handler: self.ui.evaluate( self.factory.on_select, cell ) def _selection_cells_updated ( self, event ): """ Handles multiple cell selection changes. """ gfi = self.model.get_filtered_item rio = self.model.raw_index_of cols = self.columns tl = self.grid._grid.GetSelectionBlockTopLeft() br = iter( self.grid._grid.GetSelectionBlockBottomRight() ) # Get the column items and indices in the selection: values = [] for row0, col0 in tl: row1, col1 = br.next() for row in xrange( row0, row1 + 1 ): item = gfi( row ) for col in xrange( col0, col1 + 1 ): values.append( ( ( rio( row ), col ), ( item, cols[ col ].name ) ) ) # Sort by increasing row, column index: values.sort( lambda l, r: cmp( l[0], r[0] ) ) # Save the new selection information: self.setx( selected_cell_indices = [ v[0] for v in values ]) cells = [ v[1] for v in values ] self.setx( selected_cells = cells ) # Update the toolbar status: self._update_toolbar( len( cells ) > 0 ) # Invoke the user 'on_select' handler: self.ui.evaluate( self.factory.on_select, cells ) def _selected_row_changed ( self, item ): if not self._no_notify: if item is None: self.set_selection( notify = False ) else: self.set_selection( item, notify = False ) def _selected_row_index_changed ( self, row ): if not self._no_notify: if row < 0: self.set_selection( notify = False ) else: self.set_selection( self.value[ row ], notify = False ) def _selected_rows_changed ( self, items ): if not self._no_notify: self.set_selection( items, notify = False ) def _selected_row_indices_changed ( self, indices ): if not self._no_notify: value = self.value self.set_selection( [ value[i] for i in indices ], notify = False ) def _selected_column_changed ( self, name ): if not self._no_notify: self.set_extended_selection( ( None, name ) ) def _selected_column_index_changed ( self, index ): if not self._no_notify: if index < 0: self.set_extended_selection() else: self.set_extended_selection( ( None, self.model.get_column_name[ index ] ) ) def _selected_columns_changed ( self, names ): if not self._no_notify: self.set_extended_selection( [ ( None, name ) for name in names ] ) def _selected_column_indices_changed ( self, indices ): if not self._no_notify: gcn = self.model.get_column_name self.set_extended_selection( [ ( None, gcn(i) ) for i in indices ] ) def _selected_cell_changed ( self, cell ): if not self._no_notify: self.set_extended_selection( [ cell ] ) def _selected_cell_index_changed ( self, pair ): if not self._no_notify: row, column = pair if (row < 0) or (column < 0): self.set_extended_selection() else: self.set_extended_selection( ( self.value[ row ], self.model.get_column_name[ column ] ) ) def _selected_cells_changed ( self, cells ): if not self._no_notify: self.set_extended_selection( cells ) def _selected_cell_indices_changed ( self, pairs ): if not self._no_notify: value = self.value gcn = self.model.get_column_name new_selection = [(value[row], gcn(col)) for row, col in pairs] self.set_extended_selection(new_selection) def _update_toolbar ( self, has_selection ): """ Updates the toolbar after a selection change. """ toolbar = self.toolbar if toolbar is not None: no_filter = (self.filter is None) if has_selection: indices = self.selected_indices start = indices[0] n = len( self.model.get_filtered_items() ) - 1 delete = toolbar.delete if self.auto_add: n -= 1 delete.enabled = (start <= n) else: delete.enabled = True deletable = self.factory.deletable if delete.enabled and callable( deletable ): delete.enabled = reduce( lambda l, r: l and r, [ deletable( item ) for item in self.selected_items ], True ) toolbar.search.enabled = toolbar.add.enabled = True toolbar.move_up.enabled = (no_filter and (start > 0)) toolbar.move_down.enabled = (no_filter and (indices[-1] < n)) else: toolbar.add.enabled = no_filter toolbar.search.enabled = toolbar.delete.enabled = \ toolbar.move_up.enabled = toolbar.move_down.enabled = False #--------------------------------------------------------------------------- # Handles the contents of the model being resorted: #--------------------------------------------------------------------------- def _model_sorted ( self ): """ Handles the contents of the model being resorted. """ if self.toolbar is not None: self.toolbar.no_sort.enabled = True values = self.selected_values if len( values ) > 0: do_later( self.set_extended_selection, values ) #--------------------------------------------------------------------------- # Handles the current filter being changed: #--------------------------------------------------------------------------- def _filter_changed ( self, old_filter, new_filter ): """ Handles the current filter being changed. """ if new_filter is customize_filter: do_later( self._customize_filters, old_filter ) elif self.model is not None: if ((new_filter is not None) and (not isinstance( new_filter, TableFilter ))): new_filter = TableFilter( allowed = new_filter ) self.model.filter = new_filter self.filter_modified() #--------------------------------------------------------------------------- # Refresh the list of available filters: #--------------------------------------------------------------------------- def _refresh_filters ( self, filters ): factory = self.factory # hack: The following line forces the 'filters' to be changed... factory.filters = [] factory.filters = filters #--------------------------------------------------------------------------- # Allows the user to customize the current set of table filters: #--------------------------------------------------------------------------- def _customize_filters ( self, filter ): """ Allows the user to customize the current set of table filters. """ factory = self.factory filter_editor = TableFilterEditor( editor = self, filter = filter ) enum_editor = EnumEditor( values = factory.filters[:], mode = 'list' ) ui = filter_editor.edit_traits( parent = self.control, view = View( [ [ Item( 'filter<200>@', editor = enum_editor, resizable = True ), '|<>' ], [ 'edit:edit', 'new', 'apply', 'delete:delete', '|<>' ], '-' ], title = 'Customize Filters', kind = 'livemodal', height = .25, buttons = [ 'OK', 'Cancel' ] ) ) if ui.result: self._refresh_filters( enum_editor.values ) self.filter = filter_editor.filter else: self.filter = filter #--------------------------------------------------------------------------- # Handles the user requesting that columns not be sorted: #--------------------------------------------------------------------------- def on_no_sort ( self ): """ Handles the user requesting that columns not be sorted. """ self.model.no_column_sort() self.toolbar.no_sort.enabled = False values = self.selected_values if len( values ) > 0: self.set_extended_selection( values ) #--------------------------------------------------------------------------- # Handles the user requesting to move the current item up one row: #--------------------------------------------------------------------------- def on_move_up ( self ): """ Handles the user requesting to move the current item up one row. """ model = self.model objects = [] for index in self.selected_indices: objects.append( model.get_filtered_item( index ) ) index -= 1 object = model.get_filtered_item( index ) model.delete_filtered_item_at( index ) model.insert_filtered_item_after( index, object ) if self.in_row_mode: self.set_selection( objects ) else: self.set_extended_selection( self.selected_values ) #--------------------------------------------------------------------------- # Handles the user requesting to move the current item down one row: #--------------------------------------------------------------------------- def on_move_down ( self ): """ Handles the user requesting to move the current item down one row. """ model = self.model objects = [] indices = self.selected_indices[:] indices.reverse() for index in indices: object = model.get_filtered_item( index ) objects.append( object ) model.delete_filtered_item_at( index ) model.insert_filtered_item_after( index, object ) if self.in_row_mode: self.set_selection( objects ) else: self.set_extended_selection( self.selected_values ) #--------------------------------------------------------------------------- # Handles the user requesting a table search: #--------------------------------------------------------------------------- def on_search ( self ): """ Handles the user requesting a table search. """ self.factory.search.edit_traits( parent = self.control, view = 'searchable_view', handler = TableSearchHandler( editor = self ) ) #--------------------------------------------------------------------------- # Handles the user requesting to add a new row to the table: #--------------------------------------------------------------------------- def on_add ( self ): """ Handles the user requesting to add a new row to the table. """ self.add_row() #--------------------------------------------------------------------------- # Handles the user requesting to delete the currently selected items of the # table: #--------------------------------------------------------------------------- def on_delete ( self ): """ Handles the user requesting to delete the currently selected items of the table. """ # Get the selected row indices: indices = self.selected_indices[:] values = self.selected_values[:] indices.reverse() # Make sure that we don't delete any rows while an editor is open in it self.grid.stop_editing_indices(indices) # Delete the selected rows: for i in indices: index, object = self.model.delete_filtered_item_at( i ) self._add_undo( ListUndoItem( object = self.object, name = self.name, index = index, removed = [ object ] ) ) # Compute the new selection and set it: items = self.model.get_filtered_items() n = len( items ) - 1 indices.reverse() for i in range( len( indices ) - 1, -1, -1 ): if indices[i] > n: indices[i] = n if indices[i] < 0: del indices[i] del values[i] n = len( indices ) if n > 0: if self.in_row_mode: self.set_selection( list( set( [ items[i] for i in indices ] ) ) ) else: self.set_extended_selection( list( set( [ ( items[ indices[i] ], values[i][1] ) for i in range( n ) ] ) ) ) else: self._update_toolbar( False ) #--------------------------------------------------------------------------- # Handles the user requesting to set the user preference items for the # table: #--------------------------------------------------------------------------- def on_prefs ( self ): """ Handles the user requesting to set the user preference items for the table. """ columns = self.columns[:] columns.extend( [ c for c in (self.factory.columns + self.factory.other_columns) if c not in columns ] ) self.edit_traits( parent = self.control, view = View( [ Item( 'columns', resizable = True, editor = SetEditor( values = columns, ordered = True, can_move_all = False ) ), '|<>' ], title = 'Select and Order Columns', width = 0.3, height = 0.3, resizable = True, buttons = [ 'Undo', 'OK', 'Cancel' ], kind = 'livemodal' ) ) #--------------------------------------------------------------------------- # Prepares to have a context menu action called: #--------------------------------------------------------------------------- def prepare_menu ( self, row, column ): """ Prepares to have a context menu action called. """ object = self.model.get_filtered_item( row ) selection = [ x.obj for x in self.grid.get_selection() ] if object not in selection: self.set_selection( object ) selection = [ object ] self.set_menu_context( selection, object, column ) #--------------------------------------------------------------------------- # Set one or more attributes without notifying the grid model: #--------------------------------------------------------------------------- def setx ( self, **keywords ): """ Set one or more attributes without notifying the grid model. """ self._no_notify = True for name, value in keywords.items(): setattr( self, name, value ) self._no_notify = False #-- Private Methods: ----------------------------------------------------------- #--------------------------------------------------------------------------- # Adds an 'undo' item to the undo history (if any): #--------------------------------------------------------------------------- def _add_undo ( self, undo_item, extend = False ): history = self.ui.history if history is not None: history.add( undo_item, extend ) #------------------------------------------------------------------------------- # 'TableFilterEditor' class: #------------------------------------------------------------------------------- class TableFilterEditor ( Handler ): """ Editor that manages table filters. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # TableEditor this editor is associated with editor = Instance( TableEditor ) # Current filter filter = Instance( TableFilter, allow_none = True ) # Edit the current filter edit = Button # Create a new filter and edit it new = Button # Apply the current filter to the editor's table apply = Button # Delete the current filter delete = Button #--------------------------------------------------------------------------- # 'Handler' interface: #--------------------------------------------------------------------------- def init ( self, info ): """ Initializes the controls of a user interface. """ # Save both the original filter object reference and its contents: if self.filter is None: self.filter = info.filter.factory.values[0] self._filter = self.filter self._filter_copy = self.filter.clone_traits() def closed ( self, info, is_ok ): """ Handles a dialog-based user interface being closed by the user. """ if not is_ok: # Restore the contents of the original filter: self._filter.copy_traits( self._filter_copy ) #--------------------------------------------------------------------------- # Event handlers: #--------------------------------------------------------------------------- def object_filter_changed ( self, info ): """ Handles a new filter being selected. """ filter = info.object.filter info.edit.enabled = (not filter.template) info.delete.enabled = ((not filter.template) and (len( info.filter.factory.values ) > 1)) def object_edit_changed ( self, info ): """ Handles the user clicking the **Edit** button. """ if info.initialized: items = self.editor.model.get_filtered_items() if len(items) > 0: item = items[0] else: item = None # `item` is now either the first item in the table, or None if # the table is empty. ui = self.filter.edit(item) if ui.result: self._refresh_filters( info ) def object_new_changed ( self, info ): """ Handles the user clicking the **New** button. """ if info.initialized: # Get list of available filters and find the current filter in it: factory = info.filter.factory filters = factory.values filter = self.filter index = filters.index( filter ) + 1 n = len( filters ) while (index < n) and filters[ index ].template: index += 1 # Create a new filter based on the current filter: new_filter = filter.clone_traits() new_filter.template = False new_filter.name = new_filter._name = 'New filter' # Add it to the list of filters: filters.insert( index, new_filter ) self._refresh_filters( info ) # Set up the new filter as the current filter and edit it: self.filter = new_filter do_later( self._delayed_edit, info ) def object_apply_changed ( self, info ): """ Handles the user clicking the **Apply** button. """ if info.initialized: self.init( info ) self.editor._refresh_filters( info.filter.factory.values ) self.editor.filter = self.filter def object_delete_changed ( self, info ): """ Handles the user clicking the **Delete** button. """ # Get the list of available filters: filters = info.filter.factory.values if info.initialized: # Delete the current filter: index = filters.index( self.filter ) del filters[ index ] # Select a new filter: if index >= len( filters ): index -= 1 self.filter = filters[ index ] self._refresh_filters( info ) #--------------------------------------------------------------------------- # Private methods: #--------------------------------------------------------------------------- def _refresh_filters ( self, info ): """ Refresh the filter editor's list of filters. """ factory = info.filter.factory values, factory.values = factory.values, [] factory.values = values def _delayed_edit ( self, info ): """ Edits the current filter, and deletes it if the user cancels the edit. """ ui = self.filter.edit( self.editor.model.get_filtered_item( 0 ) ) if not ui.result: self.object_delete_changed( info ) else: self._refresh_filters( info ) # Allow deletion as long as there is more than 1 filter: if (not self.filter.template) and len( info.filter.factory.values ) > 1: info.delete.enabled = True #------------------------------------------------------------------------------- # 'TableEditorToolbar' class: #------------------------------------------------------------------------------- class TableEditorToolbar ( HasPrivateTraits ): """ Toolbar displayed in table editors. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Do not sort columns: no_sort = Instance( Action, { 'name': 'No Sorting', 'tooltip': 'Do not sort columns', 'action': 'on_no_sort', 'enabled': False, 'image': ImageResource( 'table_no_sort.png' ) } ) # Move current object up one row: move_up = Instance( Action, { 'name': 'Move Up', 'tooltip': 'Move current item up one row', 'action': 'on_move_up', 'enabled': False, 'image': ImageResource( 'table_move_up.png' ) } ) # Move current object down one row: move_down = Instance( Action, { 'name': 'Move Down', 'tooltip': 'Move current item down one row', 'action': 'on_move_down', 'enabled': False, 'image': ImageResource( 'table_move_down.png' ) }) # Search the table: search = Instance( Action, { 'name': 'Search', 'tooltip': 'Search table', 'action': 'on_search', 'image': ImageResource( 'table_search.png' ) } ) # Add a row: add = Instance( Action, { 'name': 'Add', 'tooltip': 'Insert new item', 'action': 'on_add', 'image': ImageResource( 'table_add.png' ) } ) # Delete selected row: delete = Instance( Action, { 'name': 'Delete', 'tooltip': 'Delete current item', 'action': 'on_delete', 'enabled': False, 'image': ImageResource( 'table_delete.png' ) } ) # Edit the user preferences: prefs = Instance( Action, { 'name': 'Preferences', 'tooltip': 'Set user preferences for table', 'action': 'on_prefs', 'image': ImageResource( 'table_prefs.png' ) } ) # The table editor that this is the toolbar for: editor = Instance( TableEditor ) # The toolbar control: control = Any #--------------------------------------------------------------------------- # Initializes the toolbar for a specified window: #--------------------------------------------------------------------------- def __init__ ( self, parent = None, **traits ): super( TableEditorToolbar, self ).__init__( **traits ) editor = self.editor factory = editor.factory actions = [] if factory.sortable and (not factory.sort_model): actions.append( self.no_sort ) if (not editor.in_column_mode) and factory.reorderable: actions.append( self.move_up ) actions.append( self.move_down ) if editor.in_row_mode and (factory.search is not None): actions.append( self.search ) if factory.editable: if (factory.row_factory is not None) and (not factory.auto_add): actions.append( self.add ) if (factory.deletable != False) and (not editor.in_column_mode): actions.append( self.delete ) if factory.configurable: actions.append( self.prefs ) if len( actions ) > 0: toolbar = ToolBar( image_size = ( 16, 16 ), show_tool_names = False, show_divider = False, *actions ) self.control = toolbar.create_tool_bar( parent, self ) self.control.SetBackgroundColour( parent.GetBackgroundColour() ) # fixme: Why do we have to explictly set the size of the toolbar? # Is there some method that needs to be called to do the # layout? self.control.SetSize( wx.Size( 23 * len( actions ), 16 ) ) #--------------------------------------------------------------------------- # PyFace/Traits menu/toolbar controller interface: #--------------------------------------------------------------------------- def add_to_menu ( self, menu_item ): """ Adds a menu item to the menu bar being constructed. """ pass def add_to_toolbar ( self, toolbar_item ): """ Adds a toolbar item to the too bar being constructed. """ pass def can_add_to_menu ( self, action ): """ Returns whether the action should be defined in the user interface. """ return True def can_add_to_toolbar ( self, action ): """ Returns whether the toolbar action should be defined in the user interface. """ return True def perform ( self, action, action_event = None ): """ Performs the action described by a specified Action object. """ getattr( self.editor, action.action )() #------------------------------------------------------------------------------- # 'TableSearchHandler' class: #------------------------------------------------------------------------------- class TableSearchHandler ( Handler ): """ Handler for saerching a table. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # The editor that this handler is associated with editor = Instance( TableEditor ) # Find next matching item find_next = Button( 'Find Next' ) # Find previous matching item find_previous = Button( 'Find Previous' ) # Select all matching items select = Button # The user is finished searching OK = Button( 'Close' ) # Search status message: status = Str #--------------------------------------------------------------------------- # Handles the user clicking the 'Find next' button: #--------------------------------------------------------------------------- def handler_find_next_changed ( self, info ): """ Handles the user clicking the **Find** button. """ if info.initialized: editor = self.editor items = editor.model.get_filtered_items() for i in range( editor.selected_row_index + 1, len( items ) ): if info.object.filter( items[i] ): self.status = 'Item %d matches' % ( i + 1 ) editor.set_selection( items[i] ) editor.selected_row_index = i break else: self.status = 'No more matches found' #--------------------------------------------------------------------------- # Handles the user clicking the 'Find previous' button: #--------------------------------------------------------------------------- def handler_find_previous_changed ( self, info ): """ Handles the user clicking the **Find previous** button. """ if info.initialized: editor = self.editor items = editor.model.get_filtered_items() for i in range( editor.selected_row_index - 1, -1, -1 ): if info.object.filter( items[i] ): self.status = 'Item %d matches' % ( i + 1 ) editor.set_selection( items[i] ) editor.selected_row_index = i break else: self.status = 'No more matches found' #--------------------------------------------------------------------------- # Handles the user clicking the 'Select' button: #--------------------------------------------------------------------------- def handler_select_changed ( self, info ): """ Handles the user clicking the **Select** button. """ if info.initialized: editor = self.editor filter = info.object.filter items = [ item for item in editor.model.get_filtered_items() if filter( item ) ] editor.set_selection( items ) if len( items ) == 1: self.status = '1 item selected' else: self.status = '%d items selected' % len( items ) #--------------------------------------------------------------------------- # Handles the user clicking 'OK' button: #--------------------------------------------------------------------------- def handler_OK_changed ( self, info ): """ Handles the user clicking the OK button. """ if info.initialized: info.ui.dispose() # Define the SimpleEditor class. SimpleEditor = TableEditor # Define the ReadonlyEditor class. ReadonlyEditor = TableEditor traitsui-4.1.0/traitsui/wx/image_control.py0000644000175100001440000002017611674463546022065 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/29/2004 # #------------------------------------------------------------------------------ """ Defines a wxPython ImageControl widget that is used by various trait editors to display trait values iconically. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx #------------------------------------------------------------------------------- # 'ImageControl' class: #------------------------------------------------------------------------------- class ImageControl ( wx.Window ): """ A wxPython control that displays an image, which can be selected or unselected by mouse clicks. """ # Pens used to draw the 'selection' marker: _selectedPenDark = wx.Pen( wx.SystemSettings_GetColour( wx.SYS_COLOUR_3DSHADOW ), 1, wx.SOLID ) _selectedPenLight = wx.Pen( wx.SystemSettings_GetColour( wx.SYS_COLOUR_3DHIGHLIGHT ), 1, wx.SOLID ) #--------------------------------------------------------------------------- # Initializes the object: #--------------------------------------------------------------------------- def __init__ ( self, parent, bitmap, selected = None, handler = None, padding = 10 ): """ Initializes the object. """ wx.Window.__init__( self, parent, -1, size = wx.Size( bitmap.GetWidth() + padding, bitmap.GetHeight() + padding ) ) self._bitmap = bitmap self._selected = selected self._handler = handler self._mouse_over = False self._button_down = False # Set up the 'paint' event handler: wx.EVT_PAINT( self, self._on_paint ) # Set up mouse event handlers: wx.EVT_LEFT_DOWN( self, self._on_left_down ) wx.EVT_LEFT_UP( self, self._on_left_up ) wx.EVT_ENTER_WINDOW( self, self._on_enter ) wx.EVT_LEAVE_WINDOW( self, self._on_leave ) #--------------------------------------------------------------------------- # Gets/Sets the current selection state of the image: #--------------------------------------------------------------------------- def Selected ( self, selected = None ): """ Gets or sets the selection state of the image. """ if selected is not None: selected = (selected != 0) if selected != self._selected: if selected: for control in self.GetParent().GetChildren(): if (isinstance( control, ImageControl ) and control.Selected()): control.Selected( False ) break self._selected = selected self.Refresh() return self._selected #--------------------------------------------------------------------------- # Gets/Sets the current bitmap image: #--------------------------------------------------------------------------- def Bitmap ( self, bitmap = None ): """ Gets or sets the bitmap image. """ if bitmap is not None: if bitmap != self._bitmap: self._bitmap = bitmap self.Refresh() return self._bitmap #--------------------------------------------------------------------------- # Gets/Sets the current click handler: #--------------------------------------------------------------------------- def Handler ( self, handler = None ): """ Gets or sets the click handler. """ if handler is not None: if handler != self._handler: self._handler = handler self.Refresh() return self._handler #--------------------------------------------------------------------------- # Handles the mouse entering the control: #--------------------------------------------------------------------------- def _on_enter ( self, event = None ): """ Handles the mouse entering the control. """ if self._selected is not None: self._mouse_over = True self.Refresh() #--------------------------------------------------------------------------- # Handles the mouse leaving the control: #--------------------------------------------------------------------------- def _on_leave ( self, event = None ): """ Handles the mouse leaving the control. """ if self._mouse_over: self._mouse_over = False self.Refresh() #--------------------------------------------------------------------------- # Handles the user pressing the mouse button: #--------------------------------------------------------------------------- def _on_left_down ( self, event = None ): """ Handles the user pressing the mouse button. """ if self._selected is not None: self.CaptureMouse() self._button_down = True self.Refresh() #--------------------------------------------------------------------------- # Handles the user clicking the control: #--------------------------------------------------------------------------- def _on_left_up ( self, event = None ): """ Handles the user clicking the control. """ need_refresh = self._button_down if need_refresh: self.ReleaseMouse() self._button_down = False if self._selected is not None: wdx, wdy = self.GetClientSizeTuple() x = event.GetX() y = event.GetY() if (0 <= x < wdx) and (0 <= y < wdy): if self._selected != -1: self.Selected( True ) elif need_refresh: self.Refresh() if self._handler is not None: self._handler( self ) return if need_refresh: self.Refresh() #--------------------------------------------------------------------------- # Handles the control being re-painted: #--------------------------------------------------------------------------- def _on_paint ( self, event = None ): """ Handles the control being re-painted. """ wdc = wx.PaintDC( self ) wdx, wdy = self.GetClientSizeTuple() bitmap = self._bitmap bdx = bitmap.GetWidth() bdy = bitmap.GetHeight() wdc.DrawBitmap( bitmap, (wdx - bdx) / 2, (wdy - bdy) / 2, True ) pens = [ self._selectedPenLight, self._selectedPenDark ] bd = self._button_down if self._mouse_over: wdc.SetBrush( wx.TRANSPARENT_BRUSH ) wdc.SetPen( pens[ bd ] ) wdc.DrawLine( 0, 0, wdx, 0 ) wdc.DrawLine( 0, 1, 0, wdy ) wdc.SetPen( pens[ 1 - bd ] ) wdc.DrawLine( wdx - 1, 1, wdx - 1, wdy ) wdc.DrawLine( 1, wdy - 1, wdx - 1, wdy - 1 ) if self._selected is True: wdc.SetBrush( wx.TRANSPARENT_BRUSH ) wdc.SetPen( pens[ bd ] ) wdc.DrawLine( 1, 1, wdx - 1, 1 ) wdc.DrawLine( 1, 1, 1, wdy - 1 ) wdc.DrawLine( 2, 2, wdx - 2, 2 ) wdc.DrawLine( 2, 2, 2, wdy - 2 ) wdc.SetPen( pens[ 1 - bd ] ) wdc.DrawLine( wdx - 2, 2, wdx - 2, wdy - 1 ) wdc.DrawLine( 2, wdy - 2, wdx - 2, wdy - 2 ) wdc.DrawLine( wdx - 3, 3, wdx - 3, wdy - 2 ) wdc.DrawLine( 3, wdy - 3, wdx - 3, wdy - 3 ) traitsui-4.1.0/traitsui/wx/key_binding_editor.py0000644000175100001440000002204311674463546023066 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 05/20/2005 # #------------------------------------------------------------------------------- """ Defines the key binding editor for use with the KeyBinding class. This is a specialized editor used to associate a particular key with a control (i.e., the key binding editor). """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx from traits.api \ import Event, false # FIXME: ToolkitEditorFactory is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.key_binding_editor file. from traitsui.editors.key_binding_editor \ import KeyBindingEditor as ToolkitEditorFactory from pyface.wx.dialog \ import confirmation from editor \ import Editor from key_event_to_name \ import key_event_to_name #------------------------------------------------------------------------------- # 'KeyBindingEditor' class: #------------------------------------------------------------------------------- class KeyBindingEditor ( Editor ): """ An editor for modifying bindings of keys to controls. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Does the editor's control have focus currently? has_focus = false # Keyboard event key = Event # Clear field event clear = Event #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self.control = KeyBindingCtrl( self, parent, size = wx.Size( 160, 19 ) ) #--------------------------------------------------------------------------- # Handles the user entering input data in the edit control: #--------------------------------------------------------------------------- def update_object ( self, event ): """ Handles the user entering input data in the edit control. """ try: self.value = value = key_event_to_name( event ) self._binding.text = value except: pass #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ self.control.Refresh() #--------------------------------------------------------------------------- # Updates the current focus setting of the control: #--------------------------------------------------------------------------- def update_focus ( self, has_focus ): """ Updates the current focus setting of the control. """ if has_focus: self._binding.border_size = 1 self.object.owner.focus_owner = self._binding #--------------------------------------------------------------------------- # Handles a keyboard event: #--------------------------------------------------------------------------- def _key_changed ( self, event ): """ Handles a keyboard event. """ binding = self.object key_name = key_event_to_name( event ) cur_binding = binding.owner.key_binding_for( binding, key_name ) if cur_binding is not None: if confirmation( None, "'%s' has already been assigned to '%s'.\n" "Do you wish to continue?" % ( key_name, cur_binding.description ), 'Duplicate Key Definition' ) == 5104: return self.value = key_name #--------------------------------------------------------------------------- # Handles a clear field event: #--------------------------------------------------------------------------- def _clear_changed ( self ): """ Handles a clear field event. """ self.value = '' #------------------------------------------------------------------------------- # 'KeyBindingCtrl' class: #------------------------------------------------------------------------------- class KeyBindingCtrl ( wx.Window ): """ wxPython control for editing key bindings. """ #--------------------------------------------------------------------------- # Initialize the object: #--------------------------------------------------------------------------- def __init__ ( self, editor, parent, wid = -1, pos = wx.DefaultPosition, size = wx.DefaultSize ): super( KeyBindingCtrl, self ).__init__( parent, wid, pos, size, style = wx.CLIP_CHILDREN | wx.WANTS_CHARS ) # Save the reference to the controlling editor object: self.editor = editor # Indicate we don't have the focus right now: editor.has_focus = False # Set up the 'erase background' event handler: wx.EVT_ERASE_BACKGROUND( self, self._on_erase_background ) # Set up the 'paint' event handler: wx.EVT_PAINT( self, self._paint ) # Set up the focus change handlers: wx.EVT_SET_FOCUS( self, self._get_focus ) wx.EVT_KILL_FOCUS( self, self._lose_focus ) # Set up mouse event handlers: wx.EVT_LEFT_DOWN( self, self._set_focus ) wx.EVT_LEFT_DCLICK( self, self._clear_contents ) # Handle key events: wx.EVT_CHAR( self, self._on_char ) #--------------------------------------------------------------------------- # Handle keyboard keys being pressed: #--------------------------------------------------------------------------- def _on_char ( self, event ): """ Handle keyboard keys being pressed. """ self.editor.key = event #--------------------------------------------------------------------------- # Erase background event handler: #--------------------------------------------------------------------------- def _on_erase_background ( self, event ): pass #--------------------------------------------------------------------------- # Do a GUI toolkit specific screen update: #--------------------------------------------------------------------------- def _paint ( self, event ): """ Updates the screen. """ wdc = wx.PaintDC( self ) dx, dy = self.GetSizeTuple() if self.editor.has_focus: wdc.SetPen( wx.Pen( wx.RED, 2 ) ) wdc.DrawRectangle( 1, 1, dx - 1, dy - 1 ) else: wdc.SetPen( wx.Pen( wx.BLACK ) ) wdc.DrawRectangle( 0, 0, dx, dy ) wdc.SetFont( self.GetFont() ) wdc.DrawText( self.editor.str_value, 5, 3 ) #--------------------------------------------------------------------------- # Sets the keyboard focus to this window: #--------------------------------------------------------------------------- def _set_focus ( self, event ): """ Sets the keyboard focus to this window. """ self.SetFocus() #--------------------------------------------------------------------------- # Handles getting/losing the focus: #--------------------------------------------------------------------------- def _get_focus ( self, event ): """ Handles getting the focus. """ self.editor.has_focus = True self.Refresh() def _lose_focus ( self, event ): """ Handles losing the focus. """ self.editor.has_focus = False self.Refresh() #--------------------------------------------------------------------------- # Handles the user double clicking the control to clear its contents: #--------------------------------------------------------------------------- def _clear_contents ( self, event ): """ Handles the user double clicking the control to clear its contents. """ self.editor.clear = True ### EOF ####################################################################### traitsui-4.1.0/traitsui/wx/image_enum_editor.py0000644000175100001440000002367711674463546022730 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/21/2004 # #------------------------------------------------------------------------------ """ Defines the various image enumeration editors for the wxPython user interface toolkit. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx from traits.api \ import Any # FIXME: ToolkitEditorFactory is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.image_enum_editor file. from traitsui.editors.image_enum_editor \ import ToolkitEditorFactory from editor \ import Editor from helper \ import bitmap_cache, position_window, TraitsUIPanel from constants \ import WindowColor from image_control \ import ImageControl #------------------------------------------------------------------------------- # 'ReadonlyEditor' class: #------------------------------------------------------------------------------- class ReadonlyEditor ( Editor ): """ Read-only style of image enumeration editor, which displays a single ImageControl, representing the object trait's value. """ #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self.control = ImageControl( parent, bitmap_cache( '%s%s%s' % ( self.factory.prefix, self.str_value, self.factory.suffix ), False, self.factory._image_path ) ) #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ self.control.Bitmap( bitmap_cache( '%s%s%s' % ( self.factory.prefix, self.str_value, self.factory.suffix ), False, self.factory._image_path ) ) #------------------------------------------------------------------------------- # 'SimpleEditor' class: #------------------------------------------------------------------------------- class SimpleEditor ( ReadonlyEditor ): """ Simple style of image enumeration editor, which displays an ImageControl, representing the object trait's value. Clicking an image displays a dialog box for selecting an image corresponding to a different value. """ #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ super( SimpleEditor, self ).init( parent ) self.control.Selected( True ) self.control.Handler( self.popup_editor ) self.set_tooltip() #--------------------------------------------------------------------------- # Handles the user clicking the ImageControl to display the pop-up dialog: #--------------------------------------------------------------------------- def popup_editor ( self, control ): """ Handles the user clicking the ImageControl to display the pop-up dialog. """ ImageEnumDialog( self ) #------------------------------------------------------------------------------- # 'CustomEditor' class: #------------------------------------------------------------------------------- class CustomEditor ( Editor ): """ Custom style of image enumeration editor, which displays a grid of ImageControls. The user can click an image to select the corresponding value. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- update_handler = Any # Callback to call when any button clicked #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self._create_image_grid( parent ) #--------------------------------------------------------------------------- # Populates a specified window with a grid of image buttons: #--------------------------------------------------------------------------- def _create_image_grid ( self, parent ): """ Populates a specified window with a grid of image buttons. """ # Create the panel to hold the ImageControl buttons: self.control = panel = TraitsUIPanel( parent, -1 ) # Create the main sizer: if self.factory.cols > 1: sizer = wx.GridSizer( 0, self.factory.cols, 0, 0 ) else: sizer = wx.BoxSizer( wx.VERTICAL ) # Add the set of all possible choices: factory = self.factory mapping = factory._mapping cur_value = self.value for name in self.factory._names: value = mapping[ name ] control = ImageControl( panel, bitmap_cache( '%s%s%s' % ( factory.prefix, name, factory.suffix ), False, factory._image_path ), value == cur_value, self.update_object ) control.value = value sizer.Add( control, 0, wx.ALL, 2 ) self.set_tooltip( control ) # Finish setting up the control layout: panel.SetSizerAndFit( sizer ) #--------------------------------------------------------------------------- # Handles the user clicking on an ImageControl to set an object value: #--------------------------------------------------------------------------- def update_object ( self, control ): """ Handles the user clicking on an ImageControl to set an object value. """ self.value = control.value if self.update_handler is not None: self.update_handler() #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ value = self.value for control in self.control.GetChildren(): control.Selected( value == control.value ) #------------------------------------------------------------------------------- # 'ImageEnumDialog' class: #------------------------------------------------------------------------------- class ImageEnumDialog ( wx.Frame ): """ Dialog box for selecting an ImageControl """ #--------------------------------------------------------------------------- # Initializes the object: #--------------------------------------------------------------------------- def __init__ ( self, editor ): """ Initializes the object. """ wx.Frame.__init__( self, editor.control, -1, '', style = wx.SIMPLE_BORDER ) self.SetBackgroundColour( WindowColor ) wx.EVT_ACTIVATE( self, self._on_close_dialog ) self._closed = False dlg_editor = CustomEditor( self, factory = editor.factory, ui = editor.ui, object = editor.object, name = editor.name, description = editor.description, update_handler = self._close_dialog ) dlg_editor.init( self ) # Wrap the dialog around the image button panel: sizer = wx.BoxSizer( wx.VERTICAL ) sizer.Add( dlg_editor.control ) sizer.Fit( self ) # Position the dialog: position_window( self, parent = editor.control ) self.Show() #--------------------------------------------------------------------------- # Closes the dialog: #--------------------------------------------------------------------------- def _on_close_dialog ( self, event ): """ Closes the dialog. """ if not event.GetActive(): self._close_dialog() #--------------------------------------------------------------------------- # Closes the dialog: #--------------------------------------------------------------------------- def _close_dialog ( self ): """ Closes the dialog. """ if not self._closed: self._closed = True self.Destroy() ### EOF ####################################################################### traitsui-4.1.0/traitsui/wx/drop_editor.py0000644000175100001440000001256611674463546021561 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 04/13/2005 # #------------------------------------------------------------------------------ """ Defines a drop target editor for the wxPython user interface toolkit. A drop target editor handles drag and drop operations as a drop target. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx # FIXME: ToolkitEditorFactory is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.drop_editor file. from traitsui.editors.drop_editor \ import ToolkitEditorFactory from pyface.wx.drag_and_drop \ import PythonDropTarget, clipboard from text_editor \ import SimpleEditor as Editor from constants \ import DropColor #------------------------------------------------------------------------------- # 'SimpleEditor' class: #------------------------------------------------------------------------------- class SimpleEditor ( Editor ): """ Simple style of drop editor, which displays a read-only text field that contains the string representation of the object trait's value. """ # Background color when it is OK to drop objects. ok_color = DropColor #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ if self.factory.readonly: self.control = wx.TextCtrl( parent, -1, self.str_value, style = wx.TE_READONLY ) self.set_tooltip() else: super( SimpleEditor, self ).init( parent ) self.control.SetBackgroundColour( self.ok_color ) self.control.SetDropTarget( PythonDropTarget( self ) ) #--------------------------------------------------------------------------- # Returns the text representation of a specified object trait value: #--------------------------------------------------------------------------- def string_value ( self, value ): """ Returns the text representation of a specified object trait value. """ if value is None: return '' return str( value ) #--------------------------------------------------------------------------- # Handles an error that occurs while setting the object's trait value: #--------------------------------------------------------------------------- def error ( self, excp ): """ Handles an error that occurs while setting the object's trait value. """ pass #----- Drag and drop event handlers: ------------------------------------------- #--------------------------------------------------------------------------- # Handles a Python object being dropped on the control: #--------------------------------------------------------------------------- def wx_dropped_on ( self, x, y, data, drag_result ): """ Handles a Python object being dropped on the tree. """ klass = self.factory.klass value = data if self.factory.binding: value = getattr( clipboard, 'node', None ) if (klass is None) or isinstance( data, klass ): self._no_update = True try: if hasattr( value, 'drop_editor_value' ): self.value = value.drop_editor_value() else: self.value = value if hasattr( value, 'drop_editor_update' ): value.drop_editor_update( self.control ) else: self.control.SetValue( self.str_value ) finally: self._no_update = False return drag_result return wx.DragNone #--------------------------------------------------------------------------- # Handles a Python object being dragged over the control: #--------------------------------------------------------------------------- def wx_drag_over ( self, x, y, data, drag_result ): """ Handles a Python object being dragged over the tree. """ if self.factory.binding: data = getattr( clipboard, 'node', None ) try: self.object.base_trait( self.name ).validate( self.object, self.name, data ) return drag_result except: return wx.DragNone # Define the Text and ReadonlyEditor for use by the editor factory. TextEditor = ReadonlyEditor = SimpleEditor ### EOF ######################################################################## traitsui-4.1.0/traitsui/wx/themed_cell_renderer.py0000644000175100001440000002407111674463546023374 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/13/2004 # #------------------------------------------------------------------------------ """ Defines the ThemedCellRenderer class used to render theme-based cells for the TableEditor. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx from wx.grid \ import PyGridCellRenderer, GridCellStringRenderer from traitsui.ui_traits \ import convert_bitmap from helper \ import BufferDC #------------------------------------------------------------------------------- # 'ThemedCellRenderer' class: #------------------------------------------------------------------------------- class ThemedCellRenderer ( PyGridCellRenderer ): """ Defines the ThemedCellRenderer class used to render theme-based cells for the TableEditor. """ def __init__( self, column ): """ Creates a new ThemedCellRenderer. """ PyGridCellRenderer.__init__( self ) # We are merging the pyface grid GridCellRenderer interface with the # wx.grid.PyGridCellRenderer interface, so we need to do this: self.renderer = self # Save the reference to the TableColumn: self.column = column #-- PyFace grid GridCellRenderer Method Overrides -------------------------- # Invoked on left-button mouse clicks: def on_left_click ( self, grid, row, col ): return False # Invoked on left-button mouse double clicks: def on_left_dclick ( self, grid, row, col ): return False # Invoked on right-button mouse clicks: def on_right_click ( self, grid, row, col ): return False # Invoked on right-button mouse double clicks: def on_right_dclick ( self, grid, row, col ): return False # Invoked on a key press: def on_key ( self, grid, row, col, key_event ): return False # Clean-up: def dispose ( self ): del self.renderer del self.column #-- wx.GridCellRenderer Method Overrides ----------------------------------- def Draw ( self, grid, attr, dc, rect, row, col, is_selected ): """ Draws the contents of the specified grid cell. """ # Get the model object this cell is being rendered for: model = grid.grid.model object = model.get_filtered_item( row ) # Get the draw bounds: x0 = rect.x y0 = rect.y dx = rect.width dy = rect.height # Do all drawing into an off-screen buffer: bdc = BufferDC( dc, dx, dy ) # Draw the appropriate theme background: column = self.column if is_selected: theme = (column.get_selected_theme( object ) or column.get_cell_theme( object )) else: theme = column.get_cell_theme( object ) # If no column theme is specified, try to get the global theme from the # model: if theme is None: if row & 1: theme = model.alt_theme or model.cell_theme else: theme = model.cell_theme if is_selected: theme = model.selected_theme or theme if theme is not None: content = theme.content slice = theme.image_slice slice.fill( bdc, 0, 0, dx, dy ) # Set up the correct text color to use: bdc.SetTextForeground( theme.content_color ) # Calculate the margins for the draw area: left = slice.xleft + content.left top = slice.xtop + content.top right = slice.xright + content.right bottom = slice.xbottom + content.bottom ox, oy = theme.label.left, theme.label.top else: if is_selected: bg_color = grid.GetSelectionBackground() else: bg_color = attr.GetBackgroundColour() bdc.SetBackgroundMode( wx.SOLID ) bdc.SetBrush( wx.Brush( bg_color, wx.SOLID ) ) bdc.SetPen( wx.TRANSPARENT_PEN ) bdc.DrawRectangle( 0, 0, dx, dy ) # Set up the correct text color to use: bdc.SetTextForeground( attr.GetTextColour() ) # Calculate the margins for the draw area: left = right = self.column.horizontal_margin top = bottom = self.column.vertical_margin ox = oy = 0 # Get the alignment information: halign, valign = attr.GetAlignment() # Draw the bar graph (if any): maximum = column.get_maximum( object ) if (not is_selected) and (maximum > 0.0): if theme is None: left = right = top = bottom = 0 try: ratio = max( min( column.get_raw_value( object ) / maximum, 1.0 ), -1.0 ) avail_dx = dx - left - right bar_dx = int( round( ratio * avail_dx ) ) if halign == wx.ALIGN_CENTRE: bar_dx /= 2 bar_x = left + (avail_dx / 2) + min( 0, bar_dx ) else: bar_dx = abs( bar_dx ) if halign == wx.ALIGN_LEFT: bar_x = left left += self.column.horizontal_margin else: bar_x = avail_dx - bar_dx right += self.column.horizontal_margin if bar_dx > 0: bdc.SetBackgroundMode( wx.SOLID ) bdc.SetBrush( wx.Brush( column.get_graph_color( object ), wx.SOLID ) ) bdc.SetPen( wx.TRANSPARENT_PEN ) bdc.DrawRectangle( bar_x, top, bar_dx, dy - top - bottom ) except: pass if theme is None: left = right = self.column.horizontal_margin top = bottom = self.column.vertical_margin # Get the optional image bitmap and text: bitmap = convert_bitmap( column.get_image( object ) ) text = grid.GetCellValue( row, col ) # If no text or bitmap to display, then we are done: if (bitmap is None) and (text == ''): bdc.copy( x0, y0 ) return # Get the bitmap size: idx = idy = tdx = tdy = 0 if bitmap is not None: idx = bitmap.GetWidth() idy = bitmap.GetHeight() # Get the text size: if text != '': bdc.SetFont( attr.GetFont() ) tdx, tdy = bdc.GetTextExtent( text ) # Get the spacing between text and image: if bitmap is not None: idx += self.column.horizontal_margin # Calculate the x-coordinate of the image/text: if halign == wx.ALIGN_LEFT: x = left elif halign == wx.ALIGN_CENTRE: x = (left + ((dx - left - right - tdx - idx) / 2)) else: x = (dx - right - tdx - idx) # Calculate the y-coordinate of the image/text: max_dy = max( tdy, idy ) if valign == wx.ALIGN_TOP: y = top elif valign == wx.ALIGN_CENTRE: y = (top + ((dy - top - bottom - max_dy) / 2)) else: y = (dy - bottom - max_dy) # Set up the clipping region to prevent drawing outside the margins: bdc.SetClippingRegion( left, top, dx - left - right, dy - top - bottom ) # Draw the image (if left or center aligned): if (bitmap is not None) and (halign != wx.ALIGN_RIGHT): bdc.DrawBitmap( bitmap, x, y + ((max_dy - idy) / 2), True ) x += idx # Finally, draw the text: if text != '': bdc.SetBackgroundMode( wx.TRANSPARENT ) bdc.DrawText( text, x + ox, y + oy ) x += tdx + self.column.horizontal_margin # Draw the image (if right-aligned): if (bitmap is not None) and (halign == wx.ALIGN_RIGHT): bdc.DrawBitmap( bitmap, x, y + ((max_dy - idy) / 2), True ) # Discard the clipping region: bdc.DestroyClippingRegion() # Copy the buffer to the display: bdc.copy( x0, y0 ) def GetBestSize ( self, grid, attr, dc, row, col ): """ Determine best size for the cell. """ # Get the model object this cell is being rendered for: object = grid.grid.model.get_filtered_item( row ) # Get the text for this cell: text = grid.GetCellValue( row, col ) or 'My' # Now calculate and return the best size for the text and image: dc.SetFont( attr.GetFont() ) tdx, tdy = dc.GetTextExtent( text ) column = self.column bitmap = convert_bitmap( column.get_image( object ) ) if bitmap is not None: tdx += (bitmap.GetWdth() + self.column.horizontal_margin) tdy = max( tdy, bitmap.GetHeight() ) theme = column.get_cell_theme( object ) if theme is None: return wx.Size( tdx + self.column.horizontal_margin * 2, tdy + self.column.vertical_margin * 2 ) content = theme.content tdx += (content.left + content.right) tdy += (content.top + content.bottom) slice = theme.image_slice return wx.Size( max( slice.left + slice.right, slice.xleft + slice.xright + tdx ), max( slice.top + slice.bottom, slice.xtop + slice.xbottom + tdy ) ) def Clone ( self ): return self.__class__( self.column ) traitsui-4.1.0/traitsui/wx/images/0000755000175100001440000000000011674463546020130 5ustar ischnellusers00000000000000traitsui-4.1.0/traitsui/wx/images/cb_hover_on.png0000644000175100001440000000070411674463546023122 0ustar ischnellusers00000000000000PNG  IHDR* pHYsodPIDATxKAǷ1Puk@{ܩ?b"(mJ̩tYe[Rt-("*Ja:ĎKEq?bRf^̼8é@jM*_3/ݺH$QE,Q>)-ŸM4xRv Ƹ}\o M(`d}nۃ40l?4fZhtJ[Shuu*TtvB󳺫ǝ?Ԯo9.5ueHkΥ\UGca0D$dQу#*3@7!snQу,7Rwb<-QvXW_1$tEXtAuthorUlead Systems, Inc.>vIENDB`traitsui-4.1.0/traitsui/wx/images/table_move_down.png0000644000175100001440000000107711674463546024007 0ustar ischnellusers00000000000000PNG  IHDR Vu\sBIT|d pHYs a aJ%tEXtSoftwarewww.inkscape.org<IDAT(eOaǿl$P& &ĉ00Эqe M%`KQ;{,LO|<c cC'O.-ŎO/3VsDc.2_+B$dsZݹSըT+tVщjRW`1 &"ՑwݏzXP\c}2hJV{ vIENDB`traitsui-4.1.0/traitsui/wx/images/table_move_up.png0000644000175100001440000000122511674463546023457 0ustar ischnellusers00000000000000PNG  IHDRasBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<IDAT8kSA3w澌 /J"Rm(vp#n4THjqUFq?ZЅ.\\FH*JJ̽ɝqQ1| Rv;LLLbgGW='HIg.$.{Sg.&.nP[s0yB HLّmj.nV,;(ijlP$vBe&"xM?j;h>^ GKtNw±6lMZ|RVQm(T BQ@I`~; CYuRH7h[ 5Uţ{Í@[Ѵ-m#r7#@."(P (/T2[JQܿg~%//uGIENDB`traitsui-4.1.0/traitsui/wx/images/table_no_sort.png0000644000175100001440000000101211674463546023462 0ustar ischnellusers00000000000000PNG  IHDRabKGD pHYs  tIME  73IDAT8˥KA?3"ilkh@݋/JB/J XBdC(Mb51MV6zp;&QJ|y}?T|V\'+(Ctf+v|>vV eFa!=MVDPM4RPj^Ki~ jZ.N f6$,lPTr.\K1;7 Ӑ(qIyJ#jUp~8~op d?lZۦ1Qm}N1O9Њ%&r0σ):&?% ~1y=W« }=W%+{rӺ۝*IENDB`traitsui-4.1.0/traitsui/wx/images/table_colors.png0000644000175100001440000000106611674463546023311 0ustar ischnellusers00000000000000PNG  IHDRsO/bKGDFFh7SIDATxڥ=hSaޏ&mj?ũuQ]"u$U:ŢPP.$!&$M4%q}c 0Qyt_ƐCˬp~C|=ܬ2'X"EO1?u s91("',FQFTo[m!=9{O-xVVP89`#]mg|K0ti\|X9م;jC}t%foØ#erleUT`d h\MΨ۟#=mȞD:>`D"KňDB`? 凅ppjNKuKe]lc1/Q1OvIENDB`traitsui-4.1.0/traitsui/wx/images/list_editor.png0000644000175100001440000000672711674463546023173 0ustar ischnellusers00000000000000PNG  IHDRa pHYs   OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3- cHRMz%u0`:o_FIDATxLOh\U޽o$hKh[-UhTFT(UwZ\UэBԍFEQKfcq!h1ѩf2߻.f8q\.LTbiizd27qFQc.;{|gk9"40 ~8?wVCcs_X5.qsn|=`jjbTwf.e={yCnUA lэG2ˏ1)JT*g|qGg3zS4~';v> Ik0g32:\l6Z.#ʞ7NT1 AhC02Ox^ T{Tkm7fpɧ>[q͉/&h 4(:s5O>?{!>Mk@C& 7+͔qt~ >,,,@–>|pgv= RVi4a8{kӸX_uml,'K$IڝhR:p;p w0>D@IENDB`traitsui-4.1.0/traitsui/wx/images/frame.ico0000644000175100001440000000217611674463546021724 0ustar ischnellusers00000000000000h(     |/ 6!:$E+9$) c   F#_<domlkhH*s\ }  e{Ʃ{Ûz?2  \) d1(J8C#ТвֻտѼʲ˲ʧR12K@U7|J=UDY9͞ھѽǸζʪN/8?WH\TgMhQ΢ɸƵĞ*t6Rfʫ̿gdS¯dzthmzgieUXȴcH< 5PaƮs`VnczH/))$DqzЦ1;r8Fѡ.8\(m7mfnLx6}/~WX wJ/ 38ˆ #$WZ`-3C?N-4022125CHP @!7[P    d/MB`DdOo  dL1g7W Ok'Uo!SoGe\8PA[9U#;($KN&(Ttraitsui-4.1.0/traitsui/wx/images/object.png0000644000175100001440000000564611674463546022117 0ustar ischnellusers00000000000000PNG  IHDR pHYs  ~ OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3- cHRMz%u0`:o_FIDATxLKq*BtPES圻" Arܠ . a(}.?oz<= + 8#Af_+$rIlTMY="{`WYIѧWR~:z͢2=bzg?#s .` 3áXGIENDB`traitsui-4.1.0/traitsui/wx/images/file.png0000644000175100001440000000557411674463546021570 0ustar ischnellusers00000000000000PNG  IHDR pHYs  ~ OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3- cHRMz%u0`:o_FIDATxڄ ?]ԭA{e$񦛬f䆣+eS`]\y '@`P!f {"% :OfOJ GxfH{O$$ن`H띟"WkI=2|ci`#+PQzis5[;zGIENDB`traitsui-4.1.0/traitsui/wx/images/table_display.png0000644000175100001440000000066211674463546023456 0ustar ischnellusers00000000000000PNG  IHDRa pHYs  tIME "=)QIDAT8ŒKPIء*8 VWqKFQJ 8EPf A!6A BPMZ9ݏwߐ"" x@Q4-Y%ut'] iR !Z˽(JHNM:Ȧi"2a>d2qtqrtCXd7GZ;ڱMjnwBzwj/ 3I ǏU?zP&>|TQ7ç@ ξqP()c#^BoT  u${NEJNI%MAvp^oGAk AEQϿTȫ*Ȯl;HR)P2iIuQE;^E!_&2)c)OI(8 '!8(#:TrOfl(&)AVEFw朜o"rPP d{Sl9G{@T,y}oo=E! }RȍY OJ5),@^6TJaSilu>m6s„B}J BQ5l9'KqJGI+qK*m=bv Z8Ib5VZF"SS |KU=|ODљ ER-pԢ!RI!1ZXyWa"[g{Jg2ʼZ8[47HmcŠ l:}쩵GȮ}"E^,&$BŽY#uKaRl/fG3ȴE&)V2Z({wG<~$8gh(l7AZ{%9X ӛXX˒eO #ߓaaEӳ02̂?1ru(0녛Gw>u[bU,VH'eg/JX"hhhvmc߲4H+Mq6퉼pF`Aٴl2k%)ρfg_Xd]ɺ!)<.mq-H?>͒ezsz'#ۭ$fI Kȶg[Y튤֟Xme& |i[1Wq8(؝(i"n5Vj-ZX#q-NoTZ+Reyb-K*YLOcw<(N{9 3'gr_]b,H@<%YX+,KU~^|*;Nc1`dk5p.フJvɶ|^ӄkd,z~Յ/IoGYQn޼9p|ATw'|8ϥӉnKaJ #(FP2dA0a%J #(FP2dA0a%J #(FP2dA0a%J #(FP2dA0a%J #(FP2dA0a%J #(FP2dA0a%J #(FP2dA0a%u¼K(L +@GGxLII :NRbX,,s5/L.<~#H>Ub{?Y_ ^'<F߽ Se/IENDB`traitsui-4.1.0/traitsui/wx/images/table_search.png0000644000175100001440000000160211674463546023251 0ustar ischnellusers00000000000000PNG  IHDRabKGD pHYs B(xtIME +0WIIDAT8˕oSszN{glMqsQ= "xk$^( 6c xiĘ-Jd2M&ufjRnd\G\WK[۝Nj&o|7~ e˲=$rsu ,""'O:+cY*0)خkiyoÄa4Mw p ̒v7PD<~[,0Zhyw{YQs; k%CgiPC$Q*:Z"̗uE H$*cķ `.؎Kz W6'+޵EIѪkX_ĴLrQrǰ]%gJ4Ld-ľ6C_!Қ87;"_tD"_͐-d &r6 ({yyҟA'~M!-t(!hbO CRdŠ$I CU}K'1AHK-@ 3br"%nou"3$1ָ aHTgc$P]"^E0ލ֔0FoNI1e 0 qzk b -l|$bb2GX-aõX~&]I5WgIai\PdZwR(*'f1B go=ة?1# }EcHG}C`1*}mnT/7ƱRBh|gU()4L(XtP#|Qڭa F(\vǢ>d3LS[Njd1IyeOtdtne=܀%PDD vN |2mqIgxN1O aK: >ye[%e3_KY"=bЏ7՗T%{\j؂X}.c[4?}_&!5Yҙo]v)# R].yJrg cuQb0ФLfMNQH:k7ETIbyWG)#XSSekH/NɚwwyG]7i{=BrZ'iXPV5_°j?Ap4Zv&Sw7\"Q b\'Jan4٧-@O@Y%/܏EIX^`n0$TXr]9 s~!"e.QHR4š$;ØR}&Z g)1my{>YPpCTP6e|hOBh7n KRYT*,aWs7`1 b/v6Pآ'pФd!k -=У&uD>T I4FǶYK?$:2J$S? ſ̍~g!i٬5wh|Rd۞6ٺ> essk(Q4* =˾@lC%< U<#>kq d xF}T&t7pVG@a_Uw7 +oh: `Ԭ7Jx\b{P͟ }B0U^5Ohf B0 5֔THo\+LN U9sHطLu,a~!F}: rq*<>rX4`"5.1~ 7WzF? 25T,<~~ K~Q+&4e+LIKh <4P3$O{#0i68V Q֝JUq/\!I)E{uIT_bq,Š ӘAxWǥqXy#m;0-/!UFYXQ1$ İ7!)+Sz72ь̑߂@#-Z;iuH- ?LlIFu,Or*Io Z,ԨgM'aҽJ8x3icP#7<"}3) if/.סKPVz0x6m! ]!(P5)5 %(*[4b8V LJξbUqb:n, hze|Jdy_KP=Z'$=%y90IuJic ֊~n=TJW%5IZaMV aw Ɠ0CrShzD?+lz[|F`ê_%OqPIȂ嘟"r7 V(ʥ+q`xMo9 ,i=YM ( e:yc Ќ>4b%2iW{R *5ctOj!ă 1m i(&^9 r,@ ѻ&y l&4>RU]R=E*LaWz*v{IǷy+k3qwr;X=+4m/`<"cM>IM_錼2OASs4WD{?>b L5 Fd+ ~ITj ~_ $0ɫQft`|dRR$}]La /iJ |v bGѓFE=UwP\f'8C{Úg}, LijʑhE0cAнqwMQLus 0A#Ƴ$&4{2 'cX 1vqW$XPYc8HH~(a j aMAX]SJcEIb41rĉ'( an") O0$iS/PA>t%0@\E3$ 7tL ICD+ bdUYP@yqP 3}st{ai4ܒ0z`׷ Peiven%)Ko33^ռitfJR(Ǣ={Xt KZ|Xx#`-8yhO|'?wGQp_p,}X|Ħ7XWr~ttܕ ߩ-ğ@f1+!0?eA}SOjO%V:(((Y$ڶ_TΌYMs-iAFL9Є70)! D}TX*fE?H( se&e^vdFQ'k_}I*3fyGY6K+꾩2 UV-V4PŜ?">$6mE6ߤTaZ!Bŋ6\<Tx)<^a(E#^kh^VqI!TWPTrK[Fk/1"AS\@ͪtUJ01"kng[LW9錺$mI~[*5@hob' ƶ?-dIENDB`traitsui-4.1.0/traitsui/wx/images/table_delete.png0000644000175100001440000000067111674463546023253 0ustar ischnellusers00000000000000PNG  IHDRabKGD pHYs  ~tIME &SFIDATxJQ#3u!)P@=B^#MТ6Buj0 G.3TmcP.p=Å) v_J҈R.r.uI&ByӡlFR<6?fXb"ڭ fOC^VI7"/G! Ssw#gcz0P$j'܌JB&0+&20A2£-4PS4 <۶1 Y@&>;ar,Wuc hc+Jc 8'/|LbIENDB`traitsui-4.1.0/traitsui/wx/images/open.png0000644000175100001440000000115111674463546021575 0ustar ischnellusers00000000000000PNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDATxbd```.ˀJ>h@ ? qs1 31#~I0r ܊@2x/!W؀C@>ӿ>  q2N1H; h(#+Xُ[{`W]h3j?5ge`bv;5\ۇ p/wyW8D H~aՎ )@C?$a/ o~%H3_ 4~<?°7b? ? `Qǁ@ x3î? V z+~lalH!PHw :t @۫ D@L cĠ&D@?y(8^ `DC @L3(0IENDB`traitsui-4.1.0/traitsui/wx/images/table_synthetic.png0000644000175100001440000000065611674463546024026 0ustar ischnellusers00000000000000PNG  IHDRa pHYs  tIME &:mMIDAT8˥K@wM֥TTPĿ 8;PV (8::2BPjKΡ3&~޽;g ;n<]T4WoGs6NnXX9) H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3- cHRMz%u0`:o_FIDATxڤMkSAX(M]7Rhb*RAэ(Z1!b] jE3~̙9.Zj.8 ün۶?M[Q<JN@jR VAl6Kq Z@H1]My X7,_#B5@n\tqG(A]H = 5kYQAotDrOWdwXqJY>Ϛ,Śpb nMqxHX-!]e:K,&N1џFǽB5 ȩi_.G(C=k,0m|A!}>ŰtEXtAuthorUlead Systems, Inc.>vIENDB`traitsui-4.1.0/traitsui/wx/images/group.png0000644000175100001440000000102511674463546021770 0ustar ischnellusers00000000000000PNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDATxbd```, ־Rc@15址 YH'^{ "(5h_d@~aÚU @@Pkn#. 2 ~+}  o{S,f+@A x?00D3 #aj'@[v + 5>Bbh H(j;`ÀBFpXq R@ 6( ]qD q? P%K-` H @l@,D@|,chvaPb 4r@2s^IENDB`traitsui-4.1.0/traitsui/wx/images/table_undelete.png0000644000175100001440000000064611674463546023620 0ustar ischnellusers00000000000000PNG  IHDRa pHYs  tIME '.UQEIDAT8˭JP76>/ݡ/PENP:N.B8:2BP''I&Vo9rw*4s'mJ.xO&|(7m  8O*5σJ2oϨ]wq(eğ2~A*ed?s9d_鈭D1ѿ)fFYJNp;ף 2R59]ֲZgUDlFZ! Cn;OKF硔BDi0Z  emVr0.@vZ~a#ҸIENDB`traitsui-4.1.0/traitsui/wx/check_list_editor.py0000644000175100001440000002677211674463546022731 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/21/2004 # #------------------------------------------------------------------------------ """ Defines the various editors for multi-selection enumerations, for the wxPython user interface toolkit. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import logging import wx from string \ import capitalize from traits.api \ import List, Str, TraitError # FIXME: ToolkitEditorFactory is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.check_list_editor file. from traitsui.editors.check_list_editor \ import ToolkitEditorFactory from editor_factory \ import TextEditor as BaseTextEditor from editor \ import EditorWithList from helper \ import TraitsUIPanel logger = logging.getLogger(__name__) #------------------------------------------------------------------------------- # 'SimpleEditor' class: #------------------------------------------------------------------------------- class SimpleEditor ( EditorWithList ): """ Simple style of editor for checklists, which displays a combo box. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Checklist item names names = List( Str ) # Checklist item values values = List #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self.create_control( parent ) super( SimpleEditor, self ).init( parent ) self.set_tooltip() #--------------------------------------------------------------------------- # Creates the initial editor control: #--------------------------------------------------------------------------- def create_control ( self, parent ): """ Creates the initial editor control. """ self.control = wx.Choice( parent, -1, wx.Point( 0, 0 ), wx.Size( 100, 20 ), [] ) wx.EVT_CHOICE( parent, self.control.GetId(), self.update_object ) #--------------------------------------------------------------------------- # Handles the list of legal check list values being updated: #--------------------------------------------------------------------------- def list_updated ( self, values ): """ Handles updates to the list of legal checklist values. """ sv = self.string_value if (len( values ) > 0) and isinstance( values[0], basestring ): values = [ ( x, sv( x, capitalize ) ) for x in values ] self.values = valid_values = [ x[0] for x in values ] self.names = [ x[1] for x in values ] # Make sure the current value is still legal: modified = False cur_value = parse_value( self.value ) for i in range( len( cur_value ) - 1, -1, -1 ): if cur_value[i] not in valid_values: try: del cur_value[i] modified = True except TypeError, e: logger.warn('Unable to remove non-current value [%s] from ' 'values %s', cur_value[i], values) if modified: if isinstance( self.value, basestring ): cur_value = ','.join( cur_value ) self.value = cur_value self.rebuild_editor() #--------------------------------------------------------------------------- # Rebuilds the editor after its definition is modified: #--------------------------------------------------------------------------- def rebuild_editor ( self ): """ Rebuilds the editor after its definition is modified. """ control = self.control control.Clear() for name in self.names: control.Append( name ) self.update_editor() #---------------------------------------------------------------------------- # Handles the user selecting a new value from the combo box: #---------------------------------------------------------------------------- def update_object ( self, event ): """ Handles the user selecting a new value from the combo box. """ value = self.values[ self.names.index( event.GetString() ) ] if type( self.value ) is not str: value = [ value ] self.value = value #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ try: self.control.SetSelection( self.values.index( parse_value( self.value )[0] ) ) except: pass #------------------------------------------------------------------------------- # 'CustomEditor' class: #------------------------------------------------------------------------------- class CustomEditor ( SimpleEditor ): """ Custom style of editor for checklists, which displays a set of check boxes. """ #--------------------------------------------------------------------------- # Creates the initial editor control: #--------------------------------------------------------------------------- def create_control ( self, parent ): """ Creates the initial editor control. """ # Create a panel to hold all of the check boxes self.control = panel = TraitsUIPanel( parent, -1 ) #--------------------------------------------------------------------------- # Rebuilds the editor after its definition is modified: #--------------------------------------------------------------------------- def rebuild_editor ( self ): """ Rebuilds the editor after its definition is modified. """ panel = self.control panel.SetSizer( None ) panel.DestroyChildren() cur_value = parse_value( self.value ) # Create a sizer to manage the radio buttons: labels = self.names values = self.values n = len( labels ) cols = self.factory.cols rows = (n + cols - 1) / cols incr = [ n / cols ] * cols rem = n % cols for i in range( cols ): incr[i] += (rem > i) incr[-1] = -(reduce( lambda x, y: x + y, incr[:-1], 0 ) - 1) if cols > 1: sizer = wx.GridSizer( 0, cols, 2, 4 ) else: sizer = wx.BoxSizer( wx.VERTICAL ) # Add the set of all possible choices: index = 0 for i in range( rows ): for j in range( cols ): if n > 0: label = labels[ index ] control = wx.CheckBox( panel, -1, label ) control.value = value = values[ index ] control.SetValue( value in cur_value ) wx.EVT_CHECKBOX( panel, control.GetId(), self.update_object) index += incr[j] n -= 1 else: control = wx.CheckBox( panel, -1, '' ) control.Show( False ) sizer.Add( control, 0, wx.NORTH, 5 ) # Lay out the controls: panel.SetSizerAndFit( sizer ) # FIXME: There are cases where one of the parent panel's of the check # list editor has a fixed 'min size' which prevents the check list # editor from expanding correctly, so we currently are making sure # that all of the parent panels do not have a fixed min size before # doing the layout/refresh: parent = panel.GetParent() while isinstance( parent, wx.Panel ): parent.SetMinSize( wx.Size( -1, -1 ) ) panel = parent parent = parent.GetParent() panel.Layout() panel.Refresh() #--------------------------------------------------------------------------- # Handles the user clicking one of the 'custom' check boxes: #--------------------------------------------------------------------------- def update_object ( self, event ): """ Handles the user clicking one of the custom check boxes. """ control = event.GetEventObject() cur_value = parse_value( self.value ) if control.GetValue(): cur_value.append( control.value ) else: cur_value.remove( control.value ) if isinstance(self.value, basestring): cur_value = ','.join( cur_value ) self.value = cur_value #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ new_values = parse_value( self.value ) for control in self.control.GetChildren(): if control.IsShown(): control.SetValue( control.value in new_values ) #------------------------------------------------------------------------------- # 'TextEditor' class: #------------------------------------------------------------------------------- class TextEditor ( BaseTextEditor ): """ Text style of editor for checklists, which displays a text field. """ #--------------------------------------------------------------------------- # Handles the user changing the contents of the edit control: #--------------------------------------------------------------------------- def update_object ( self, event ): """ Handles the user changing the contents of the edit control. """ try: value = self.control.GetValue() value = eval( value ) except: pass try: self.value = value except TraitError, excp: pass #------------------------------------------------------------------------------- # Parse a value into a list: #------------------------------------------------------------------------------- def parse_value ( value ): """ Parses a value into a list. """ if value is None: return [] if type( value ) is not str: return value[:] return [ x.strip() for x in value.split( ',' ) ] ### EOF ######################################################################## traitsui-4.1.0/traitsui/wx/extra/0000755000175100001440000000000011674463546020006 5ustar ischnellusers00000000000000traitsui-4.1.0/traitsui/wx/extra/windows/0000755000175100001440000000000011674463546021500 5ustar ischnellusers00000000000000traitsui-4.1.0/traitsui/wx/extra/windows/ie_html_editor.py0000644000175100001440000002246211674463546025047 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2007, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 03/11/2007 # #------------------------------------------------------------------------------- """ Traits UI MS Internet Explorer editor. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import re import webbrowser import wx if wx.Platform == '__WXMSW__': # The new version of IEHTMLWindow (wx 2.8.8.0) is mostly compatible with # the old one, but it has changed the API for handling COM events, so we # cannot use it. try: import wx.lib.iewin_old as iewin except ImportError: import wx.lib.iewin as iewin from traits.api \ import Bool, Event, Property, Str from traitsui.wx.editor \ import Editor from traitsui.basic_editor_factory \ import BasicEditorFactory #------------------------------------------------------------------------------- # Constants #------------------------------------------------------------------------------- RELATIVE_OBJECTS_PATTERN = re.compile(r'src=["\'](?!https?:)([\s\w/\.]+?)["\']', re.IGNORECASE) #------------------------------------------------------------------------------- # '_IEHTMLEditor' class: #------------------------------------------------------------------------------- class _IEHTMLEditor ( Editor ): """ Traits UI MS Internet Explorer editor. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Is the table editor is scrollable? This value overrides the default. scrollable = True # External objects referenced in the HTML are relative to this url base_url = Str # Event fired when the browser home page should be displayed: home = Event # Event fired when the browser should show the previous page: back = Event # Event fired when the browser should show the next page: forward = Event # Event fired when the browser should stop loading the current page: stop = Event # Event fired when the browser should refresh the current page: refresh = Event # Event fired when the browser should search the current page: search = Event # The current browser status: status = Str # The current browser page title: title = Str # The URL of the page that just finished loading: page_loaded = Str # The current page content as HTML: html = Property #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self.control = ie = iewin.IEHtmlWindow( parent, -1, style = wx.NO_FULL_REPAINT_ON_RESIZE ) self.set_tooltip() factory = self.factory self.base_url = factory.base_url self.sync_value( factory.home, 'home', 'from' ) self.sync_value( factory.back, 'back', 'from' ) self.sync_value( factory.forward, 'forward', 'from' ) self.sync_value( factory.stop, 'stop', 'from' ) self.sync_value( factory.refresh, 'refresh', 'from' ) self.sync_value( factory.search, 'search', 'from' ) self.sync_value( factory.status, 'status', 'to' ) self.sync_value( factory.title, 'title', 'to' ) self.sync_value( factory.page_loaded, 'page_loaded', 'to' ) self.sync_value( factory.html, 'html', 'to' ) self.sync_value( factory.base_url_name, 'base_url', 'from' ) parent.Bind( iewin.EVT_StatusTextChange, self._status_modified, ie ) parent.Bind( iewin.EVT_TitleChange, self._title_modified, ie ) parent.Bind( iewin.EVT_DocumentComplete, self._page_loaded_modified,ie ) parent.Bind( iewin.EVT_NewWindow2, self._new_window_modified, ie ) parent.Bind( iewin.EVT_BeforeNavigate2, self._navigate_requested, ie ) #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ value = self.str_value.strip() # We can correct URLs via the BeforeNavigate Event, but the COM # interface provides no such option for images. Sadly, we are forced # to take a more brute force approach. if self.base_url: rep = lambda m: r'src="%s%s"' % ( self.base_url, m.group( 1 ) ) value = re.sub( RELATIVE_OBJECTS_PATTERN, rep, value ) if value == '': self.control.LoadString( '' ) elif value[:1] == '<': self.control.LoadString( value ) elif (value[:4] != 'http') or (value.find( '://' ) < 0): try: file = open( value, 'rb' ) self.control.LoadStream( file ) file.close() except: pass else: self.control.Navigate( value ) #-- Property Implementations ----------------------------------------------- def _get_html ( self ): return self.control.GetText() def _set_html ( self, value ): self.control.LoadString( value ) #-- Event Handlers --------------------------------------------------------- def _home_changed ( self ): self.control.GoHome() def _back_changed ( self ): self.control.GoBack() def _forward_changed ( self ): self.control.GoForward() def _stop_changed ( self ): self.control.Stop() def _search_changed ( self ): self.control.GoSearch() def _refresh_changed ( self ): self.control.Refresh( iewin.REFRESH_COMPLETELY ) def _status_modified ( self, event ): self.status = event.Text def _title_modified ( self, event ): self.title = event.Text def _page_loaded_modified ( self, event ): self.page_loaded = event.URL self.trait_property_changed( 'html', '', self.html ) def _new_window_modified ( self, event ): # If the event is cancelled, new windows can be disabled. # At this point we've opted to allow new windows pass def _navigate_requested ( self, event ): # The way NavigateToString works is to navigate to about:blank then # load the supplied HTML into the document property. This borks # relative URLs. if event.URL.startswith ( 'about:' ): base = self.base_url if not base.endswith( '/' ): base += '/' event.URL = base + event.URL[6:] if self.factory.open_externally: event.Cancel = True webbrowser.get( 'windows-default' ).open_new( event.URL ) #------------------------------------------------------------------------------- # Create the editor factory object: #------------------------------------------------------------------------------- # wxPython editor factory for MS Internet Explorer editors: class IEHTMLEditor ( BasicEditorFactory ): # The editor class to be created: klass = _IEHTMLEditor # External objects referenced in the HTML are relative to this url base_url = Str # The object trait containing the base URL base_url_name = Str # Should links be opened in an external browser? open_externally = Bool(False) # Optional name of trait used to tell browser to show Home page: home = Str # Optional name of trait used to tell browser to view the previous page: back = Str # Optional name of trait used to tell browser to view the next page: forward = Str # Optional name of trait used to tell browser to stop loading page: stop = Str # Optional name of trait used to tell browser to refresh the current page: refresh = Str # Optional name of trait used to tell browser to search the current page: search = Str # Optional name of trait used to contain the current browser status: status = Str # Optional name of trait used to contain the current browser page title: title = Str # Optional name of trait used to contain the URL of the page that just # completed loading: page_loaded = Str # Optional name of trait used to get/set the page content as HTML: html = Str traitsui-4.1.0/traitsui/wx/extra/windows/flash_editor.py0000644000175100001440000000570011674463546024517 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2007, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 03/11/2007 # #------------------------------------------------------------------------------- """ Traits UI MS Flash editor. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx if wx.Platform == '__WXMSW__': from wx.lib.flashwin import FlashWindow from traitsui.wx.editor \ import Editor from traitsui.basic_editor_factory \ import BasicEditorFactory #------------------------------------------------------------------------------- # '_FlashEditor' class: #------------------------------------------------------------------------------- class _FlashEditor ( Editor ): """ Traits UI Flash editor. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Is the table editor is scrollable? This value overrides the default. scrollable = True #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self.control = FlashWindow( parent ) self.set_tooltip() #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ value = self.str_value.strip() if value.find( '://' ) < 0: value = 'file://' + value wx.BeginBusyCursor() self.control.LoadMovie( 0, value ) wx.EndBusyCursor() #------------------------------------------------------------------------------- # Create the editor factory object: #------------------------------------------------------------------------------- # wxPython editor factory for Flash editors: class FlashEditor ( BasicEditorFactory ): # The editor class to be created: klass = _FlashEditor traitsui-4.1.0/traitsui/wx/extra/windows/__init__.py0000644000175100001440000000000111674463546023600 0ustar ischnellusers00000000000000 traitsui-4.1.0/traitsui/wx/extra/led_editor.py0000644000175100001440000000606711674463546022503 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2007, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 03/02/2007 # #------------------------------------------------------------------------------- """ Traits UI 'display only' LED numeric editor. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from wx.gizmos \ import LEDNumberCtrl, LED_ALIGN_LEFT, LED_ALIGN_CENTER, LED_ALIGN_RIGHT from traits.api \ import Enum from traitsui.wx.editor \ import Editor from traitsui.basic_editor_factory \ import BasicEditorFactory #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- # LED alignment styles: LEDStyles = { 'left': LED_ALIGN_LEFT, 'center': LED_ALIGN_CENTER, 'right': LED_ALIGN_RIGHT, } #------------------------------------------------------------------------------- # '_LEDEditor' class: #------------------------------------------------------------------------------- class _LEDEditor ( Editor ): """ Traits UI 'display only' LED numeric editor. """ #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self.control = LEDNumberCtrl( parent, -1 ) self.control.SetAlignment( LEDStyles[ self.factory.alignment ] ) self.set_tooltip() #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ self.control.SetValue( self.str_value ) #------------------------------------------------------------------------------- # Create the editor factory object: #------------------------------------------------------------------------------- # wxPython editor factory for LED editors: class LEDEditor ( BasicEditorFactory ): # The editor class to be created: klass = _LEDEditor # The alignment of the numeric text within the control: alignment = Enum( 'right', 'left', 'center' ) traitsui-4.1.0/traitsui/wx/extra/__init__.py0000644000175100001440000000000111674463546022106 0ustar ischnellusers00000000000000 traitsui-4.1.0/traitsui/wx/extra/bounds_editor.py0000644000175100001440000001604111674463546023222 0ustar ischnellusers00000000000000import wx from traits.api import Float, Any, Str, Trait from traitsui.editors.api import RangeEditor from traitsui.wx.editor import Editor from traitsui.wx.helper import TraitsUIPanel, Slider class _BoundsEditor(Editor): evaluate = Any min = Any max = Any low = Any high = Any format = Str def init(self, parent): """ Finishes initializing the editor by creating the underlying toolkit widget. """ factory = self.factory if not factory.low_name: self.low = factory.low self.min = self.low if not factory.high_name: self.high = factory.high self.max = self.high self.max = factory.max self.min = factory.min self.format = factory.format self.evaluate = factory.evaluate self.sync_value( factory.evaluate_name, 'evaluate', 'from' ) self.sync_value( factory.low_name, 'low', 'both' ) self.sync_value( factory.high_name, 'high', 'both' ) self.control = panel = TraitsUIPanel( parent, -1 ) sizer = wx.FlexGridSizer(2,3, 0, 0) # low text box self._label_lo = wx.TextCtrl(panel, -1, self.format % self.low, size=wx.Size(56, 20), style=wx.TE_PROCESS_ENTER ) sizer.Add(self._label_lo, 0, wx.ALIGN_CENTER) wx.EVT_TEXT_ENTER(panel, self._label_lo.GetId(), self.update_low_on_enter) wx.EVT_KILL_FOCUS(self._label_lo, self.update_low_on_enter) # low slider self.control.lslider = Slider(panel, -1, 0, 0, 10000, size=wx.Size( 100, 20 ), style=wx.SL_HORIZONTAL|wx.SL_AUTOTICKS ) self.control.lslider.SetValue(self._convert_to_slider(self.low)) self.control.lslider.SetTickFreq( 1000, 1 ) self.control.lslider.SetPageSize( 1000 ) self.control.lslider.SetLineSize( 100 ) wx.EVT_SCROLL( self.control.lslider, self.update_object_on_scroll ) sizer.Add(self.control.lslider, 1, wx.EXPAND) sizer.AddStretchSpacer(0) # high slider sizer.AddStretchSpacer(0) self.control.rslider = Slider(panel, -1, self._convert_to_slider(self.high), 0, 10000, size=wx.Size( 100, 20 ), style=wx.SL_HORIZONTAL|wx.SL_AUTOTICKS ) self.control.rslider.SetTickFreq( 1000, 1 ) self.control.rslider.SetPageSize( 1000 ) self.control.rslider.SetLineSize( 100 ) wx.EVT_SCROLL( self.control.rslider, self.update_object_on_scroll ) sizer.Add(self.control.rslider, 1, wx.EXPAND) # high text box self._label_hi = wx.TextCtrl(panel, -1, self.format % self.high, size=wx.Size(56, 20), style=wx.TE_PROCESS_ENTER ) sizer.Add(self._label_hi, 0, wx.ALIGN_CENTER) wx.EVT_TEXT_ENTER(panel, self._label_hi.GetId(), self.update_high_on_enter) wx.EVT_KILL_FOCUS(self._label_hi, self.update_high_on_enter) self.set_tooltip(self.control.lslider) self.set_tooltip(self.control.rslider) self.set_tooltip(self._label_lo) self.set_tooltip(self._label_hi) # Set-up the layout: panel.SetSizerAndFit(sizer) def update_low_on_enter(self, value): try: try: low = eval(unicode(self._label_lo.GetValue()).strip()) if self.evaluate is not None: low = self.evaluate(low) except Exception, ex: low = self.low self._label_lo.SetValue(self.format % self.low) if not self.factory.is_float: low = int(low) if low > self.high: low = self.high - self._step_size() self._label_lo.SetValue(self.format % low) self.control.lslider.SetValue(self._convert_to_slider(low)) self.low = low except: pass def update_high_on_enter(self, value): try: try: high = eval(unicode(self._label_hi.GetValue()).strip()) if self.evaluate is not None: high = self.evaluate(high) except: high = self.high self._label_hi.SetValue(self.format % self.high) if not self.factory.is_float: high = int(high) if high < self.low: high = self.low + self._step_size() self._label_hi.SetValue(self.format % high) self.control.rslider.SetValue(self._convert_to_slider(high)) self.high = high except: pass def update_object_on_scroll(self, evt): low = self._convert_from_slider(self.control.lslider.GetValue()) high = self._convert_from_slider(self.control.rslider.GetValue()) if low >= high: if evt.Position == self.control.lslider.GetValue(): low = self.high - self._step_size() else: high = self.low + self._step_size() if self.factory.is_float: self.low = low self.high = high else: self.low = int(low) self.high = int(high) # update the sliders to the int values or the sliders # will jiggle self.control.lslider.SetValue(self._convert_to_slider(low)) self.control.rslider.SetValue(self._convert_to_slider(high)) def update_editor(self): return def _check_max_and_min(self): # check if max & min have been defined: if self.max is None: self.max = self.high if self.min is None: self.min = self.low def _step_size(self): slider_delta = self.control.lslider.GetMax() - self.control.lslider.GetMin() range_delta = self.max - self.min return float(range_delta)/slider_delta def _convert_from_slider(self, slider_val): self._check_max_and_min() return self.min + slider_val * self._step_size() def _convert_to_slider(self, value): self._check_max_and_min() return self.control.lslider.GetMin() + (value-self.min) / self._step_size() def _low_changed(self, low): if self.control is None: return if self._label_lo is not None: self._label_lo.SetValue(self.format % low) self.control.lslider.SetValue(self._convert_to_slider(low)) def _high_changed(self, high): if self.control is None: return if self._label_hi is not None: self._label_hi.SetValue(self.format % high) self.control.rslider.SetValue(self._convert_to_slider(self.high)) class BoundsEditor(RangeEditor): min = Trait(None, Float) max = Trait(None, Float) def _get_simple_editor_class(self): return _BoundsEditor def _get_custom_editor_class(self): return _BoundsEditor traitsui-4.1.0/traitsui/wx/themed_checkbox_editor.py0000644000175100001440000002067411674463546023730 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2007, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 07/04/2007 # #------------------------------------------------------------------------------- """ Traits UI themed checkbox editor. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx from traits.api \ import Instance, Str from traitsui.ui_traits \ import ATheme, Image, Position, Spacing from traitsui.wx.editor \ import Editor from traitsui.basic_editor_factory \ import BasicEditorFactory from themed_control \ import ThemedControl #------------------------------------------------------------------------------- # '_ThemedCheckboxEditor' class: #------------------------------------------------------------------------------- class _ThemedCheckboxEditor ( Editor ): """ Traits UI themed checkbox editor. """ # The ThemedControl used for the checkbox: checkbox = Instance( ThemedControl ) #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ # Create the checkbox and its control: item = self.item factory = self.factory label = self.string_value( factory.label or item.label ) min_size = ( 0, 0 ) if factory.theme is not None: min_size = ( 80, 0 ) self.checkbox = checkbox = ThemedControl( **factory.get( 'image', 'position', 'spacing', 'theme' ) ).set( text = label, controller = self, min_size = min_size ) self.control = checkbox.create_control( parent ) # Set the tooltip: self.set_tooltip() #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ if self.checkbox.state == 'hover': self._set_hover_theme() else: self._set_theme() #-- ThemedControl Event Handlers ------------------------------------------- def normal_motion ( self, x, y, event ): self._set_hover_theme( 'hover' ) self.control.CaptureMouse() def hover_left_down ( self, x, y, event ): self.control.ReleaseMouse() self._set_hover_theme( 'down', not self.value ) def hover_motion ( self, x, y, event ): if not self.checkbox.in_control( x, y ): self.control.ReleaseMouse() self._set_theme( 'normal' ) def down_left_up ( self, x, y, event ): if self.checkbox.in_control( x, y ): self.value = not self.value self.normal_motion( x, y, event ) else: self._set_theme( 'normal' ) def down_motion ( self, x, y, event ): if not self.checkbox.in_control( x, y ): self._set_theme() else: self._set_hover_theme( value = not self.value ) #-- Private Methods -------------------------------------------------------- def _set_theme ( self, state = None, value = None ): """ Sets the theme, image, offset and optional checkbox state to use for a specified checkbox state value. """ if value is None: value = self.value factory = self.factory theme, image = factory.theme, factory.image if value: theme, image = factory.on_theme, factory.on_image n = (1 * value) * (theme is not None) self.checkbox.set( offset = ( n, n ), theme = theme or factory.theme, image = image or factory.image, state = state or self.checkbox.state ) def _set_hover_theme ( self, state = None, value = None ): """ Sets the theme, image, offset and optional checkbox state to use for a specified checkbox state value while in hover mode. """ if value is None: value = self.value factory = self.factory theme, image = factory.hover_off_theme, factory.hover_off_image if value: theme = factory.hover_on_theme or factory.on_theme image = factory.hover_on_image or factory.on_image n = (1 * value) * (theme is not None) self.checkbox.set( offset = ( n, n ), theme = theme or factory.theme, image = image or factory.image, state = state or self.checkbox.state ) #------------------------------------------------------------------------------- # Create the editor factory object: #------------------------------------------------------------------------------- # wxPython editor factory for themed checkbox editors: class ThemedCheckboxEditor ( BasicEditorFactory ): # The editor class to be created: klass = _ThemedCheckboxEditor # The checkbox label: label = Str # The basic theme for the checkbox (i.e. the 'off' state): theme = ATheme # The optional 'on' state theme for the checkbox: on_theme = ATheme # The optional 'hover off' state theme for the checkbox: hover_off_theme = ATheme # The optional 'hover on' state theme for the checbox: hover_on_theme = ATheme # The optional image to display in the checkbox (i.e. the 'off' state): image = Image( 'cb_off' ) # The optional 'on' state image to display in the checkbox: on_image = Image( 'cb_on' ) # The optional 'hover off' state image to display in the checkbox: hover_off_image = Image( 'cb_hover_off' ) # The optional 'hover on' state image to display in the checkbox: hover_on_image = Image( 'cb_hover_on' ) # The position of the image relative to the text: position = Position # The amount of space between the image and the text: spacing = Spacing #------------------------------------------------------------------------------- # Helper function for creating themed checkboxes: #------------------------------------------------------------------------------- def themed_checkbox_editor ( style = None, show_checkbox = True, **traits ): """ Simplifies creation of a ThemedCheckboxEditor by setting up the themes and images automatically based on the value of the *style* and *show_checkbox* arguments. """ tce = ThemedCheckboxEditor( **traits ) if not show_checkbox: tce.set( image = None, on_image = None, hover_off_image = None, hover_on_image = None ) if isinstance( style, basestring ): group = style[0:1].upper() if (len( group ) == 0) or (group not in 'BCGJTY'): group = 'B' row = style[1:2].upper() all_rows = '0123456789ABCDEFGHIJKL' if (len( row ) == 0) or (row not in all_rows): row = 'H' column = style[2:3].upper() all_columns = '12345789AB' if (len( column ) == 0) or (column not in all_columns): column = '5' tce.theme = '@%s%s%s' % ( group, row, column ) if style[-1:] == '.': return tce alt_row = '44456349A78FFFGHEFKLIJ'[ all_rows.index( row ) ] alt_column = '66666CCCCC'[ all_columns.index( column ) ] tce.set( on_theme = '@%s%s%s' % ( group, alt_row, column ), hover_on_theme = '@%s%s%s' % ( group, alt_row, alt_column ), hover_off_theme = '@%s%s%s' % ( group, row, alt_column ) ) return tce traitsui-4.1.0/traitsui/wx/instance_editor.py0000644000175100001440000006004311674463546022412 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/21/2004 # #------------------------------------------------------------------------------ """ Defines the various instance editors for the wxPython user interface toolkit. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx from traits.api \ import HasTraits, Property # FIXME: ToolkitEditorFactory is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.instance_editor file. from traitsui.editors.instance_editor \ import ToolkitEditorFactory from traitsui.ui_traits \ import AView from traitsui.helper \ import user_name_for from traitsui.handler \ import Handler from traitsui.instance_choice \ import InstanceChoiceItem from editor \ import Editor from constants \ import DropColor, is_wx26 from helper \ import TraitsUIPanel, position_window from pyface.wx.drag_and_drop \ import PythonDropTarget #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- OrientationMap = { 'default': None, 'horizontal': wx.HORIZONTAL, 'vertical': wx.VERTICAL } #------------------------------------------------------------------------------- # 'CustomEditor' class: #------------------------------------------------------------------------------- class CustomEditor ( Editor ): """ Custom style of editor for instances. If selection among instances is allowed, the editor displays a combo box listing instances that can be selected. If the current instance is editable, the editor displays a panel containing trait editors for all the instance's traits. """ # Background color when an item can be dropped on the editor: ok_color = DropColor # The orientation of the instance editor relative to the instance selector: orientation = wx.VERTICAL # Class constant: extra = 0 #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # List of InstanceChoiceItem objects used by the editor items = Property # The maximum extra padding that should be allowed around the editor: # (Override of the Editor base class trait) border_size = 0 # The view to use for displaying the instance: view = AView #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ factory = self.factory if factory.name != '': self._object, self._name, self._value = \ self.parse_extended_name( factory.name ) # Create a panel to hold the object trait's view: if factory.editable: self.control = self._panel = parent = TraitsUIPanel( parent, -1 ) # Build the instance selector if needed: selectable = factory.selectable droppable = factory.droppable items = self.items for item in items: droppable |= item.is_droppable() selectable |= item.is_selectable() if selectable: self._object_cache = {} item = self.item_for( self.value ) if item is not None: self._object_cache[ id( item ) ] = self.value self._choice = choice = wx.Choice( parent, -1, wx.Point( 0, 0 ), wx.Size( -1, -1 ), [] ) wx.EVT_CHOICE( choice, choice.GetId(), self.update_object ) if droppable: self._choice.SetBackgroundColour( self.ok_color ) self.set_tooltip( self._choice ) if factory.name != '': self._object.on_trait_change( self.rebuild_items, self._name, dispatch = 'ui' ) self._object.on_trait_change( self.rebuild_items, self._name + '_items', dispatch = 'ui' ) factory.on_trait_change( self.rebuild_items, 'values', dispatch = 'ui' ) factory.on_trait_change( self.rebuild_items, 'values_items', dispatch = 'ui' ) self.rebuild_items() elif droppable: self._choice = wx.TextCtrl( parent, -1, '', style = wx.TE_READONLY ) self._choice.SetBackgroundColour( self.ok_color ) self.set_tooltip( self._choice ) if droppable: self._choice.SetDropTarget( PythonDropTarget( self ) ) orientation = OrientationMap[ factory.orientation ] if orientation is None: orientation = self.orientation if (selectable or droppable) and factory.editable: sizer = wx.BoxSizer( orientation ) sizer.Add( self._choice, self.extra, wx.EXPAND ) if orientation == wx.VERTICAL: sizer.Add( wx.StaticLine( parent, -1, style = wx.LI_HORIZONTAL ), 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 5 ) self.create_editor( parent, sizer ) parent.SetSizer( sizer ) elif self.control is None: if self._choice is None: self._choice = choice = wx.Choice( parent, -1, wx.Point( 0, 0 ), wx.Size( -1, -1 ), [] ) wx.EVT_CHOICE( choice, choice.GetId(), self.update_object ) self.control = self._choice else: sizer = wx.BoxSizer( orientation ) self.create_editor( parent, sizer ) parent.SetSizer( sizer ) # Synchronize the 'view' to use: # fixme: A normal assignment can cause a crash (for unknown reasons) in # some cases, so we make sure that no notifications are generated: self.trait_setq( view = factory.view ) self.sync_value( factory.view_name, 'view', 'from' ) #--------------------------------------------------------------------------- # Disposes of the contents of an editor: #--------------------------------------------------------------------------- def dispose ( self ): """ Disposes of the contents of an editor. """ # Make sure we aren't hanging on to any object refs: self._object_cache = None if self._ui is not None: self._ui.dispose() choice = self._choice if choice is not None: if isinstance( choice, wx.Choice ): wx.EVT_CHOICE( choice, choice.GetId(), None ) if self._object is not None: self._object.on_trait_change( self.rebuild_items, self._name, remove = True ) self._object.on_trait_change( self.rebuild_items, self._name + '_items', remove = True ) self.factory.on_trait_change( self.rebuild_items, 'values', remove = True ) self.factory.on_trait_change( self.rebuild_items, 'values_items', remove = True ) super( CustomEditor, self ).dispose() #--------------------------------------------------------------------------- # Creates the editor control: #--------------------------------------------------------------------------- def create_editor ( self, parent, sizer ): """ Creates the editor control. """ self._panel = TraitsUIPanel( parent, -1 ) sizer.Add( self._panel, 1, wx.EXPAND ) #--------------------------------------------------------------------------- # Gets the current list of InstanceChoiceItem items: #--------------------------------------------------------------------------- def _get_items ( self ): """ Gets the current list of InstanceChoiceItem items. """ if self._items is not None: return self._items factory = self.factory if self._value is not None: values = self._value() + factory.values else: values = factory.values items = [] adapter = factory.adapter for value in values: if not isinstance( value, InstanceChoiceItem ): value = adapter( object = value ) items.append( value ) self._items = items return items #--------------------------------------------------------------------------- # Rebuilds the object selector list: #--------------------------------------------------------------------------- def rebuild_items ( self ): """ Rebuilds the object selector list. """ # Clear the current cached values: self._items = None # Rebuild the contents of the selector list: name = None value = self.value choice = self._choice choice.Clear() for item in self.items: if item.is_selectable(): item_name = item.get_name() choice.Append( item_name ) if item.is_compatible( value ): name = item_name # Reselect the current item if possible: if name is not None: choice.SetStringSelection( name ) else: # Otherwise, current value is no longer valid, try to discard it: try: self.value = None except: pass #--------------------------------------------------------------------------- # Returns the InstanceChoiceItem for a specified object: #--------------------------------------------------------------------------- def item_for ( self, object ): """ Returns the InstanceChoiceItem for a specified object. """ for item in self.items: if item.is_compatible( object ): return item return None #--------------------------------------------------------------------------- # Returns the view to use for a specified object: #--------------------------------------------------------------------------- def view_for ( self, object, item ): """ Returns the view to use for a specified object. """ view = '' if item is not None: view = item.get_view() if view == '': view = self.view return self.ui.handler.trait_view_for( self.ui.info, view, object, self.object_name, self.name ) #--------------------------------------------------------------------------- # Handles the user selecting a new value from the combo box: #--------------------------------------------------------------------------- def update_object ( self, event ): """ Handles the user selecting a new value from the combo box. """ name = event.GetString() for item in self.items: if name == item.get_name(): id_item = id( item ) object = self._object_cache.get( id_item ) if object is None: object = item.get_object() if (not self.factory.editable) and item.is_factory: view = self.view_for( object, self.item_for( object ) ) view.ui( object, self.control, 'modal' ) if self.factory.cachable: self._object_cache[ id_item ] = object self.value = object self.resynch_editor() break #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ # Attach the current object value to the control (for use by # DockWindowFeature): # fixme: This code is somewhat fragile since it assumes that if a # DockControl is involved, the parent of this editor will be the # control being managed by the DockControl. parent = self.control.GetParent() parent._object = self.value dock_control = getattr( parent, '_dock_control', None ) if dock_control is not None: dock_control.reset_tab() # Synchronize the editor contents: self.resynch_editor() # Update the selector (if any): choice = self._choice item = self.item_for( self.value ) if (choice is not None) and (item is not None): name = item.get_name( self.value ) if self._object_cache is not None: if choice.FindString( name ) < 0: choice.Append( name ) choice.SetStringSelection( name ) else: choice.SetValue( name ) #--------------------------------------------------------------------------- # Resynchronizes the contents of the editor when the object trait changes # external to the editor: #--------------------------------------------------------------------------- def resynch_editor ( self ): """ Resynchronizes the contents of the editor when the object trait changes externally to the editor. """ panel = self._panel if panel is not None: # Compute/update the maximum size the panel has ever been: dx, dy = panel.GetSizeTuple() mdx = mdy = 0 if self._panel_size is not None: mdx, mdy = self._panel_size self._panel_size = size = wx.Size( max( mdx, dx ), max( mdy, dy ) ) # Dispose of the previous contents of the panel: panel.SetSizer( None ) if self._ui is not None: self._ui.dispose() self._ui = None else: panel.DestroyChildren() # Create the new content for the panel: sizer = wx.BoxSizer( wx.VERTICAL ) stretch = 0 value = self.value if not isinstance( value, HasTraits ): str_value = '' if value is not None: str_value = self.str_value control = wx.StaticText( panel, -1, str_value ) else: view = self.view_for( value, self.item_for( value ) ) context = value.trait_context() handler = None if isinstance( value, Handler ): handler = value context.setdefault( 'context', self.object ) context.setdefault( 'context_handler', self.ui.handler ) self._ui = ui = view.ui( context, panel, 'subpanel', value.trait_view_elements(), handler, self.factory.id ) control = ui.control self.scrollable = ui._scrollable ui.parent = self.ui if view.resizable or view.scrollable or ui._scrollable: stretch = 1 # Make sure the panel and its contents are correctly sized (This # code is complicated by the various layout bugs present in wx. # Tamper with it at your own risk!): control.Freeze() if stretch and (size != ( 20, 20 )): control.SetSize( size ) panel.SetSize( size ) else: panel.SetSize( control.GetSize() ) sizer.Add( control, stretch, wx.EXPAND ) panel.SetSizer( sizer ) control.Thaw() self.control.Layout() parent = self.control.GetParent() parent.Layout() # It is possible that this instance editor is embedded at some level # in a ScrolledWindow. If so, we need to inform the window that the # size of the editor's contents have (potentially) changed: # NB: There is a typo in the wxPython 2.6 code that prevents the # 'SendSizeEvent' from working correctly, so we just skip it. if not is_wx26: while ((parent is not None) and (not isinstance( parent, wx.ScrolledWindow ))): parent = parent.GetParent() if parent is not None: parent.SendSizeEvent() #--------------------------------------------------------------------------- # Handles an error that occurs while setting the object's trait value: #--------------------------------------------------------------------------- def error ( self, excp ): """ Handles an error that occurs while setting the object's trait value. """ pass #--------------------------------------------------------------------------- # Returns the editor's control for indicating error status: #--------------------------------------------------------------------------- def get_error_control ( self ): """ Returns the editor's control for indicating error status. """ return (self._choice or self.control) #-- UI preference save/restore interface ----------------------------------- #--------------------------------------------------------------------------- # Restores any saved user preference information associated with the # editor: #--------------------------------------------------------------------------- def restore_prefs ( self, prefs ): """ Restores any saved user preference information associated with the editor. """ ui = self._ui if (ui is not None) and (prefs.get( 'id' ) == ui.id): ui.set_prefs( prefs.get( 'prefs' ) ) #--------------------------------------------------------------------------- # Returns any user preference information associated with the editor: #--------------------------------------------------------------------------- def save_prefs ( self ): """ Returns any user preference information associated with the editor. """ ui = self._ui if (ui is not None) and (ui.id != ''): return { 'id': ui.id, 'prefs': ui.get_prefs() } return None #-- Drag and drop event handlers ------------------------------------------- #--------------------------------------------------------------------------- # Handles a Python object being dropped on the control: #--------------------------------------------------------------------------- def wx_dropped_on ( self, x, y, data, drag_result ): """ Handles a Python object being dropped on the tree. """ for item in self.items: if item.is_droppable() and item.is_compatible( data ): if self._object_cache is not None: self.rebuild_items() self.value = data return drag_result return wx.DragNone #--------------------------------------------------------------------------- # Handles a Python object being dragged over the control: #--------------------------------------------------------------------------- def wx_drag_over ( self, x, y, data, drag_result ): """ Handles a Python object being dragged over the tree. """ for item in self.items: if item.is_droppable() and item.is_compatible( data ): return drag_result return wx.DragNone #-- Traits event handlers -------------------------------------------------- def _view_changed ( self, view ): self.resynch_editor() #------------------------------------------------------------------------------- # 'SimpleEditor' class: #------------------------------------------------------------------------------- class SimpleEditor ( CustomEditor ): """ Simple style of editor for instances, which displays a button. Clicking the button displays a dialog box in which the instance can be edited. """ # Class constants: orientation = wx.HORIZONTAL extra = 2 #--------------------------------------------------------------------------- # Creates the editor control: #--------------------------------------------------------------------------- def create_editor ( self, parent, sizer ): """ Creates the editor control (a button). """ self._button = button = wx.Button( parent, -1, '' ) sizer.Add( button, 1, wx.EXPAND | wx.LEFT, 5 ) wx.EVT_BUTTON( button, button.GetId(), self.edit_instance ) #--------------------------------------------------------------------------- # Disposes of the contents of an editor: #--------------------------------------------------------------------------- def dispose ( self ): """ Disposes of the contents of an editor. """ button = self._button if button is not None: wx.EVT_BUTTON( button, button.GetId(), None ) super( SimpleEditor, self ).dispose() #--------------------------------------------------------------------------- # Edit the contents of the object trait when the user clicks the button: #--------------------------------------------------------------------------- def edit_instance ( self, event ): """ Edit the contents of the object trait when the user clicks the button. """ # Create the user interface: factory = self.factory view = self.ui.handler.trait_view_for( self.ui.info, factory.view, self.value, self.object_name, self.name ) ui = self.value.edit_traits( view, self.control, factory.kind, id = factory.id ) # Check to see if the view was 'modal', in which case it will already # have been closed (i.e. is None) by the time we get control back: if ui.control is not None: # Position the window on the display: position_window( ui.control ) # Chain our undo history to the new user interface if it does not # have its own: if ui.history is None: ui.history = self.ui.history #--------------------------------------------------------------------------- # Resynchronizes the contents of the editor when the object trait changes # external to the editor: #--------------------------------------------------------------------------- def resynch_editor ( self ): """ Resynchronizes the contents of the editor when the object trait changes externally to the editor. """ button = self._button if button is not None: label = self.factory.label if label == '': label = user_name_for( self.name ) button.SetLabel( label ) button.Enable( isinstance( self.value, HasTraits ) ) ### EOF ####################################################################### traitsui-4.1.0/traitsui/wx/range_editor.py0000644000175100001440000010731711674463546021710 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/21/2004 # #------------------------------------------------------------------------------ """ Defines the various range editors for the wxPython user interface toolkit. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import sys import wx from math \ import log10 from traits.api \ import TraitError, Str, Float, Any, Bool # FIXME: ToolkitEditorFactory is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.range_editor file. from traitsui.editors.range_editor \ import ToolkitEditorFactory from editor_factory \ import TextEditor from editor \ import Editor from constants \ import OKColor, ErrorColor from helper \ import TraitsUIPanel, Slider #------------------------------------------------------------------------------- # 'BaseRangeEditor' class: #------------------------------------------------------------------------------- class BaseRangeEditor ( Editor ): """ The base class for Range editors. Using an evaluate trait, if specified, when assigning numbers the object trait. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Function to evaluate floats/ints evaluate = Any #--------------------------------------------------------------------------- # Sets the associated object trait's value: #--------------------------------------------------------------------------- def _set_value ( self, value ): if self.evaluate is not None: value = self.evaluate( value ) Editor._set_value( self, value ) #------------------------------------------------------------------------------- # 'SimpleSliderEditor' class: #------------------------------------------------------------------------------- class SimpleSliderEditor ( BaseRangeEditor ): """ Simple style of range editor that displays a slider and a text field. The user can set a value either by moving the slider or by typing a value in the text field. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Low value for the slider range low = Any # High value for the slider range high = Any # Formatting string used to format value and labels format = Str # Flag indicating that the UI is in the process of being updated ui_changing = Bool( False ) #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ factory = self.factory if not factory.low_name: self.low = factory.low if not factory.high_name: self.high = factory.high self.format = factory.format self.evaluate = factory.evaluate self.sync_value( factory.evaluate_name, 'evaluate', 'from' ) size = wx.DefaultSize if factory.label_width > 0: size = wx.Size( factory.label_width, 20 ) self.sync_value( factory.low_name, 'low', 'from' ) self.sync_value( factory.high_name, 'high', 'from' ) self.control = panel = TraitsUIPanel( parent, -1 ) sizer = wx.BoxSizer( wx.HORIZONTAL ) fvalue = self.value if not (self.low <= fvalue <= self.high): fvalue_text = '' fvalue = self.low else: try: fvalue_text = self.format % fvalue except (ValueError, TypeError), e: fvalue_text = '' ivalue = self._convert_to_slider(fvalue) self._label_lo = wx.StaticText( panel, -1, '999999', size = size, style = wx.ALIGN_RIGHT | wx.ST_NO_AUTORESIZE ) sizer.Add( self._label_lo, 0, wx.ALIGN_CENTER ) panel.slider = slider = Slider( panel, -1, ivalue, 0, 10000, size = wx.Size( 80, 20 ), style = wx.SL_HORIZONTAL | wx.SL_AUTOTICKS ) slider.SetTickFreq( 1000, 1 ) slider.SetPageSize( 1000 ) slider.SetLineSize( 100 ) wx.EVT_SCROLL( slider, self.update_object_on_scroll ) sizer.Add( slider, 1, wx.EXPAND ) self._label_hi = wx.StaticText( panel, -1, '999999', size = size ) sizer.Add( self._label_hi, 0, wx.ALIGN_CENTER ) panel.text = text = wx.TextCtrl( panel, -1, fvalue_text, size = wx.Size( 56, 20 ), style = wx.TE_PROCESS_ENTER ) wx.EVT_TEXT_ENTER( panel, text.GetId(), self.update_object_on_enter ) wx.EVT_KILL_FOCUS( text, self.update_object_on_enter ) sizer.Add( text, 0, wx.LEFT | wx.EXPAND, 4 ) low_label = factory.low_label if factory.low_name != '': low_label = self.format % self.low high_label = factory.high_label if factory.high_name != '': high_label = self.format % self.high self._label_lo.SetLabel( low_label ) self._label_hi.SetLabel( high_label ) self.set_tooltip( slider ) self.set_tooltip( self._label_lo ) self.set_tooltip( self._label_hi ) self.set_tooltip( text ) # Set-up the layout: panel.SetSizerAndFit( sizer ) #--------------------------------------------------------------------------- # Handles the user changing the current slider value: #--------------------------------------------------------------------------- def update_object_on_scroll ( self, event ): """ Handles the user changing the current slider value. """ value = self._convert_from_slider(event.GetPosition()) event_type = event.GetEventType() if ((event_type == wx.wxEVT_SCROLL_ENDSCROLL) or (self.factory.auto_set and (event_type == wx.wxEVT_SCROLL_THUMBTRACK)) or (self.factory.enter_set and (event_type == wx.wxEVT_SCROLL_THUMBRELEASE))): try: self.ui_changing = True self.control.text.SetValue( self.format % value ) self.value = value except TraitError: pass finally: self.ui_changing = False #--------------------------------------------------------------------------- # Handle the user pressing the 'Enter' key in the edit control: #--------------------------------------------------------------------------- def update_object_on_enter ( self, event ): """ Handles the user pressing the Enter key in the text field. """ # There are cases where this method is called with self.control == None. if self.control is None: return try: try: value = self.control.text.GetValue().strip() if self.factory.is_float: value = float(value) else: value = int(value) except Exception, ex: # The user entered something that didn't eval as a number (e.g., 'foo'). # Pretend it didn't happen (i.e. do not change self.value). value = self.value self.control.text.SetValue( str( value ) ) self.value = value if not self.ui_changing: self.control.slider.SetValue( self._convert_to_slider(self.value) ) self.control.text.SetBackgroundColour(OKColor) self.control.text.Refresh() if self._error is not None: self._error = None self.ui.errors -= 1 except TraitError: pass #--------------------------------------------------------------------------- # Handles an error that occurs while setting the object's trait value: #--------------------------------------------------------------------------- def error ( self, excp ): """ Handles an error that occurs while setting the object's trait value. """ if self._error is None: self._error = True self.ui.errors += 1 super(SimpleSliderEditor, self).error(excp) self.set_error_state( True ) #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ value = self.value try: text = self.format % value 1 / (self.low <= value <= self.high) except: text = '' value = self.low ivalue = self._convert_to_slider( value ) self.control.text.SetValue( text ) self.control.slider.SetValue( ivalue ) def _convert_to_slider(self, value): """ Returns the slider setting corresponding to the user-supplied value. """ if self.high > self.low: ivalue = int( (float( value - self.low ) / (self.high - self.low)) * 10000.0 ) else: ivalue = self.low return ivalue def _convert_from_slider(self, ivalue): """ Returns the float or integer value corresponding to the slider setting. """ value = self.low + ((float( ivalue ) / 10000.0) * (self.high - self.low)) if not self.factory.is_float: value = int(round(value)) return value #--------------------------------------------------------------------------- # Returns the editor's control for indicating error status: #--------------------------------------------------------------------------- def get_error_control ( self ): """ Returns the editor's control for indicating error status. """ return self.control.text #--------------------------------------------------------------------------- # Handles the 'low'/'high' traits being changed: #--------------------------------------------------------------------------- def _low_changed ( self, low ): if self.value < low: if self.factory.is_float: self.value = float( low ) else: self.value = int( low ) if self._label_lo is not None: self._label_lo.SetLabel( self.format % low ) self.update_editor() def _high_changed ( self, high ): if self.value > high: if self.factory.is_float: self.value = float( high ) else: self.value = int( high ) if self._label_hi is not None: self._label_hi.SetLabel( self.format % high ) self.update_editor() #------------------------------------------------------------------------------- class LogRangeSliderEditor ( SimpleSliderEditor ): #------------------------------------------------------------------------------- """ A slider editor for log-spaced values """ def _convert_to_slider(self, value): """ Returns the slider setting corresponding to the user-supplied value. """ value = max(value, self.low) ivalue = int( (log10(value) - log10(self.low)) / (log10(self.high) - log10(self.low)) * 10000.0) return ivalue def _convert_from_slider(self, ivalue): """ Returns the float or integer value corresponding to the slider setting. """ value = float( ivalue ) / 10000.0 * (log10(self.high) -log10(self.low)) # Do this to handle floating point errors, where fvalue may exceed # self.high. fvalue = min(self.low*10**(value), self.high) if not self.factory.is_float: fvalue = int(round(fvalue)) return fvalue #------------------------------------------------------------------------------- # 'LargeRangeSliderEditor' class: #------------------------------------------------------------------------------- class LargeRangeSliderEditor ( BaseRangeEditor ): """ A slider editor for large ranges. The editor displays a slider and a text field. A subset of the total range is displayed in the slider; arrow buttons at each end of the slider let the user move the displayed range higher or lower. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Low value for the slider range low = Any( 0 ) # High value for the slider range high = Any( 1 ) # Low end of displayed range cur_low = Float # High end of displayed range cur_high = Float # Flag indicating that the UI is in the process of being updated ui_changing = Bool( False ) #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ factory = self.factory # Initialize using the factory range defaults: self.low = factory.low self.high = factory.high self.evaluate = factory.evaluate # Hook up the traits to listen to the object. self.sync_value( factory.low_name, 'low', 'from' ) self.sync_value( factory.high_name, 'high', 'from' ) self.sync_value( factory.evaluate_name, 'evaluate', 'from' ) self.init_range() low = self.cur_low high = self.cur_high self._set_format() self.control = panel = TraitsUIPanel( parent, -1 ) sizer = wx.BoxSizer( wx.HORIZONTAL ) fvalue = self.value try: fvalue_text = self._format % fvalue 1 / (low <= fvalue <= high) except: fvalue_text = '' fvalue = low if high > low: ivalue = int( (float( fvalue - low ) / (high - low)) * 10000 ) else: ivalue = low # Lower limit label: label_lo = wx.StaticText( panel, -1, '999999' ) panel.label_lo = label_lo sizer.Add( label_lo, 2, wx.ALIGN_CENTER ) # Lower limit button: bmp = wx.ArtProvider.GetBitmap( wx.ART_GO_BACK, size = ( 15, 15 ) ) button_lo = wx.BitmapButton( panel, -1, bitmap = bmp, size = ( -1, 20 ), style = wx.BU_EXACTFIT | wx.NO_BORDER ) panel.button_lo = button_lo button_lo.Bind( wx.EVT_BUTTON, self.reduce_range, button_lo ) sizer.Add( button_lo, 1, wx.ALIGN_CENTER ) # Slider: panel.slider = slider = Slider( panel, -1, ivalue, 0, 10000, size = wx.Size( 80, 20 ), style = wx.SL_HORIZONTAL | wx.SL_AUTOTICKS ) slider.SetTickFreq( 1000, 1 ) slider.SetPageSize( 1000 ) slider.SetLineSize( 100 ) wx.EVT_SCROLL( slider, self.update_object_on_scroll ) sizer.Add( slider, 6, wx.EXPAND ) # Upper limit button: bmp = wx.ArtProvider.GetBitmap( wx.ART_GO_FORWARD, size = ( 15, 15 ) ) button_hi = wx.BitmapButton( panel, -1, bitmap = bmp, size = ( -1, 20 ), style = wx.BU_EXACTFIT | wx.NO_BORDER ) panel.button_hi = button_hi button_hi.Bind( wx.EVT_BUTTON, self.increase_range, button_hi ) sizer.Add( button_hi, 1, wx.ALIGN_CENTER ) # Upper limit label: label_hi = wx.StaticText( panel, -1, '999999' ) panel.label_hi = label_hi sizer.Add( label_hi, 2, wx.ALIGN_CENTER ) # Text entry: panel.text = text = wx.TextCtrl( panel, -1, fvalue_text, size = wx.Size( 56, 20 ), style = wx.TE_PROCESS_ENTER ) wx.EVT_TEXT_ENTER( panel, text.GetId(), self.update_object_on_enter ) wx.EVT_KILL_FOCUS( text, self.update_object_on_enter ) sizer.Add( text, 0, wx.LEFT | wx.EXPAND, 4 ) # Set-up the layout: panel.SetSizerAndFit( sizer ) label_lo.SetLabel( str(low) ) label_hi.SetLabel( str(high) ) self.set_tooltip( slider ) self.set_tooltip( label_lo ) self.set_tooltip( label_hi ) self.set_tooltip( text ) # Update the ranges and button just in case. self.update_range_ui() #--------------------------------------------------------------------------- # Handles the user changing the current slider value: #--------------------------------------------------------------------------- def update_object_on_scroll ( self, event ): """ Handles the user changing the current slider value. """ low = self.cur_low high = self.cur_high value = low + ((float( event.GetPosition() ) / 10000.0) * (high - low)) self.control.text.SetValue( self._format % value ) event_type = event.GetEventType() try: self.ui_changing = True if ((event_type == wx.wxEVT_SCROLL_ENDSCROLL) or (self.factory.auto_set and (event_type == wx.wxEVT_SCROLL_THUMBTRACK)) or (self.factory.enter_set and (event_type == wx.wxEVT_SCROLL_THUMBRELEASE))): if self.factory.is_float: self.value = value else: self.value = int( value ) finally: self.ui_changing = False #--------------------------------------------------------------------------- # Handle the user pressing the 'Enter' key in the edit control: #--------------------------------------------------------------------------- def update_object_on_enter ( self, event ): """ Handles the user pressing the Enter key in the text field. """ try: value = self.control.text.GetValue().strip() try: if self.factory.is_float: value = float(value) else: value = int(value) except Exception, ex: # The user entered something that didn't eval as a number (e.g., 'foo'). # Pretend it didn't happen (i.e. do not change self.value). value = self.value self.control.text.SetValue( str( value ) ) self.value = value self.control.text.SetBackgroundColour(OKColor) self.control.text.Refresh() # Update the slider range. # Set ui_changing to True to avoid recursion: # the update_range_ui method will try to set the value in the text # box, which will again fire this method if auto_set is True. if not self.ui_changing: self.ui_changing = True self.init_range() self.update_range_ui() self.ui_changing = False if self._error is not None: self._error = None self.ui.errors -= 1 except TraitError, excp: pass #--------------------------------------------------------------------------- # Handles an error that occurs while setting the object's trait value: #--------------------------------------------------------------------------- def error ( self, excp ): """ Handles an error that occurs while setting the object's trait value. """ if self._error is None: self._error = True self.ui.errors += 1 super(LargeRangeSliderEditor, self).error(excp) self.set_error_state( True ) #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ value = self.value low = self.low high = self.high try: text = self._format % value 1 / (low <= value <= high) except: value = low self.value = value if not self.ui_changing: self.init_range() self.update_range_ui() def update_range_ui ( self ): """ Updates the slider range controls. """ low, high = self.cur_low, self.cur_high value = self.value self._set_format() self.control.label_lo.SetLabel( self._format % low ) self.control.label_hi.SetLabel( self._format % high ) if high > low: ivalue = int( (float( value - low ) / (high - low)) * 10000.0 ) else: ivalue = low self.control.slider.SetValue( ivalue ) text = self._format % self.value self.control.text.SetValue( text ) factory = self.factory f_low, f_high = self.low, self.high if low == f_low: self.control.button_lo.Disable() else: self.control.button_lo.Enable() if high == f_high: self.control.button_hi.Disable() else: self.control.button_hi.Enable() def init_range ( self ): """ Initializes the slider range controls. """ value = self.value factory = self.factory low, high = self.low, self.high if (high is None) and (low is not None): high = -low mag = abs( value ) if mag <= 10.0: cur_low = max( value - 10, low ) cur_high = min( value + 10, high ) else: d = 0.5 * (10**int( log10( mag ) + 1 )) cur_low = max( low, value - d ) cur_high = min( high, value + d ) self.cur_low, self.cur_high = cur_low, cur_high def reduce_range ( self, event ): """ Reduces the extent of the displayed range. """ factory = self.factory low, high = self.low, self.high if abs( self.cur_low ) < 10: self.cur_low = max( -10, low ) self.cur_high = min( 10, high ) elif self.cur_low > 0: self.cur_high = self.cur_low self.cur_low = max( low, self.cur_low / 10 ) else: self.cur_high = self.cur_low self.cur_low = max( low, self.cur_low * 10 ) self.ui_changing = True self.value = min( max( self.value, self.cur_low ), self.cur_high ) self.ui_changing = False self.update_range_ui() def increase_range ( self, event ): """ Increased the extent of the displayed range. """ factory = self.factory low, high = self.low, self.high if abs( self.cur_high ) < 10: self.cur_low = max( -10, low ) self.cur_high = min( 10, high ) elif self.cur_high > 0: self.cur_low = self.cur_high self.cur_high = min( high, self.cur_high * 10 ) else: self.cur_low = self.cur_high self.cur_high = min( high, self.cur_high / 10 ) self.ui_changing = True self.value = min( max( self.value, self.cur_low ), self.cur_high ) self.ui_changing = False self.update_range_ui() def _set_format ( self ): self._format = '%d' factory = self.factory low, high = self.cur_low, self.cur_high diff = high - low if factory.is_float: if diff > 99999: self._format = '%.2g' elif diff > 1: self._format = '%%.%df' % max( 0, 4 - int( log10( high - low ) ) ) else: self._format = '%.3f' #--------------------------------------------------------------------------- # Returns the editor's control for indicating error status: #--------------------------------------------------------------------------- def get_error_control ( self ): """ Returns the editor's control for indicating error status. """ return self.control.text #--------------------------------------------------------------------------- # Handles the 'low'/'high' traits being changed: #--------------------------------------------------------------------------- def _low_changed ( self, low ): if self.control is not None: if self.value < low: if self.factory.is_float: self.value = float( low ) else: self.value = int( low ) self.update_editor() def _high_changed ( self, high ): if self.control is not None: if self.value > high: if self.factory.is_float: self.value = float( high ) else: self.value = int( high ) self.update_editor() #------------------------------------------------------------------------------- # 'SimpleSpinEditor' class: #------------------------------------------------------------------------------- class SimpleSpinEditor ( BaseRangeEditor ): """ A simple style of range editor that displays a spin box control. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Low value for the slider range low = Any # High value for the slider range high = Any #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ factory = self.factory if not factory.low_name: self.low = factory.low if not factory.high_name: self.high = factory.high self.sync_value( factory.low_name, 'low', 'from' ) self.sync_value( factory.high_name, 'high', 'from' ) low = self.low high = self.high self.control = wx.SpinCtrl( parent, -1, self.str_value, min = low, max = high, initial = self.value ) wx.EVT_SPINCTRL( parent, self.control.GetId(), self.update_object ) wx.EVT_TEXT( parent, self.control.GetId(), self.update_object ) self.set_tooltip() #--------------------------------------------------------------------------- # Handle the user selecting a new value from the spin control: #--------------------------------------------------------------------------- def update_object ( self, event ): """ Handles the user selecting a new value in the spin box. """ self._locked = True try: self.value = self.control.GetValue() finally: self._locked = False #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ if not self._locked: try: self.control.SetValue( int( self.value ) ) except: pass #--------------------------------------------------------------------------- # Handles the 'low'/'high' traits being changed: #--------------------------------------------------------------------------- def _low_changed ( self, low ): if self.value < low: if self.factory.is_float: self.value = float( low ) else: self.value = int( low ) if self.control: self.control.SetRange( self.low, self.high ) self.control.SetValue( int( self.value ) ) def _high_changed ( self, high ): if self.value > high: if self.factory.is_float: self.value = float( high ) else: self.value = int( high ) if self.control: self.control.SetRange( self.low, self.high ) self.control.SetValue( int( self.value ) ) #------------------------------------------------------------------------------- # 'RangeTextEditor' class: #------------------------------------------------------------------------------- class RangeTextEditor ( TextEditor ): """ Editor for ranges that displays a text field. If the user enters a value that is outside the allowed range, the background of the field changes color to indicate an error. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Function to evaluate floats/ints evaluate = Any #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ if self.factory.enter_set: control = wx.TextCtrl( parent, -1, self.str_value, style = wx.TE_PROCESS_ENTER ) wx.EVT_TEXT_ENTER( parent, control.GetId(), self.update_object ) else: control = wx.TextCtrl( parent, -1, self.str_value ) wx.EVT_KILL_FOCUS( control, self.update_object ) if self.factory.auto_set: wx.EVT_TEXT( parent, control.GetId(), self.update_object ) self.evaluate = self.factory.evaluate self.sync_value( self.factory.evaluate_name, 'evaluate', 'from' ) self.control = control self.set_tooltip() #--------------------------------------------------------------------------- # Handles the user entering input data in the edit control: #--------------------------------------------------------------------------- def update_object ( self, event ): """ Handles the user entering input data in the edit control. """ # There are cases where this method is called with self.control == None. if self.control is None: return value = self.control.GetValue() # Try to convert the string value entered by the user to a numerical value. try: if self.evaluate is not None: value = self.evaluate(value) else: if self.factory.is_float: value = float(value) else: value = int(value) except Exception, excp: # The conversion failed. self.error(excp) return # Try to assign the numerical value to the trait. # This may fail because of constraints on the trait. try: self.value = value self.control.SetBackgroundColour(OKColor) self.control.Refresh() if self._error is not None: self._error = None self.ui.errors -= 1 except TraitError, excp: pass #--------------------------------------------------------------------------- # Handles an error that occurs while setting the object's trait value: #--------------------------------------------------------------------------- def error ( self, excp ): """ Handles an error that occurs while setting the object's trait value. """ if self._error is None: self._error = True self.ui.errors += 1 super(RangeTextEditor, self).error(excp) self.set_error_state( True ) #------------------------------------------------------------------------------- # 'SimpleEnumEditor' factory adaptor: #------------------------------------------------------------------------------- def SimpleEnumEditor ( parent, factory, ui, object, name, description ): return CustomEnumEditor( parent, factory, ui, object, name, description, 'simple' ) #------------------------------------------------------------------------------- # 'CustomEnumEditor' factory adaptor: #------------------------------------------------------------------------------- def CustomEnumEditor ( parent, factory, ui, object, name, description, style = 'custom' ): """ Factory adapter that returns a enumeration editor of the specified style. """ if factory._enum is None: import traitsui.editors.enum_editor as enum_editor factory._enum = enum_editor.ToolkitEditorFactory( values = range( factory.low, factory.high + 1 ), cols = factory.cols ) if style == 'simple': return factory._enum.simple_editor( ui, object, name, description, parent ) return factory._enum.custom_editor( ui, object, name, description, parent ) #------------------------------------------------------------------------------- # Defines the mapping between editor factory 'mode's and Editor classes: #------------------------------------------------------------------------------- # Mapping between editor factory modes and simple editor classes SimpleEditorMap = { 'slider': SimpleSliderEditor, 'xslider': LargeRangeSliderEditor, 'spinner': SimpleSpinEditor, 'enum': SimpleEnumEditor, 'text': RangeTextEditor, 'logslider': LogRangeSliderEditor } # Mapping between editor factory modes and custom editor classes CustomEditorMap = { 'slider': SimpleSliderEditor, 'xslider': LargeRangeSliderEditor, 'spinner': SimpleSpinEditor, 'enum': CustomEnumEditor, 'text': RangeTextEditor, 'logslider': LogRangeSliderEditor } ### EOF ####################################################################### traitsui-4.1.0/traitsui/wx/boolean_editor.py0000644000175100001440000001072711674463546022231 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/21/2004 # #------------------------------------------------------------------------------ """ Defines the various Boolean editors for the wxPython user interface toolkit. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx # FIXME: ToolkitEditorFactory is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.boolean_editor file. from traitsui.editors.boolean_editor \ import ToolkitEditorFactory from editor \ import Editor # This needs to be imported in here for use by the editor factory for boolean # editors (declared in traitsui). The editor factory's text_editor # method will use the TextEditor in the ui. from text_editor \ import SimpleEditor as TextEditor from constants \ import ReadonlyColor #------------------------------------------------------------------------------- # 'SimpleEditor' class: #------------------------------------------------------------------------------- class SimpleEditor ( Editor ): """ Simple style of editor for Boolean values, which displays a check box. """ #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self.control = wx.CheckBox( parent, -1, '' ) wx.EVT_CHECKBOX( parent, self.control.GetId(), self.update_object ) self.set_tooltip() #--------------------------------------------------------------------------- # Handles the user clicking on the checkbox: #--------------------------------------------------------------------------- def update_object ( self, event ): """ Handles the user clicking the checkbox. """ self.value = (self.control.GetValue() != 0) #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ self.control.SetValue( self.value ) #------------------------------------------------------------------------------- # 'ReadonlyEditor' class: #------------------------------------------------------------------------------- class ReadonlyEditor ( Editor ): """ Read-only style of editor for Boolean values, which displays static text of either "True" or "False". """ #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self.control = wx.TextCtrl( parent, -1, '', style = wx.TE_READONLY ) self.control.SetBackgroundColour( ReadonlyColor ) #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: # # (Should normally be overridden in a subclass) #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ if self.value: self.control.SetValue( 'True' ) else: self.control.SetValue( 'False' ) traitsui-4.1.0/traitsui/wx/editor.py0000644000175100001440000003253711674463546020535 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/21/2004 # #------------------------------------------------------------------------------ """ Defines the base class for wxPython editors. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx from traits.api \ import HasTraits, Int, Instance, Str, Callable # CIRCULAR IMPORT FIXME: # We are importing from the source instead of from the api in order to # avoid circular imports. The 'toolkit.py' file imports from 'helper' which in # turns imports from this file. Therefore, trying to import # 'traitsui.wx' (which imports the toolkit) will lead to importing # all of the editor factories declared in traitsui.api. In addition,# some of the editor factories have a Color trait defined, and this will lead # to an import of the wx 'toolkit' causing a circular import problem. # Another solution could be to move the GroupEditor object from helper to this # file. from traitsui.editor \ import Editor as UIEditor from constants \ import WindowColor, OKColor, ErrorColor #------------------------------------------------------------------------------- # 'Editor' class: #------------------------------------------------------------------------------- class Editor ( UIEditor ): """ Base class for wxPython editors for Traits-based UIs. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Style for embedding control in a sizer: layout_style = Int( wx.EXPAND ) # The maximum extra padding that should be allowed around the editor: border_size = Int( 4 ) #--------------------------------------------------------------------------- # Handles the 'control' trait being set: #--------------------------------------------------------------------------- def _control_changed ( self, control ): """ Handles the **control** trait being set. """ if control is not None: control._editor = self #--------------------------------------------------------------------------- # Assigns focus to the editor's underlying toolkit widget: #--------------------------------------------------------------------------- def set_focus ( self ): """ Assigns focus to the editor's underlying toolkit widget. """ if self.control is not None: self.control.SetFocus() #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ new_value = self.str_value if self.control.GetValue() != new_value: self.control.SetValue( new_value ) #--------------------------------------------------------------------------- # Handles an error that occurs while setting the object's trait value: #--------------------------------------------------------------------------- def error ( self, excp ): """ Handles an error that occurs while setting the object's trait value. """ dlg = wx.MessageDialog( self.control, str( excp ), self.description + ' value error', wx.OK | wx.ICON_INFORMATION ) dlg.ShowModal() dlg.Destroy() #--------------------------------------------------------------------------- # Sets the tooltip for a specified control: #--------------------------------------------------------------------------- def set_tooltip ( self, control = None ): """ Sets the tooltip for a specified control. """ desc = self.description if desc == '': desc = self.object.base_trait( self.name ).desc if desc is None: return False desc = 'Specifies ' + desc if control is None: control = self.control control.SetToolTipString( desc ) return True #--------------------------------------------------------------------------- # Handles the 'enabled' state of the editor being changed: #--------------------------------------------------------------------------- def _enabled_changed ( self, enabled ): """ Handles the **enabled** state of the editor being changed. """ control = self.control if control is not None: control.Enable( enabled ) control.Refresh() #--------------------------------------------------------------------------- # Handles the 'visible' state of the editor being changed: #--------------------------------------------------------------------------- def _visible_changed ( self, visible ): """ Handles the **visible** state of the editor being changed. """ control = self.control parent = control.GetParent() # Handle the case where the item whose visibility has changed is a # notebook page: sizer = parent.GetSizer() from pyface.dock.api import DockSizer if isinstance(sizer, DockSizer): dock_controls = sizer.GetContents().get_controls(False) for dock_control in dock_controls: if dock_control.control is control: dock_control.visible = visible sizer.Layout() # Handle a normal item: else: if self.label_control is not None: self.label_control.Show( visible ) control.Show( visible ) # If only control.Layout() is called there are certain cases where # the newly visible items are sized incorrectly (see ticket 1797) if parent is None: control.Layout() else: parent.Layout() #--------------------------------------------------------------------------- # Returns the editor's control for indicating error status: #--------------------------------------------------------------------------- def get_error_control ( self ): """ Returns the editor's control for indicating error status. """ return self.control #--------------------------------------------------------------------------- # Returns whether or not the editor is in an error state: #--------------------------------------------------------------------------- def in_error_state ( self ): """ Returns whether or not the editor is in an error state. """ return False #--------------------------------------------------------------------------- # Sets the editor's current error state: #--------------------------------------------------------------------------- def set_error_state ( self, state = None, control = None ): """ Sets the editor's current error state. """ if state is None: state = self.invalid state = state or self.in_error_state() if control is None: control = self.get_error_control() or [] if not isinstance( control, list ): control = [ control ] for item in control: if state: color = ErrorColor if getattr( item, '_ok_color', None ) is None: item._ok_color = item.GetBackgroundColour() else: color = getattr( item, '_ok_color', None ) if color is None: color = OKColor if isinstance( item, wx.Panel ): color = WindowColor item.SetBackgroundColour( color ) item.Refresh() #--------------------------------------------------------------------------- # Handles the editor's invalid state changing: #--------------------------------------------------------------------------- def _invalid_changed ( self, state ): """ Handles the editor's invalid state changing. """ self.set_error_state() #------------------------------------------------------------------------------- # 'EditorWithList' class: #------------------------------------------------------------------------------- class EditorWithList ( Editor ): """ Editor for an object that contains a list. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Object containing the list being monitored list_object = Instance( HasTraits ) # Name of the monitored trait list_name = Str # Function used to evaluate the current list object value: list_value = Callable #--------------------------------------------------------------------------- # Initializes the object: #--------------------------------------------------------------------------- def init ( self, parent ): """ Initializes the object. """ factory = self.factory name = factory.name if name != '': self.list_object, self.list_name, self.list_value = \ self.parse_extended_name( name ) else: self.list_object, self.list_name = factory, 'values' self.list_value = lambda: factory.values self.list_object.on_trait_change( self._list_updated, self.list_name + '[]', dispatch = 'ui' ) self._list_updated() #--------------------------------------------------------------------------- # Disconnects the listeners set up by the constructor: #--------------------------------------------------------------------------- def dispose ( self ): """ Disconnects the listeners set up by the constructor. """ self.list_object.on_trait_change( self._list_updated, self.list_name + '[]', remove = True ) super( EditorWithList, self ).dispose() #--------------------------------------------------------------------------- # Handles the monitored trait being updated: #--------------------------------------------------------------------------- def _list_updated ( self ): """ Handles the monitored trait being updated. """ self.list_updated( self.list_value() ) #--------------------------------------------------------------------------- # Handles the monitored list being updated: #--------------------------------------------------------------------------- def list_updated ( self, values ): """ Handles the monitored list being updated. """ raise NotImplementedError #------------------------------------------------------------------------------- # 'EditorFromView' class: #------------------------------------------------------------------------------- class EditorFromView ( Editor ): """ An editor generated from a View object. """ #--------------------------------------------------------------------------- # Initializes the object: #--------------------------------------------------------------------------- def init ( self, parent ): """ Initializes the object. """ self._ui = ui = self.init_ui( parent ) if ui.history is None: ui.history = self.ui.history self.control = ui.control #--------------------------------------------------------------------------- # Creates and returns the traits UI defined by this editor: # (Must be overridden by a subclass): #--------------------------------------------------------------------------- def init_ui ( self, parent ): """ Creates and returns the traits UI defined by this editor. (Must be overridden by a subclass). """ raise NotImplementedError #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ # Normally nothing needs to be done here, since it should all be handled # by the editor's internally created traits UI: pass #--------------------------------------------------------------------------- # Dispose of the editor: #--------------------------------------------------------------------------- def dispose ( self ): """ Disposes of the editor. """ self._ui.dispose() super( EditorFromView, self ).dispose() traitsui-4.1.0/traitsui/wx/title_editor.py0000644000175100001440000000461611674463546021733 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2006, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 07/06/2006 # #------------------------------------------------------------------------------- """ Define an editor that displays a string value as a title. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from editor \ import Editor from pyface.heading_text \ import HeadingText # FIXME: TitleEditor (the editor factory for title editors) is a proxy class # defined here just for backward compatibility. The class has been moved to # traitsui.editors.title_editor. from traitsui.editors.title_editor \ import TitleEditor #------------------------------------------------------------------------------- # '_TitleEditor' class: #------------------------------------------------------------------------------- class _TitleEditor ( Editor ): #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self._control = HeadingText( parent ) self.control = self._control.control self.set_tooltip() #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes external to the editor. """ self._control.text = self.str_value #--EOF------------------------------------------------------------------------- traitsui-4.1.0/traitsui/wx/table_model.py0000644000175100001440000007664311674463546021524 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 07/01/2005 # #------------------------------------------------------------------------------ """ Defines the table grid model used by the table editor based on the PyFace grid control. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import logging import wx import wx.grid as wxg from traits.api \ import HasPrivateTraits, Any, Str, Instance, Event, Bool, \ on_trait_change from traitsui.api \ import View, Item, Editor from traitsui.editors.table_editor \ import ReversedList from traitsui.table_filter \ import TableFilter from traitsui.ui_traits \ import SequenceTypes from pyface.ui.wx.grid.api \ import GridModel, GridSortEvent from pyface.ui.wx.grid.trait_grid_cell_adapter \ import TraitGridCellAdapter from pyface.timer.api \ import do_later logger = logging.getLogger(__name__) #------------------------------------------------------------------------------- # 'TraitGridSelection' class: #------------------------------------------------------------------------------- class TraitGridSelection ( HasPrivateTraits ): """ Structure for holding specification information. """ # The selected object obj = Any # The specific trait selected on the object name = Str #------------------------------------------------------------------------------- # 'TableModel' class: #------------------------------------------------------------------------------- class TableModel ( GridModel ): """ Model for table data. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # The editor that created this model editor = Instance( Editor ) # The current filter filter = Instance( TableFilter, allow_none = True ) # Current filter summary message filter_summary = Str( 'All items' ) # Display the table items in reverse order? reverse = Bool( False ) # Event fired when the table has been sorted sorted = Event # The current 'auto_add' row auto_add_row = Any #--------------------------------------------------------------------------- # 'object' interface: #--------------------------------------------------------------------------- #--------------------------------------------------------------------------- # Initializes the object: #--------------------------------------------------------------------------- def __init__ ( self, **traits ): """ Initializes the object. """ super( TableModel, self ).__init__( **traits ) # Attach trait handlers to the list object: editor = self.editor object = editor.context_object name = ' ' + editor.extended_name # Set up listeners for any of the model data changing: object.on_trait_change( self._on_data_changed, name, dispatch = 'ui' ) object.on_trait_change( self.fire_content_changed, name + '.-', dispatch = 'ui' ) # Set up listeners for any column definitions changing: editor.on_trait_change( self.update_columns, 'columns', dispatch = 'ui' ) editor.on_trait_change( self.update_columns, 'columns_items', dispatch = 'ui' ) # Initialize the current filter from the editor's default filter: self.filter = editor.filter # If we are using 'auto_add' mode, create the first 'auto_add' row: if editor.auto_add: self.auto_add_row = row = editor.create_new_row() if row is not None: row.on_trait_change( self.on_auto_add_row, dispatch = 'ui' ) #-- TableModel Interface --------------------------------------------------- #--------------------------------------------------------------------------- # Disposes of the model when it is no longer needed: #--------------------------------------------------------------------------- def dispose ( self ): """ Disposes of the model when it is no longer needed. """ editor = self.editor object = editor.context_object name = ' ' + editor.extended_name # Remove listeners for any of the model data changing: object.on_trait_change( self._on_data_changed, name, remove = True ) object.on_trait_change( self.fire_content_changed, name + '.-', remove = True ) # Remove listeners for any column definitions changing: editor.on_trait_change( self.update_columns, 'columns', remove = True ) editor.on_trait_change( self.update_columns, 'columns_items', remove = True ) # Make sure we have removed listeners from the current filter also: if self.filter is not None: self.filter.on_trait_change( self._filter_modified, remove = True ) # Clean-up any links that should be broken: self.editor = None #--------------------------------------------------------------------------- # Returns all model items matching the current filter: #--------------------------------------------------------------------------- def get_filtered_items ( self ): """ Returns all model items matching the current filter. """ return self.__filtered_items() #--------------------------------------------------------------------------- # Returns a single specified item from those items matching the current # filter: #--------------------------------------------------------------------------- def get_filtered_item ( self, index = 0 ): """ Returns a single specified item from those items matching the current filter. """ try: return self.__filtered_items()[ index ] except: logger.error( 'TableModel error: Request for invalid row %d out of ' '%d' % ( index, len( self.__filtered_items() ) ) ) return None #--------------------------------------------------------------------------- # Returns the raw, unfiltered index corresponding to a specified filtered # index: #--------------------------------------------------------------------------- def raw_index_of ( self, row ): """ Returns the raw, unfiltered index corresponding to a specified filtered index. """ if self._filtered_cache is None: return row return self.editor.filtered_indices[ row ] #--------------------------------------------------------------------------- # Inserts an object after a specified filtered index: #--------------------------------------------------------------------------- def insert_filtered_item_after ( self, index, item ): """ Inserts an object after a specified filtered index. """ mapped_index = 0 n = len( self.editor.filtered_indices ) if index >= n: if (index != 0) or (n != 0): raise IndexError elif index >= 0: mapped_index = self.editor.filtered_indices[ index ] + 1 self.__items().insert( mapped_index, item ) sorted = self._sort_model() if sorted: mapped_index = self.__items().index( item ) self._filtered_cache = None return ( mapped_index, sorted ) #--------------------------------------------------------------------------- # Deletes the object at the specified filtered index: #--------------------------------------------------------------------------- def delete_filtered_item_at ( self, index ): """ Deletes the object at the specified filtered index. """ if index >= len( self.editor.filtered_indices ): raise IndexError mapped_index = self.editor.filtered_indices[ index ] items = self.__items() object = items[ mapped_index ] del items[ mapped_index ] self._filtered_cache = None return ( mapped_index, object ) #--------------------------------------------------------------------------- # Updates the table view when columns have been changed: #--------------------------------------------------------------------------- def update_columns ( self ): """ Updates the table view when columns have been changed. """ self._columns = None self.fire_structure_changed() self.editor.refresh() #--------------------------------------------------------------------------- # Resets any sorting being performed on the underlying model: #--------------------------------------------------------------------------- def no_column_sort ( self ): """ Resets any sorting being performed on the underlying model. """ self._sorter = self._filtered_cache = None self.column_sorted = GridSortEvent(index = -1) #self.fire_structure_changed() #-- Event Handlers --------------------------------------------------------- #--------------------------------------------------------------------------- # Handles the contents of the filter being changed: #--------------------------------------------------------------------------- @on_trait_change( 'filter.+' ) def _filter_modified ( self ): """ Handles the contents of the filter being changed. """ self._filtered_cache = None self.fire_structure_changed() self.editor.filter_modified() #--------------------------------------------------------------------------- # Handles the grid firing a 'click' event: #--------------------------------------------------------------------------- def _click_changed ( self, event ): """ Handles the grid firing a 'click' event. """ row, col = event # Fire the same event on the editor after mapping it to a model object # and column name: object = self.get_filtered_item( row ) column = self.__get_column( col ) self.editor.click = ( object, column ) # Check to see if the column has a view to display: view = column.get_view( object ) if view is not None: column.get_object( object ).edit_traits( view = view, parent = self._bounds_for( row, col ) ) # Invoke the column's click handler: column.on_click( object ) #--------------------------------------------------------------------------- # Handles the grid firing a 'dclick' event: #--------------------------------------------------------------------------- def _dclick_changed ( self, event ): """ Handles the grid firing a 'dclick' event. """ row, col = event # Fire the same event on the editor after mapping it to a model object # and column name: object = self.get_filtered_item( row ) column = self.__get_column( col ) self.editor.dclick = ( object, column ) # Invoke the column's double-click handler: column.on_dclick( object ) #--------------------------------------------------------------------------- # Handles the user modifying the current 'auto_add' mode row: #--------------------------------------------------------------------------- def on_auto_add_row ( self ): """ Handles the user modifying the current 'auto_add' mode row. """ object = self.auto_add_row object.on_trait_change( self.on_auto_add_row, remove = True ) self.auto_add_row = row = self.editor.create_new_row() if row is not None: row.on_trait_change( self.on_auto_add_row, dispatch = 'ui' ) do_later( self.editor.add_row, object, len( self.get_filtered_items() ) - 2 ) #-- GridModel Interface ---------------------------------------------------- def get_column_count ( self ): """ Returns the number of columns for this table. """ return len( self.__get_columns() ) def get_column_name ( self, index ): """ Returns the label of the column specified by the (zero-based) index. """ return self.__get_column( index ).get_label() def get_column_size ( self, index ): """ Returns the size in pixels of the column indexed by *index*. A value of -1 or None means to use the default. """ return self.__get_column( index ).get_width() def get_cols_drag_value ( self, cols ): """ Returns the value to use when the specified columns are dragged or copied and pasted. The parameter *cols* is a list of column indexes. """ return [ self.__get_data_column( col ) for col in cols ] def get_cols_selection_value ( self, cols ): """ Returns a list of TraitGridSelection objects containing the objects corresponding to the grid rows and the traits corresponding to the specified columns. """ values = [] for obj in self.__items( False ): values.extend( [ TraitGridSelection( obj = obj, name = self.__get_column_name( col ) ) for col in cols ] ) return values def sort_by_column ( self, col, reverse = False ): """ Sorts the model data by the column indexed by *col*. """ # Make sure we allow sorts by column: factory = self.editor.factory if not factory.sortable: return # Flush the object cache: self._filtered_cache = None # Cache the sorting information for later: self._sorter = self.__get_column( col ).cmp self._reverse = reverse # If model sorting is requested, do it now: self._sort_model() # Indicate the we have been sorted: self.sorted = True self.column_sorted = GridSortEvent( index = col, reversed = reverse ) def is_column_read_only ( self, index ): """ Returns True if the column specified by the zero-based *index* is read-only. """ return (not self.__get_column( index ).editable) def get_row_count ( self ): """ Return the number of rows for this table. """ return len( self.__filtered_items() ) def get_row_name ( self, index ): """ Return the name of the row specified by the (zero-based) *index*. """ return '' def get_rows_drag_value ( self, rows ): """ Returns the value to use when the specified rows are dragged or copied and pasted. The parameter *rows* is a list of row indexes. If there is only one row listed, then return the corresponding trait object. If more than one row is listed, then return a list of objects. """ items = self.__filtered_items() return [ items[ row ] for row in rows ] def get_rows_selection_value ( self, rows ): """ Returns a list of TraitGridSelection objects containing the object corresponding to the selected rows. """ items = self.__filtered_items() return [ TraitGridSelection( obj = items[ row ] ) for row in rows ] def is_row_read_only ( self, index ): """ Returns True if the row specified by the zero-based *index* is read-only. """ return False def get_cell_editor ( self, row, col ): """ Returns the editor for the specified cell. """ if self.editor is None: return None column = self.__get_column( col ) object = self.get_filtered_item( row ) editor = column.get_editor( object ) if editor is None: return None editor._ui = self.editor.ui target, name = column.target_name( object ) return TraitGridCellAdapter( editor, target, name, '', context = self.editor.ui.context, style = column.get_style( object ), width = column.get_edit_width( object ), height = column.get_edit_height( object ) ) def get_cell_renderer ( self, row, col ): """ Returns the renderer for the specified cell. """ return self.__get_column( col ).get_renderer( self.get_filtered_item( row ) ) def get_cell_drag_value ( self, row, col ): """ Returns the value to use when the specified cell is dragged or copied and pasted. """ return self.__get_column( col ).get_drag_value( self.get_filtered_item( row ) ) def get_cell_selection_value ( self, row, col ): """ Returns a TraitGridSelection object specifying the data stored in the table at (*row*, *col*). """ return TraitGridSelection( obj = self.get_filtered_item( row ), name = self.__get_column_name( col ) ) def resolve_selection ( self, selection_list ): """ Returns a list of (row, col) grid-cell coordinates that correspond to the objects in *selection_list*. For each coordinate, if the row is -1, it indicates that the entire column is selected. Likewise coordinates with a column of -1 indicate an entire row that is selected. For the TableModel, the objects in *selection_list* must be TraitGridSelection objects. """ items = self.__filtered_items() cells = [] for selection in selection_list: row = -1 if selection.obj is not None: try: row = items.index( selection.obj ) except ValueError: continue column = -1 if selection.name != '': column = self._get_column_index_by_trait( selection.name ) if column is None: continue cells.append( ( row, column ) ) return cells def get_cell_context_menu ( self, row, col ): """ Returns a Menu object that generates the appropriate context menu for this cell. """ column = self.__get_column( col ) menu = column.get_menu( self.get_filtered_item( row ) ) editor = self.editor if menu is None: menu = editor.factory.menu if menu is None: menu_name = editor.factory.menu_name if menu_name : menu = getattr(self.editor.object, menu_name, None) if menu is not None: editor.prepare_menu( row, column ) return ( menu, editor ) return None def get_value ( self, row, col ): """ Returns the value stored in the table at (*row*, *col*). """ object = self.get_filtered_item( row ) if object is self.auto_add_row: return '' value = self.__get_column( col ).get_value( object ) formats = self.__get_column_formats( col ) if (value is not None) and (formats is not None): format = formats.get( type( value ) ) if format is not None: try: if callable( format ): value = format( value ) else: value = format % value except: pass return value def is_valid_cell_value ( self, row, col, value ): """ Tests whether *value* is valid for the cell at (*row*, *col*). Returns True if value is acceptable, and False otherwise. """ return self.__get_column( col ).is_droppable( self.get_filtered_item( row ), value ) def is_cell_empty ( self, row, col ): """ Returns True if the cell at (*row*, *col*) has a None value, and False otherwise. """ return (self.get_value( row, col ) is None) def is_cell_read_only ( self, row, col ): """ Returns True if the cell at (*row*, *col*) is read-only, and False otherwise. """ return (not self.__get_column( col ).is_editable( self.get_filtered_item( row ) )) def get_cell_bg_color ( self, row, col ): """ Returns a wxColour object specifying the background color of the specified cell. """ return self.__get_column( col ).get_cell_color( self.get_filtered_item( row ) ) def get_cell_text_color ( self, row, col ): """ Returns a wxColour object specifying the text color of the specified cell. """ column = self.__get_column(col) item = self.get_filtered_item(row) return column.get_text_color(item) def get_cell_font ( self, row, col ): """ Returns a wxFont object specifying the font of the specified cell. """ return self.__get_column( col ).get_text_font( self.get_filtered_item( row ) ) def get_cell_halignment ( self, row, col ): """ Returns a string specifying the horizontal alignment of the specified cell. Returns 'left' for left alignment, 'right' for right alignment, or 'center' for center alignment. """ return self.__get_column( col ).get_horizontal_alignment( self.get_filtered_item( row ) ) def get_cell_valignment ( self, row, col ): """ Returns a string specifying the vertical alignment of the specified cell. Returns 'top' for top alignment, 'bottom' for bottom alignment, or 'center' for center alignment. """ return self.__get_column( col ).get_vertical_alignment( self.get_filtered_item( row ) ) #--------------------------------------------------------------------------- # Protected 'GridModel' interface: #--------------------------------------------------------------------------- def _insert_rows ( self, pos, num_rows ): """ Inserts *num_rows* at *pos*; fires an event only if a factory method for new rows is defined or the model is not empty. Otherwise, it returns 0. """ count = 0 factory = self.editor.factory.row_factory if factory is None: items = self.__items( False ) if len( items ) > 0: factory = items[0].__class__ if factory is not None: new_data = [ x for x in [ factory() for i in range( num_rows ) ] if x is not None ] if len( new_data ) > 0: count = self._insert_rows_into_model( pos, new_data ) self.rows_added = ( 'added', pos, new_data ) return count def _delete_rows ( self, pos, num_rows ): """ Removes rows *pos* through *pos* + *num_rows* from the model. """ row_count = self.get_rows_count() if (pos + num_rows) > row_count: num_rows = row_count - pos return self._delete_rows_from_model( pos, num_rows ) def _set_value ( self, row, col, value ): """ Sets the value of the cell at (*row*, *col*) to *value*. Raises a ValueError if the value is vetoed or the cell at the specified position does not exist. """ new_rows = 0 column = self.__get_column( col ) obj = None try: obj = self.get_filtered_item( row ) except: # Add a new row: new_rows = self._insert_rows( self.get_row_count(), 1 ) if new_rows > 0: # Now set the value on the new object: try: obj = self.get_filtered_item( self.get_row_count() - 1 ) except: # fixme: what do we do in this case? veto the set somehow? # raise an exception? pass if obj is not None: self._set_data_on_row( obj, column, value ) return new_rows def _move_column ( self, frm, to ): """ Moves a specified **frm** column to before the specified **to** column. Returns **True** if successful; **False** otherwise. """ to_column = None if to < len( self.__get_columns() ): to_column = self.__get_column( to ) return self.editor.move_column( self.__get_column( frm ), to_column ) #--------------------------------------------------------------------------- # Protected interface: #--------------------------------------------------------------------------- def _set_data_on_row ( self, row, column, value ): """ Sets the cell specified by (*row*, *col*) to *value, which can be either a member of the row object, or a no-argument method on that object. """ column.set_value( row, value ) def _insert_rows_into_model ( self, pos, new_data ): """ Inserts the given new rows into the model. """ raw_pos = self.raw_index_of( pos ) self.__items()[ raw_pos: raw_pos ] = new_data def _delete_rows_from_model ( self, pos, num_rows ): """ Deletes the specified rows from the model. """ raw_rows = [ self.raw_index_of( i ) for i in range( pos, pos + num_rows ) ] raw_rows.sort() raw_rows.reverse() items = self.__items() for row in raw_rows: del items[ row ] return num_rows #--------------------------------------------------------------------------- # Trait event handlers: #--------------------------------------------------------------------------- def _on_data_changed ( self ): """ Forces the grid to refresh when the underlying list changes. """ # Invalidate the current cache (if any): self._filtered_cache = None self.fire_structure_changed() def _mouse_cell_changed ( self, new ): """ Handles the user mousing over a specified cell. """ row, col = new column = self.__get_column( col ) object = self.get_filtered_item( row ) # Update the tooltip if necessary: tooltip = column.get_tooltip( object ) if tooltip != self._tooltip: self._tooltip = tooltip self.editor.grid._grid_window.SetToolTip( wx.ToolTip( tooltip ) ) if column.is_auto_editable( object ): x, y, dx, dy = self._bounds_for( row, col ) if column.is_editable( object ): view = View( Item( name = column.name, editor = column.get_editor( object ), style = column.get_style( object ), show_label = False, padding = -4 ), kind = 'info', width = dx, height = dy ) else: view = column.get_view( object ) if view is None: return column.get_object( object ).edit_traits( view = view, parent = ( x, y, dx, dy ) ) #--------------------------------------------------------------------------- # Private interface: #--------------------------------------------------------------------------- def _bounds_for ( self, row, col ): """ Returns the coordinates and size of the specified cell in the form: ( x, y, dx, dy ). """ grid = self.editor.grid coords = wxg.GridCellCoords( row, col ) x, y, dx, dy = grid._grid.BlockToDeviceRect( coords, coords ) x, y = grid._grid_window.ClientToScreenXY( x, y ) return ( x, y, dx, dy ) def _sort_model ( self ): """ Sorts the underlying model if that is what the user requested. """ editor = self.editor sorted = (editor.factory.sort_model and (self._sorter is not None)) if sorted: items = self.__items( False )[:] items.sort( self._sorter ) if self.reverse ^ self._reverse: items.reverse() editor.value = items return sorted def __items ( self, ordered = True ): """ Returns the raw list of model objects. """ result = self.editor.value if not isinstance( result, SequenceTypes ): return [ result ] if ordered and self.reverse: return ReversedList( result ) return result def __filtered_items ( self ): """ Returns the list of all model objects that pass the current filter. """ fc = self._filtered_cache if fc is None: items = self.__items() filter = self.filter if filter is None: nitems = [ nitem for nitem in enumerate( items ) ] self.filter_summary = 'All %s items' % len( nitems ) else: if not callable( filter ): filter = filter.filter nitems = [ nitem for nitem in enumerate( items ) if filter( nitem[1] ) ] self.filter_summary = '%s of %s items' % ( len( nitems ), len( items ) ) sorter = self._sorter if sorter is not None: nitems.sort( lambda l, r: sorter( l[1], r[1] ) ) if self._reverse: nitems.reverse() self.editor.filtered_indices = [ x[0] for x in nitems ] self._filtered_cache = fc = [ x[1] for x in nitems ] if self.auto_add_row is not None: self._filtered_cache.append( self.auto_add_row ) return fc def __get_data_column ( self, col ): """ Returns a list of model data from the column indexed by *col*. """ column = self.__get_column( col ) return [ column.get_value( item ) for item in self.__filtered_items() ] def __get_columns ( self ): columns = self._columns if columns is None: self._columns = columns = [ c for c in self.editor.columns if c.visible ] return columns def __get_column ( self, col ): try: return self.__get_columns()[ col ] except: return self.__get_columns()[0] def __get_column_name ( self, col ): return self.__get_column( col ).name def __get_column_formats ( self, col ): return None # Not used/implemented currently def _get_column_index_by_trait ( self, name ): for i, col in enumerate( self.__get_columns() ): if name == col.name: return i traitsui-4.1.0/traitsui/wx/scrubber_editor.py0000644000175100001440000004643511674463546022426 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2007, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 07/14/2008 # #------------------------------------------------------------------------------- """ Traits UI simple, scrubber-based integer or float value editor. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx from math \ import log10, pow from traits.api \ import Any, BaseRange, BaseEnum, Str, Float, TraitError, \ on_trait_change from traitsui.api \ import View, Item, EnumEditor # FIXME: ScrubberEditor is a proxy class defined here just for backward # compatibility (represents the editor factory for scrubber editors). # The class has been moved to traitsui.editors.scrubber_editor from traitsui.editors.scrubber_editor \ import ScrubberEditor from traitsui.wx.editor \ import Editor from pyface.timer.api \ import do_after from constants \ import ErrorColor from image_slice \ import paint_parent from helper \ import disconnect, disconnect_no_id, BufferDC #------------------------------------------------------------------------------- # '_ScrubberEditor' class: #------------------------------------------------------------------------------- class _ScrubberEditor ( Editor ): """ Traits UI simple, scrubber-based integer or float value editor. """ # The low end of the slider range: low = Any # The high end of the slider range: high = Any # The smallest allowed increment: increment = Float # The current text being displayed: text = Str # The mapping to use (only for Enum's): mapping = Any #-- Class Variables -------------------------------------------------------- text_styles = { 'left': wx.TE_LEFT, 'center': wx.TE_CENTRE, 'right': wx.TE_RIGHT } #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ factory = self.factory # Establish the range of the slider: low_name = high_name = '' low, high = factory.low, factory.high if high <= low: low = high = None handler = self.object.trait( self.name ).handler if isinstance( handler, BaseRange ): low_name, high_name = handler._low_name, handler._high_name if low_name == '': low = handler._low if high_name == '': high = handler._high elif isinstance( handler, BaseEnum ): if handler.name == '': self.mapping = handler.values else: self.sync_value( handler.name, 'mapping', 'from' ) low, high = 0, self.high # Create the control: self.control = control = wx.Window( parent, -1, size = wx.Size( 50, 18 ), style = wx.FULL_REPAINT_ON_RESIZE | wx.TAB_TRAVERSAL ) # Set up the painting event handlers: wx.EVT_ERASE_BACKGROUND( control, self._erase_background ) wx.EVT_PAINT( control, self._on_paint ) wx.EVT_SET_FOCUS( control, self._set_focus ) # Set up mouse event handlers: wx.EVT_LEAVE_WINDOW( control, self._leave_window ) wx.EVT_ENTER_WINDOW( control, self._enter_window ) wx.EVT_LEFT_DOWN( control, self._left_down ) wx.EVT_LEFT_UP( control, self._left_up ) wx.EVT_MOTION( control, self._motion ) wx.EVT_MOUSEWHEEL( control, self._mouse_wheel ) # Set up the control resize handler: wx.EVT_SIZE( control, self._resize ) # Set the tooltip: self._can_set_tooltip = (not self.set_tooltip()) # Save the values we calculated: self.set( low = low, high = high ) self.sync_value( low_name, 'low', 'from' ) self.sync_value( high_name, 'high', 'from' ) # Force a reset (in case low = high = None, which won't cause a # notification to fire): self._reset_scrubber() #--------------------------------------------------------------------------- # Disposes of the contents of an editor: #--------------------------------------------------------------------------- def dispose ( self ): """ Disposes of the contents of an editor. """ # Remove all of the wx event handlers: disconnect_no_id( self.control, wx.EVT_ERASE_BACKGROUND, wx.EVT_PAINT, wx.EVT_SET_FOCUS, wx.EVT_LEAVE_WINDOW, wx.EVT_ENTER_WINDOW, wx.EVT_LEFT_DOWN, wx.EVT_LEFT_UP, wx.EVT_MOTION, wx.EVT_MOUSEWHEEL, wx.EVT_SIZE ) # Disconnect the pop-up text event handlers: self._disconnect_text() super( _ScrubberEditor, self ).dispose() #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ self.text = self.string_value( self.value ) self._text_size = None self._refresh() self._enum_completed() #--------------------------------------------------------------------------- # Updates the object when the scrubber value changes: #--------------------------------------------------------------------------- def update_object ( self, value ): """ Updates the object when the scrubber value changes. """ if self.mapping is not None: value = self.mapping[ int( value ) ] if value != self.value: try: self.value = value self.update_editor() except TraitError: value = int( value ) if value != self.value: self.value = value self.update_editor() #--------------------------------------------------------------------------- # Handles an error that occurs while setting the object's trait value: #--------------------------------------------------------------------------- def error ( self, excp ): """ Handles an error that occurs while setting the object's trait value. """ pass #-- Trait Event Handlers --------------------------------------------------- def _mapping_changed ( self, mapping ): """ Handles the Enum mapping being changed. """ self.high = len( mapping ) - 1 #-- Private Methods -------------------------------------------------------- @on_trait_change( 'low, high' ) def _reset_scrubber ( self ): """ Sets the the current tooltip. """ low, high = self.low, self.high if self._can_set_tooltip: if self.mapping is not None: tooltip = '[%s]' % (', '.join( self.mapping )) if len( tooltip ) > 80: tooltip = '' elif high is None: tooltip = '' if low is not None: tooltip = '[%g..]' % low elif low is None: tooltip = '[..%g]' % high else: tooltip = '[%g..%g]' % ( low, high ) self.control.SetToolTipString( tooltip ) # Establish the slider increment: increment = self.factory.increment if increment <= 0.0: if (low is None) or (high is None) or isinstance( low, int ): increment = 1.0 else: increment = pow( 10, round( log10( (high - low) / 100.0 ) ) ) self.increment = increment self.update_editor() def _get_text_bounds ( self ): """ Get the window bounds of where the current text should be displayed. """ tdx, tdy, descent, leading = self._get_text_size() wdx, wdy = self.control.GetClientSizeTuple() ty = ((wdy - (tdy - descent)) / 2) - 1 alignment = self.factory.alignment if alignment == 'left': tx = 0 elif alignment == 'center': tx = (wdx - tdx) / 2 else: tx = wdx - tdx return ( tx, ty, tdx, tdy ) def _get_text_size ( self ): """ Returns the text size information for the window. """ if self._text_size is None: self._text_size = self.control.GetFullTextExtent( self.text.strip() or 'M' ) return self._text_size def _refresh ( self ): """ Refreshes the contents of the control. """ if self.control is not None: self.control.Refresh() def _set_scrubber_position ( self, event, delta ): """ Calculates a new scrubber value for a specified mouse position change. """ clicks = 3 increment = self.increment if event.ShiftDown(): increment *= 10.0 clicks = 7 elif event.ControlDown(): increment /= 10.0 value = self._value + (delta / clicks) * increment if self.low is not None: value = max( value, self.low ) if self.high is not None: value = min( value, self.high ) self.update_object( value ) def _delayed_click ( self ): """ Handle a delayed click response. """ self._pending = False def _pop_up_editor ( self ): """ Pop-up a text control to allow the user to enter a value using the keyboard. """ self.control.SetCursor( wx.StockCursor( wx.CURSOR_ARROW ) ) if self.mapping is not None: self._pop_up_enum() else: self._pop_up_text() def _pop_up_enum ( self ): self._ui = self.object.edit_traits( view = View( Item( self.name, id = 'drop_down', show_label = False, padding = -4, editor = EnumEditor( name = 'editor.mapping' ) ), kind = 'subpanel' ), parent = self.control, context = { 'object': self.object, 'editor': self } ) dx, dy = self.control.GetSizeTuple() drop_down = self._ui.info.drop_down.control drop_down.SetDimensions( 0, 0, dx, dy ) drop_down.SetFocus() wx.EVT_KILL_FOCUS( drop_down, self._enum_completed ) def _pop_up_text ( self ): control = self.control self._text = text = wx.TextCtrl( control, -1, str( self.value ), size = control.GetSize(), style = self.text_styles[ self.factory.alignment ] | wx.TE_PROCESS_ENTER ) text.SetSelection( -1, -1 ) text.SetFocus() wx.EVT_TEXT_ENTER( control, text.GetId(), self._text_completed ) wx.EVT_KILL_FOCUS( text, self._text_completed ) wx.EVT_ENTER_WINDOW( text, self._enter_text ) wx.EVT_LEAVE_WINDOW( text, self._leave_text ) wx.EVT_CHAR( text, self._key_entered ) def _destroy_text ( self ): """ Destroys the current text control. """ self._ignore_focus = self._in_text_window self._disconnect_text() self.control.DestroyChildren() self._text = None def _disconnect_text ( self ): """ Disconnects the event handlers for the pop up text editor. """ if self._text is not None: disconnect( self._text, wx.EVT_TEXT_ENTER ) disconnect_no_id( self._text, wx.EVT_KILL_FOCUS, wx.EVT_ENTER_WINDOW, wx.EVT_LEAVE_WINDOW, wx.EVT_CHAR ) def _init_value ( self ): """ Initializes the current value when the user begins a drag or moves the mouse wheel. """ if self.mapping is not None: try: self._value = list( self.mapping ).index( self.value ) except: self._value = 0 else: self._value = self.value #--- wxPython Event Handlers ----------------------------------------------- def _erase_background ( self, event ): """ Do not erase the background here (do it in the 'on_paint' handler). """ pass def _on_paint ( self, event ): """ Paint the background using the associated ImageSlice object. """ control = self.control dc = BufferDC( control ) # Draw the background: factory = self.factory color = factory.color_ if self._x is not None: if factory.active_color_ is not None: color = factory.active_color_ elif self._hover: if factory.hover_color_ is not None: color = factory.hover_color_ if color is None: paint_parent( dc, control ) brush = wx.TRANSPARENT_BRUSH else: brush = wx.Brush( color ) color = factory.border_color_ if color is not None: pen = wx.Pen( color ) else: pen = wx.TRANSPARENT_PEN if (pen != wx.TRANSPARENT_PEN) or (brush != wx.TRANSPARENT_BRUSH): wdx, wdy = control.GetClientSizeTuple() dc.SetBrush( brush ) dc.SetPen( pen ) dc.DrawRectangle( 0, 0, wdx, wdy ) # Draw the current text value: dc.SetBackgroundMode( wx.TRANSPARENT ) dc.SetTextForeground( factory.text_color_ ) dc.SetFont( control.GetFont() ) tx, ty, tdx, tdy = self._get_text_bounds() dc.DrawText( self.text, tx, ty ) # Copy the buffer contents to the display: dc.copy() def _resize ( self, event ): """ Handles the control being resized. """ if self._text is not None: self._text.SetSize( self.control.GetSize() ) def _set_focus ( self, event ): """ Handle the control getting the keyboard focus. """ if ((not self._ignore_focus) and (self._x is None) and (self._text is None)): self._pop_up_editor() event.Skip() def _enter_window ( self, event ): """ Handles the mouse entering the window. """ self._hover = True self.control.SetCursor( wx.StockCursor( wx.CURSOR_HAND ) ) if not self._ignore_focus: self._ignore_focus = True self.control.SetFocus() self._ignore_focus = False if self._x is not None: if self.factory.active_color_ != self.factory.color_: self.control.Refresh() elif self.factory.hover_color_ != self.factory.color_: self.control.Refresh() def _leave_window ( self, event ): """ Handles the mouse leaving the window. """ self._hover = False if self.factory.hover_color_ != self.factory.color_: self.control.Refresh() def _left_down ( self, event ): """ Handles the left mouse being pressed. """ self._x, self._y = event.GetX(), event.GetY() self._pending = True self._init_value() self.control.CaptureMouse() if self.factory.active_color_ != self.factory.hover_color_: self.control.Refresh() do_after( 200, self._delayed_click ) def _left_up ( self, event ): """ Handles the left mouse button being released. """ self.control.ReleaseMouse() if self._pending: self._pop_up_editor() self._x = self._y = self._value = self._pending = None if self._hover or (self.factory.active_color_ != self.factory.color_): self.control.Refresh() def _motion ( self, event ): """ Handles the mouse moving. """ if self._x is not None: x, y = event.GetX(), event.GetY() dx = x - self._x adx = abs( dx ) dy = y - self._y ady = abs( dy ) if self._pending: if (adx + ady) < 3: return self._pending = False if adx > ady: delta = dx else: delta = -dy self._set_scrubber_position( event, delta ) def _mouse_wheel ( self, event ): """ Handles the mouse wheel moving. """ if self._hover: self._init_value() clicks = 3 if event.ShiftDown(): clicks = 7 delta = clicks * (event.GetWheelRotation() / event.GetWheelDelta()) self._set_scrubber_position( event, delta ) def _update_value ( self, event ): """ Updates the object value from the current text control value. """ control = event.GetEventObject() try: self.update_object( float( control.GetValue() ) ) return True except TraitError: control.SetBackgroundColour( ErrorColor ) control.Refresh() return False def _enter_text ( self, event ): """ Handles the mouse entering the pop-up text control. """ self._in_text_window = True def _leave_text ( self, event ): """ Handles the mouse leaving the pop-up text control. """ self._in_text_window = False def _text_completed ( self, event ): """ Handles the user pressing the 'Enter' key in the text control. """ if self._update_value( event ): self._destroy_text() def _enum_completed ( self, event = None ): """ Handles the Enum drop-down control losing focus. """ if self._ui is not None: self._ignore_focus = True disconnect_no_id( self._ui.info.drop_down.control, wx.EVT_KILL_FOCUS ) self._ui.dispose() del self._ui def _key_entered ( self, event ): """ Handles individual key strokes while the text control is active. """ key_code = event.GetKeyCode() if key_code == wx.WXK_ESCAPE: self._destroy_text() return if key_code == wx.WXK_TAB: if self._update_value( event ): if event.ShiftDown(): self.control.Navigate( 0 ) else: self.control.Navigate() return event.Skip() traitsui-4.1.0/traitsui/wx/toolkit.py0000644000175100001440000006671011674463546020734 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/13/2004 # #------------------------------------------------------------------------------ """ Defines the concrete implementations of the traits Toolkit interface for the wxPython user interface toolkit. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- # Make sure that importimg from this backend is OK: from traitsui.toolkit import assert_toolkit_import assert_toolkit_import('wx') import wx # Make sure a wx.App object is created early: _app = wx.GetApp() if _app is None: _app = wx.PySimpleApp() from traits.api \ import HasPrivateTraits, Instance, Property, Category, cached_property from traits.trait_notifiers \ import set_ui_handler from traitsui.ui \ import UI from traitsui.theme \ import Theme from traitsui.dock_window_theme \ import DockWindowTheme from traitsui.toolkit \ import Toolkit from pyface.wx.drag_and_drop \ import PythonDropTarget from constants \ import WindowColor, screen_dx, screen_dy from helper \ import position_window #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- EventSuffix = { wx.wxEVT_LEFT_DOWN: 'left_down', wx.wxEVT_LEFT_DCLICK: 'left_dclick', wx.wxEVT_LEFT_UP: 'left_up', wx.wxEVT_MIDDLE_DOWN: 'middle_down', wx.wxEVT_MIDDLE_DCLICK: 'middle_dclick', wx.wxEVT_MIDDLE_UP: 'middle_up', wx.wxEVT_RIGHT_DOWN: 'right_down', wx.wxEVT_RIGHT_DCLICK: 'right_dclick', wx.wxEVT_RIGHT_UP: 'right_up', wx.wxEVT_MOTION: 'mouse_move', wx.wxEVT_ENTER_WINDOW: 'enter', wx.wxEVT_LEAVE_WINDOW: 'leave', wx.wxEVT_MOUSEWHEEL: 'mouse_wheel', wx.wxEVT_PAINT: 'paint', } # Types of popup views: Popups = set( ( 'popup', 'popover', 'info' ) ) #------------------------------------------------------------------------------- # Handles UI notification handler requests that occur on a thread other than # the UI thread: #------------------------------------------------------------------------------- def ui_handler ( handler, *args ): """ Handles UI notification handler requests that occur on a thread other than the UI thread. """ wx.CallAfter( handler, *args ) # Tell the traits notification handlers to use this UI handler set_ui_handler( ui_handler ) #------------------------------------------------------------------------------- # 'GUIToolkit' class: #------------------------------------------------------------------------------- class GUIToolkit ( Toolkit ): """ Implementation class for wxPython toolkit. """ #--------------------------------------------------------------------------- # Create wxPython specific user interfaces using information from the # specified UI object: #--------------------------------------------------------------------------- def ui_panel ( self, ui, parent ): """ Creates a wxPython panel-based user interface using information from the specified UI object. """ import ui_panel ui_panel.ui_panel( ui, parent ) def ui_subpanel ( self, ui, parent ): """ Creates a wxPython subpanel-based user interface using information from the specified UI object. """ import ui_panel ui_panel.ui_subpanel( ui, parent ) def ui_livemodal ( self, ui, parent ): """ Creates a wxPython modal "live update" dialog user interface using information from the specified UI object. """ import ui_live ui_live.ui_livemodal( ui, parent ) def ui_live ( self, ui, parent ): """ Creates a wxPython non-modal "live update" window user interface using information from the specified UI object. """ import ui_live ui_live.ui_live( ui, parent ) def ui_modal ( self, ui, parent ): """ Creates a wxPython modal dialog user interface using information from the specified UI object. """ import ui_modal ui_modal.ui_modal( ui, parent ) def ui_nonmodal ( self, ui, parent ): """ Creates a wxPython non-modal dialog user interface using information from the specified UI object. """ import ui_modal ui_modal.ui_nonmodal( ui, parent ) def ui_popup ( self, ui, parent ): """ Creates a wxPython temporary "live update" popup dialog user interface using information from the specified UI object. """ import ui_live ui_live.ui_popup( ui, parent ) def ui_popover ( self, ui, parent ): """ Creates a wxPython temporary "live update" popup dialog user interface using information from the specified UI object. """ import ui_live ui_live.ui_popover( ui, parent ) def ui_info ( self, ui, parent ): """ Creates a wxPython temporary "live update" popup dialog user interface using information from the specified UI object. """ import ui_live ui_live.ui_info( ui, parent ) def ui_wizard ( self, ui, parent ): """ Creates a wxPython wizard dialog user interface using information from the specified UI object. """ import ui_wizard ui_wizard.ui_wizard( ui, parent ) def view_application ( self, context, view, kind = None, handler = None, id = '', scrollable = None, args = None ): """ Creates a wxPython modal dialog user interface that runs as a complete application, using information from the specified View object. Parameters ---------- context : object or dictionary A single object or a dictionary of string/object pairs, whose trait attributes are to be edited. If not specified, the current object is used. view : view or string A View object that defines a user interface for editing trait attribute values. kind : string The type of user interface window to create. See the **traitsui.view.kind_trait** trait for values and their meanings. If *kind* is unspecified or None, the **kind** attribute of the View object is used. handler : Handler object A handler object used for event handling in the dialog box. If None, the default handler for Traits UI is used. id : string A unique ID for persisting preferences about this user interface, such as size and position. If not specified, no user preferences are saved. scrollable : Boolean Indicates whether the dialog box should be scrollable. When set to True, scroll bars appear on the dialog box if it is not large enough to display all of the items in the view at one time. """ import view_application return view_application.view_application( context, view, kind, handler, id, scrollable, args ) #--------------------------------------------------------------------------- # Positions the associated dialog window on the display: #--------------------------------------------------------------------------- def position ( self, ui ): """ Positions the associated dialog window on the display. """ view = ui.view window = ui.control # Set up the default position of the window: parent = window.GetParent() if parent is None: px, py = 0, 0 pdx, pdy = screen_dx, screen_dy else: px, py = parent.GetPositionTuple() pdx, pdy = parent.GetSizeTuple() # Calculate the correct width and height for the window: cur_width, cur_height = window.GetSizeTuple() width = view.width height = view.height if width < 0.0: width = cur_width elif width <= 1.0: width = int( width * screen_dx ) else: width = int( width ) if height < 0.0: height = cur_height elif height <= 1.0: height = int( height * screen_dy ) else: height = int( height ) if view.kind in Popups: position_window( window, width, height ) return # Calculate the correct position for the window: x = view.x y = view.y if x < -99999.0: # BH- I think this is the case when there is a parent # so this logic tries to place it in the middle of the parent # if possible, otherwise tries an offset from the parent x = px + (pdx - width)/2 if x < 0: x = px + 20 elif x <= -1.0: x = px + pdx - width + int( x ) + 1 elif x < 0.0: x = px + pdx - width + int( x * pdx ) elif x <= 1.0: x = px + int( x * pdx ) else: x = int( x ) if y < -99999.0: # BH- I think this is the case when there is a parent # so this logic tries to place it in the middle of the parent # if possible, otherwise tries an offset from the parent y = py + (pdy - height)/2 if y < 0: y = py + 20 elif y <= -1.0: y = py + pdy - height + int( y ) + 1 elif x < 0.0: y = py + pdy - height + int( y * pdy ) elif y <= 1.0: y = py + int( y * pdy ) else: y = int( y ) # make sure the position is on the visible screen, maybe # the desktop had been resized? x = min(x, wx.DisplaySize()[0]) y = min(y, wx.DisplaySize()[1]) # Position and size the window as requested: window.SetDimensions( max( 0, x ), max( 0, y ), width, height ) #--------------------------------------------------------------------------- # Shows a 'Help' window for a specified UI and control: #--------------------------------------------------------------------------- def show_help ( self, ui, control ): """ Shows a help window for a specified UI and control. """ import ui_panel ui_panel.show_help( ui, control ) #--------------------------------------------------------------------------- # Saves user preference information associated with a UI window: #--------------------------------------------------------------------------- def save_window ( self, ui ): """ Saves user preference information associated with a UI window. """ import helper helper.save_window( ui ) #--------------------------------------------------------------------------- # Rebuilds a UI after a change to the content of the UI: #--------------------------------------------------------------------------- def rebuild_ui ( self, ui ): """ Rebuilds a UI after a change to the content of the UI. """ parent = size = None if ui.control is not None: size = ui.control.GetSize() parent = ui.control._parent info = ui.info ui.recycle() ui.info= info info.ui = ui ui.rebuild( ui, parent ) if parent is not None: ui.control.SetSize( size ) sizer = parent.GetSizer() if sizer is not None: sizer.Add( ui.control, 1, wx.EXPAND ) #--------------------------------------------------------------------------- # Sets the title for the UI window: #--------------------------------------------------------------------------- def set_title ( self, ui ): """ Sets the title for the UI window. """ ui.control.SetTitle( ui.title ) #--------------------------------------------------------------------------- # Sets the icon for the UI window: #--------------------------------------------------------------------------- def set_icon ( self, ui ): """ Sets the icon for the UI window. """ from pyface.image_resource import ImageResource if isinstance( ui.icon, ImageResource ): ui.control.SetIcon( ui.icon.create_icon() ) #--------------------------------------------------------------------------- # Converts a keystroke event into a corresponding key name: #--------------------------------------------------------------------------- def key_event_to_name ( self, event ): """ Converts a keystroke event into a corresponding key name. """ import key_event_to_name return key_event_to_name.key_event_to_name( event ) #--------------------------------------------------------------------------- # Hooks all specified events for all controls in a ui so that they can be # routed to the correct event handler: #--------------------------------------------------------------------------- def hook_events ( self, ui, control, events = None, handler = None, drop_target = None ): """ Hooks all specified events for all controls in a UI so that they can be routed to the correct event handler. """ if events is None: events = ( wx.wxEVT_LEFT_DOWN, wx.wxEVT_LEFT_DCLICK, wx.wxEVT_LEFT_UP, wx.wxEVT_MIDDLE_DOWN, wx.wxEVT_MIDDLE_DCLICK, wx.wxEVT_MIDDLE_UP, wx.wxEVT_RIGHT_DOWN, wx.wxEVT_RIGHT_DCLICK, wx.wxEVT_RIGHT_UP, wx.wxEVT_MOTION, wx.wxEVT_ENTER_WINDOW, wx.wxEVT_LEAVE_WINDOW, wx.wxEVT_MOUSEWHEEL, wx.wxEVT_PAINT ) control.SetDropTarget( PythonDropTarget( DragHandler( ui = ui, control = control ) ) ) elif events == 'keys': events = ( wx.wxEVT_CHAR, ) if handler is None: handler = ui.route_event id = control.GetId() event_handler = wx.EvtHandler() connect = event_handler.Connect for event in events: connect( id, id, event, handler ) control.PushEventHandler( event_handler ) for child in control.GetChildren(): self.hook_events( ui, child, events, handler, drop_target ) #--------------------------------------------------------------------------- # Routes a 'hooked' event to the correct handler method: #--------------------------------------------------------------------------- def route_event ( self, ui, event ): """ Routes a hooked event to the correct handler method. """ suffix = EventSuffix[ event.GetEventType() ] control = event.GetEventObject() handler = ui.handler method = None owner = getattr( control, '_owner', None ) if owner is not None: method = getattr( handler, 'on_%s_%s' % ( owner.get_id(), suffix ), None ) if method is None: method = (getattr( handler, 'on_%s' % suffix, None ) or getattr( handler, 'on_any_event', None )) if (method is None) or (method( ui.info, owner, event ) is False): event.Skip() #--------------------------------------------------------------------------- # Indicates that an event should continue to be processed by the toolkit #--------------------------------------------------------------------------- def skip_event ( self, event ): """ Indicates that an event should continue to be processed by the toolkit. """ event.Skip() #--------------------------------------------------------------------------- # Destroys a specified GUI toolkit control: #--------------------------------------------------------------------------- def destroy_control ( self, control ): """ Destroys a specified GUI toolkit control. """ control.Destroy() #--------------------------------------------------------------------------- # Destroys all of the child controls of a specified GUI toolkit control: #--------------------------------------------------------------------------- def destroy_children ( self, control ): """ Destroys all of the child controls of a specified GUI toolkit control. """ control.DestroyChildren() #--------------------------------------------------------------------------- # Returns a ( width, height ) tuple containing the size of a specified # toolkit image: #--------------------------------------------------------------------------- def image_size ( self, image ): """ Returns a ( width, height ) tuple containing the size of a specified toolkit image. """ return ( image.GetWidth(), image.GetHeight() ) #--------------------------------------------------------------------------- # Returns a dictionary of useful constants: #--------------------------------------------------------------------------- def constants ( self ): """ Returns a dictionary of useful constants. Currently, the dictionary should have the following key/value pairs: - WindowColor': the standard window background color in the toolkit specific color format. """ return { 'WindowColor': WindowColor } #--------------------------------------------------------------------------- # Returns a renderer used to render 'themed' table cells for a specified # TableColumn object: #--------------------------------------------------------------------------- def themed_cell_renderer ( self, column ): """ Returns a renderer used to render 'themed' table cells for a specified TableColum object. """ from themed_cell_renderer import ThemedCellRenderer return ThemedCellRenderer( column ) #--------------------------------------------------------------------------- # GUI toolkit dependent trait definitions: #--------------------------------------------------------------------------- def color_trait ( self, *args, **traits ): import color_trait as ct return ct.WxColor( *args, **traits ) def rgb_color_trait ( self, *args, **traits ): import rgb_color_trait as rgbct return rgbct.RGBColor( *args, **traits ) def font_trait ( self, *args, **traits ): import font_trait as ft return ft.WxFont( *args, **traits ) #--------------------------------------------------------------------------- # 'Editor' class methods: #--------------------------------------------------------------------------- # Generic UI-base editor: def ui_editor ( self ): import ui_editor return ui_editor.UIEditor # # # Drag and drop: # def dnd_editor ( self, *args, **traits ): # import dnd_editor as dnd # return dnd.ToolkitEditorFactory( *args, **traits) # # # Key Binding: # def key_binding_editor ( self, *args, **traits ): # import key_binding_editor as kbe # return kbe.ToolkitEditorFactory( *args, **traits ) # # # History: # def history_editor ( self, *args, **traits ): # import history_editor as he # return he.HistoryEditor( *args, **traits ) # # # HTML: # def html_editor ( self, *args, **traits ): # import html_editor as he # return he.ToolkitEditorFactory( *args, **traits ) # # # Image: # def image_editor ( self, *args, **traits ): # import image_editor as ie # return ie.ImageEditor( *args, **traits ) # # # ListStr: # def list_str_editor ( self, *args, **traits ): # import list_str_editor as lse # return lse.ListStrEditor( *args, **traits ) # # # Ordered set: # def ordered_set_editor ( self, *args, **traits ): # import ordered_set_editor as ose # return ose.ToolkitEditorFactory( *args, **traits ) # # # Plot: # def plot_editor ( self, *args, **traits ): # import plot_editor as pe # return pe.ToolkitEditorFactory( *args, **traits ) # # # Popup: # def popup_editor ( self, *args, **traits ): # import popup_editor as pe # return pe.PopupEditor( *args, **traits ) # # # RGB Color: # def rgb_color_editor ( self, *args, **traits ): # import rgb_color_editor as rgbce # return rgbce.ToolkitEditorFactory( *args, **traits ) # # # Scrubber: # def scrubber_editor ( self, *args, **traits ): # import scrubber_editor as se # return se.ScrubberEditor( *args, **traits ) # # # Shell: def shell_editor ( self, *args, **traits ): import shell_editor as se return se.ToolkitEditorFactory( *args, **traits ) # # # Tabular: # def tabular_editor ( self, *args, **traits ): # import tabular_editor as te # return te.TabularEditor( *args, **traits ) # # # Value: # def value_editor ( self, *args, **traits ): # import value_editor as ve # return ve.ToolkitEditorFactory( *args, **traits ) #------------------------------------------------------------------------------- # 'DragHandler' class: #------------------------------------------------------------------------------- class DragHandler ( HasPrivateTraits ): """ Handler for drag events. """ #--------------------------------------------------------------------------- # Traits definitions: #--------------------------------------------------------------------------- # The UI associated with the drag handler ui = Instance( UI ) # The wx control associated with the drag handler control = Instance( wx.Window ) #-- Drag and drop event handlers: ---------------------------------------------- #--------------------------------------------------------------------------- # Handles a Python object being dropped on the control: #--------------------------------------------------------------------------- def wx_dropped_on ( self, x, y, data, drag_result ): """ Handles a Python object being dropped on the window. """ return self._drag_event( 'dropped_on', x, y, data, drag_result ) #--------------------------------------------------------------------------- # Handles a Python object being dragged over the control: #--------------------------------------------------------------------------- def wx_drag_over ( self, x, y, data, drag_result ): """ Handles a Python object being dragged over the tree. """ return self._drag_event( 'drag_over', x, y, data, drag_result ) #--------------------------------------------------------------------------- # Handles a dragged Python object leaving the window: #--------------------------------------------------------------------------- def wx_drag_leave ( self, data ): """ Handles a dragged Python object leaving the window. """ return self._drag_event( 'drag_leave' ) #--------------------------------------------------------------------------- # Handles routing a drag event to the appropriate handler: #--------------------------------------------------------------------------- def _drag_event ( self, suffix, x = None, y = None, data = None, drag_result = None ): """ Handles routing a drag event to the appropriate handler. """ control = self.control handler = self.ui.handler method = None owner = getattr( control, '_owner', None ) if owner is not None: method = getattr( handler, 'on_%s_%s' % ( owner.get_id(), suffix ), None ) if method is None: method = getattr( handler, 'on_%s' % suffix, None ) if method is None: return wx.DragNone if x is None: result = method( self.ui.info, owner ) else: result = method( self.ui.info, owner, x, y, data, drag_result ) if result is None: result = drag_result return result #------------------------------------------------------------------------------- # Defines the extensions needed to make the generic Theme class specific to # wxPython: #------------------------------------------------------------------------------- class WXTheme ( Category, Theme ): """ Defines the extensions needed to make the generic Theme class specific to wxPython. """ # The color to use for content text: content_color = Property # The color to use for label text: label_color = Property # The image slice used to draw the theme: image_slice = Property( depends_on = 'image' ) #-- Property Implementations ----------------------------------------------- def _get_content_color ( self ): if self._content_color is None: color = wx.BLACK islice = self.image_slice if islice is not None: color = islice.content_color self._content_color = color return self._content_color def _set_content_color ( self, color ): self._content_color = color def _get_label_color ( self ): if self._label_color is None: color = wx.BLACK islice = self.image_slice if islice is not None: color = islice.label_color self._label_color = color return self._label_color def _set_label_color ( self, color ): self._label_color = color @cached_property def _get_image_slice ( self ): from image_slice import image_slice_for if self.image is None: return None return image_slice_for( self.image ) #------------------------------------------------------------------------------- # Defines the extensions needed to make the generic DockWindowTheme class # specific to wxPython: #------------------------------------------------------------------------------- class WXDockWindowTheme ( Category, DockWindowTheme ): """ Defines the extensions needed to make the generic DockWindowTheme class specific to wxPython. """ # The bitmap for the 'tab_inactive_edge' image: tab_inactive_edge_bitmap = Property( depends_on = 'tab_inactive_edge' ) # The bitmap for the 'tab_hover_edge' image: tab_hover_edge_bitmap = Property( depends_on = 'tab_hover_edge' ) #-- Property Implementations ----------------------------------------------- @cached_property def _get_tab_inactive_edge_bitmap ( self ): image = self.tab_inactive_edge if image is None: return None return image.create_image().ConvertToBitmap() @cached_property def _get_tab_hover_edge_bitmap ( self ): image = self.tab_hover_edge if image is None: return self.tab_inactive_edge_bitmap return image.create_image().ConvertToBitmap() traitsui-4.1.0/traitsui/wx/basic_editor_factory.py0000644000175100001440000000306711674463546023421 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2008, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/21/2004 # #------------------------------------------------------------------------------ ## Deprecated proxy for the BasicEditorFactory class declared in # traitsui, declared here just for backward compatibility. import warnings from traitsui.basic_editor_factory \ import BasicEditorFactory as AbstractBasicEditorFactory #------------------------------------------------------------------------------- # 'BasicEditorFactory' class # Deprecated alias for traitsui.editor_factory.EditorFactory #------------------------------------------------------------------------------- class BasicEditorFactory(AbstractBasicEditorFactory): """ Deprecated alias for traitsui.basic_editor_factory.BasicEditorFactory. """ def __init__(self, *args, **kwds): super(BasicEditorFactory, self).__init__(*args, **kwds) warnings.warn("DEPRECATED: Use traitsui.basic_editor_factory" ".BasicEditorFactory instead.", DeprecationWarning) #---EOF------------------------------------------------------------------------- traitsui-4.1.0/traitsui/wx/rgb_color_editor.py0000644000175100001440000000707511674463546022564 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 11/22/2004 # #------------------------------------------------------------------------------ """ Defines a subclass of the base wxPython color editor factory, for colors that are represented as tuples of the form ( *red*, *green*, *blue* ), where *red*, *green* and *blue* are floats in the range from 0.0 to 1.0. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx from traits.trait_base \ import SequenceTypes # Note: The ToolkitEditorFactory class imported from color_editor is the # abstract ToolkitEditorFactory class (in traitsui.api) along with # wx-specific methods added via a category. We need to override the # implementations of the wx-specific methods here. from color_editor \ import ToolkitEditorFactory as BaseColorToolkitEditorFactory #--------------------------------------------------------------------------- # The wxPython ToolkitEditorFactory class. #--------------------------------------------------------------------------- class ToolkitEditorFactory(BaseColorToolkitEditorFactory): """ wxPython editor factory for color editors. """ #--------------------------------------------------------------------------- # Gets the wxPython color equivalent of the object: #--------------------------------------------------------------------------- def to_wx_color ( self, editor, color=None ): """ Gets the wxPython color equivalent of the object trait. """ if color is None: try: color = getattr( editor.object, editor.name + '_' ) except AttributeError: color = getattr( editor.object, editor.name ) if isinstance(color, tuple): return wx.Colour( int( color[0] * 255.0 ), int( color[1] * 255.0 ), int( color[2] * 255.0 ) ) return color #--------------------------------------------------------------------------- # Gets the application equivalent of a wxPython value: #--------------------------------------------------------------------------- def from_wx_color ( self, color ): """ Gets the application equivalent of a wxPython value. """ return ( color.Red() / 255.0, color.Green() / 255.0, color.Blue() / 255.0 ) #--------------------------------------------------------------------------- # Returns the text representation of a specified color value: #--------------------------------------------------------------------------- def str_color ( self, color ): """ Returns the text representation of a specified color value. """ if type( color ) in SequenceTypes: return "(%d,%d,%d)" % ( int( color[0] * 255.0 ), int( color[1] * 255.0 ), int( color[2] * 255.0 ) ) return super(ToolkitEditorFactory, self).str_color(color) traitsui-4.1.0/traitsui/wx/animated_gif_editor_28.py0000644000175100001440000000726111674463546023531 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2007, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 03/02/2007 # #------------------------------------------------------------------------------- """ Defines an editor for playing animated GIF files. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from wx.animate \ import Animation, AnimationCtrl from traits.api \ import Bool, Str from traitsui.wx.editor \ import Editor from traitsui.basic_editor_factory \ import BasicEditorFactory #------------------------------------------------------------------------------- # '_AnimatedGIFEditor' class: #------------------------------------------------------------------------------- class _AnimatedGIFEditor ( Editor ): """ Editor that displays an animated GIF file. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Is the animated GIF file currently playing? playing = Bool( True ) #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self._animate = Animation( self.value ) self.control = AnimationCtrl( parent, -1, self._animate ) self.control.SetUseWindowBackgroundColour() self.sync_value( self.factory.playing, 'playing', 'from' ) self.set_tooltip() #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ if not self.playing: self.control.Stop() self.control.LoadFile( self.value ) self._file_loaded = True if self.playing: self.control.Play() #--------------------------------------------------------------------------- # Handles the editor 'playing' trait being changed: #--------------------------------------------------------------------------- def _playing_changed ( self ): if self._file_loaded: if self.playing: self.control.Play() else: self.control.Stop() #------------------------------------------------------------------------------- # Create the editor factory object: #------------------------------------------------------------------------------- # wxPython editor factory for animated GIF editors: class AnimatedGIFEditor ( BasicEditorFactory ): # The editor class to be created: klass = _AnimatedGIFEditor # The optional trait used to control whether the animated GIF file is # playing or not: playing = Str traitsui-4.1.0/traitsui/wx/custom_editor.py0000644000175100001440000000556211674463546022125 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 07/19/2005 # #------------------------------------------------------------------------------ """ Defines the wxPython implementation of the editor used to wrap a non-Traits based custom control. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx # FIXME: ToolkitEditorFactory is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.custom_editor file. from traitsui.editors.custom_editor \ import ToolkitEditorFactory from editor \ import Editor from helper \ import open_fbi #------------------------------------------------------------------------------- # 'CustomEditor' class: #------------------------------------------------------------------------------- class CustomEditor ( Editor ): """ Wrapper for a custom editor control """ #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ factory = self.factory.factory if factory is not None: try: self.control = factory( *(( parent, self ) + self.factory.args ) ) except: open_fbi() if self.control is None: self.control = control = wx.StaticText( parent, -1, 'An error occurred creating a custom editor.\n' 'Please contact the developer.' ) control.SetBackgroundColour( wx.RED ) control.SetForegroundColour( wx.WHITE ) self.set_tooltip() #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ pass ### EOF ####################################################################### traitsui-4.1.0/traitsui/wx/tree_editor.py0000644000175100001440000024012611674463546021547 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 12/03/2004 # #------------------------------------------------------------------------------ """ Defines the tree editor for the wxPython user interface toolkit. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import os import wx import copy try: from pyface.wx.drag_and_drop import PythonDropSource, \ PythonDropTarget except: PythonDropSource = PythonDropTarget = None from pyface.resource_manager \ import resource_manager from pyface.image_list \ import ImageList from traits.api \ import HasStrictTraits, Any, Str, Event, TraitError from traits.trait_base \ import enumerate from traitsui.api \ import View, TreeNode, ObjectTreeNode, MultiTreeNode, Image # FIXME: ToolkitEditorFactory is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.tree_editor file. from traitsui.editors.tree_editor \ import ToolkitEditorFactory from traitsui.undo \ import ListUndoItem from traitsui.tree_node \ import ITreeNodeAdapterBridge from traitsui.tree_node \ import ITreeNodeAdapterBridge from traitsui.menu \ import Menu, Action, Separator from pyface.api \ import ImageResource from pyface.dock.api \ import DockWindow, DockSizer, DockSection, DockRegion, DockControl from constants \ import OKColor from editor \ import Editor from helper \ import open_fbi, TraitsUIPanel, TraitsUIScrolledPanel #------------------------------------------------------------------------------- # Global data: #------------------------------------------------------------------------------- # Paste buffer for copy/cut/paste operations paste_buffer = None #------------------------------------------------------------------------------- # The core tree node menu actions: #------------------------------------------------------------------------------- NewAction = 'NewAction' CopyAction = Action( name = 'Copy', action = 'editor._menu_copy_node', enabled_when = 'editor._is_copyable(object)' ) CutAction = Action( name = 'Cut', action = 'editor._menu_cut_node', enabled_when = 'editor._is_cutable(object)' ) PasteAction = Action( name = 'Paste', action = 'editor._menu_paste_node', enabled_when = 'editor._is_pasteable(object)' ) DeleteAction = Action( name = 'Delete', action = 'editor._menu_delete_node', enabled_when = 'editor._is_deletable(object)' ) RenameAction = Action( name = 'Rename', action = 'editor._menu_rename_node', enabled_when = 'editor._is_renameable(object)' ) #------------------------------------------------------------------------------- # 'SimpleEditor' class: #------------------------------------------------------------------------------- class SimpleEditor ( Editor ): """ Simple style of tree editor. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Is the tree editor is scrollable? This value overrides the default. scrollable = True # Allows an external agent to set the tree selection selection = Event # The currently selected object selected = Any # The event fired when a tree node is activated by double clicking or # pressing the enter key on a node. activated = Event # The event fired when a tree node is clicked on: click = Event # The event fired when a tree node is double-clicked on: dclick = Event # The event fired when the application wants to veto an operation: veto = Event #-- Private Traits --------------------------------------------------------- # An icon used by a TreeNode: _icon = Image #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ factory = self.factory style = self._get_style() if factory.editable: # Check to see if the tree view is based on a shared trait editor: if factory.shared_editor: factory_editor = factory.editor # If this is the editor that defines the trait editor panel: if factory_editor is None: # Remember which editor has the trait editor in the factory: factory._editor = self # Create the trait editor panel: self.control = TraitsUIPanel( parent, -1 ) self.control._node_ui = self.control._editor_nid = None # Check to see if there are any existing editors that are # waiting to be bound to the trait editor panel: editors = factory._shared_editors if editors is not None: for editor in factory._shared_editors: # If the editor is part of this UI: if editor.ui is self.ui: # Then bind it to the trait editor panel: editor._editor = self.control # Indicate all pending editors have been processed: factory._shared_editors = None # We only needed to build the trait editor panel, so exit: return # Check to see if the matching trait editor panel has been # created yet: editor = factory_editor._editor if (editor is None) or (editor.ui is not self.ui): # If not, add ourselves to the list of pending editors: shared_editors = factory_editor._shared_editors if shared_editors is None: factory_editor._shared_editors = shared_editors = [] shared_editors.append( self ) else: # Otherwise, bind our trait editor panel to the shared one: self._editor = editor.control # Finally, create only the tree control: self.control = self._tree = tree = wx.TreeCtrl( parent, -1, style = style ) else: # If editable, create a tree control and an editor panel: self._is_dock_window = True theme = factory.dock_theme or self.item.container.dock_theme self.control = splitter = DockWindow( parent, theme = theme ).control self._tree = tree = wx.TreeCtrl( splitter, -1, style = style ) self._editor = editor = TraitsUIScrolledPanel( splitter ) editor.SetSizer( wx.BoxSizer( wx.VERTICAL ) ) editor.SetScrollRate( 16, 16 ) editor.SetMinSize( wx.Size( 100, 100 ) ) self._editor._node_ui = self._editor._editor_nid = None item = self.item hierarchy_name = editor_name = '' style = 'fixed' name = item.label if name != '': hierarchy_name = name + ' Hierarchy' editor_name = name + ' Editor' style = item.dock splitter.SetSizer( DockSizer( contents = DockSection( contents = [ DockRegion( contents = [ DockControl( name = hierarchy_name, id = 'tree', control = tree, style = style ) ] ), DockRegion( contents = [ DockControl( name = editor_name, id = 'editor', control = self._editor, style = style ) ] ) ], is_row = (factory.orientation == 'horizontal') ) ) ) else: # Otherwise, just create the tree control: self.control = self._tree = tree = wx.TreeCtrl( parent, -1, style = style ) # Set up to show tree node icon (if requested): if factory.show_icons: self._image_list = ImageList( *factory.icon_size ) tree.AssignImageList( self._image_list ) # Set up the mapping between objects and tree id's: self._map = {} # Initialize the 'undo state' stack: self._undoable = [] # Get the tree control id: tid = tree.GetId() # Set up the mouse event handlers: wx.EVT_LEFT_DOWN( tree, self._on_left_down ) wx.EVT_RIGHT_DOWN( tree, self._on_right_down ) wx.EVT_LEFT_DCLICK(tree, self._on_left_dclick ) # Set up the tree event handlers: wx.EVT_TREE_ITEM_EXPANDING( tree, tid, self._on_tree_item_expanding ) wx.EVT_TREE_ITEM_EXPANDED( tree, tid, self._on_tree_item_expanded ) wx.EVT_TREE_ITEM_COLLAPSING( tree, tid, self._on_tree_item_collapsing ) wx.EVT_TREE_ITEM_COLLAPSED( tree, tid, self._on_tree_item_collapsed ) wx.EVT_TREE_ITEM_ACTIVATED( tree, tid, self._on_tree_item_activated ) wx.EVT_TREE_SEL_CHANGED( tree, tid, self._on_tree_sel_changed ) wx.EVT_TREE_BEGIN_DRAG( tree, tid, self._on_tree_begin_drag ) wx.EVT_TREE_BEGIN_LABEL_EDIT( tree, tid, self._on_tree_begin_label_edit) wx.EVT_TREE_END_LABEL_EDIT( tree, tid, self._on_tree_end_label_edit ) wx.EVT_TREE_ITEM_GETTOOLTIP( tree, tid, self._on_tree_item_gettooltip ) # Set up general mouse events wx.EVT_MOTION(tree, self._on_hover) # Synchronize external object traits with the editor: self.sync_value( factory.selected, 'selected' ) self.sync_value( factory.activated,'activated', 'to' ) self.sync_value( factory.click, 'click', 'to' ) self.sync_value( factory.dclick, 'dclick', 'to' ) self.sync_value( factory.veto, 'veto', 'from' ) # Set up the drag and drop target: if PythonDropTarget is not None: tree.SetDropTarget( PythonDropTarget( self ) ) #--------------------------------------------------------------------------- # Disposes of the contents of an editor: #--------------------------------------------------------------------------- def dispose ( self ): """ Disposes of the contents of an editor. """ tree = self._tree if tree is not None: id = tree.GetId() wx.EVT_LEFT_DOWN( tree, None ) wx.EVT_RIGHT_DOWN( tree, None ) wx.EVT_TREE_ITEM_EXPANDING( tree, id, None ) wx.EVT_TREE_ITEM_EXPANDED( tree, id, None ) wx.EVT_TREE_ITEM_COLLAPSING( tree, id, None ) wx.EVT_TREE_ITEM_COLLAPSED( tree, id, None ) wx.EVT_TREE_ITEM_ACTIVATED( tree, id, None ) wx.EVT_TREE_SEL_CHANGED( tree, id, None ) wx.EVT_TREE_BEGIN_DRAG( tree, id, None ) wx.EVT_TREE_BEGIN_LABEL_EDIT( tree, id, None ) wx.EVT_TREE_END_LABEL_EDIT( tree, id, None ) wx.EVT_TREE_ITEM_GETTOOLTIP( tree, id, None ) nid = self._tree.GetRootItem() if nid.IsOk(): self._delete_node( nid ) super( SimpleEditor, self ).dispose() #--------------------------------------------------------------------------- # Handles the 'selection' trait being changed: #--------------------------------------------------------------------------- def _selection_changed ( self, selection ): """ Handles the **selection** event. """ try: self._tree.SelectItem( self._object_info( selection )[2] ) except: pass #--------------------------------------------------------------------------- # Handles the 'selected' trait being changed: #--------------------------------------------------------------------------- def _selected_changed ( self, selected ): """ Handles the **selected** trait being changed. """ if not self._no_update_selected: self._selection_changed( selected ) #--------------------------------------------------------------------------- # Handles the 'veto' event being fired: #--------------------------------------------------------------------------- def _veto_changed ( self ): """ Handles the 'veto' event being fired. """ self._veto = True #--------------------------------------------------------------------------- # Returns the style settings used for displaying the wx tree: #--------------------------------------------------------------------------- def _get_style ( self ): """ Returns the style settings used for displaying the wx tree. """ factory = self.factory style = wx.TR_EDIT_LABELS | wx.TR_HAS_BUTTONS | wx.CLIP_CHILDREN # Turn lines off if explicit or for appearance on *nix: if ((factory.lines_mode == 'off') or ((factory.lines_mode == 'appearance') and (os.name == 'posix'))): style |= wx.TR_NO_LINES if factory.hide_root: style |= (wx.TR_HIDE_ROOT | wx.TR_LINES_AT_ROOT) if factory.selection_mode != 'single': style |= wx.TR_MULTIPLE | wx.TR_EXTENDED return style #--------------------------------------------------------------------------- # Handles the user entering input data in the edit control: #--------------------------------------------------------------------------- def update_object ( self, event ): """ Handles the user entering input data in the edit control. """ try: self.value = self._get_value() self.control.SetBackgroundColour( OKColor ) self.control.Refresh() except TraitError, excp: pass #--------------------------------------------------------------------------- # Saves the current 'expanded' state of all tree nodes: #--------------------------------------------------------------------------- def _save_state ( self ): tree = self._tree nid = tree.GetRootItem() state = {} if nid.IsOk(): nodes_to_do = [ nid ] while nodes_to_do: node = nodes_to_do.pop() data = self._get_node_data( node ) try: is_expanded = tree.IsExpanded( node ) except: is_expanded = True state[ hash( data[-1] ) ] = ( data[0], is_expanded ) for cnid in self._nodes( node ): nodes_to_do.append( cnid ) return state #--------------------------------------------------------------------------- # Restores the 'expanded' state of all tree nodes: #--------------------------------------------------------------------------- def _restore_state ( self, state ): if not state: return tree = self._tree nid = tree.GetRootItem() if nid.IsOk(): nodes_to_do = [ nid ] while nodes_to_do: node = nodes_to_do.pop() for cnid in self._nodes( node ): data = self._get_node_data( cnid ) key = hash( data[-1] ) if key in state: was_expanded, current_state = state[ key ] if was_expanded: self._expand_node( cnid ) if current_state: tree.Expand( cnid ) nodes_to_do.append( cnid ) #--------------------------------------------------------------------------- # Expands all nodes starting from the current selection: #--------------------------------------------------------------------------- def expand_all ( self ): """ Expands all nodes, starting from the selected node. """ tree = self._tree def _do_expand ( nid ): expanded, node, object = self._get_node_data( nid ) if self._has_children( node, object ): tree.SetItemHasChildren( nid, True ) self._expand_node( nid ) tree.Expand( nid ) nid = tree.GetSelection() if nid.IsOk(): nodes_to_do = [ nid ] while nodes_to_do: node = nodes_to_do.pop() _do_expand( node ) for n in self._nodes( node ): _do_expand( n ) nodes_to_do.append( n ) #--------------------------------------------------------------------------- # Expands from the specified node the specified number of sub-levels: #--------------------------------------------------------------------------- def expand_levels ( self, nid, levels, expand = True ): """ Expands from the specified node the specified number of sub-levels. """ if levels > 0: expanded, node, object = self._get_node_data( nid ) if self._has_children( node, object ): self._tree.SetItemHasChildren( nid, True ) self._expand_node( nid ) if expand: self._tree.Expand( nid ) for cnid in self._nodes( nid ): self.expand_levels( cnid, levels - 1 ) #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ tree = self._tree saved_state = {} if tree is not None: nid = tree.GetRootItem() if nid.IsOk(): self._delete_node( nid ) object, node = self._node_for( self.value ) if node is not None: icon = self._get_icon( node, object ) self._root_nid = nid = tree.AddRoot( node.get_label( object ), icon, icon ) self._map[ id( object ) ] = [ ( node.get_children_id( object ), nid ) ] self._add_listeners( node, object ) self._set_node_data( nid, ( False, node, object) ) if self.factory.hide_root or self._has_children( node, object ): tree.SetItemHasChildren( nid, True ) self._expand_node( nid ) if not self.factory.hide_root: tree.Expand( nid ) tree.SelectItem( nid ) self._on_tree_sel_changed() self.expand_levels( nid, self.factory.auto_open, False ) # It seems like in some cases, an explicit Refresh is needed to # trigger a screen update: tree.Refresh() # fixme: Clear the current editor (if any)... #--------------------------------------------------------------------------- # Returns the editor's control for indicating error status: #--------------------------------------------------------------------------- def get_error_control ( self ): """ Returns the editor's control for indicating error status. """ return self._tree #--------------------------------------------------------------------------- # Appends a new node to the specified node: #--------------------------------------------------------------------------- def _append_node ( self, nid, node, object ): """ Appends a new node to the specified node. """ return self._insert_node( nid, None, node, object ) #--------------------------------------------------------------------------- # Inserts a new node before a specified index into the children of the # specified node: #--------------------------------------------------------------------------- def _insert_node ( self, nid, index, node, object ): """ Inserts a new node before a specified index into the children of the specified node. """ tree = self._tree icon = self._get_icon( node, object ) label = node.get_label( object ) if index is None: cnid = tree.AppendItem( nid, label, icon, icon ) else: cnid = tree.InsertItemBefore( nid, index, label, icon, icon ) has_children = self._has_children( node, object ) tree.SetItemHasChildren( cnid, has_children ) self._set_node_data( cnid, ( False, node, object ) ) self._map.setdefault( id( object ), [] ).append( ( node.get_children_id( object ), cnid ) ) self._add_listeners( node, object ) # Automatically expand the new node (if requested): if has_children and node.can_auto_open( object ): tree.Expand( cnid ) # Return the newly created node: return cnid #--------------------------------------------------------------------------- # Deletes a specified tree node and all its children: #--------------------------------------------------------------------------- def _delete_node ( self, nid ): """ Deletes a specified tree node and all of its children. """ for cnid in self._nodes_for( nid ): self._delete_node( cnid ) expanded, node, object = self._get_node_data( nid ) id_object = id( object ) object_info = self._map[ id_object ] for i, info in enumerate( object_info ): if nid == info[1]: del object_info[i] break if len( object_info ) == 0: self._remove_listeners( node, object ) del self._map[ id_object ] # We set the '_locked' flag here because wx seems to generate a # 'node selected' event when the node is deleted. This can lead to # some bad side effects. So the 'node selected' event handler exits # immediately if the '_locked' flag is set: self._locked = True self._tree.Delete( nid ) self._locked = False # If the deleted node had an active editor panel showing, remove it: if (self._editor is not None) and (nid == self._editor._editor_nid): self._clear_editor() #--------------------------------------------------------------------------- # Expands the contents of a specified node (if required): #--------------------------------------------------------------------------- def _expand_node ( self, nid ): """ Expands the contents of a specified node (if required). """ expanded, node, object = self._get_node_data( nid ) # Lazily populate the item's children: if not expanded: for child in node.get_children( object ): child, child_node = self._node_for( child ) if child_node is not None: self._append_node( nid, child_node, child ) # Indicate the item is now populated: self._set_node_data( nid, ( True, node, object) ) #--------------------------------------------------------------------------- # Returns each of the child nodes of a specified node id: #--------------------------------------------------------------------------- def _nodes ( self, nid ): """ Returns each of the child nodes of a specified node. """ tree = self._tree cnid, cookie = tree.GetFirstChild( nid ) while cnid.IsOk(): yield cnid cnid, cookie = tree.GetNextChild( nid, cookie ) def _nodes_for ( self, nid ): """ Returns all child node ids of a specified node id. """ return [ cnid for cnid in self._nodes( nid ) ] #--------------------------------------------------------------------------- # Return the index of a specified node id within its parent: #--------------------------------------------------------------------------- def _node_index ( self, nid ): pnid = self._tree.GetItemParent( nid ) if not pnid.IsOk(): return ( None, None, None ) for i, cnid in enumerate( self._nodes( pnid ) ): if cnid == nid: ignore, pnode, pobject = self._get_node_data( pnid ) return ( pnode, pobject, i ) #--------------------------------------------------------------------------- # Returns whether a specified object has any children: #--------------------------------------------------------------------------- def _has_children ( self, node, object ): """ Returns whether a specified object has any children. """ return (node.allows_children( object ) and node.has_children( object )) #--------------------------------------------------------------------------- # Returns whether a given object is droppable on the node: #--------------------------------------------------------------------------- def _is_droppable ( self, node, object, add_object, for_insert ): """ Returns whether a given object is droppable on the node. """ if for_insert and (not node.can_insert( object )): return False return node.can_add( object, add_object ) #--------------------------------------------------------------------------- # Returns a droppable version of a specified object: #--------------------------------------------------------------------------- def _drop_object ( self, node, object, dropped_object, make_copy = True ): """ Returns a droppable version of a specified object. """ new_object = node.drop_object( object, dropped_object ) if (new_object is not dropped_object) or (not make_copy): return new_object return copy.deepcopy( new_object ) #--------------------------------------------------------------------------- # Returns the icon index for the specified object: #--------------------------------------------------------------------------- def _get_icon ( self, node, object, is_expanded = False ): """ Returns the index of the specified object icon. """ if self._image_list is None: return -1 icon_name = node.get_icon( object, is_expanded ) if isinstance( icon_name, basestring ): if icon_name[:1] == '@': self._icon = icon_name icon_name = self._icon else: if icon_name[:1] == '<': icon_name = icon_name[1:-1] path = self else: path = node.get_icon_path( object ) if isinstance( path, basestring ): path = [ path, node ] else: path.append( node ) reference = resource_manager.locate_image( icon_name, path ) if reference is None: return -1 file_name = reference.filename # If it is an ImageResource, get its file name directly: if isinstance( icon_name, ImageResource ): file_name = icon_name return self._image_list.GetIndex( file_name ) #--------------------------------------------------------------------------- # Adds the event listeners for a specified object: #--------------------------------------------------------------------------- def _add_listeners ( self, node, object ): """ Adds the event listeners for a specified object. """ if node.allows_children( object ): node.when_children_replaced( object, self._children_replaced, False) node.when_children_changed( object, self._children_updated, False) node.when_label_changed( object, self._label_updated, False ) #--------------------------------------------------------------------------- # Removes any event listeners from a specified object: #--------------------------------------------------------------------------- def _remove_listeners ( self, node, object ): """ Removes any event listeners from a specified object. """ if node.allows_children( object ): node.when_children_replaced( object, self._children_replaced, True ) node.when_children_changed( object, self._children_updated, True ) node.when_label_changed( object, self._label_updated, True ) #--------------------------------------------------------------------------- # Returns the tree node data for a specified object in the form # ( expanded, node, nid ): #--------------------------------------------------------------------------- def _object_info ( self, object, name = '' ): """ Returns the tree node data for a specified object in the form ( expanded, node, nid ). """ info = self._map[ id( object ) ] for name2, nid in info: if name == name2: break else: nid = info[0][1] expanded, node, ignore = self._get_node_data( nid ) return ( expanded, node, nid ) def _object_info_for ( self, object, name = '' ): """ Returns the tree node data for a specified object as a list of the form: [ ( expanded, node, nid ), ... ]. """ result = [] for name2, nid in self._map[ id( object ) ]: if name == name2: expanded, node, ignore = self._get_node_data( nid ) result.append( ( expanded, node, nid ) ) return result #--------------------------------------------------------------------------- # Returns the TreeNode associated with a specified object: #--------------------------------------------------------------------------- def _node_for ( self, object ): """ Returns the TreeNode associated with a specified object. """ if ((type( object ) is tuple) and (len( object ) == 2) and isinstance( object[1], TreeNode )): return object # Select all nodes which understand this object: factory = self.factory nodes = [ node for node in factory.nodes if object is not None and node.is_node_for( object ) ] # If only one found, we're done, return it: if len( nodes ) == 1: return ( object, nodes[0] ) # If none found, try to create an adapted node for the object: if len( nodes ) == 0: return ( object, ITreeNodeAdapterBridge( adapter = object ) ) # Use all selected nodes that have the same 'node_for' list as the # first selected node: base = nodes[0].node_for nodes = [ node for node in nodes if base == node.node_for ] # If only one left, then return that node: if len( nodes ) == 1: return ( object, nodes[0] ) # Otherwise, return a MultiTreeNode based on all selected nodes... # Use the node with no specified children as the root node. If not # found, just use the first selected node as the 'root node': root_node = None for i, node in enumerate( nodes ): if node.get_children_id( object ) == '': root_node = node del nodes[i] break else: root_node = nodes[0] # If we have a matching MultiTreeNode already cached, return it: key = ( root_node, ) + tuple( nodes ) if key in factory.multi_nodes: return ( object, factory.multi_nodes[ key ] ) # Otherwise create one, cache it, and return it: factory.multi_nodes[ key ] = multi_node = MultiTreeNode( root_node = root_node, nodes = nodes ) return ( object, multi_node ) #--------------------------------------------------------------------------- # Returns the TreeNode associated with a specified class: #--------------------------------------------------------------------------- def _node_for_class ( self, klass ): """ Returns the TreeNode associated with a specified class. """ for node in self.factory.nodes: if issubclass( klass, tuple( node.node_for ) ): return node return None #--------------------------------------------------------------------------- # Returns the node and class associated with a specified class name: #--------------------------------------------------------------------------- def _node_for_class_name ( self, class_name ): """ Returns the node and class associated with a specified class name. """ for node in self.factory.nodes: for klass in node.node_for: if class_name == klass.__name__: return ( node, klass ) return ( None, None ) #--------------------------------------------------------------------------- # Updates the icon for a specified node: #--------------------------------------------------------------------------- def _update_icon ( self, event, is_expanded ): """ Updates the icon for a specified node. """ self._update_icon_for_nid( event.GetItem() ) #--------------------------------------------------------------------------- # Updates the icon for a specified node id: #--------------------------------------------------------------------------- def _update_icon_for_nid ( self, nid ): """ Updates the icon for a specified node ID. """ if self._image_list is not None: expanded, node, object = self._get_node_data( nid ) icon = self._get_icon( node, object, expanded ) self._tree.SetItemImage( nid, icon, wx.TreeItemIcon_Normal ) self._tree.SetItemImage( nid, icon, wx.TreeItemIcon_Selected ) #--------------------------------------------------------------------------- # Unpacks an event to see whether a tree item was involved: #--------------------------------------------------------------------------- def _unpack_event ( self, event ): """ Unpacks an event to see whether a tree item was involved. """ try: point = event.GetPosition() except: point = event.GetPoint() nid = None if hasattr( event, 'GetItem' ): nid = event.GetItem() if (nid is None) or (not nid.IsOk()): nid, flags = self._tree.HitTest( point ) if nid.IsOk(): return self._get_node_data( nid ) + ( nid, point ) return ( None, None, None, nid, point ) #--------------------------------------------------------------------------- # Returns information about the node at a specified point: #--------------------------------------------------------------------------- def _hit_test ( self, point ): """ Returns information about the node at a specified point. """ nid, flags = self._tree.HitTest( point ) if nid.IsOk(): return self._get_node_data( nid ) + ( nid, point ) return ( None, None, None, nid, point ) #--------------------------------------------------------------------------- # Begins an 'undoable' transaction: #--------------------------------------------------------------------------- def _begin_undo ( self ): """ Begins an "undoable" transaction. """ ui = self.ui self._undoable.append( ui._undoable ) if (ui._undoable == -1) and (ui.history is not None): ui._undoable = ui.history.now #--------------------------------------------------------------------------- # Ends an 'undoable' transaction: #--------------------------------------------------------------------------- def _end_undo ( self ): if self._undoable.pop() == -1: self.ui._undoable = -1 #--------------------------------------------------------------------------- # Gets an 'undo' item for a change made to a node's children: #--------------------------------------------------------------------------- def _get_undo_item ( self, object, name, event ): return ListUndoItem( object = object, name = name, index = event.index, added = event.added, removed = event.removed ) #--------------------------------------------------------------------------- # Performs an undoable 'append' operation: #--------------------------------------------------------------------------- def _undoable_append ( self, node, object, data, make_copy = True ): """ Performs an undoable append operation. """ try: self._begin_undo() if make_copy: data = copy.deepcopy( data ) node.append_child( object, data ) finally: self._end_undo() #--------------------------------------------------------------------------- # Performs an undoable 'insert' operation: #--------------------------------------------------------------------------- def _undoable_insert ( self, node, object, index, data, make_copy = True ): """ Performs an undoable insert operation. """ try: self._begin_undo() if make_copy: data = copy.deepcopy( data ) node.insert_child( object, index, data ) finally: self._end_undo() #--------------------------------------------------------------------------- # Performs an undoable 'delete' operation: #--------------------------------------------------------------------------- def _undoable_delete ( self, node, object, index ): """ Performs an undoable delete operation. """ try: self._begin_undo() node.delete_child( object, index ) finally: self._end_undo() #--------------------------------------------------------------------------- # Gets the id associated with a specified object (if any): #--------------------------------------------------------------------------- def _get_object_nid ( self, object, name = '' ): """ Gets the ID associated with a specified object (if any). """ info = self._map.get( id( object ) ) if info is None: return None for name2, nid in info: if name == name2: return nid else: return info[0][1] #--------------------------------------------------------------------------- # Clears the current editor pane (if any): #--------------------------------------------------------------------------- def _clear_editor ( self ): """ Clears the current editor pane (if any). """ editor = self._editor if editor._node_ui is not None: editor.SetSizer( None ) editor._node_ui.dispose() editor._node_ui = editor._editor_nid = None #--------------------------------------------------------------------------- # Gets/Sets the node specific data: #--------------------------------------------------------------------------- def _get_node_data ( self, nid ): """ Gets the node specific data. """ if nid == self._root_nid: return self._root_nid_data return self._tree.GetPyData( nid ) def _set_node_data ( self, nid, data ): """ Sets the node specific data. """ if nid == self._root_nid: self._root_nid_data = data else: self._tree.SetPyData( nid, data ) #----- User callable methods: -------------------------------------------------- #--------------------------------------------------------------------------- # Gets the object associated with a specified node: #--------------------------------------------------------------------------- def get_object ( self, nid ): """ Gets the object associated with a specified node. """ return self._get_node_data( nid )[2] #--------------------------------------------------------------------------- # Returns the object which is the immmediate parent of a specified object # in the tree: #--------------------------------------------------------------------------- def get_parent ( self, object, name = '' ): """ Returns the object that is the immmediate parent of a specified object in the tree. """ nid = self._get_object_nid( object, name ) if nid is not None: pnid = self._tree.GetItemParent( nid ) if pnid.IsOk(): return self.get_object( pnid ) return None #--------------------------------------------------------------------------- # Returns the node associated with a specified object: #--------------------------------------------------------------------------- def get_node ( self, object, name = '' ): """ Returns the node associated with a specified object. """ nid = self._get_object_nid( object, name ) if nid is not None: return self._get_node_data( nid )[1] return None #-- Tree Event Handlers: --------------------------------------------------- #--------------------------------------------------------------------------- # Handles a tree node expanding: #--------------------------------------------------------------------------- def _on_tree_item_expanding ( self, event ): """ Handles a tree node expanding. """ if self._veto: self._veto = False event.Veto() return nid = event.GetItem() tree = self._tree expanded, node, object = self._get_node_data( nid ) # If 'auto_close' requested for this node type, close all of the node's # siblings: if node.can_auto_close( object ): snid = nid while True: snid = tree.GetPrevSibling( snid ) if not snid.IsOk(): break tree.Collapse( snid ) snid = nid while True: snid = tree.GetNextSibling( snid ) if not snid.IsOk(): break tree.Collapse( snid ) # Expand the node (i.e. populate its children if they are not there # yet): self._expand_node( nid ) #--------------------------------------------------------------------------- # Handles a tree node being expanded: #--------------------------------------------------------------------------- def _on_tree_item_expanded ( self, event ): """ Handles a tree node being expanded. """ self._update_icon( event, True ) #--------------------------------------------------------------------------- # Handles a tree node collapsing: #--------------------------------------------------------------------------- def _on_tree_item_collapsing ( self, event ): """ Handles a tree node collapsing. """ if self._veto: self._veto = False event.Veto() #--------------------------------------------------------------------------- # Handles a tree node being collapsed: #--------------------------------------------------------------------------- def _on_tree_item_collapsed ( self, event ): """ Handles a tree node being collapsed. """ self._update_icon( event, False ) #--------------------------------------------------------------------------- # Handles a tree node being selected: #--------------------------------------------------------------------------- def _on_tree_sel_changed ( self, event = None ): """ Handles a tree node being selected. """ if self._locked: return # Get the new selection: object = None not_handled = True nids = self._tree.GetSelections() selected = [] for nid in nids: if not nid.IsOk(): continue # If there is a real selection, get the associated object: expanded, node, sel_object = self._get_node_data( nid ) selected.append(sel_object) # Try to inform the node specific handler of the selection, # if there are multiple selections, we only care about the # first (or maybe the last makes more sense?) if nid == nids[0]: object = sel_object not_handled = node.select( object ) # Set the value of the new selection: if self.factory.selection_mode == 'single': self._no_update_selected = True self.selected = object self._no_update_selected = False else: self._no_update_selected = True self.selected = selected self._no_update_selected = False # If no one has been notified of the selection yet, inform the editor's # select handler (if any) of the new selection: if not_handled is True: self.ui.evaluate( self.factory.on_select, object ) # Check to see if there is an associated node editor pane: editor = self._editor if editor is not None: # If we already had a node editor, destroy it: editor.Freeze() self._clear_editor() # If there is a selected object, create a new editor for it: if object is not None: # Try to chain the undo history to the main undo history: view = node.get_view( object ) if view is None or isinstance(view, str) : view = object.trait_view(view) if (self.ui.history is not None) or (view.kind == 'subpanel'): ui = object.edit_traits( parent = editor, view = view, kind = 'subpanel' ) else: # Otherwise, just set up our own new one: ui = object.edit_traits( parent = editor, view = view, kind = 'panel' ) # Make our UI the parent of the new UI: ui.parent = self.ui # Remember the new editor's UI and node info: editor._node_ui = ui editor._editor_nid = nid # Finish setting up the editor: sizer = wx.BoxSizer( wx.VERTICAL ) sizer.Add( ui.control, 1, wx.EXPAND ) editor.SetSizer( sizer ) editor.Layout() # fixme: The following is a hack needed to make the editor window # (which is a wx.ScrolledWindow) recognize that its contents have # been changed: dx, dy = editor.GetSize() editor.SetSize( wx.Size( dx, dy + 1 ) ) editor.SetSize( wx.Size( dx, dy ) ) # Allow the editor view to show any changes that have occurred: editor.Thaw() def _on_hover(self, event): """ Handles the mouse moving over a tree node """ id, flags = self._tree.HitTest(event.GetPosition()) if flags & wx.TREE_HITTEST_ONITEMLABEL: expanded, node, object = self._get_node_data( id ) if self.factory.on_hover is not None: self.ui.evaluate( self.factory.on_hover, object ) self._veto = True elif self.factory and self.factory.on_hover is not None: self.ui.evaluate( self.factory.on_hover, None ) # allow other events to be processed event.Skip(True) #--------------------------------------------------------------------------- # Handles a tree item being activated: #--------------------------------------------------------------------------- def _on_tree_item_activated ( self, event ): """ Handles a tree item being activated. """ expanded, node, object = self._get_node_data( event.GetItem() ) # Fire the 'activated' event with the clicked on object as value: self.activated = object # FIXME: Firing the dclick event also for backward compatibility on wx. # Change it occur on mouse double click only. self.dclick = object #--------------------------------------------------------------------------- # Handles the user starting to edit a tree node label: #--------------------------------------------------------------------------- def _on_tree_begin_label_edit ( self, event ): """ Handles the user starting to edit a tree node label. """ item = event.GetItem() parent = self._tree.GetItemParent( item ) can_rename = True if parent.IsOk(): expanded, node, object = self._get_node_data( parent ) can_rename = node.can_rename( object ) if can_rename: expanded, node, object = self._get_node_data( item ) if node.can_rename_me( object ): return event.Veto() #--------------------------------------------------------------------------- # Handles the user completing tree node label editing: #--------------------------------------------------------------------------- def _on_tree_end_label_edit ( self, event ): """ Handles the user completing tree node label editing. """ label = event.GetLabel() if len( label ) > 0: expanded, node, object = self._get_node_data( event.GetItem() ) # Tell the node to change the label. If it raises an exception, # that means it didn't like the label, so veto the tree node change: try: node.set_label( object, label ) return except: pass event.Veto() #--------------------------------------------------------------------------- # Handles a drag operation starting on a tree node: #--------------------------------------------------------------------------- def _on_tree_begin_drag ( self, event ): """ Handles a drag operation starting on a tree node. """ if PythonDropSource is not None: expanded, node, object, nid, point = self._unpack_event( event ) if node is not None: try: self._dragging = nid PythonDropSource( self._tree, node.get_drag_object( object ) ) finally: self._dragging = None #--------------------------------------------------------------------------- # Handles a tooltip request on a tree node: #--------------------------------------------------------------------------- def _on_tree_item_gettooltip ( self, event ): """ Handles a tooltip request on a tree node. """ nid = event.GetItem() if nid.IsOk(): node_data = self._get_node_data( nid ) if node_data is not None: expanded, node, object = node_data tooltip = node.get_tooltip( object ) if tooltip != '': event.SetToolTip( tooltip ) event.Skip() #--------------------------------------------------------------------------- # Handles a tree item being double-clicked: #--------------------------------------------------------------------------- def _on_left_dclick ( self, event ): """ Handle left mouse dclick to emit dclick event for associated node. """ # Determine what node (if any) was clicked on: expanded, node, object, nid, point = self._unpack_event( event ) # If the mouse is over a node, then process the click: if node is not None: if ((node.dclick( object ) is True) and (self.factory.on_dclick is not None)): self.ui.evaluate( self.factory.on_dclick, object ) # Fire the 'dclick' event with the object as its value: # FIXME: This is instead done in _on_item_activated for backward # compatibility only on wx toolkit. #self.dclick = object # Allow normal mouse event processing to occur: event.Skip() #--------------------------------------------------------------------------- # Handles the user left clicking on a tree node: #--------------------------------------------------------------------------- def _on_left_down ( self, event ): """ Handles the user right clicking on a tree node. """ # Determine what node (if any) was clicked on: expanded, node, object, nid, point = self._unpack_event( event ) # If the mouse is over a node, then process the click: if node is not None: if ((node.click( object ) is True) and (self.factory.on_click is not None)): self.ui.evaluate( self.factory.on_click, object ) # Fire the 'click' event with the object as its value: self.click = object # Allow normal mouse event processing to occur: event.Skip() #--------------------------------------------------------------------------- # Handles the user right clicking on a tree node: #--------------------------------------------------------------------------- def _on_right_down ( self, event ): """ Handles the user right clicking on a tree node. """ expanded, node, object, nid, point = self._unpack_event( event ) if node is not None: self._data = ( node, object, nid ) self._context = { 'object': object, 'editor': self, 'node': node, 'info': self.ui.info, 'handler': self.ui.handler } # Try to get the parent node of the node clicked on: pnid = self._tree.GetItemParent( nid ) if pnid.IsOk(): ignore, parent_node, parent_object = self._get_node_data( pnid ) else: parent_node = parent_object = None self._menu_node = node self._menu_parent_node = parent_node self._menu_parent_object = parent_object menu = node.get_menu( object ) if menu is None: # Use the standard, default menu: menu = self._standard_menu( node, object ) elif isinstance( menu, Menu ): # Use the menu specified by the node: group = menu.find_group( NewAction ) if group is not None: # Only set it the first time: group.id = '' actions = self._new_actions( node, object ) if len( actions ) > 0: group.insert( 0, Menu( name = 'New', *actions ) ) else: # All other values mean no menu should be displayed: menu = None # Only display the menu if a valid menu is defined: if menu is not None: wxmenu = menu.create_menu( self._tree, self ) self._tree.PopupMenuXY( wxmenu, point[0] - 10, point[1] - 10 ) wxmenu.Destroy() # Reset all menu related cached values: self._data = self._context = self._menu_node = \ self._menu_parent_node = self._menu_parent_object = None #--------------------------------------------------------------------------- # Returns the standard contextual pop-up menu: #--------------------------------------------------------------------------- def _standard_menu ( self, node, object ): """ Returns the standard contextual pop-up menu. """ actions = [ CutAction, CopyAction, PasteAction, Separator(), DeleteAction, Separator(), RenameAction ] # See if the 'New' menu section should be added: items = self._new_actions( node, object ) if len( items ) > 0: actions[0:0] = [ Menu( name = 'New', *items ), Separator() ] return Menu( *actions ) #--------------------------------------------------------------------------- # Returns a list of Actions that will create 'new' objects: #--------------------------------------------------------------------------- def _new_actions ( self, node, object ): """ Returns a list of Actions that will create new objects. """ object = self._data[1] items = [] add = node.get_add( object ) if len( add ) > 0: for klass in add: prompt = False if isinstance( klass, tuple ): klass, prompt = klass add_node = self._node_for_class( klass ) if add_node is not None: class_name = klass.__name__ name = add_node.get_name( object ) if name == '': name = class_name items.append( Action( name = name, action = "editor._menu_new_node('%s',%s)" % ( class_name, prompt ) ) ) return items #--------------------------------------------------------------------------- # Menu action helper methods: #--------------------------------------------------------------------------- def _is_copyable ( self, object ): parent = self._menu_parent_node if isinstance( parent, ObjectTreeNode ): return parent.can_copy( self._menu_parent_object ) return ((parent is not None) and parent.can_copy( object )) def _is_cutable ( self, object ): parent = self._menu_parent_node if isinstance( parent, ObjectTreeNode ): can_cut = (parent.can_copy( self._menu_parent_object ) and parent.can_delete( self._menu_parent_object )) else: can_cut = ((parent is not None) and parent.can_copy( object ) and parent.can_delete( object )) return (can_cut and self._menu_node.can_delete_me( object )) def _is_pasteable ( self, object ): from pyface.wx.clipboard import clipboard return self._menu_node.can_add( object, clipboard.object_type ) def _is_deletable ( self, object ): parent = self._menu_parent_node if isinstance( parent, ObjectTreeNode ): can_delete = parent.can_delete( self._menu_parent_object ) else: can_delete = ((parent is not None) and parent.can_delete( object )) return (can_delete and self._menu_node.can_delete_me( object )) def _is_renameable ( self, object ): parent = self._menu_parent_node if isinstance( parent, ObjectTreeNode ): can_rename = parent.can_rename( self._menu_parent_object ) elif parent is not None: can_rename = parent.can_rename( object ) else: can_rename = True return (can_rename and self._menu_node.can_rename_me( object )) #----- Drag and drop event handlers: ------------------------------------------- #--------------------------------------------------------------------------- # Handles a Python object being dropped on the tree: #--------------------------------------------------------------------------- def wx_dropped_on ( self, x, y, data, drag_result ): """ Handles a Python object being dropped on the tree. """ if isinstance( data, list ): rc = wx.DragNone for item in data: rc = self.wx_dropped_on( x, y, item, drag_result ) return rc expanded, node, object, nid, point = self._hit_test( wx.Point( x, y ) ) if node is not None: if drag_result == wx.DragMove: if not self._is_droppable( node, object, data, False ): return wx.DragNone if self._dragging is not None: data = self._drop_object( node, object, data, False ) if data is not None: try: self._begin_undo() self._undoable_delete( *self._node_index( self._dragging ) ) self._undoable_append( node, object, data, False ) finally: self._end_undo() else: data = self._drop_object( node, object, data ) if data is not None: self._undoable_append( node, object, data, False ) return drag_result to_node, to_object, to_index = self._node_index( nid ) if to_node is not None: if self._dragging is not None: data = self._drop_object( node, to_object, data, False ) if data is not None: from_node, from_object, from_index = \ self._node_index( self._dragging ) if ((to_object is from_object) and (to_index > from_index)): to_index -= 1 try: self._begin_undo() self._undoable_delete( from_node, from_object, from_index ) self._undoable_insert( to_node, to_object, to_index, data, False ) finally: self._end_undo() else: data = self._drop_object( to_node, to_object, data ) if data is not None: self._undoable_insert( to_node, to_object, to_index, data, False ) return drag_result return wx.DragNone #--------------------------------------------------------------------------- # Handles a Python object being dragged over the tree: #--------------------------------------------------------------------------- def wx_drag_over ( self, x, y, data, drag_result ): """ Handles a Python object being dragged over the tree. """ expanded, node, object, nid, point = self._hit_test( wx.Point( x, y ) ) insert = False if (node is not None) and (drag_result == wx.DragCopy): node, object, index = self._node_index( nid ) insert = True if ((self._dragging is not None) and (not self._is_drag_ok( self._dragging, data, object ))): return wx.DragNone if ((node is not None) and self._is_droppable( node, object, data, insert )): return drag_result return wx.DragNone #--------------------------------------------------------------------------- # Makes sure that the target is not the same as or a child of the source # object: #--------------------------------------------------------------------------- def _is_drag_ok ( self, snid, source, target ): if (snid is None) or (target is source): return False for cnid in self._nodes( snid ): if not self._is_drag_ok( cnid, self._get_node_data( cnid )[2], target ): return False return True #----- pyface.action 'controller' interface implementation: -------------------- #--------------------------------------------------------------------------- # Adds a menu item to the menu being constructed: #--------------------------------------------------------------------------- def add_to_menu ( self, menu_item ): """ Adds a menu item to the menu bar being constructed. """ action = menu_item.item.action self.eval_when( action.enabled_when, menu_item, 'enabled' ) self.eval_when( action.checked_when, menu_item, 'checked' ) #--------------------------------------------------------------------------- # Adds a tool bar item to the tool bar being constructed: #--------------------------------------------------------------------------- def add_to_toolbar ( self, toolbar_item ): """ Adds a toolbar item to the toolbar being constructed. """ self.add_to_menu( toolbar_item ) #--------------------------------------------------------------------------- # Returns whether the menu action should be defined in the user interface: #--------------------------------------------------------------------------- def can_add_to_menu ( self, action ): """ Returns whether the action should be defined in the user interface. """ if action.defined_when != '': try: if not eval( action.defined_when, globals(), self._context ): return False except: open_fbi() if action.visible_when != '': try: if not eval( action.visible_when, globals(), self._context ): return False except: open_fbi() return True #--------------------------------------------------------------------------- # Returns whether the toolbar action should be defined in the user # interface: #--------------------------------------------------------------------------- def can_add_to_toolbar ( self, action ): """ Returns whether the toolbar action should be defined in the user interface. """ return self.can_add_to_menu( action ) #--------------------------------------------------------------------------- # Performs the action described by a specified Action object: #--------------------------------------------------------------------------- def perform ( self, action, action_event = None ): """ Performs the action described by a specified Action object. """ self.ui.do_undoable( self._perform, action ) def _perform ( self, action ): node, object, nid = self._data method_name = action.action info = self.ui.info handler = self.ui.handler if method_name.find( '.' ) >= 0: if method_name.find( '(' ) < 0: method_name += '()' try: eval( method_name, globals(), { 'object': object, 'editor': self, 'node': node, 'info': info, 'handler': handler } ) except: from traitsui.api import raise_to_debug raise_to_debug() return method = getattr( handler, method_name, None ) if method is not None: method( info, object ) return if action.on_perform is not None: action.on_perform( object ) #----- Menu support methods: --------------------------------------------------- #--------------------------------------------------------------------------- # Evaluates a condition within a defined context and sets a specified # object trait based on the (assumed) boolean result: #--------------------------------------------------------------------------- def eval_when ( self, condition, object, trait ): """ Evaluates a condition within a defined context, and sets a specified object trait based on the result, which is assumed to be a Boolean. """ if condition != '': value = True try: if not eval( condition, globals(), self._context ): value = False except: open_fbi() setattr( object, trait, value ) #----- Menu event handlers: ---------------------------------------------------- #--------------------------------------------------------------------------- # Copies the current tree node object to the paste buffer: #--------------------------------------------------------------------------- def _menu_copy_node ( self ): """ Copies the current tree node object to the paste buffer. """ from pyface.wx.clipboard import clipboard clipboard.data = self._data[1] self._data = None #--------------------------------------------------------------------------- # Cuts the current tree node object into the paste buffer: #--------------------------------------------------------------------------- def _menu_cut_node ( self ): """ Cuts the current tree node object into the paste buffer. """ from pyface.wx.clipboard import clipboard node, object, nid = self._data clipboard.data = object self._data = None self._undoable_delete( *self._node_index( nid ) ) #--------------------------------------------------------------------------- # Pastes the current contents of the paste buffer into the current node: #--------------------------------------------------------------------------- def _menu_paste_node ( self ): """ Pastes the current contents of the paste buffer into the current node. """ from pyface.wx.clipboard import clipboard node, object, nid = self._data self._data = None self._undoable_append( node, object, clipboard.object_data, False ) #--------------------------------------------------------------------------- # Deletes the current node from the tree: #--------------------------------------------------------------------------- def _menu_delete_node ( self ): """ Deletes the current node from the tree. """ node, object, nid = self._data self._data = None rc = node.confirm_delete( object ) if rc is not False: if rc is not True: if self.ui.history is None: # If no undo history, ask user to confirm the delete: dlg = wx.MessageDialog( self._tree, 'Are you sure you want to delete %s?' % node.get_label( object ), 'Confirm Deletion', style = wx.OK | wx.CANCEL | wx.ICON_EXCLAMATION ) if dlg.ShowModal() != wx.ID_OK: return self._undoable_delete( *self._node_index( nid ) ) #--------------------------------------------------------------------------- # Renames the current tree node: #--------------------------------------------------------------------------- def _menu_rename_node ( self ): """ Renames the current tree node. """ node, object, nid = self._data self._data = None object_label = ObjectLabel( label = node.get_label( object ) ) if object_label.edit_traits().result: label = object_label.label.strip() if label != '': node.set_label( object, label ) #--------------------------------------------------------------------------- # Adds a new object to the current node: #--------------------------------------------------------------------------- def _menu_new_node ( self, class_name, prompt = False ): """ Adds a new object to the current node. """ node, object, nid = self._data self._data = None new_node, new_class = self._node_for_class_name( class_name ) new_object = new_class() if (not prompt) or new_object.edit_traits( parent = self.control, kind = 'livemodal' ).result: self._undoable_append( node, object, new_object, False ) # Automatically select the new object if editing is being performed: if self.factory.editable: self._tree.SelectItem( self._tree.GetLastChild( nid ) ) #-- Model event handlers --------------------------------------------------- #--------------------------------------------------------------------------- # Handles the children of a node being completely replaced: #--------------------------------------------------------------------------- def _children_replaced ( self, object, name = '', new = None ): """ Handles the children of a node being completely replaced. """ tree = self._tree for expanded, node, nid in self._object_info_for( object, name ): children = node.get_children( object ) # Only add/remove the changes if the node has already been expanded: if expanded: # Delete all current child nodes: for cnid in self._nodes_for( nid ): self._delete_node( cnid ) # Add all of the children back in as new nodes: for child in children: child, child_node = self._node_for( child ) if child_node is not None: self._append_node( nid, child_node, child ) # Indicate whether the node has any children now: tree.SetItemHasChildren( nid, len( children ) > 0 ) # Try to expand the node (if requested): if node.can_auto_open( object ): tree.Expand( nid ) #--------------------------------------------------------------------------- # Handles the children of a node being changed: #--------------------------------------------------------------------------- def _children_updated ( self, object, name, event ): """ Handles the children of a node being changed. """ # Log the change that was made (removing '_items' from the end of the # name): name = name[:-6] self.log_change( self._get_undo_item, object, name, event ) start = event.index end = start + len( event.removed ) tree = self._tree for expanded, node, nid in self._object_info_for( object, name ): n = len( node.get_children( object ) ) # Only add/remove the changes if the node has already been expanded: if expanded: # Remove all of the children that were deleted: for cnid in self._nodes_for( nid )[ start: end ]: self._delete_node( cnid ) # Add all of the children that were added: remaining = n - len( event.removed ) child_index = 0 for child in event.added: child, child_node = self._node_for( child ) if child_node is not None: insert_index = (start + child_index) if \ (start < remaining) else None self._insert_node( nid, insert_index, child_node, child ) child_index += 1 # Indicate whether the node has any children now: tree.SetItemHasChildren( nid, n > 0 ) # Try to expand the node (if requested): root = tree.GetRootItem() if node.can_auto_open( object ): if ( nid != root ) or not self.factory.hide_root: tree.Expand( nid ) #--------------------------------------------------------------------------- # Handles the label of an object being changed: #--------------------------------------------------------------------------- def _label_updated ( self, object, name, label ): """ Handles the label of an object being changed. """ nids = {} for name2, nid in self._map[ id( object ) ]: if nid not in nids: nids[ nid ] = None node = self._get_node_data( nid )[1] self._tree.SetItemText( nid, node.get_label( object ) ) self._update_icon_for_nid ( nid ) #-- UI preference save/restore interface --------------------------------------- #--------------------------------------------------------------------------- # Restores any saved user preference information associated with the # editor: #--------------------------------------------------------------------------- def restore_prefs ( self, prefs ): """ Restores any saved user preference information associated with the editor. """ if self._is_dock_window: if isinstance( prefs, dict ): structure = prefs.get( 'structure' ) else: structure = prefs self.control.GetSizer().SetStructure( self.control, structure ) #--------------------------------------------------------------------------- # Returns any user preference information associated with the editor: #--------------------------------------------------------------------------- def save_prefs ( self ): """ Returns any user preference information associated with the editor. """ if self._is_dock_window: return { 'structure': self.control.GetSizer().GetStructure() } return None #-- End UI preference save/restore interface ----------------------------------- #------------------------------------------------------------------------------- # 'ObjectLabel' class: #------------------------------------------------------------------------------- class ObjectLabel ( HasStrictTraits ): """ An editable label for an object. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Label to be edited label = Str #--------------------------------------------------------------------------- # Traits view definition: #--------------------------------------------------------------------------- traits_view = View( 'label', title = 'Edit Label', kind = 'modal', buttons = [ 'OK', 'Cancel' ] ) ### EOF ####################################################################### traitsui-4.1.0/traitsui/wx/code_editor.py0000644000175100001440000004427411674463546021530 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2006, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 01/27/2006 # #------------------------------------------------------------------------------ """ Defines a source code editor for the wxPython user interface toolkit, useful for tools such as debuggers. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx import wx.stc as stc from traits.api \ import Str, List, Int, Event, Bool, TraitError, on_trait_change from traits.trait_base \ import SequenceTypes # FIXME: ToolkitEditorFactory is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.code_editor file. from traitsui.editors.code_editor \ import ToolkitEditorFactory from pyface.api \ import PythonEditor from pyface.util.python_stc \ import faces from editor \ import Editor from constants \ import OKColor, ErrorColor #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- # Marker line constants: # Marks a marked line MARK_MARKER = 0 # Marks a line matching the current search SEARCH_MARKER = 1 # Marks the currently selected line SELECTED_MARKER = 2 #------------------------------------------------------------------------------- # 'SourceEditor' class: #------------------------------------------------------------------------------- class SourceEditor ( Editor ): """ Editor for source code, which displays a PyFace PythonEditor. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # The code editor is scrollable. This value overrides the default. scrollable = True # Is the editor read only? readonly = Bool( False ) # The currently selected line selected_line = Int # The currently selected text selected_text = Str # The list of line numbers to mark mark_lines = List( Int ) # The current line number line = Event # The current column column = Event # calltip clicked event calltip_clicked = Event # The STC lexer use lexer = Int # The lines to be dimmed dim_lines = List(Int) dim_color = Str _dim_style_number = Int(16) # 0-15 are reserved for the python lexer # The lines to have squiggles drawn under them squiggle_lines = List(Int) squiggle_color = Str #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ factory = self.factory self._editor = editor = PythonEditor( parent, show_line_numbers = factory.show_line_numbers ) self.control = control = editor.control # There are a number of events which aren't well documented that look # to be useful in future implmentations, below are a subset of the # events that look interesting: # EVT_STC_AUTOCOMP_SELECTION # EVT_STC_HOTSPOT_CLICK # EVT_STC_HOTSPOT_DCLICK # EVT_STC_DOUBLECLICK # EVT_STC_MARGINCLICK control.SetSize( wx.Size( 300, 124 ) ) # Clear out the goofy hotkeys for zooming text control.CmdKeyClear(ord('B'), stc.STC_SCMOD_CTRL) control.CmdKeyClear(ord('N'), stc.STC_SCMOD_CTRL) # Set up the events wx.EVT_KILL_FOCUS( control, self.wx_update_object ) stc.EVT_STC_CALLTIP_CLICK( control, control.GetId(), self._calltip_clicked ) if factory.auto_scroll and (factory.selected_line != ''): wx.EVT_SIZE( control, self._update_selected_line ) if factory.auto_set: editor.on_trait_change( self.update_object, 'changed', dispatch = 'ui' ) if factory.key_bindings is not None: editor.on_trait_change( self.key_pressed, 'key_pressed', dispatch = 'ui' ) if self.readonly: control.SetReadOnly( True ) # Set up the lexer control.SetLexer(stc.STC_LEX_CONTAINER) control.Bind(stc.EVT_STC_STYLENEEDED, self._style_needed) try: self.lexer = getattr(stc, 'STC_LEX_' + self.factory.lexer.upper()) except AttributeError: self.lexer = stc.STC_LEX_NULL # Define the markers we use: control.MarkerDefine( MARK_MARKER, stc.STC_MARK_BACKGROUND, background = factory.mark_color_ ) control.MarkerDefine( SEARCH_MARKER, stc.STC_MARK_BACKGROUND, background = factory.search_color_ ) control.MarkerDefine( SELECTED_MARKER, stc.STC_MARK_BACKGROUND, background = factory.selected_color_ ) # Make sure the editor has been initialized: self.update_editor() # Set up any event listeners: self.sync_value( factory.mark_lines, 'mark_lines', 'from', is_list = True ) self.sync_value( factory.selected_line, 'selected_line', 'from' ) self.sync_value( factory.selected_text, 'selected_text', 'to' ) self.sync_value( factory.line, 'line' ) self.sync_value( factory.column, 'column' ) self.sync_value( factory.calltip_clicked, 'calltip_clicked') self.sync_value(factory.dim_lines, 'dim_lines', 'from', is_list=True) if self.factory.dim_color == '': self.dim_color = 'dark grey' else: self.sync_value(factory.dim_color, 'dim_color', 'from') self.sync_value(factory.squiggle_lines, 'squiggle_lines', 'from', is_list=True) if factory.squiggle_color == '': self.squiggle_color = 'red' else: self.sync_value(factory.squiggle_color, 'squiggle_color', 'from') # Check if we need to monitor the line or column position being changed: if (factory.line != '') or (factory.column != '') or \ (factory.selected_text != ''): stc.EVT_STC_UPDATEUI( control, control.GetId(), self._position_changed ) self.set_tooltip() #--------------------------------------------------------------------------- # Handles the user entering input data in the edit control: #--------------------------------------------------------------------------- def wx_update_object ( self, event ): """ Handles the user entering input data in the edit control. """ self.update_object() event.Skip() def update_object ( self ): """ Handles the user entering input data in the edit control. """ if not self._locked: try: value = self.control.GetText() if isinstance( self.value, SequenceTypes ): value = value.split() self.value = value self.control.SetBackgroundColour( OKColor ) self.control.Refresh() except TraitError, excp: pass #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ self._locked = True new_value = self.value if isinstance( new_value, SequenceTypes ): new_value = '\n'.join( [ line.rstrip() for line in new_value ] ) control = self.control if control.GetText() != new_value: readonly = control.GetReadOnly() control.SetReadOnly( False ) l1 = control.GetFirstVisibleLine() pos = control.GetCurrentPos() control.SetText( new_value ) control.GotoPos( pos ) control.ScrollToLine( l1 ) control.SetReadOnly( readonly ) self._mark_lines_changed() self._selected_line_changed() self._style_document() self._locked = False #--------------------------------------------------------------------------- # Handles the calltip being clicked: #--------------------------------------------------------------------------- def _calltip_clicked ( self, event ): self.calltip_clicked = True #--------------------------------------------------------------------------- # Handles the set of 'marked lines' being changed: #--------------------------------------------------------------------------- def _mark_lines_changed ( self ): """ Handles the set of marked lines being changed. """ lines = self.mark_lines control = self.control lc = control.GetLineCount() control.MarkerDeleteAll( MARK_MARKER ) for line in lines: if 0 < line <= lc: control.MarkerAdd( line - 1, MARK_MARKER ) control.Refresh() def _mark_lines_items_changed ( self ): self._mark_lines_changed() #--------------------------------------------------------------------------- # Handles the currently 'selected line' being changed: #--------------------------------------------------------------------------- def _selected_line_changed ( self ): """ Handles a change in which line is currently selected. """ line = self.selected_line control = self.control line = max( 1, min( control.GetLineCount(), line ) ) - 1 control.MarkerDeleteAll( SELECTED_MARKER ) control.MarkerAdd( line, SELECTED_MARKER ) control.GotoLine( line ) if self.factory.auto_scroll: control.ScrollToLine( line - (control.LinesOnScreen() / 2) ) control.Refresh() #--------------------------------------------------------------------------- # Handles the 'line' trait being changed: #--------------------------------------------------------------------------- def _line_changed ( self, line ): if not self._locked: self.control.GotoLine( line - 1 ) #--------------------------------------------------------------------------- # Handles the 'column' trait being changed: #--------------------------------------------------------------------------- def _column_changed ( self, column ): if not self._locked: control = self.control line = control.LineFromPosition( control.GetCurrentPos() ) control.GotoPos( control.PositionFromLine( line ) + column - 1 ) #--------------------------------------------------------------------------- # Handles the cursor position being changed: #--------------------------------------------------------------------------- def _position_changed ( self, event ): """ Handles the cursor position being changed. """ control = self.control pos = control.GetCurrentPos() line = control.LineFromPosition( pos ) self._locked = True self.line = line + 1 self.column = pos - control.PositionFromLine( line ) + 1 self._locked = False self.selected_text = control.GetSelectedText() #--------------------------------------------------------------------------- # Handles a key being pressed within the editor: #--------------------------------------------------------------------------- def key_pressed ( self, event ): """ Handles a key being pressed within the editor. """ self.factory.key_bindings.do( event.event, self.ui.handler, self.ui.info ) #--------------------------------------------------------------------------- # Handles the styling of the editor: #--------------------------------------------------------------------------- def _dim_color_changed(self): self.control.StyleSetForeground(self._dim_style_number, self.dim_color) self.control.StyleSetFaceName(self._dim_style_number, "courier new") self.control.StyleSetSize(self._dim_style_number, faces['size']) self.control.Refresh() def _squiggle_color_changed(self): self.control.IndicatorSetStyle(2, stc.STC_INDIC_SQUIGGLE) self.control.IndicatorSetForeground(2, self.squiggle_color) self.control.Refresh() @on_trait_change('dim_lines, squiggle_lines') def _style_document(self): """ Force the STC to fire a STC_STYLENEEDED event for the entire document. """ self.control.ClearDocumentStyle() self.control.Colourise(0, -1) self.control.Refresh() def _style_needed(self, event): """ Handles an STC request for styling for some area. """ position = self.control.GetEndStyled() start_line = self.control.LineFromPosition(position) end = event.GetPosition() end_line = self.control.LineFromPosition(end) # Fixes a strange a bug with the STC widget where creating a new line # after a dimmed line causes it to mysteriously lose its styling if start_line in self.dim_lines: start_line -= 1 # Trying to Colourise only the lines that we want does not seem to work # so we do the whole area and then override the styling on certain lines if self.lexer != stc.STC_LEX_NULL: self.control.SetLexer(self.lexer) self.control.Colourise(position, end) self.control.SetLexer(stc.STC_LEX_CONTAINER) for line in xrange(start_line, end_line+1): # We don't use LineLength here because it includes newline # characters. Styling these leads to strange behavior. position = self.control.PositionFromLine(line) style_length = self.control.GetLineEndPosition(line) - position if line+1 in self.dim_lines: # Set styling mask to only style text bits, not indicator bits self.control.StartStyling(position, 0x1f) self.control.SetStyling(style_length, self._dim_style_number) elif self.lexer == stc.STC_LEX_NULL: self.control.StartStyling(position, 0x1f) self.control.SetStyling(style_length, stc.STC_STYLE_DEFAULT) if line+1 in self.squiggle_lines: self.control.StartStyling(position, stc.STC_INDIC2_MASK) self.control.SetStyling(style_length, stc.STC_INDIC2_MASK) else: self.control.StartStyling(position, stc.STC_INDIC2_MASK) self.control.SetStyling(style_length, stc.STC_STYLE_DEFAULT) #--------------------------------------------------------------------------- # Handles an error that occurs while setting the object's trait value: #--------------------------------------------------------------------------- def error ( self, excp ): """ Handles an error that occurs while setting the object's trait value. """ self.control.SetBackgroundColour( ErrorColor ) self.control.Refresh() #--------------------------------------------------------------------------- # Disposes of the contents of an editor: #--------------------------------------------------------------------------- def dispose ( self ): """ Disposes of the contents of an editor. """ if self.factory.auto_set: self._editor.on_trait_change( self.update_object, 'changed', remove = True ) if self.factory.key_bindings is not None: self._editor.on_trait_change( self.key_pressed, 'key_pressed', remove = True ) wx.EVT_KILL_FOCUS( self.control, None ) super( SourceEditor, self ).dispose() #-- UI preference save/restore interface ----------------------------------- #--------------------------------------------------------------------------- # Restores any saved user preference information associated with the # editor: #--------------------------------------------------------------------------- def restore_prefs ( self, prefs ): """ Restores any saved user preference information associated with the editor. """ if self.factory.key_bindings is not None: key_bindings = prefs.get( 'key_bindings' ) if key_bindings is not None: self.factory.key_bindings.merge( key_bindings ) #--------------------------------------------------------------------------- # Returns any user preference information associated with the editor: #--------------------------------------------------------------------------- def save_prefs ( self ): """ Returns any user preference information associated with the editor. """ return { 'key_bindings': self.factory.key_bindings } # Define the simple, custom, text and readonly editors, which will be accessed # by the editor factory for code editors. CustomEditor = SimpleEditor = TextEditor = SourceEditor class ReadonlyEditor(SourceEditor): # Set the value of the readonly trait. readonly = True ### EOF ######################################################################## traitsui-4.1.0/traitsui/wx/image_slice.py0000644000175100001440000003777011674463546021514 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2007, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 06/06/2007 # #------------------------------------------------------------------------------- """ Class to aid in automatically computing the 'slice' points for a specified ImageResource and then drawing it that it can be 'stretched' to fit a larger region than the original image. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx from colorsys \ import rgb_to_hls from numpy \ import reshape, fromstring, uint8 from traits.api \ import HasPrivateTraits, Instance, Int, List, Color, Enum, Bool from pyface.image_resource \ import ImageResource from constants \ import WindowColor from constants import is_mac import traitsui.wx.constants #------------------------------------------------------------------------------- # Recursively paint the parent's background if they have an associated image # slice. #------------------------------------------------------------------------------- def paint_parent ( dc, window ): """ Recursively paint the parent's background if they have an associated image slice. """ parent = window.GetParent() slice = getattr( parent, '_image_slice', None ) if slice is not None: x, y = window.GetPositionTuple() dx, dy = parent.GetSizeTuple() slice.fill( dc, -x, -y, dx, dy ) else: # Otherwise, just paint the normal window background color: dx, dy = window.GetClientSizeTuple() if is_mac and hasattr(window, '_border') and window._border: dc.SetBackgroundMode(wx.TRANSPARENT) dc.SetBrush( wx.Brush( wx.Colour(0, 0, 0, 0))) else: dc.SetBrush( wx.Brush( parent.GetBackgroundColour() ) ) dc.SetPen( wx.TRANSPARENT_PEN ) dc.DrawRectangle( 0, 0, dx, dy ) return slice #------------------------------------------------------------------------------- # 'ImageSlice' class: #------------------------------------------------------------------------------- class ImageSlice ( HasPrivateTraits ): #-- Trait Definitions ------------------------------------------------------ # The ImageResource to be sliced and drawn: image = Instance( ImageResource ) # The minimum number of adjacent, identical rows/columns needed to identify # a repeatable section: threshold = Int( 10 ) # The maximum number of 'stretchable' rows and columns: stretch_rows = Enum( 1, 2 ) stretch_columns = Enum( 1, 2 ) # Width/height of the image borders: top = Int bottom = Int left = Int right = Int # Width/height of the extended image borders: xtop = Int xbottom = Int xleft = Int xright = Int # The color to use for content text: content_color = Instance( wx.Colour ) # The color to use for label text: label_color = Instance( wx.Colour ) # The background color of the image: bg_color = Color # Should debugging slice lines be drawn? debug = Bool( False ) #-- Private Traits --------------------------------------------------------- # The current image's opaque bitmap: opaque_bitmap = Instance( wx.Bitmap ) # The current image's transparent bitmap: transparent_bitmap = Instance( wx.Bitmap ) # Size of the current image: dx = Int dy = Int # Size of the current image's slices: dxs = List dys = List # Fixed minimum size of current image: fdx = Int fdy = Int #-- Public Methods --------------------------------------------------------- def fill ( self, dc, x, y, dx, dy, transparent = False ): """ 'Stretch fill' the specified region of a device context with the sliced image. """ # Create the source image dc: idc = wx.MemoryDC() if transparent: idc.SelectObject( self.transparent_bitmap ) else: idc.SelectObject( self.opaque_bitmap ) # Set up the drawing parameters: sdx, sdy = self.dx, self.dx dxs, dys = self.dxs, self.dys tdx, tdy = dx - self.fdx, dy - self.fdy # Calculate vertical slice sizes to use for source and destination: n = len( dxs ) if n == 1: pdxs = [ ( 0, 0 ), ( 1, max( 1, tdx/2 ) ), ( sdx - 2, sdx - 2 ), ( 1, max( 1, tdx - (tdx/2) ) ), ( 0, 0 ) ] elif n == 3: pdxs = [ ( dxs[0], dxs[0] ), ( dxs[1], max( 0, tdx ) ), ( 0, 0 ), ( 0, 0 ), ( dxs[2], dxs[2] ) ] else: pdxs = [ ( dxs[0], dxs[0] ), ( dxs[1], max( 0, tdx/2 ) ), ( dxs[2], dxs[2] ), ( dxs[3], max( 0, tdx - (tdx/2) ) ), ( dxs[4], dxs[4] ) ] # Calculate horizontal slice sizes to use for source and destination: n = len( dys ) if n == 1: pdys = [ ( 0, 0 ), ( 1, max( 1, tdy/2 ) ), ( sdy - 2, sdy - 2 ), ( 1, max( 1, tdy - (tdy/2) ) ), ( 0, 0 ) ] elif n == 3: pdys = [ ( dys[0], dys[0] ), ( dys[1], max( 0, tdy ) ), ( 0, 0 ), ( 0, 0 ), ( dys[2], dys[2] ) ] else: pdys = [ ( dys[0], dys[0] ), ( dys[1], max( 0, tdy/2 ) ), ( dys[2], dys[2] ), ( dys[3], max( 0, tdy - (tdy/2) ) ), ( dys[4], dys[4] ) ] # Iterate over each cell, performing a stretch fill from the source # image to the destination window: last_x, last_y = x + dx, y + dy y0, iy0 = y, 0 for idy, wdy in pdys: if y0 >= last_y: break if wdy != 0: x0, ix0 = x, 0 for idx, wdx in pdxs: if x0 >= last_x: break if wdx != 0: self._fill( idc, ix0, iy0, idx, idy, dc, x0, y0, wdx, wdy ) x0 += wdx ix0 += idx y0 += wdy iy0 += idy if self.debug: dc.SetPen( wx.Pen( wx.RED ) ) dc.DrawLine( x, y + self.top, last_x, y + self.top ) dc.DrawLine( x, last_y - self.bottom - 1, last_x, last_y - self.bottom - 1 ) dc.DrawLine( x + self.left, y, x + self.left, last_y ) dc.DrawLine( last_x - self.right - 1, y, last_x - self.right - 1, last_y ) #-- Event Handlers --------------------------------------------------------- def _image_changed ( self, image ): """ Handles the 'image' trait being changed. """ # Save the original bitmap as the transparent version: self.transparent_bitmap = bitmap = \ image.create_image().ConvertToBitmap() # Save the bitmap size information: self.dx = dx = bitmap.GetWidth() self.dy = dy = bitmap.GetHeight() # Create the opaque version of the bitmap: self.opaque_bitmap = wx.EmptyBitmap( dx, dy ) mdc2 = wx.MemoryDC() mdc2.SelectObject( self.opaque_bitmap ) mdc2.SetBrush( wx.Brush( WindowColor ) ) mdc2.SetPen( wx.TRANSPARENT_PEN ) mdc2.DrawRectangle( 0, 0, dx, dy ) mdc = wx.MemoryDC() mdc.SelectObject( bitmap ) mdc2.Blit( 0, 0, dx, dy, mdc, 0, 0, useMask = True ) mdc.SelectObject( wx.NullBitmap ) mdc2.SelectObject( wx.NullBitmap ) # Finally, analyze the image to find out its characteristics: self._analyze_bitmap() #-- Private Methods -------------------------------------------------------- def _analyze_bitmap ( self ): """ Analyzes the bitmap. """ # Get the image data: threshold = self.threshold bitmap = self.opaque_bitmap dx, dy = self.dx, self.dy image = bitmap.ConvertToImage() # Convert the bitmap data to a numpy array for analysis: data = reshape( fromstring( image.GetData(), uint8 ), ( dy, dx, 3 ) ) # Find the horizontal slices: matches = [] y, last = 0, dy - 1 max_diff = 0.10 * dx while y < last: y_data = data[y] for y2 in xrange( y + 1, dy ): if abs( y_data - data[y2] ).sum() > max_diff: break n = y2 - y if n >= threshold: matches.append( ( y, n ) ) y = y2 n = len( matches ) if n == 0: if dy > 50: matches = [ ( 0, dy ) ] else: matches = [ ( dy / 2, 1 ) ] elif n > self.stretch_rows: matches.sort( lambda l, r: cmp( r[1], l[1] ) ) matches = matches[ : self.stretch_rows ] # Calculate and save the horizontal slice sizes: self.fdy, self.dys = self._calculate_dxy( dy, matches ) # Find the vertical slices: matches = [] x, last = 0, dx - 1 max_diff = 0.10 * dy while x < last: x_data = data[:,x] for x2 in xrange( x + 1, dx ): if abs( x_data - data[:,x2] ).sum() > max_diff: break n = x2 - x if n >= threshold: matches.append( ( x, n ) ) x = x2 n = len( matches ) if n == 0: if dx > 50: matches = [ ( 0, dx ) ] else: matches = [ ( dx / 2, 1 ) ] elif n > self.stretch_columns: matches.sort( lambda l, r: cmp( r[1], l[1] ) ) matches = matches[ : self.stretch_columns ] # Calculate and save the vertical slice sizes: self.fdx, self.dxs = self._calculate_dxy( dx, matches ) # Save the border size information: self.top = min( dy / 2, self.dys[0] ) self.bottom = min( dy / 2, self.dys[-1] ) self.left = min( dx / 2, self.dxs[0] ) self.right = min( dx / 2, self.dxs[-1] ) # Find the optimal size for the borders (i.e. xleft, xright, ... ): self._find_best_borders( data ) # Save the background color: x, y = (dx / 2), (dy / 2) r, g, b = data[ y, x ] self.bg_color = (0x10000 * r) + (0x100 * g) + b # Find the best contrasting text color (black or white): self.content_color = self._find_best_color( data, x, y ) # Find the best contrasting label color: if self.xtop >= self.xbottom: self.label_color = self._find_best_color( data, x, self.xtop / 2 ) else: self.label_color = self._find_best_color( data, x, dy - (self.xbottom / 2) - 1 ) def _fill ( self, idc, ix, iy, idx, idy, dc, x, y, dx, dy ): """ Performs a stretch fill of a region of an image into a region of a window device context. """ last_x, last_y = x + dx, y + dy while y < last_y: ddy = min( idy, last_y - y ) x0 = x while x0 < last_x: ddx = min( idx, last_x - x0 ) dc.Blit( x0, y, ddx, ddy, idc, ix, iy, useMask = True ) x0 += ddx y += ddy def _calculate_dxy ( self, d, matches ): """ Calculate the size of all image slices for a specified set of matches. """ if len( matches ) == 1: d1, d2 = matches[0] return ( d - d2, [ d1, d2, d - d1 - d2 ] ) d1, d2 = matches[0] d3, d4 = matches[1] return ( d - d2 - d4, [ d1, d2, d3 - d1 - d2, d4, d - d3 - d4 ] ) def _find_best_borders ( self, data ): """ Find the best set of image slice border sizes (e.g. for images with rounded corners, there should exist a better set of borders than the ones computed by the image slice algorithm. """ # Make sure the image size is worth bothering about: dx, dy = self.dx, self.dy if (dx < 5) or (dy < 5): return # Calculate the starting point: left = right = dx / 2 top = bottom = dy / 2 # Calculate the end points: last_y = dy - 1 last_x = dx - 1 # Mark which edges as 'scanning': t = b = l = r = True # Keep looping while at last one edge is still 'scanning': while l or r or t or b: # Calculate the current core area size: height = bottom - top + 1 width = right - left + 1 # Try to extend all edges that are still 'scanning': nl = (l and (left > 0) and self._is_equal( data, left - 1, top, left, top, 1, height )) nr = (r and (right < last_x) and self._is_equal( data, right + 1, top, right, top, 1, height )) nt = (t and (top > 0) and self._is_equal( data, left, top - 1, left, top, width, 1 )) nb = (b and (bottom < last_y) and self._is_equal( data, left, bottom + 1, left, bottom, width, 1 )) # Now check the corners of the edges: tl = ((not nl) or (not nt) or self._is_equal( data, left - 1, top - 1, left, top, 1, 1 )) tr = ((not nr) or (not nt) or self._is_equal( data, right + 1, top - 1, right, top, 1, 1 )) bl = ((not nl) or (not nb) or self._is_equal( data, left - 1, bottom + 1, left, bottom, 1, 1 )) br = ((not nr) or (not nb) or self._is_equal( data, right + 1, bottom + 1, right, bottom, 1, 1 )) # Calculate the new edge 'scanning' values: l = nl and tl and bl r = nr and tr and br t = nt and tl and tr b = nb and bl and br # Adjust the coordinate of an edge if it is still 'scanning': left -= l right += r top -= t bottom += b # Now compute the best set of image border sizes using the current set # and the ones we just calculated: self.xleft = min( self.left, left ) self.xright = min( self.right, dx - right - 1 ) self.xtop = min( self.top, top ) self.xbottom = min( self.bottom, dy - bottom - 1 ) def _find_best_color ( self, data, x, y ): """ Find the best contrasting text color for a specified pixel coordinate. """ r, g, b = data[ y, x ] h, l, s = rgb_to_hls( r / 255.0, g / 255.0, b / 255.0 ) text_color = wx.BLACK if l < 0.50: text_color = wx.WHITE return text_color def _is_equal ( self, data, x0, y0, x1, y1, dx, dy ): """ Determines if two identically sized regions of an image array are 'the same' (i.e. within some slight color variance of each other). """ return (abs( data[ y0: y0 + dy, x0: x0 + dx ] - data[ y1: y1 + dy, x1: x1 + dx ] ).sum() < 0.10 * dx * dy) #------------------------------------------------------------------------------- # Returns a (possibly cached) ImageSlice: #------------------------------------------------------------------------------- image_slice_cache = {} def image_slice_for ( image ): """ Returns a (possibly cached) ImageSlice. """ global image_slice_cache result = image_slice_cache.get( image ) if result is None: image_slice_cache[ image ] = result = ImageSlice( image = image ) return result traitsui-4.1.0/traitsui/wx/history_editor.py0000644000175100001440000001314611674463546022311 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/21/2004 # #------------------------------------------------------------------------------- """ Defines a text editor which displays a text field and maintains a history of previously entered values. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from traits.api \ import Any, on_trait_change from pyface.timer.api \ import do_later from editor \ import Editor from history_control \ import HistoryControl #------------------------------------------------------------------------------- # '_HistoryEditor' class: #------------------------------------------------------------------------------- class _HistoryEditor ( Editor ): """ Simple style text editor, which displays a text field and maintains a history of previously entered values, the maximum number of which is specified by the 'entries' trait of the HistoryEditor factory. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # The history control: history = Any #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self.history = history = HistoryControl( value = self.value, entries = self.factory.entries, auto_set = self.factory.auto_set ) self.control = history.create_control( parent ) self.set_tooltip() def dispose ( self ): """ Disposes of the contents of an editor. """ self.history.dispose() self.history = None super( _HistoryEditor, self ).dispose() #--------------------------------------------------------------------------- # Handles the user entering input data in the edit control: #--------------------------------------------------------------------------- @on_trait_change( 'history:value' ) def _value_changed ( self, value ): """ Handles the history object's 'value' trait being changed. """ if not self._dont_update: history = self.history try: self._dont_update = True self.value = history.value history.error = False except: history.error = True do_later( self.set, _dont_update = False ) #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ if not self._dont_update: self._dont_update = True self.history.value = self.value self.history.error = False self._dont_update = False #--------------------------------------------------------------------------- # Handles an error that occurs while setting the object's trait value: #--------------------------------------------------------------------------- def error ( self, excp ): """ Handles an error that occurs while setting the object's trait value. """ pass #-- UI preference save/restore interface ----------------------------------- #--------------------------------------------------------------------------- # Restores any saved user preference information associated with the # editor: #--------------------------------------------------------------------------- def restore_prefs ( self, prefs ): """ Restores any saved user preference information associated with the editor. """ self.history.history = \ prefs.get( 'history', [] )[ : self.factory.entries ] #--------------------------------------------------------------------------- # Returns any user preference information associated with the editor: #--------------------------------------------------------------------------- def save_prefs ( self ): """ Returns any user preference information associated with the editor. """ # If the view closed successfully, try to update the history with the # current value: if self.ui.result: self._dont_update = True self.history.set_value( self.value ) self._dont_update = False return { 'history': self.history.history[:] } # EOF ######################################################################### traitsui-4.1.0/traitsui/wx/html_editor.py0000644000175100001440000001207611674463546021555 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/21/2004 # #------------------------------------------------------------------------------ """ Defines the HTML "editor" for the wxPython user interface toolkit. HTML editors interpret and display HTML-formatted text, but do not modify it. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import os.path import webbrowser import wx.html as wh from traits.api import Str # FIXME: ToolkitEditorFactory is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.html_editor file. from traitsui.editors.html_editor import ToolkitEditorFactory from editor import Editor #------------------------------------------------------------------------------- # URLResolvingHtmlWindow class: #------------------------------------------------------------------------------- class URLResolvingHtmlWindow( wh.HtmlWindow ): """ Overrides OnOpeningURL method of HtmlWindow to append the base URL local links. """ def __init__( self, parent, open_externally, base_url ): wh.HtmlWindow.__init__( self, parent ) self.open_externally = open_externally self.base_url = base_url def OnLinkClicked ( self, link_info ): """ Handle the base url and opening in a new browser window for links. """ if self.open_externally: url = link_info.GetHref() if (self.base_url and not url.startswith( ( 'http://', 'https://' ) )): url = self.base_url + url if not url.startswith( ( 'file://', 'http://', 'https://' ) ): url = 'file://' + url webbrowser.open_new( url ) def OnOpeningURL( self, url_type, url ): """ According to the documentation, this method is supposed to be called for both images and link clicks, but it appears to only be called for image loading, hence the base url handling code in OnLinkClicked. """ if (self.base_url and not os.path.isabs(url) and not url.startswith( ( 'http://', 'https://', self.base_url ) )): return self.base_url + url else: return wh.HTML_OPEN #------------------------------------------------------------------------------- # 'SimpleEditor' class: #------------------------------------------------------------------------------- class SimpleEditor ( Editor ): """ Simple style of editor for HTML, which displays interpreted HTML. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Is the HTML editor scrollable? This values override the default. scrollable = True # External objects referenced in the HTML are relative to this URL base_url = Str #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self.control = URLResolvingHtmlWindow( parent , self.factory.open_externally, self.base_url ) self.control.SetBorders( 2 ) self.base_url = self.factory.base_url self.sync_value( self.factory.base_url_name, 'base_url', 'from' ) #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes external to the editor. """ text = self.str_value if self.factory.format_text: text = self.factory.parse_text( text ) self.control.SetPage( text ) #-- Event Handlers --------------------------------------------------------- def _base_url_changed(self): url = self.base_url if not url.endswith( '/' ): url += '/' self.control.base_url = url self.update_editor() #--EOF------------------------------------------------------------------------- traitsui-4.1.0/traitsui/wx/themed_control.py0000644000175100001440000002337611674463546022256 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2007, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 07/03/2007 # #------------------------------------------------------------------------------- """ Defines 'ThemedControl, a themed control based class. A 'themed' control is a control (optionally) supporting a stretchable background image. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx from traits.api \ import HasTraits, Str, Int, Enum, Bool, Property, Event, Tuple, Instance, \ cached_property, on_trait_change from traitsui.api \ import default_theme from traitsui.ui_traits \ import Image, Position, Alignment, Spacing from image_slice import ImageSlice from themed_window \ import ThemedWindow #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- # The size of an empty text string: ZeroTextSize = ( 0, 0, 0, 0 ) # An empty position and size bounds: EmptyBounds = ( 0, 0, 0, 0 ) # Targets for '_get_bounds_for' method: TheText = 0 TheBitmap = 1 TheControl = 2 #------------------------------------------------------------------------------- # 'ThemedControl' class: #------------------------------------------------------------------------------- class ThemedControl ( ThemedWindow ): #-- Public Traits ---------------------------------------------------------- # An (optional) image to be drawn inside the control: image = Image( event = 'updated' ) # The (optional) text to be displayed inside the control: text = Str( event = 'updated' ) # The position of the image relative to the text: position = Position( event = 'updated' ) # The amount of spacing between the image and the text: spacing = Spacing( event = 'updated' ) # Is the text value private (like a password): password = Bool( False, event = 'updated' ) # An additional, optional offset to apply to the text/image position: offset = Tuple( Int, Int ) # Minimum default size for the control: min_size = Tuple( Int, Int ) # Is the control enabled: enabled = Bool( True ) #-- Private Traits --------------------------------------------------------- # An event fired when any display related value changes: updated = Event # The underlying wx.Window control: control = Instance( wx.Window ) # The current text value to display: current_text = Property( depends_on = 'text, password' ) # The best size for the control: best_size = Property # The size of the current text: text_size = Property( depends_on = 'current_text, control' ) # The position and size of the current text within the control: text_bounds = Property( depends_on = 'updated' ) # The position and size of the current bitmap within the control: bitmap_bounds = Property( depends_on = 'updated' ) #-- Public Methods --------------------------------------------------------- def create_control ( self, parent ): """ Creates the underlying wx.Window object. """ self.control = control = wx.Window( parent, -1, size = wx.Size( 70, 20 ), style = wx.FULL_REPAINT_ON_RESIZE | wx.WANTS_CHARS ) # Initialize the control (set-up event handlers, ...): self.init_control() # Make sure all internal state gets initialized: self._image_changed( self.image ) # Make sure the control is sized correctly: size = self.best_size control.SetMinSize( size ) control.SetSize( size ) return control #-- Property Implementations ----------------------------------------------- @cached_property def _get_current_text ( self ): """ Returns the current text to display. """ if self.password: return '*' * len( self.text ) return self.text def _get_best_size ( self ): """ Returns the 'best' size for the control. """ cx, cy, cdx, cdy = self._get_bounds_for( TheControl ) mdx, mdy = self.min_size return wx.Size( max( cdx, mdx ), max( cdy, mdy ) ) @cached_property def _get_text_size ( self ): """ Returns the text size information for the window. """ text = self.current_text if (text == '') or (self.control is None): return ZeroTextSize return self.control.GetFullTextExtent( text ) @cached_property def _get_text_bounds ( self ): """ Returns the position and size of the text within the window. """ return self._get_bounds_for( TheText ) @cached_property def _get_bitmap_bounds ( self ): """ Returns the size and position of the bitmap within the window. """ return self._get_bounds_for( TheBitmap ) #-- Event Handlers --------------------------------------------------------- @on_trait_change( 'theme.+, image' ) def _updated_changed ( self ): """ Handles any update related trait being changed. """ if self.control is not None: self.control.Refresh() def _image_changed ( self, image ): """ Handles the image being changed by updating the corresponding bitmap. """ if image is None: self._bitmap = None else: self._bitmap = image.create_image().ConvertToBitmap() #-- wxPython Event Handlers ------------------------------------------------ def _paint_fg ( self, dc ): """ Paints the foreground into the specified device context. """ self.enabled = self.control.IsEnabled() # Get the text and image offset to use: theme = self.theme or default_theme label = theme.label ox, oy = label.left, label.top ox2, oy2 = self.offset ox += ox2 oy += oy2 # Draw the bitmap (if any): ix, iy, idx, idy = self.bitmap_bounds if idx != 0: dc.DrawBitmap( self._bitmap, ix + ox, iy + oy, True ) # Draw the text (if any): tx, ty, tdx, tdy = self.text_bounds if tdx != 0: dc.SetBackgroundMode( wx.TRANSPARENT ) dc.SetTextForeground( theme.content_color ) dc.SetFont( self.control.GetFont() ) dc.DrawText( self.current_text, tx + ox, ty + oy ) def _size ( self, event ): """ Handles the control being resized. """ super( ThemedControl, self )._size( event ) self.updated = True #-- Private Methods -------------------------------------------------------- def _get_bounds_for ( self, item ): """ Returns all text and image related position and size information. """ control = self.control if control is None: return EmptyBounds tdx, tdy, descent, leading = self.text_size bitmap = self._bitmap if bitmap is None: bdx, bdy = 0, 0 else: bdx, bdy = bitmap.GetWidth(), bitmap.GetHeight() if (tdx + bdx) == 0: return EmptyBounds wdx, wdy = control.GetClientSizeTuple() spacing = (tdx != 0) * (bdx != 0) * self.spacing theme = self.theme or default_theme slice = theme.image_slice or ImageSlice() content = theme.content position = self.position if position in ( 'above', 'below' ): cdx = max( tdx, bdx ) cdy = tdy + spacing + bdy else: cdx = tdx + spacing + bdx cdy = max( tdy, bdy ) if item == TheControl: cdx += content.left + content.right cdy += content.top + content.bottom return ( 0, 0, max( slice.left + slice.right, slice.xleft + slice.xright + cdx ), max( slice.top + slice.bottom, slice.xtop + slice.xbottom + cdy ) ) alignment = theme.alignment if alignment == 'default': alignment = self.default_alignment if alignment == 'left': x = slice.xleft + content.left elif alignment == 'center': x = slice.xleft + content.left + ((wdx - slice.xleft - slice.xright - content.left - content.right - cdx) / 2) else: x = wdx - slice.xright - content.right - cdx if position == 'left': bx = x tx = bx + bdx + spacing elif position == 'right': tx = x bx = tx + tdx + spacing else: x += (max( tdx, bdx ) / 2) tx = x - (tdx / 2 ) bx = x - (bdx / 2 ) y = slice.xtop + content.top + ((wdy - slice.xtop - slice.xbottom - content.top - content.bottom - cdy) / 2) if position == 'above': by = y ty = by + bdy + spacing elif position == 'below': ty = y by = ty + tdy + spacing else: y += (max( tdy, bdy ) / 2) ty = y - ((tdy + 1) / 2) by = y - (bdy / 2) if item == TheText: return ( tx, ty, tdx, tdy ) return ( bx, by, bdx, bdy ) traitsui-4.1.0/traitsui/wx/null_editor.py0000644000175100001440000000456311674463546021565 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2006, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 07/26/2006 # #------------------------------------------------------------------------------- """ Defines a completely empty editor, intended to be used as a spacer. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx # FIXME: ToolkitEditorFactory is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.null_editor file. from traitsui.editors.null_editor \ import NullEditor as ToolkitEditorFactory from editor \ import Editor #------------------------------------------------------------------------------- # 'NullEditor' class: #------------------------------------------------------------------------------- class NullEditor ( Editor ): """ A completely empty editor. """ #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self.control = control = wx.Window( parent, -1, size = wx.Size( 1, 1 ) ) control.SetBackgroundColour( parent.GetBackgroundColour() ) #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ pass traitsui-4.1.0/traitsui/wx/editor_factory.py0000644000175100001440000001737411674463546022266 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/21/2004 # #------------------------------------------------------------------------------ """ Defines the base wxPython EditorFactory class and classes the various styles of editors used in a Traits-based user interface. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import warnings import wx from traits.api \ import TraitError, Any, Bool, Event, Str from traitsui.editor_factory \ import EditorFactory as BaseEditorFactory from editor \ import Editor from constants \ import WindowColor #------------------------------------------------------------------------------- # 'EditorFactory' class # Deprecated alias for traitsui.editor_factory.EditorFactory #------------------------------------------------------------------------------- class EditorFactory(BaseEditorFactory): """ Deprecated alias for traitsui.editor_factory.EditorFactory. """ def __init__(self, *args, **kwds): super(EditorFactory, self).__init__(*args, **kwds) warnings.warn("DEPRECATED: Use traitsui.editor_factory." ".EditorFactory instead.", DeprecationWarning) #------------------------------------------------------------------------------- # 'SimpleEditor' class: #------------------------------------------------------------------------------- class SimpleEditor ( Editor ): """ Base class for simple style editors, which displays a text field containing the text representation of the object trait value. Clicking in the text field displays an editor-specific dialog box for changing the value. """ # Has the left mouse button been pressed: left_down = Bool( False ) #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self.control = self.create_control( parent ) wx.EVT_LEFT_DOWN( self.control, self._enable_popup_editor ) wx.EVT_LEFT_UP( self.control, self._show_popup_editor ) self.set_tooltip() #--------------------------------------------------------------------------- # Creates the control to use for the simple editor: #--------------------------------------------------------------------------- def create_control ( self, parent ): """ Creates the control to use for the simple editor. """ return wx.TextCtrl( parent, -1, self.str_value, style = wx.TE_READONLY ) #--------------------------------------------------------------------------- # Invokes the pop-up editor for an object trait: # # (Normally overridden in a subclass) #--------------------------------------------------------------------------- def popup_editor ( self, event ): """ Invokes the pop-up editor for an object trait. """ pass def _enable_popup_editor ( self, event ): """ Mark the left mouse button as being pressed currently. """ self.left_down = True def _show_popup_editor ( self, event ): """ Display the popup editor if the left mouse button was pressed previously. """ if self.left_down: self.left_down = False self.popup_editor( event ) #------------------------------------------------------------------------------- # 'TextEditor' class: #------------------------------------------------------------------------------- class TextEditor ( Editor ): """ Base class for text style editors, which displays an editable text field, containing a text representation of the object trait value. """ #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self.control = wx.TextCtrl( parent, -1, self.str_value, style = wx.TE_PROCESS_ENTER ) wx.EVT_KILL_FOCUS( self.control, self.update_object ) wx.EVT_TEXT_ENTER( parent, self.control.GetId(), self.update_object ) self.set_tooltip() #--------------------------------------------------------------------------- # Handles the user changing the contents of the edit control: #--------------------------------------------------------------------------- def update_object ( self, event ): """ Handles the user changing the contents of the edit control. """ try: self.value = self.control.GetValue() except TraitError, excp: pass #------------------------------------------------------------------------------- # 'ReadonlyEditor' class: #------------------------------------------------------------------------------- class ReadonlyEditor ( Editor ): """ Base class for read-only style editors, which displays a read-only text field, containing a text representation of the object trait value. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # layout_style = 0 # Style for imbedding control in a sizer (override) #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ if (self.item.resizable is True) or (self.item.height != -1.0): self.control = wx.TextCtrl( parent, -1, self.str_value, style = wx.NO_BORDER | wx.TE_MULTILINE | wx.TE_READONLY ) self.control.SetBackgroundColour( WindowColor ) else: self.control = wx.StaticText( parent, -1, self.str_value, style = wx.ALIGN_LEFT ) self.layout_style = 0 self.set_tooltip() #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ new_value = self.str_value if (self.item.resizable is True) or (self.item.height!= -1.0): if self.control.GetValue() != new_value: self.control.SetValue( new_value ) elif self.control.GetLabel() != new_value: self.control.SetLabel( new_value ) traitsui-4.1.0/traitsui/wx/date_editor.py0000644000175100001440000007416111674463546021531 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005--2009, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: Judah De Paula # Date: 2/26/2009 # #------------------------------------------------------------------------------ """ A Traits UI editor that wraps a WX calendar panel. Future Work ----------- The class needs to be extend to provide the four basic editor types, Simple, Custom, Text, and ReadOnly. """ import datetime import wx import wx.calendar from traits.api import Bool from traitsui.wx.editor import Editor from traitsui.wx.constants import WindowColor from traitsui.wx.text_editor \ import ReadonlyEditor as TextReadonlyEditor #------------------------------------------------------------------------------ #-- Simple Editor #------------------------------------------------------------------------------ class SimpleEditor (Editor): """ Simple Traits UI date editor. Shows a text box, and a date-picker widget. """ def init ( self, parent ): """ Finishes initializing the editor by creating the underlying widget. """ # MS-Win's DatePickerCtrl comes with a check-box we don't want. # GenericDatePickerCtrl was exposed in wxPython version 2.8.8 only. if 'wxMSW' in wx.PlatformInfo and wx.VERSION > (2,8,8): date_widget = wx.GenericDatePickerCtrl else: # Linux / OS-X / windows date_widget = wx.DatePickerCtrl self.control = date_widget(parent, size=(120,-1), style = wx.DP_DROPDOWN | wx.DP_SHOWCENTURY | wx.DP_ALLOWNONE) self.control.Bind(wx.EVT_DATE_CHANGED, self.day_selected) return def day_selected(self, event): """ Event for when calendar is selected, update/create date string. """ date = event.GetDate() # WX sometimes has year == 0 temporarily when doing state changes. if date.IsValid() and date.GetYear() != 0: year = date.GetYear() # wx 2.8.8 has 0-indexed months. month = date.GetMonth() + 1 day = date.GetDay() try: self.value = datetime.date(year, month, day) except ValueError: print 'Invalid date:', year, month, day raise return def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ if self.value: date = self.control.GetValue() # FIXME: A Trait assignment should support fixing an invalid # date in the widget. if date.IsValid(): # Important: set the day before setting the month, otherwise wx may fail # to set the month. date.SetYear(self.value.year) date.SetDay(self.value.day) # wx 2.8.8 has 0-indexed months. date.SetMonth(self.value.month - 1) self.control.SetValue(date) self.control.Refresh() return #-- end SimpleEditor definition ----------------------------------------------- #------------------------------------------------------------------------------ #-- Custom Editor #------------------------------------------------------------------------------ SELECTED_FG = wx.Colour(255, 0, 0) UNAVAILABLE_FG = wx.Colour(192, 192, 192) DRAG_HIGHLIGHT_FG = wx.Colour(255, 255, 255) DRAG_HIGHLIGHT_BG = wx.Colour(128, 128, 255) try: MOUSE_BOX_FILL = wx.Colour(0, 0, 255, 32) NORMAL_HIGHLIGHT_FG = wx.Colour(0, 0, 0, 0) NORMAL_HIGHLIGHT_BG = wx.Colour(255, 255, 255, 0) # Alpha channel in wx.Colour does not exist prior to version 2.7.1.1 except TypeError: MOUSE_BOX_FILL = wx.Colour(0, 0, 255) NORMAL_HIGHLIGHT_FG = wx.Colour(0, 0, 0) NORMAL_HIGHLIGHT_BG = wx.Colour(255, 255, 255) class wxMouseBoxCalendarCtrl(wx.calendar.CalendarCtrl): """ Subclass to add a mouse-over box-selection tool. Description ----------- Add a Mouse drag-box highlight feature that can be used by the CustomEditor to detect user selections. CalendarCtrl must be subclassed to get a device context to draw on top of the Calendar, otherwise the calendar widgets are always painted on top of the box during repaints. """ def __init__(self, *args, **kwargs): super(wxMouseBoxCalendarCtrl, self).__init__(*args, **kwargs) self.selecting = False self.box_selected = [] self.sel_start = (0,0) self.sel_end = (0,0) self.Bind(wx.EVT_RIGHT_DOWN, self.start_select) self.Bind(wx.EVT_RIGHT_UP, self.end_select) self.Bind(wx.EVT_LEAVE_WINDOW, self.end_select) self.Bind(wx.EVT_MOTION, self.on_select) self.Bind(wx.EVT_PAINT, self.on_paint) self.Bind(wx.calendar.EVT_CALENDAR_SEL_CHANGED, self.highlight_changed) def boxed_days(self): """ Compute the days that are under the box selection. Returns ------- A list of wx.DateTime objects under the mouse box. """ x1, y1 = self.sel_start x2, y2 = self.sel_end if x1 > x2: x1, x2 = x2, x1 if y1 > y2: y1, y2 = y2, y1 grid = [] for i in range(x1, x2, 15): for j in range(y1, y2, 15): grid.append(wx.Point(i,j)) grid.append(wx.Point(i, y2)) # Avoid jitter along the edge since the final points change. for j in range(y1, y2, 20): grid.append(wx.Point(x2, j)) grid.append(wx.Point(x2, y2)) selected_days = [] for point in grid: (result, date, weekday) = self.HitTest(point) if result == wx.calendar.CAL_HITTEST_DAY: if date not in selected_days: selected_days.append(date) return selected_days def highlight_changed(self, event=None): """ Hide the default highlight to take on the selected date attr. Description ----------- A feature of the wx CalendarCtrl is that there are selected days, that always are shown and the user can move around with left-click. But it's confusing and misleading when there are multiple CalendarCtrl objects linked in one editor. So we hide the highlights in this CalendarCtrl by making it mimic the attribute of the selected day. Highlights apparently can't take on a border style, so to be truly invisible, normal days cannot have borders. """ if event: event.Skip() date = self.GetDate() attr = self.GetAttr(date.GetDay()) if attr is None: bg_color = NORMAL_HIGHLIGHT_BG fg_color = NORMAL_HIGHLIGHT_FG else: bg_color = attr.GetBackgroundColour() fg_color = attr.GetTextColour() self.SetHighlightColours(fg_color, bg_color) self.Refresh() return #-- event handlers -------------------------------------------------------- def start_select(self, event): event.Skip() self.selecting = True self.box_selected = [] self.sel_start = (event.m_x, event.m_y) self.sel_end = self.sel_start def end_select(self, event): event.Skip() self.selecting = False self.Refresh() def on_select(self, event): event.Skip() if not self.selecting: return self.sel_end = (event.m_x, event.m_y) self.box_selected = self.boxed_days() self.Refresh() def on_paint(self, event): event.Skip() dc = wx.PaintDC(self) if not self.selecting: return x = self.sel_start[0] y = self.sel_start[1] w = self.sel_end[0] - x h = self.sel_end[1] - y gc = wx.GraphicsContext.Create(dc) pen = gc.CreatePen(wx.BLACK_PEN) gc.SetPen(pen) points = [(x,y), (x+w, y), (x+w,y+h), (x,y+h), (x,y)] gc.DrawLines(points) brush = gc.CreateBrush(wx.Brush(MOUSE_BOX_FILL)) gc.SetBrush(brush) gc.DrawRectangle(x, y, w, h) #-- end wxMouseBoxCalendarCtrl ------------------------------------------------ class MultiCalendarCtrl(wx.Panel): """ WX panel containing calendar widgets for use by the CustomEditor. Description ----------- Handles multi-selection of dates by special handling of the wxMouseBoxCalendarCtrl widget. Doing single-select across multiple calendar widgets is also supported though most of the interesting functionality is then unused. """ def __init__(self, parent, ID, editor, multi_select, shift_to_select, on_mixed_select, allow_future, months, padding, *args, **kwargs): super(MultiCalendarCtrl, self).__init__(parent, ID, *args, **kwargs) self.sizer = wx.BoxSizer() self.SetSizer(self.sizer) self.SetBackgroundColour(WindowColor) self.date = wx.DateTime_Now() self.today = self.date_from_datetime(self.date) # Object attributes self.multi_select = multi_select self.shift_to_select = shift_to_select self.on_mixed_select = on_mixed_select self.allow_future = allow_future self.editor = editor self.selected_days = editor.value self.months = months self.padding = padding self.cal_ctrls = [] # State to remember when a user is doing a shift-click selection. self._first_date = None self._drag_select = [] self._box_select = [] # Set up the individual month frames. for i in range(-(self.months-1), 1): cal = self._make_calendar_widget(i) self.cal_ctrls.insert(0, cal) if i != 0: self.sizer.AddSpacer(wx.Size(padding, padding)) # Initial painting self.selected_list_changed() return def date_from_datetime(self, dt): """ Convert a wx DateTime object to a Python Date object. Parameters ---------- dt : wx.DateTime A valid date to convert to a Python Date object """ new_date = datetime.date(dt.GetYear(), dt.GetMonth()+1, dt.GetDay()) return new_date def datetime_from_date(self, date): """ Convert a Python Date object to a wx DateTime object. Ignores time. Parameters ---------- date : datetime.Date object A valid date to convert to a wx.DateTime object. Since there is no time information in a Date object the defaults of DateTime are used. """ dt = wx.DateTime() dt.SetYear(date.year) dt.SetMonth(date.month-1) dt.SetDay(date.day) return dt def shift_datetime(self, old_date, months): """ Create a new DateTime from *old_date* with an offset number of *months*. Parameters ---------- old_date : DateTime The old DateTime to make a date copy of. Does not copy time. months : int A signed int to add or subtract from the old date months. Does not support jumping more than 12 months. """ new_date = wx.DateTime() new_month = old_date.GetMonth() + months new_year = old_date.GetYear() if new_month < 0: new_month += 12 new_year -= 1 elif new_month > 11: new_month -= 12 new_year += 1 new_day = min(old_date.GetDay(), 28) new_date.Set(new_day, new_month, new_year) return new_date def selected_list_changed(self, evt=None): """ Update the date colors of the days in the widgets. """ for cal in self.cal_ctrls: cur_month = cal.GetDate().GetMonth() + 1 cur_year = cal.GetDate().GetYear() selected_days = self.selected_days # When multi_select is False wrap in a list to pass the for-loop. if self.multi_select == False: if selected_days == None: selected_days = [] else: selected_days = [selected_days] # Reset all the days to the correct colors. for day in range(1,32): try: paint_day = datetime.date(cur_year, cur_month, day) if not self.allow_future and paint_day > self.today: attr = wx.calendar.CalendarDateAttr(colText=UNAVAILABLE_FG) cal.SetAttr(day, attr) elif paint_day in selected_days: attr = wx.calendar.CalendarDateAttr(colText=SELECTED_FG) cal.SetAttr(day, attr) else: cal.ResetAttr(day) except ValueError: # Blindly creating Date objects sometimes produces invalid. pass cal.highlight_changed() return def _make_calendar_widget(self, month_offset): """ Add a calendar widget to the screen and hook up callbacks. Parameters ---------- month_offset : int The number of months from today, that the calendar should start at. """ date = self.shift_datetime(self.date, month_offset) panel = wx.Panel(self, -1) cal = wxMouseBoxCalendarCtrl(panel, -1, date, style = wx.calendar.CAL_SUNDAY_FIRST | wx.calendar.CAL_SEQUENTIAL_MONTH_SELECTION #| wx.calendar.CAL_SHOW_HOLIDAYS ) self.sizer.Add(panel) cal.highlight_changed() # Set up control to sync the other calendar widgets and coloring: self.Bind(wx.calendar.EVT_CALENDAR_MONTH, self.month_changed, cal) self.Bind(wx.calendar.EVT_CALENDAR_YEAR, self.month_changed, cal) wx.EVT_LEFT_DOWN(cal, self._left_down) if self.multi_select: wx.EVT_LEFT_UP(cal, self._left_up) wx.EVT_RIGHT_UP(cal, self._process_box_select) wx.EVT_LEAVE_WINDOW(cal, self._process_box_select) wx.EVT_MOTION(cal, self._mouse_drag) self.Bind(wx.calendar.EVT_CALENDAR_WEEKDAY_CLICKED, self._weekday_clicked, cal) return cal def unhighlight_days(self, days): """ Turn off all highlights in all cals, but leave any selected color. Parameters ---------- days : List(Date) The list of dates to add. Possibly includes dates in the future. """ for cal in self.cal_ctrls: c = cal.GetDate() for date in days: if date.year == c.GetYear() and date.month == c.GetMonth()+1: # Unselected days either need to revert to the # unavailable color, or the default attribute color. if (not self.allow_future and ((date.year, date.month, date.day) > (self.today.year, self.today.month, self.today.day))): attr = wx.calendar.CalendarDateAttr(colText=UNAVAILABLE_FG) else: attr = wx.calendar.CalendarDateAttr( colText=NORMAL_HIGHLIGHT_FG, colBack=NORMAL_HIGHLIGHT_BG) if date in self.selected_days: attr.SetTextColour(SELECTED_FG) cal.SetAttr(date.day, attr) cal.highlight_changed() return def highlight_days(self, days): """ Color the highlighted list of days across all calendars. Parameters ---------- days : List(Date) The list of dates to add. Possibly includes dates in the future. """ for cal in self.cal_ctrls: c = cal.GetDate() for date in days: if date.year == c.GetYear() and date.month == c.GetMonth()+1: attr = wx.calendar.CalendarDateAttr( colText=DRAG_HIGHLIGHT_FG, colBack=DRAG_HIGHLIGHT_BG ) cal.SetAttr(date.day, attr) cal.highlight_changed() cal.Refresh() def add_days_to_selection(self, days): """ Add a list of days to the selection, using a specified style. Parameters ---------- days : List(Date) The list of dates to add. Possibly includes dates in the future. Description ----------- When a user multi-selects entries and some of those entries are already selected and some are not, what should be the behavior for the seletion? Options:: 'toggle' -- Toggle each day to it's opposite state. 'on' -- Always turn them on. 'off' -- Always turn them off. 'max_change' -- Change all to same state, with most days changing. For example 1 selected and 9 not, then they would all get selected. 'min_change' -- Change all to same state, with min days changing. For example 1 selected and 9 not, then they would all get unselected. """ if not days: return style = self.on_mixed_select new_list = list(self.selected_days) if style == 'toggle': for day in days: if self.allow_future or day <= self.today: if day in new_list: new_list.remove(day) else: new_list.append(day) else: already_selected = len([day for day in days if day in new_list]) if style == 'on' or already_selected == 0: add_items = True elif style == 'off' or already_selected == len(days): add_items = False elif (self.on_mixed_select == 'max_change' and already_selected <= (len(days) / 2.0)): add_items = True elif (self.on_mixed_select == 'min_change' and already_selected > (len(days) / 2.0)): add_items = True else: # Cases where max_change is off or min_change off. add_items = False for day in days: # Skip if we don't allow future, and it's a future day. if self.allow_future or day <= self.today: if add_items and day not in new_list: new_list.append(day) elif not add_items and day in new_list: new_list.remove(day) self.selected_days = new_list # Link the list back to the model to make a Traits List change event. self.editor.value = new_list return def single_select_day(self, dt): """ In non-multiselect switch the selection to a new date. Parameters ---------- dt : wx.DateTime The newly selected date that should become the new calendar selection. Description ----------- Only called when we're using the single-select mode of the calendar widget, so we can assume that the selected_dates is a None or a Date singleton. """ selection = self.date_from_datetime(dt) if dt.IsValid() and (self.allow_future or selection <= self.today): self.selected_days = selection self.selected_list_changed() # Modify the trait on the editor so that the events propagate. self.editor.value = self.selected_days return def _shift_drag_update(self, event): """ Shift-drag in progress. """ cal = event.GetEventObject() result, dt, weekday = cal.HitTest(event.GetPosition()) self.unhighlight_days(self._drag_select) self._drag_select = [] # Prepare for an abort, don't highlight new selections. if ((self.shift_to_select and not event.ShiftDown()) or result != wx.calendar.CAL_HITTEST_DAY): cal.highlight_changed() for cal in self.cal_ctrls: cal.Refresh() return # Construct the list of selections. last_date = self.date_from_datetime(dt) if last_date <= self._first_date: first, last = last_date, self._first_date else: first, last = self._first_date, last_date while first <= last: if self.allow_future or first <= self.today: self._drag_select.append(first) first = first + datetime.timedelta(1) self.highlight_days(self._drag_select) return #------------------------------------------------------------------------ # Event handlers #------------------------------------------------------------------------ def _process_box_select(self, event): """ Possibly move the calendar box-selected days into our selected days. """ event.Skip() self.unhighlight_days(self._box_select) if not event.Leaving(): self.add_days_to_selection(self._box_select) self.selected_list_changed() self._box_select = [] def _weekday_clicked(self, evt): """ A day on the weekday bar has been clicked. Select all days. """ evt.Skip() weekday = evt.GetWeekDay() cal = evt.GetEventObject() month = cal.GetDate().GetMonth()+1 year = cal.GetDate().GetYear() days = [] # Messy math to compute the dates of each weekday in the month. # Python uses Monday=0, while wx uses Sunday=0. month_start_weekday = (datetime.date(year, month, 1).weekday()+1) %7 weekday_offset = (weekday - month_start_weekday) % 7 for day in range(weekday_offset, 31, 7): try: day = datetime.date(year, month, day+1) if self.allow_future or day <= self.today: days.append(day) except ValueError: pass self.add_days_to_selection(days) self.selected_list_changed() return def _left_down(self, event): """ Handle user selection of days. """ event.Skip() cal = event.GetEventObject() result, dt, weekday = cal.HitTest(event.GetPosition()) if result == wx.calendar.CAL_HITTEST_DAY and not self.multi_select: self.single_select_day(dt) return # Inter-month-drag selection. A quick no-movement mouse-click is # equivalent to a multi-select of a single day. if (result == wx.calendar.CAL_HITTEST_DAY and (not self.shift_to_select or event.ShiftDown()) and not cal.selecting): self._first_date = self.date_from_datetime(dt) self._drag_select = [self._first_date] # Start showing the highlight colors with a mouse_drag event. self._mouse_drag(event) return def _left_up(self, event): """ Handle the end of a possible run-selection. """ event.Skip() cal = event.GetEventObject() result, dt, weekday = cal.HitTest(event.GetPosition()) # Complete a drag-select operation. if (result == wx.calendar.CAL_HITTEST_DAY and (not self.shift_to_select or event.ShiftDown()) and self._first_date): last_date = self.date_from_datetime(dt) if last_date <= self._first_date: first, last = last_date, self._first_date else: first, last = self._first_date, last_date newly_selected = [] while first <= last: newly_selected.append(first) first = first + datetime.timedelta(1) self.add_days_to_selection(newly_selected) self.unhighlight_days(newly_selected) # Reset a drag-select operation, even if it wasn't completed because # of a loss of focus or the Shift key prematurely released. self._first_date = None self._drag_select = [] self.selected_list_changed() return def _mouse_drag(self, event): """ Called when the mouse in being dragged within the main panel. """ event.Skip() cal = event.GetEventObject() if not cal.selecting and self._first_date: self._shift_drag_update(event) if cal.selecting: self.unhighlight_days(self._box_select) self._box_select = [self.date_from_datetime(dt) for dt in cal.boxed_days()] self.highlight_days(self._box_select) return def month_changed(self, evt=None): """ Link the calendars together so if one changes, they all change. TODO: Maybe wx.calendar.CAL_HITTEST_INCMONTH could be checked and the event skipped, rather than now where we undo the update after the event has gone through. """ evt.Skip() cal_index = self.cal_ctrls.index(evt.GetEventObject()) current_date = self.cal_ctrls[cal_index].GetDate() for i, cal in enumerate(self.cal_ctrls): # Current month is already updated, just need to shift the others if i != cal_index: new_date = self.shift_datetime(current_date, cal_index - i) cal.SetDate(new_date) cal.highlight_changed() # Back-up if we're not allowed to move into future months. if not self.allow_future: month = self.cal_ctrls[0].GetDate().GetMonth()+1 year = self.cal_ctrls[0].GetDate().GetYear() if (year, month) > (self.today.year, self.today.month): for i, cal in enumerate(self.cal_ctrls): new_date = self.shift_datetime(wx.DateTime_Now(), -i) cal.SetDate(new_date) cal.highlight_changed() # Redraw the selected days. self.selected_list_changed() #-- end CalendarCtrl ---------------------------------------------------------- class CustomEditor(Editor): """ Show multiple months with MultiCalendarCtrl. Allow multi-select. Trait Listeners --------------- The wx editor directly modifies the *value* trait of the Editor, which is the named trait of the corresponding Item in your View. Therefore you can listen for changes to the user's selection by directly listening to the item changed event. TODO ---- Some more listeners need to be hooked up. For example, in single-select mode, changing the value does not cause the calendar to update. Also, the selection-add and remove is noisy, triggering an event for each addition rather than waiting until everything has been added and removed. Sample ------ Example usage:: class DateListPicker(HasTraits): calendar = List traits_view = View(Item('calendar', editor=DateEditor(), style='custom', show_label=False)) """ #-- Editor interface ------------------------------------------------------ def init (self, parent): """ Finishes initializing the editor by creating the underlying widget. """ if self.factory.multi_select and not isinstance(self.value, list): raise ValueError('Multi-select is True, but editing a non-list.') elif not self.factory.multi_select and isinstance(self.value, list): raise ValueError('Multi-select is False, but editing a list.') calendar_ctrl = MultiCalendarCtrl(parent, -1, self, self.factory.multi_select, self.factory.shift_to_select, self.factory.on_mixed_select, self.factory.allow_future, self.factory.months, self.factory.padding) self.control = calendar_ctrl return def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ self.control.selected_list_changed() return #-- end CustomEditor definition ----------------------------------------------- #------------------------------------------------------------------------------ #-- Text Editor #------------------------------------------------------------------------------ # TODO: Write me. Possibly use TextEditor as a model to show a string # representation of the date, and have enter-set do a date evaluation. class TextEditor (SimpleEditor): pass #-- end TextEditor definition ------------------------------------------------- #------------------------------------------------------------------------------ #-- Readonly Editor #------------------------------------------------------------------------------ class ReadonlyEditor (TextReadonlyEditor): """ Use a TextEditor for the view. """ def _get_str_value(self): """ Replace the default string value with our own date verision. """ if not self.value: return self.factory.message else: return self.value.strftime(self.factory.strftime) #-- end ReadonlyEditor definition --------------------------------------------- #-- eof ----------------------------------------------------------------------- traitsui-4.1.0/traitsui/wx/constants.py0000644000175100001440000000430111674463546021247 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/22/2004 # #------------------------------------------------------------------------------ """ Defines constants used by the wxPython implementation of the various text editors and text editor factories. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import sys import wx #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- # Define platform and wx version constants: is_mac = (sys.platform == 'darwin') is_wx26 = (float( '.'.join( wx.__version__.split( '.' )[0:2] ) ) < 2.8) # Default dialog title DefaultTitle = 'Edit properties' # Color of valid input OKColor = wx.WHITE # Color to highlight input errors ErrorColor = wx.Colour( 255, 192, 192 ) # Color for background of read-only fields ReadonlyColor = wx.Colour( 244, 243, 238 ) # Color for background of fields where objects can be dropped DropColor = wx.Colour( 215, 242, 255 ) # Color for an editable field EditableColor = wx.WHITE # Color for background of windows (like dialog background color) if is_mac: WindowColor = wx.Colour( 232, 232, 232 ) BorderedGroupColor = wx.Colour( 224, 224, 224 ) else: WindowColor = wx.SystemSettings_GetColour( wx.SYS_COLOUR_MENUBAR ) # Standard width of an image bitmap standard_bitmap_width = 120 # Width of a scrollbar scrollbar_dx = wx.SystemSettings_GetMetric( wx.SYS_VSCROLL_X ) # Screen size values: screen_dx = wx.SystemSettings_GetMetric( wx.SYS_SCREEN_X ) screen_dy = wx.SystemSettings_GetMetric( wx.SYS_SCREEN_Y ) traitsui-4.1.0/traitsui/wx/menu.py0000644000175100001440000003044211674463546020204 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 01/24/2002 # #------------------------------------------------------------------------------ """ Dynamically construct wxPython Menus or MenuBars from a supplied string description of the menu. Menu Description Syntax:: submenu_label {help_string} menuitem_label | accelerator {help_string} [~/-name]: code *submenu_label* Label of a sub menu *menuitem_label* Label of a menu item {*help_string*} Help string to display on the status line (optional) *accelerator* Accelerator key (e.g., Ctrl-C) (The '|' and keyname are optional, but must be used together.) [~] The menu item is checkable, but is not checked initially (optional) [/] The menu item is checkable, and is checked initially (optional) [-] The menu item disabled initially (optional) [*name*] Symbolic name used to refer to menu item (optional) *code* Python code invoked when menu item is selected A line beginning with a hyphen (-) is interpreted as a menu separator. """ #=============================================================================== # Imports: #=============================================================================== import wx import re import string #=============================================================================== # Constants: #=============================================================================== help_pat = re.compile( r'(.*){(.*)}(.*)' ) options_pat = re.compile( r'(.*)\[(.*)\](.*)' ) # Mapping of key name strings to wxPython key codes key_map = { 'F1': wx.WXK_F1, 'F2': wx.WXK_F2, 'F3': wx.WXK_F3, 'F4': wx.WXK_F4, 'F5': wx.WXK_F5, 'F6': wx.WXK_F6, 'F7': wx.WXK_F7, 'F8': wx.WXK_F8, 'F9': wx.WXK_F9, 'F10': wx.WXK_F10, 'F11': wx.WXK_F11, 'F12': wx.WXK_F12 } #------------------------------------------------------------------------------- # 'MakeMenu' class: #------------------------------------------------------------------------------- class MakeMenu: """ Manages creation of menus. """ # Initialize the globally unique menu ID: cur_id = 1000 #--------------------------------------------------------------------------- # Initializes the object: #--------------------------------------------------------------------------- def __init__ ( self, desc, owner, popup = False, window = None ): """ Initializes the object. """ self.owner = owner if window is None: window = owner self.window = window self.indirect = getattr( owner, 'call_menu', None ) self.names = {} self.desc = desc.split( '\n' ) self.index = 0 self.keys = [] if popup: self.menu = menu = wx.Menu() self.parse( menu, -1 ) else: self.menu = menu = wx.MenuBar() self.parse( menu, -1 ) window.SetMenuBar( menu ) if len( self.keys ) > 0: window.SetAcceleratorTable( wx.AcceleratorTable( self.keys ) ) #--------------------------------------------------------------------------- # Recursively parses menu items from the description: #--------------------------------------------------------------------------- def parse ( self, menu, indent ): """ Recursively parses menu items from the description. """ while True: # Make sure we have not reached the end of the menu description yet: if self.index >= len( self.desc ): return # Get the next menu description line and check its indentation: dline = self.desc[ self.index ] line = dline.lstrip() indented = len( dline ) - len( line ) if indented <= indent: return # Indicate that the current line has been processed: self.index += 1 # Check for a blank or comment line: if (line == '') or (line[0:1] == '#'): continue # Check for a menu separator: if line[0:1] == '-': menu.AppendSeparator() continue # Allocate a new menu ID: MakeMenu.cur_id += 1 cur_id = MakeMenu.cur_id # Extract the help string (if any): help = '' match = help_pat.search( line ) if match: help = ' ' + match.group(2).strip() line = match.group(1) + match.group(3) # Check for a menu item: col = line.find( ':' ) if col >= 0: handler = line[ col + 1: ].strip() if handler != '': if self.indirect: self.indirect( cur_id, handler ) handler = self.indirect else: try: exec ('def handler(event,self=self.owner):\n %s\n' % handler) except: handler = null_handler else: try: exec 'def handler(event,self=self.owner):\n%s\n' % ( self.get_body( indented ), ) in globals() except: handler = null_handler wx.EVT_MENU( self.window, cur_id, handler ) not_checked = checked = disabled = False line = line[ : col ] match = options_pat.search( line ) if match: line = match.group(1) + match.group(3) not_checked, checked, disabled, name = option_check( '~/-', match.group(2).strip() ) if name != '': self.names[ name ] = cur_id setattr( self.owner, name, MakeMenuItem( self, cur_id ) ) label = line.strip() col = label.find( '|' ) if col >= 0: key = label[ col + 1: ].strip() label = '%s%s%s' % ( label[ : col ].strip(), '\t', key ) key = key.upper() flag = wx.ACCEL_NORMAL col = key.find( '-' ) if col >= 0: flag = { 'CTRL': wx.ACCEL_CTRL, 'SHIFT': wx.ACCEL_SHIFT, 'ALT': wx.ACCEL_ALT }.get( key[ : col ].strip(), wx.ACCEL_CTRL ) key = key[ col + 1: ].strip() code = key_map.get( key, None ) try: if code is None: code = ord( key ) self.keys.append( wx.AcceleratorEntry( flag, code, cur_id ) ) except: pass menu.Append( cur_id, label, help, not_checked or checked ) if checked: menu.Check( cur_id, True ) if disabled: menu.Enable( cur_id, False ) continue # Else must be the start of a sub menu: submenu = wx.Menu() label = line.strip() # Recursively parse the sub-menu: self.parse( submenu, indented ) # Add the menu to its parent: try: menu.AppendMenu( cur_id, label, submenu, help ) except: # Handle the case where 'menu' is really a 'MenuBar' (which does # not understand 'MenuAppend'): menu.Append( submenu, label ) #--------------------------------------------------------------------------- # Returns the body of an inline method: #--------------------------------------------------------------------------- def get_body ( self, indent ): """ Returns the body of an inline method. """ result = [] while self.index < len( self.desc ): line = self.desc[ self.index ] if (len( line ) - len( line.lstrip() )) <= indent: break result.append( line ) self.index += 1 result = '\n'.join( result ).rstrip() if result != '': return result return ' pass' #--------------------------------------------------------------------------- # Returns the id associated with a specified name: #--------------------------------------------------------------------------- def get_id ( self, name ): """ Returns the ID associated with a specified name. """ if isinstance(name, basestring): return self.names[ name ] return name #--------------------------------------------------------------------------- # Checks (or unchecks) a menu item specified by name: #--------------------------------------------------------------------------- def checked ( self, name, check = None ): """ Checks (or unchecks) a menu item specified by name. """ if check is None: return self.menu.IsChecked( self.get_id( name ) ) self.menu.Check( self.get_id( name ), check ) #--------------------------------------------------------------------------- # Enables (or disables) a menu item specified by name: #--------------------------------------------------------------------------- def enabled ( self, name, enable = None ): """ Enables (or disables) a menu item specified by name. """ if enable is None: return self.menu.IsEnabled( self.get_id( name ) ) self.menu.Enable( self.get_id( name ), enable ) #--------------------------------------------------------------------------- # Gets/Sets the label for a menu item: #--------------------------------------------------------------------------- def label ( self, name, label = None ): """ Gets or sets the label for a menu item. """ if label is None: return self.menu.GetLabel( self.get_id( name ) ) self.menu.SetLabel( self.get_id( name ), label ) #------------------------------------------------------------------------------- # 'MakeMenuItem' class: #------------------------------------------------------------------------------- class MakeMenuItem: """ A menu item for a menu managed by MakeMenu. """ def __init__ ( self, menu, id ): self.menu = menu self.id = id def checked ( self, check = None ): return self.menu.checked( self.id, check ) def toggle ( self ): checked = not self.checked() self.checked( checked ) return checked def enabled ( self, enable = None ): return self.menu.enabled( self.id, enable ) def label ( self, label = None ): return self.menu.label( self.id, label ) #------------------------------------------------------------------------------- # Determine whether a string contains any specified option characters, and # remove them if it does: #------------------------------------------------------------------------------- def option_check ( test, string ): """ Determines whether a string contains any specified option characters, and removes them if it does. """ result = [] for char in test: col = string.find( char ) result.append( col >= 0 ) if col >= 0: string = string[ : col ] + string[ col + 1: ] return result + [ string.strip() ] #------------------------------------------------------------------------------- # Null menu option selection handler: #------------------------------------------------------------------------------- def null_handler ( event ): print 'null_handler invoked' traitsui-4.1.0/traitsui/wx/ui_wizard.py0000644000175100001440000002372611674463546021244 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 11/01/2004 # #------------------------------------------------------------------------------ """ Creates a wizard-based wxPython user interface for a specified UI object. A wizard is a dialog box that displays a series of pages, which the user can navigate with forward and back buttons. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx import wx.wizard as wz from constants \ import DefaultTitle from helper \ import restore_window, save_window, GroupEditor from ui_panel \ import fill_panel_for_group from traits.api \ import Trait, Str #------------------------------------------------------------------------------- # Trait definitions: #------------------------------------------------------------------------------- # Trait that allows only None or a string value none_str_trait = Trait( '', None, str ) #------------------------------------------------------------------------------- # Creates a wizard-based wxPython user interface for a specified UI object: #------------------------------------------------------------------------------- def ui_wizard ( ui, parent ): """ Creates a wizard-based wxPython user interface for a specified UI object. """ # Create the copy of the 'context' we will need while editing: context = ui.context ui._context = context new_context = {} for name, value in context.items(): if value is not None: new_context[ name ] = value.clone_traits() else: new_context[ name ] = None ui.context = new_context # Now bind the context values to the 'info' object: ui.info.bind_context() # Create the wxPython wizard window: title = ui.view.title if title == '': title = DefaultTitle ui.control = wizard = wz.Wizard( parent, -1, title ) # Create all of the wizard pages: pages = [] editor_pages = [] info = ui.info shadow_group = ui.view.content.get_shadow( ui ) min_dx = min_dy = 0 # Create a dictionary mapping each contained group in shadow_group to # its id and enabled_when fields. group_fields_mapping = {} for group in shadow_group.get_content(): # FIXME: When the group's id or enabled_when or visible_when is # set, the "fill_panel_for_group" will create a new Panel to hold the # contents of the group (instead of adding them to the page itself). # This leads to an incorrect sizing of the panel(not sure why # actually): example would be 'test_ui2.py' in # Traits/integrationtests/ui. In addition, # it leads to incorrect bindings (of the id) on the UIInfo object: # the id is bound to the GroupEditor created in "fill_panel.." # instead of the PageGroupEditor created here. # A simple solution is to clear out these fields before calling # "fill_panel_for_group", and then reset these traits. group_fields_mapping[group] = (group.id, group.enabled_when) (group.id, group.enabled_when) = ('', '') page = UIWizardPage( wizard, editor_pages ) pages.append( page ) fill_panel_for_group( page, group, ui ) # Size the page correctly, then calculate cumulative minimum size: sizer = page.GetSizer() sizer.Fit( page ) size = sizer.CalcMin() min_dx = max( min_dx, size.GetWidth() ) min_dy = max( min_dy, size.GetHeight() ) # If necessary, create a PageGroupEditor and attach it to the right # places: (group.id, group.enabled_when) = group_fields_mapping[group] if group.id or group.enabled_when: page.editor = editor = PageGroupEditor( control = page ) if group.id: page.id = group.id editor_pages.append( page ) info.bind( page.id, editor ) if group.enabled_when: ui.add_enabled( group.enabled_when, editor ) # Size the wizard correctly: wizard.SetPageSize( wx.Size( min_dx, min_dy ) ) # Set up the wizard 'page changing' event handler: wz.EVT_WIZARD_PAGE_CHANGING( wizard, wizard.GetId(), page_changing ) # Size the wizard and the individual pages appropriately: prev_page = pages[0] wizard.FitToPage( prev_page ) # Link the pages together: for page in pages[1:]: page.SetPrev( prev_page ) prev_page.SetNext( page ) prev_page = page # Finalize the display of the wizard: try: ui.prepare_ui() except: ui.control.Destroy() ui.control.ui = None ui.control = None ui.result = False raise # Position the wizard on the display: ui.handler.position( ui.info ) # Restore the user_preference items for the user interface: restore_window( ui ) # Run the wizard: if wizard.RunWizard( pages[0] ): # If successful, apply the modified context to the original context: original = ui._context for name, value in ui.context.items(): if value is not None: original[ name ].copy_traits( value ) else: original[ name ] = None ui.result = True else: ui.result = False # Clean up loose ends, like restoring the original context: save_window( ui ) ui.finish() ui.context = ui._context ui._context = {} #------------------------------------------------------------------------------- # Handles the user attempting to change the current wizard page: #------------------------------------------------------------------------------- def page_changing ( event ): """ Handles the user attempting to change the current wizard page. """ # Get the page the user is trying to go to: page = event.GetPage() if event.GetDirection(): new_page = page.GetNext() else: new_page = page.GetPrev() # If the page has a disabled PageGroupEditor object, veto the page change: if ((new_page is not None) and (new_page.editor is not None) and (not new_page.editor.enabled)): event.Veto() # If their is a message associated with the editor, display it: msg = new_page.editor.msg if msg != '': wx.MessageBox( msg ) #------------------------------------------------------------------------------- # 'UIWizardPage' class: #------------------------------------------------------------------------------- class UIWizardPage ( wz.PyWizardPage ): """ A page within a wizard interface. """ #--------------------------------------------------------------------------- # Initializes the object: #--------------------------------------------------------------------------- def __init__ ( self, wizard, pages ): wz.PyWizardPage.__init__ ( self, wizard ) self.next = self.previous = self.editor = None self.pages = pages #--------------------------------------------------------------------------- # Sets the next page after this one: #--------------------------------------------------------------------------- def SetNext ( self, page ): """ Sets the next page after this one. """ self.next = page #--------------------------------------------------------------------------- # Sets the previous page before this one: #--------------------------------------------------------------------------- def SetPrev ( self, page ): """ Sets the previous page to this one. """ self.previous = page #--------------------------------------------------------------------------- # Returns the next page after this one: #--------------------------------------------------------------------------- def GetNext ( self ): """ Returns the next page after this one. """ editor = self.editor if (editor is not None) and (editor.next != ''): next = editor.next if next == None: return None for page in self.pages: if page.id == next: return page return self.next #--------------------------------------------------------------------------- # Returns the previous page before this one: #--------------------------------------------------------------------------- def GetPrev ( self ): """ Returns the previous page to this one. """ editor = self.editor if (editor is not None) and (editor.previous != ''): previous = editor.previous if previous is None: return None for page in self.pages: if page.id == previous: return page return self.previous #------------------------------------------------------------------------------- # 'PageGroupEditor' class: #------------------------------------------------------------------------------- class PageGroupEditor ( GroupEditor ): """ Editor for a group, which displays a page. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # ID of next page to display next = none_str_trait # ID of previous page to display previous = none_str_trait # Message to display if user can't link to page msg = Str traitsui-4.1.0/traitsui/wx/key_event_to_name.py0000644000175100001440000001065111674463546022733 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 09/22/2005 # #------------------------------------------------------------------------------- """ Converts a wx.KeyEvent to a standardized "name". """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- # Mapping from wxPython special key names to Enable key names key_map = { wx.WXK_BACK: 'Backspace', wx.WXK_TAB: 'Tab', wx.WXK_RETURN: 'Enter', wx.WXK_ESCAPE: 'Esc', wx.WXK_DELETE: 'Delete', wx.WXK_START: 'Start', wx.WXK_LBUTTON: 'Left Button', wx.WXK_RBUTTON: 'Right Button', wx.WXK_CANCEL: 'Cancel', wx.WXK_MBUTTON: 'Middle Button', wx.WXK_CLEAR: 'Clear', wx.WXK_SHIFT: 'Shift', wx.WXK_CONTROL: 'Control', wx.WXK_MENU: 'Menu', wx.WXK_PAUSE: 'Pause', wx.WXK_CAPITAL: 'Capital', wx.WXK_PRIOR: 'Page Up', wx.WXK_NEXT: 'Page Down', wx.WXK_END: 'End', wx.WXK_HOME: 'Home', wx.WXK_LEFT: 'Left', wx.WXK_UP: 'Up', wx.WXK_RIGHT: 'Right', wx.WXK_DOWN: 'Down', wx.WXK_SELECT: 'Select', wx.WXK_PRINT: 'Print', wx.WXK_EXECUTE: 'Execute', wx.WXK_SNAPSHOT: 'Snapshot', wx.WXK_INSERT: 'Insert', wx.WXK_HELP: 'Help', wx.WXK_NUMPAD0: 'Numpad 0', wx.WXK_NUMPAD1: 'Numpad 1', wx.WXK_NUMPAD2: 'Numpad 2', wx.WXK_NUMPAD3: 'Numpad 3', wx.WXK_NUMPAD4: 'Numpad 4', wx.WXK_NUMPAD5: 'Numpad 5', wx.WXK_NUMPAD6: 'Numpad 6', wx.WXK_NUMPAD7: 'Numpad 7', wx.WXK_NUMPAD8: 'Numpad 8', wx.WXK_NUMPAD9: 'Numpad 9', wx.WXK_MULTIPLY: 'Multiply', wx.WXK_ADD: 'Add', wx.WXK_SEPARATOR: 'Separator', wx.WXK_SUBTRACT: 'Subtract', wx.WXK_DECIMAL: 'Decimal', wx.WXK_DIVIDE: 'Divide', wx.WXK_F1: 'F1', wx.WXK_F2: 'F2', wx.WXK_F3: 'F3', wx.WXK_F4: 'F4', wx.WXK_F5: 'F5', wx.WXK_F6: 'F6', wx.WXK_F7: 'F7', wx.WXK_F8: 'F8', wx.WXK_F9: 'F9', wx.WXK_F10: 'F10', wx.WXK_F11: 'F11', wx.WXK_F12: 'F12', wx.WXK_F13: 'F13', wx.WXK_F14: 'F14', wx.WXK_F15: 'F15', wx.WXK_F16: 'F16', wx.WXK_F17: 'F17', wx.WXK_F18: 'F18', wx.WXK_F19: 'F19', wx.WXK_F20: 'F20', wx.WXK_F21: 'F21', wx.WXK_F22: 'F22', wx.WXK_F23: 'F23', wx.WXK_F24: 'F24', wx.WXK_NUMLOCK: 'Num Lock', wx.WXK_SCROLL: 'Scroll Lock' } #------------------------------------------------------------------------------- # Converts a keystroke event into a corresponding key name: #------------------------------------------------------------------------------- def key_event_to_name ( event ): """ Converts a keystroke event into a corresponding key name. """ key_code = event.GetKeyCode() if event.ControlDown() and (1 <= key_code <= 26): key = chr( key_code + 96 ) else: key = key_map.get( key_code ) if key is None: try: key = chr( key_code ) except: # Handle the case of strange keyboard codes (such as the Apple # keyboard 'apple' key): key = 'unknown' name = '' if event.AltDown(): name = 'Alt' if event.ControlDown(): name += '-Ctrl' if event.ShiftDown() and ((name != '') or (len( key ) > 1)): name += '-Shift' if key == ' ': key = 'Space' if len( name ) > 0: key = key.lower() name += ('-' + key) if name[:1] == '-': return name[1:] return name traitsui-4.1.0/traitsui/wx/color_column.py0000644000175100001440000000457211674463546021740 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # #------------------------------------------------------------------------------ """ Table column object for Color traits. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from wx \ import Colour as WxColour from traitsui.table_column \ import ObjectColumn #------------------------------------------------------------------------------- # 'ColorColumn' class: #------------------------------------------------------------------------------- class ColorColumn ( ObjectColumn ): """ Table column object for Color traits. """ #-- ObjectColumn Overrides ----------------------------------------------------- def get_cell_color ( self, object ): """ Returns the cell background color for the column for a specified object. """ color_values = getattr( object, self.name + '_' ) if type( color_values ) is tuple: wxcolor = WxColour( *self._as_int_rgb_tuple( color_values ) ) else: wxcolor = super( ColorColumn, self ).get_cell_color( object ) return wxcolor def get_value ( self, object ): """ Gets the value of the column for a specified object. """ value = getattr( self.get_object( object ), self.name ) if type( value ) is tuple: value = "(%3d, %3d, %3d)" % self._as_int_rgb_tuple( value[:-1] ) elif type( value ) is not str: value = str( value ) return value #-- Private Methods ------------------------------------------------------------ def _as_int_rgb_tuple ( self, color_values ): """ Returns object color as RGB integers. """ return ( int( 255 * color_values[0] ), int( 255 * color_values[1] ), int( 255 * color_values[2] ) ) traitsui-4.1.0/traitsui/wx/helper.py0000644000175100001440000006133011674463546020517 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/25/2004 # #------------------------------------------------------------------------------ """ Defines helper functions and classes used to define wxPython-based trait editors and trait editor factories. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx import wx.lib.scrolledpanel import sys from os.path \ import join, dirname, abspath from traits.api \ import HasPrivateTraits, Enum, CTrait, Instance, Any, Int, \ Event, Bool, BaseTraitHandler, TraitError from traitsui.ui_traits \ import convert_image, SequenceTypes from pyface.timer.api \ import do_later from constants \ import standard_bitmap_width, screen_dx, screen_dy from editor \ import Editor #------------------------------------------------------------------------------- # Trait definitions: #------------------------------------------------------------------------------- # Layout orientation for a control and its associated editor Orientation = Enum( 'horizontal', 'vertical' ) #------------------------------------------------------------------------------- # Data: #------------------------------------------------------------------------------- # Bitmap cache dictionary (indexed by filename) _bitmap_cache = {} ### NOTE: This needs major improvements: app_path = None traits_path = None #------------------------------------------------------------------------------- # Convert an image file name to a cached bitmap: #------------------------------------------------------------------------------- def bitmap_cache ( name, standard_size, path = None ): """ Converts an image file name to a cached bitmap. """ global app_path, traits_path if name[:1] == '@': image = convert_image( name.replace( ' ', '_' ).lower() ) if image is not None: return image.create_image().ConvertToBitmap() if path is None: if traits_path is None: import traitsui.wx traits_path = join( dirname( traitsui.wx.__file__ ), 'images' ) path = traits_path elif path == '': if app_path is None: app_path = join( dirname( sys.argv[0] ), '..', 'images' ) path = app_path filename = abspath( join( path, name.replace( ' ', '_' ).lower() + '.gif' )) bitmap = _bitmap_cache.get( filename + ('*'[ not standard_size: ]) ) if bitmap is not None: return bitmap std_bitmap = bitmap = wx.BitmapFromImage( wx.Image( filename ) ) _bitmap_cache[ filename ] = bitmap dx = bitmap.GetWidth() if dx < standard_bitmap_width: dy = bitmap.GetHeight() std_bitmap = wx.EmptyBitmap( standard_bitmap_width, dy ) dc1 = wx.MemoryDC() dc2 = wx.MemoryDC() dc1.SelectObject( std_bitmap ) dc2.SelectObject( bitmap ) dc1.SetPen( wx.TRANSPARENT_PEN ) dc1.SetBrush( wx.WHITE_BRUSH ) dc1.DrawRectangle( 0, 0, standard_bitmap_width, dy ) dc1.Blit( (standard_bitmap_width - dx) / 2, 0, dx, dy, dc2, 0, 0 ) _bitmap_cache[ filename + '*' ] = std_bitmap if standard_size: return std_bitmap return bitmap #------------------------------------------------------------------------------- # Returns an appropriate width for a wxChoice widget based upon the list of # values it contains: #------------------------------------------------------------------------------- def choice_width ( values ): """ Returns an appropriate width for a wxChoice widget based upon the list of values it contains: """ return max( [ len( x ) for x in values ] ) * 6 #------------------------------------------------------------------------------- # Saves the user preference items for a specified UI: #------------------------------------------------------------------------------- def save_window ( ui ): """ Saves the user preference items for a specified UI. """ control = ui.control ui.save_prefs( control.GetPositionTuple() + control.GetSizeTuple() ) #------------------------------------------------------------------------------- # Restores the user preference items for a specified UI: #------------------------------------------------------------------------------- def restore_window ( ui, is_popup = False ): """ Restores the user preference items for a specified UI. """ prefs = ui.restore_prefs() if prefs is not None: x, y, dx, dy = prefs # Check to see if the window's position is within a display. # If it is not entirely within 1 display, move it and/or # resize it to the closest window closest = find_closest_display(x,y) x, y, dx, dy = get_position_for_display(x, y, dx, dy, closest) if is_popup: position_window( ui.control, dx, dy ) else: if (dx, dy) == (0,0): # The window was saved minimized ui.control.SetDimensions( x, y, -1, -1 ) else: ui.control.SetDimensions( x, y, dx, dy ) def find_closest_display(x, y): """ For a virtual screen position, find the closest display. There are a few reasons to use this function: * the number of displays changed * the size of the displays changed * the orientation of one or more displays changed. """ closest = None for display_num in range(wx.Display.GetCount()): display = wx.Display(display_num) if closest is None: closest = display else: def _distance(x, y, display): dis_x, dis_y, dis_w, dis_h = display.GetGeometry() dis_mid_x = (dis_x+dis_w)/2 dis_mid_y = (dis_y+dis_h)/2 return (x-dis_mid_x)**2 + (y-dis_mid_y)**2 if _distance(x, y, display) < _distance(x, y, closest): closest = display return closest def get_position_for_display(x, y, dx, dy, display): """ calculates a valid position and size for a window to fit inside a display """ dis_x, dis_y, dis_w, dis_h = display.GetGeometry() dx = min(dx, dis_w) dy = min(dy, dis_h) if ((x + dx) > (dis_x + dis_w)) or (x < dis_x): x = dis_x if ((y + dy) > (dis_y + dis_h)) or (y < dis_y): y = dis_y return x, y, dx, dy #------------------------------------------------------------------------------- # Positions a window on the screen with a specified width and height so that # the window completely fits on the screen if possible: #------------------------------------------------------------------------------- def position_window ( window, width = None, height = None, parent = None ): """ Positions a window on the screen with a specified width and height so that the window completely fits on the screen if possible. """ dx, dy = window.GetSizeTuple() width = width or dx height = height or dy if parent is None: parent = window._parent if parent is None: # Center the popup on the screen: window.SetDimensions( (screen_dx - width) / 2, (screen_dy - height) / 2, width, height ) return # Calculate the desired size of the popup control: if isinstance( parent, wx.Window ): x, y = parent.ClientToScreenXY( 0, 0 ) parent_dx, parent_dy = parent.GetSizeTuple() else: # Special case of parent being a screen position and size tuple (used # to pop-up a dialog for a table cell): x, y, parent_dx, parent_dy = parent adjacent = (getattr( window, '_kind', 'popup' ) == 'popup') width = min( max( parent_dx, width ), screen_dx ) height = min( height, screen_dy ) closest = find_closest_display(x,y) if adjacent: y += parent_dy x, y, dx, dy = get_position_for_display(x, y, width, height, closest) window.SetDimensions(x, y, dx, dy) #------------------------------------------------------------------------------- # Returns the top-level window for a specified control: #------------------------------------------------------------------------------- def top_level_window_for ( control ): """ Returns the top-level window for a specified control. """ parent = control.GetParent() while parent is not None: control = parent parent = control.GetParent() return control #------------------------------------------------------------------------------- # Recomputes the mappings for a new set of enumeration values: #------------------------------------------------------------------------------- def enum_values_changed ( values ): """ Recomputes the mappings for a new set of enumeration values. """ if isinstance( values, dict ): data = [ ( unicode( v ), n ) for n, v in values.items() ] if len( data ) > 0: data.sort( lambda x, y: cmp( x[0], y[0] ) ) col = data[0][0].find( ':' ) + 1 if col > 0: data = [ ( n[ col: ], v ) for n, v in data ] elif not isinstance( values, SequenceTypes ): handler = values if isinstance( handler, CTrait ): handler = handler.handler if not isinstance( handler, BaseTraitHandler ): raise TraitError, "Invalid value for 'values' specified" if handler.is_mapped: data = [ ( unicode( n ), n ) for n in handler.map.keys() ] data.sort( lambda x, y: cmp( x[0], y[0] ) ) else: data = [ ( unicode( v ), v ) for v in handler.values ] else: data = [ ( unicode( v ), v ) for v in values ] names = [ x[0] for x in data ] mapping = {} inverse_mapping = {} for name, value in data: mapping[ name ] = value inverse_mapping[ value ] = name return ( names, mapping, inverse_mapping ) #------------------------------------------------------------------------------- # Disconnects a wx event handle from its associated control: #------------------------------------------------------------------------------- def disconnect ( control, *events ): """ Disconnects a wx event handle from its associated control. """ id = control.GetId() for event in events: event( control, id, None ) def disconnect_no_id ( control, *events ): """ Disconnects a wx event handle from its associated control. """ for event in events: event( control, None ) #------------------------------------------------------------------------------- # Creates a wx.Panel that correctly sets its background color to be the same # as its parents: #------------------------------------------------------------------------------- class TraitsUIPanel ( wx.Panel ): def __init__ ( self, parent, *args, **kw ): """ Creates a wx.Panel that correctly sets its background color to be the same as its parents. """ bg_color = kw.pop('bg_color', None) wx.Panel.__init__( self, parent, *args, **kw ) wx.EVT_CHILD_FOCUS( self, self.OnChildFocus ) if bg_color: self.SetBackgroundColour(bg_color) else: self.SetBackgroundColour( parent.GetBackgroundColour() ) def OnChildFocus ( self, event ): """ If the ChildFocusEvent contains one of the Panel's direct children, then we will Skip it to let it pass up the widget hierarchy. Otherwise, we consume the event to make sure it doesn't go any farther. This works around a problem in wx 2.8.8.1 where each Panel in a nested hierarchy generates many events that might consume too many resources. We do, however, let one event bubble up to the top so that it may inform a top-level ScrolledPanel that a descendant has acquired focus. """ if event.GetWindow() in self.GetChildren(): event.Skip() #------------------------------------------------------------------------------- # 'ChildFocusOverride' class: #------------------------------------------------------------------------------- # PyEvtHandler was only introduced in wxPython 2.8.8. Fortunately, it is only # necessary in wxPython 2.8.8. if wx.__version__ < '2.8.8': class ChildFocusOverride ( object ): def __init__ ( self, window ): # Set up the event listener. window.Bind( wx.EVT_CHILD_FOCUS, window.OnChildFocus ) else: class ChildFocusOverride ( wx.PyEvtHandler ): """ Override the scroll-to-focus behaviour in wx 2.8.8's ScrolledWindow C++ implementation for ScrolledPanel. Instantiating this class with the ScrolledPanel will register the new instance as the event handler for the panel. """ def __init__ ( self, window ): self.window = window wx.PyEvtHandler.__init__( self ) # Make self the event handler for the window. window.PushEventHandler( self ) def ProcessEvent ( self, event ): if isinstance( event, wx.ChildFocusEvent ): # Handle this one with our code and don't let the C++ event handler # get it. return self.window.OnChildFocus( event ) else: # Otherwise, just pass this along in the event handler chain. result = self.GetNextHandler().ProcessEvent( event ) return result #------------------------------------------------------------------------------- # 'TraitsUIScrolledPanel' class: #------------------------------------------------------------------------------- class TraitsUIScrolledPanel ( wx.lib.scrolledpanel.ScrolledPanel ): def __init__ ( self, parent, id = -1, pos = wx.DefaultPosition, size = wx.DefaultSize, style = wx.TAB_TRAVERSAL, name = "scrolledpanel" ): wx.PyScrolledWindow.__init__( self, parent, id, pos = pos, size = size, style = style, name = name ) # FIXME: The ScrolledPanel class calls SetInitialSize in its __init__ # method, but for some reason, that leads to very a small window size. # Calling SetSize seems to work okay, but its not clear why # SetInitialSize does not work. self.SetSize( size ) self.SetBackgroundColour( parent.GetBackgroundColour() ) # Override the C++ ChildFocus event handler: ChildFocusOverride( self ) def OnChildFocus ( self, event ): """ Handle a ChildFocusEvent. Returns a boolean so it can be used as a library call, too. """ self.ScrollChildIntoView( self.FindFocus() ) return True def ScrollChildIntoView ( self, child ): """ Scrolls the panel such that the specified child window is in view. This method overrides the original in the base class so that nested subpanels are handled correctly. """ if child is None: return sppux, sppuy = self.GetScrollPixelsPerUnit() vsx, vsy = self.GetViewStart() crx, cry, crdx, crdy = child.GetRect() subwindow = child.GetParent() while subwindow not in [self, None]: # Make sure that the descendant's position information is relative # to us, not its local parent. pwx,pwy = subwindow.GetRect()[:2] crx, cry = crx + pwx, cry + pwy subwindow = subwindow.GetParent() cr = wx.Rect( crx, cry, crdx, crdy ) client_size = self.GetClientSize() new_vsx, new_vsy = -1, -1 # Is it before the left edge? if (cr.x < 0) and (sppux > 0): new_vsx = vsx + (cr.x / sppux) # Is it above the top? if (cr.y < 0) and (sppuy > 0): new_vsy = vsy + (cr.y / sppuy) # For the right and bottom edges, scroll enough to show the whole # control if possible, but if not just scroll such that the top/left # edges are still visible: # Is it past the right edge ? if (cr.right > client_size.width) and (sppux > 0): diff = (cr.right - client_size.width) / sppux if (cr.x - (diff * sppux)) > 0: new_vsx = vsx + diff + 1 else: new_vsx = vsx + (cr.x / sppux) # Is it below the bottom ? if (cr.bottom > client_size.height) and (sppuy > 0): diff = (cr.bottom - client_size.height) / sppuy if (cr.y - (diff * sppuy)) > 0: new_vsy = vsy + diff + 1 else: new_vsy = vsy + (cr.y / sppuy) # Perform the scroll if any adjustments are needed: if (new_vsx != -1) or (new_vsy != -1): self.Scroll( new_vsx, new_vsy ) #------------------------------------------------------------------------------- # Initializes standard wx event handlers for a specified control and object: #------------------------------------------------------------------------------- # Standard wx event handlers: handlers = ( ( wx.EVT_ERASE_BACKGROUND, '_erase_background' ), ( wx.EVT_PAINT, '_paint' ), ( wx.EVT_SIZE, '_size' ), ( wx.EVT_LEFT_DOWN, '_left_down' ), ( wx.EVT_LEFT_UP, '_left_up' ), ( wx.EVT_LEFT_DCLICK, '_left_dclick' ), ( wx.EVT_MIDDLE_DOWN, '_middle_down' ), ( wx.EVT_MIDDLE_UP, '_middle_up' ), ( wx.EVT_MIDDLE_DCLICK, '_middle_dclick' ), ( wx.EVT_RIGHT_DOWN, '_right_down' ), ( wx.EVT_RIGHT_UP, '_right_up' ), ( wx.EVT_RIGHT_DCLICK, '_right_dclick' ), ( wx.EVT_MOTION, '_motion' ), ( wx.EVT_ENTER_WINDOW, '_enter' ), ( wx.EVT_LEAVE_WINDOW, '_leave' ), ( wx.EVT_MOUSEWHEEL, '_wheel' ) ) def init_wx_handlers ( control, object, prefix = '' ): """ Initializes a standard set of wx event handlers for a specified control and object using a specified prefix. """ global handlers for handler, name in handlers: method = getattr( object, prefix + name, None ) if method is not None: handler( control, method ) #------------------------------------------------------------------------------- # Safely tries to pop up an FBI window if etsdevtools.debug is installed #------------------------------------------------------------------------------- def open_fbi(): try: from etsdevtools.developer.helper.fbi import if_fbi if not if_fbi(): import traceback traceback.print_exc() except ImportError: pass #------------------------------------------------------------------------------- # 'GroupEditor' class: #------------------------------------------------------------------------------- class GroupEditor ( Editor ): #--------------------------------------------------------------------------- # Initializes the object: #--------------------------------------------------------------------------- def __init__ ( self, **traits ): """ Initializes the object. """ self.set( **traits ) #------------------------------------------------------------------------------- # 'PopupControl' class: #------------------------------------------------------------------------------- class PopupControl ( HasPrivateTraits ): #-- Constructor Traits ----------------------------------------------------- # The control the popup should be positioned relative to: control = Instance( wx.Window ) # The minimum width of the popup: width = Int # The minimum height of the popup: height = Int # Should the popup be resizable? resizable = Bool( False ) #-- Public Traits ---------------------------------------------------------- # The value (if any) set by the popup control: value = Any # Event fired when the popup control is closed: closed = Event #-- Private Traits --------------------------------------------------------- # The popup control: popup = Instance( wx.Window ) #-- Public Methods --------------------------------------------------------- def __init__ ( self, **traits ): """ Initializes the object. """ super( PopupControl, self ).__init__( **traits ) style = wx.SIMPLE_BORDER if self.resizable: style = wx.RESIZE_BORDER self.popup = popup = wx.Frame( None, -1, '', style = style ) wx.EVT_ACTIVATE( popup, self._on_close_popup ) self.create_control( popup ) self._position_control() popup.Show() def create_control ( self ): """ Creates the control. Must be overridden by a subclass. """ raise NotImplementedError def dispose ( self ): """ Called when the popup is being closed to allow any custom clean-up. Can be overridden by a subclass. """ pass #-- Event Handlers --------------------------------------------------------- def _value_changed ( self, value ): """ Handles the 'value' being changed. """ do_later( self._close_popup ) #-- Private Methods -------------------------------------------------------- def _position_control ( self ): """ Initializes the popup control's initial position and size. """ # Calculate the desired size of the popup control: px, cy = self.control.ClientToScreenXY( 0, 0 ) cdx, cdy = self.control.GetSizeTuple() pdx, pdy = self.popup.GetSizeTuple() pdx, pdy = max( pdx, cdx, self.width ), max( pdy, self.height ) # Calculate the best position and size for the pop-up: py = cy + cdy if (py + pdy) > screen_dy: if (cy - pdy) < 0: bottom = screen_dy - py if cy > bottom: py, pdy = 0, cy else: pdy = bottom else: py = cy - pdy # Finally, position the popup control: self.popup.SetDimensions( px, py, pdx, pdy ) def _on_close_popup ( self, event ): """ Closes the popup control when it is deactivated. """ if not event.GetActive(): self._close_popup() def _close_popup ( self ): """ Closes the dialog. """ wx.EVT_ACTIVATE( self.popup, None ) self.dispose() self.closed = True self.popup.Destroy() self.popup = self.control = None #------------------------------------------------------------------------------- # 'BufferDC' class: #------------------------------------------------------------------------------- class BufferDC ( wx.MemoryDC ): """ An off-screen buffer class. This class implements a off-screen output buffer. Data is meant to be drawn in the buffer and then blitted directly to the output device context. """ def __init__ ( self, dc, width = None, height = None ): """Initializes the buffer.""" wx.MemoryDC.__init__( self ) # If only a single argument is passed, it is assumed to be a wx.Window # and that we have been created within a 'paint' event for that window: if width is None: width, height = dc.GetClientSize() dc = wx.PaintDC( dc ) self.dc = dc self.bitmap = wx.EmptyBitmap( width, height ) self.SelectObject( self.bitmap ) self.SetFont( dc.GetFont() ) def copy ( self, x = 0, y = 0 ): """ Performs the blit of the buffer contents to the specified device context location. """ self.dc.Blit( x, y, self.bitmap.GetWidth(), self.bitmap.GetHeight(), self, 0, 0 ) #------------------------------------------------------------------------------- # 'Slider' class: #------------------------------------------------------------------------------- class Slider ( wx.Slider ): """ This is a 'fixed' version of the wx.Slider control which does not erase its background, which can cause a lot of update flicker and is completely unnecessary. """ def __init__ ( self, *args, **kw ): super( Slider, self ).__init__( *args, **kw ) wx.EVT_ERASE_BACKGROUND( self, self._erase_background ) def _erase_background ( self, event ): pass traitsui-4.1.0/traitsui/wx/themed_window.py0000644000175100001440000002144111674463546022074 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2007, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 07/09/2007 # #------------------------------------------------------------------------------- """ Defines a ThemedWindow base class for creating themed windows. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx from traits.api \ import HasPrivateTraits, HasTraits, Instance, Str, Enum, Any, Bool from traitsui.ui_traits \ import ATheme from helper \ import init_wx_handlers, BufferDC #------------------------------------------------------------------------------- # 'ThemedWindow' class: #------------------------------------------------------------------------------- class ThemedWindow ( HasPrivateTraits ): #-- Public Traits ---------------------------------------------------------- # The theme associated with this window: theme = ATheme # The default alignment to use: default_alignment = Enum( 'left', 'center', 'right' ) # The current mouse event state: state = Str( 'normal' ) # Optional controller used for overriding event handling: controller = Instance( HasTraits ) # Should debugging information be overlaid on the theme? debug = Bool( False ) #-- Public Methods --------------------------------------------------------- def init_control ( self ): """ Initializes the underlying wx.Window object. """ init_wx_handlers( self.control, self ) def in_control ( self, x, y ): """ Returns whether a specified (x,y) coordinate is inside the control or not. """ wdx, wdy = self.control.GetClientSize() return ((0 <= x < wdx) and (0 <= y < wdy)) def refresh ( self ): """ Refreshes the contents of the control. """ if self.control is not None: self.control.Refresh() def capture_mouse ( self ): """ Grab control of the mouse and indicate that we are controlling it. """ if not self._has_capture: self._has_capture = True self.control.CaptureMouse() def release_mouse ( self ): """ Grab control of the mouse and indicate that we are controlling it. """ if self._has_capture: self._has_capture = False self.control.ReleaseMouse() #-- Trait Event Handlers --------------------------------------------------- def _theme_changed ( self ): """ Handles the 'theme' trait being changed. """ self.refresh() #-- wxPython Event Handlers ------------------------------------------------ def _erase_background ( self, event ): """ Do not erase the background here (do it in the 'on_paint' handler). """ pass def _paint ( self, event ): """ Paint the background using the associated ImageSlice object. """ dc = BufferDC( self.control ) self._paint_bg( dc ) self._paint_fg( dc ) dc.copy() def _paint_bg ( self, dc ): """ Paints the background into the supplied device context using the associated ImageSlice object and returns the image slice used (if any). """ from image_slice import paint_parent # Repaint the parent's theme (if necessary): paint_parent( dc, self.control ) # Draw the background theme (if any): if self.theme is not None: slice = self.theme.image_slice if slice is not None: wdx, wdy = self.control.GetClientSize() slice.fill( dc, 0, 0, wdx, wdy, True ) if self.debug: dc.SetPen( wx.Pen( wx.RED ) ) dc.SetBrush( wx.TRANSPARENT_BRUSH ) theme = self.theme border = theme.border dc.DrawRectangle( border.left, border.top, wdx - border.right - border.left, wdy - border.bottom - border.top ) dc.DrawRectangle( border.left + 3, border.top + 3, wdx - border.right - border.left - 6, wdy - border.bottom - border.top - 6 ) content = theme.content x = slice.xleft + content.left y = slice.xtop + content.top dc.DrawRectangle( x - 1, y - 1, wdx - slice.xright - content.right - x + 2, wdy - slice.xbottom - content.bottom - y + 2 ) label = theme.label if slice.xtop >= slice.xbottom: y, dy = 0, slice.xtop else: y, dy = wdy - slice.xbottom, slice.xbottom if dy >= 13: x = slice.xleft + label.left y += label.top dc.DrawRectangle( x - 1, y - 1, wdx - slice.xright - label.right - x + 2, dy - label.bottom - label.top + 2 ) def _paint_fg ( self, dc ): """ Paints the foreground of the window into the supplied device context. """ pass def _size ( self, event ): """ Handles the control being resized. """ control = self.control if control is not None: control.Layout() control.Refresh() def _left_down ( self, event ): """ Handles a left mouse button down event. """ self.control.SetFocus() self.capture_mouse() self._mouse_event( 'left_down', event ) def _left_up ( self, event ): """ Handles a left mouse button up event. """ if self._has_capture: self._has_capture = False self.control.ReleaseMouse() self._mouse_event( 'left_up', event ) def _left_dclick ( self, event ): """ Handles a left mouse button double click event. """ self.capture_mouse() self._mouse_event( 'left_dclick', event ) def _middle_down ( self, event ): """ Handles a middle mouse button down event. """ self.capture_mouse() self._mouse_event( 'middle_down', event ) def _middle_up ( self, event ): """ Handles a middle mouse button up event. """ self.release_mouse() self._mouse_event( 'middle_up', event ) def _middle_dclick ( self, event ): """ Handles a middle mouse button double click event. """ self.capture_mouse() self._mouse_event( 'middle_dclick', event ) def _right_down ( self, event ): """ Handles a right mouse button down event. """ self.capture_mouse() self._mouse_event( 'right_down', event ) def _right_up ( self, event ): """ Handles a right mouse button up event. """ self.release_mouse() self._mouse_event( 'right_up', event ) def _right_dclick ( self, event ): """ Handles a right mouse button double click event. """ self.capture_mouse() self._mouse_event( 'right_dclick', event ) def _motion ( self, event ): """ Handles a mouse move event. """ self._mouse_event( 'motion', event ) def _enter ( self, event ): """ Handles the mouse entering the window event. """ self._mouse_event( 'enter', event ) def _leave ( self, event ): """ Handles the mouse leaving the window event. """ self._mouse_event( 'leave', event ) def _wheel ( self, event ): """ Handles a mouse wheel event. """ self._mouse_event( 'wheel', event ) #-- Private Methods -------------------------------------------------------- def _mouse_event ( self, name, event ): """ Routes a mouse event to the proper handler (if any). """ method_name = '%s_%s' % ( self.state, name ) method = None if self.controller is not None: method = getattr( self.controller, method_name, None ) if method is None: method = getattr( self, method_name, None ) if method is not None: method( event.GetX(), event.GetY(), event ) traitsui-4.1.0/traitsui/wx/font_editor.py0000644000175100001440000004015711674463546021560 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/21/2004 # #------------------------------------------------------------------------------ """ Defines the various font editors and the font editor factory, for the wxPython user interface toolkit.. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx from traits.api import Bool from traitsui.editors.font_editor \ import ToolkitEditorFactory as BaseToolkitEditorFactory from editor_factory \ import SimpleEditor as BaseSimpleEditor, \ TextEditor as BaseTextEditor, \ ReadonlyEditor as BaseReadonlyEditor from editor \ import Editor from helper \ import TraitsUIPanel, disconnect #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- # Standard font point sizes PointSizes = [ '8', '9', '10', '11', '12', '14', '16', '18', '20', '22', '24', '26', '28', '36', '48', '72' ] # All available font styles Styles = ['Normal', 'Slant', 'Italic'] # All available font weights Weights = ['Normal', 'Light', 'Bold'] # All available font facenames facenames = None #--------------------------------------------------------------------------- # The wxPython ToolkitEditorFactory class. #--------------------------------------------------------------------------- ## We need to add wx-specific methods to the editor factory, and so we create ## a subclass of the BaseToolkitEditorFactory. class ToolkitEditorFactory(BaseToolkitEditorFactory): """ wxPython editor factory for font editors. """ show_style = Bool(False) show_weight = Bool(False) #--------------------------------------------------------------------------- # Returns a wxFont object corresponding to a specified object's font trait: #--------------------------------------------------------------------------- def to_wx_font ( self, editor ): """ Returns a wxFont object corresponding to a specified object's font trait. """ font = editor.value return wx.Font( font.GetPointSize(), font.GetFamily(), font.GetStyle(), font.GetWeight(), font.GetUnderlined(), font.GetFaceName() ) #--------------------------------------------------------------------------- # Gets the application equivalent of a wxPython Font value: #--------------------------------------------------------------------------- def from_wx_font ( self, font ): """ Gets the application equivalent of a wxPython Font value. """ return font #--------------------------------------------------------------------------- # Returns the text representation of the specified object trait value: #--------------------------------------------------------------------------- def str_font ( self, font ): """ Returns the text representation of the specified object trait value. """ weight = { wx.LIGHT: ' Light', wx.BOLD: ' Bold' }.get( font.GetWeight(), '' ) style = { wx.SLANT: ' Slant', wx.ITALIC:' Italic' }.get( font.GetStyle(), '' ) return '%s point %s%s%s' % ( font.GetPointSize(), font.GetFaceName(), style, weight ) #--------------------------------------------------------------------------- # Returns a list of all available font facenames: #--------------------------------------------------------------------------- def all_facenames ( self ): """ Returns a list of all available font facenames. """ global facenames if facenames is None: facenames = FontEnumerator().facenames() facenames.sort() return facenames #------------------------------------------------------------------------------- # 'SimpleFontEditor' class: #------------------------------------------------------------------------------- class SimpleFontEditor ( BaseSimpleEditor ): """ Simple style of font editor, which displays a text field that contains a text representation of the font value (using that font if possible). Clicking the field displays a font selection dialog box. """ #--------------------------------------------------------------------------- # Invokes the pop-up editor for an object trait: #--------------------------------------------------------------------------- def popup_editor ( self, event ): """ Invokes the pop-up editor for an object trait. """ font_data = wx.FontData() font_data.SetInitialFont( self.factory.to_wx_font( self ) ) dialog = wx.FontDialog( self.control, font_data ) if dialog.ShowModal() == wx.ID_OK: self.value = self.factory.from_wx_font( dialog.GetFontData().GetChosenFont() ) self.update_editor() dialog.Destroy() #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ super( SimpleFontEditor, self ).update_editor() set_font( self ) #--------------------------------------------------------------------------- # Returns the text representation of a specified font value: #--------------------------------------------------------------------------- def string_value ( self, font ): """ Returns the text representation of a specified font value. """ return self.factory.str_font( font ) #------------------------------------------------------------------------------- # 'CustomFontEditor' class: #------------------------------------------------------------------------------- class CustomFontEditor ( Editor ): """ Custom style of font editor, which displays the following: * A combo box containing all available type face names. * A combo box containing the available type sizes. * A combo box containing the available type styles """ #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ # Create a panel to hold all of the buttons: self.control = panel = TraitsUIPanel( parent, -1 ) sizer = wx.BoxSizer( wx.VERTICAL ) # Add all of the font choice controls: sizer2 = wx.BoxSizer( wx.HORIZONTAL ) facenames = self.factory.all_facenames() control = self._facename = wx.Choice( panel, -1, wx.Point( 0, 0 ), wx.Size( -1, -1 ), facenames ) sizer2.Add( control, 4, wx.EXPAND ) wx.EVT_CHOICE( panel, control.GetId(), self.update_object_parts ) control = self._point_size = wx.Choice( panel, -1, wx.Point( 0, 0 ), wx.Size( -1, -1 ), PointSizes ) sizer2.Add( control, 1, wx.EXPAND | wx.LEFT, 3 ) wx.EVT_CHOICE( panel, control.GetId(), self.update_object_parts ) if self.factory.show_style: self._style = wx.Choice(panel, -1, wx.Point(0,0), wx.Size(-1, -1), Styles) sizer2.Add(self._style, 1, wx.EXPAND | wx.LEFT, 3) wx.EVT_CHOICE( panel, self._style.GetId(), self.update_object_parts ) if self.factory.show_weight: self._weight = wx.Choice(panel, -1, wx.Point(0,0), wx.Size(-1, -1), Weights) sizer2.Add(self._weight, 1, wx.EXPAND | wx.LEFT, 3) wx.EVT_CHOICE( panel, self._weight.GetId(), self.update_object_parts ) sizer.Add( sizer2, 0, wx.EXPAND ) # Set-up the layout: panel.SetSizer( sizer ) self.set_tooltip() #--------------------------------------------------------------------------- # Disposes of the contents of an editor: #--------------------------------------------------------------------------- def dispose ( self ): """ Disposes of the contents of an editor. """ disconnect( self._facename, wx.EVT_CHOICE ) disconnect( self._point_size, wx.EVT_CHOICE ) if self.factory.show_style: disconnect(self._style, wx.EVT_CHOICE) if self.factory.show_weight: disconnect(self._weight, wx.EVT_CHOICE) super( CustomFontEditor, self ).dispose() #--------------------------------------------------------------------------- # Handles the user modifying one of the font components: #--------------------------------------------------------------------------- def update_object_parts ( self, event ): """ Handles the user modifying one of the font components. """ point_size = int( self._point_size.GetStringSelection() ) facename = self._facename.GetStringSelection() style = wx.FONTSTYLE_NORMAL if self.factory.show_style: style += self._style.GetCurrentSelection() weight = wx.FONTWEIGHT_NORMAL if self.factory.show_weight: weight += self._weight.GetCurrentSelection() font = wx.Font( point_size, wx.DEFAULT, style, weight, faceName = facename ) self.value = self.factory.from_wx_font( font ) #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ font = self.factory.to_wx_font( self ) try: self._facename.SetStringSelection( font.GetFaceName() ) except: self._facename.SetSelection( 0 ) try: self._point_size.SetStringSelection( str( font.GetPointSize() ) ) except: self._point_size.SetSelection( 0 ) #--------------------------------------------------------------------------- # Returns the text representation of a specified font value: #--------------------------------------------------------------------------- def string_value ( self, font ): """ Returns the text representation of a specified font value. """ return self.factory.str_font( font ) #------------------------------------------------------------------------------- # 'TextFontEditor' class: #------------------------------------------------------------------------------- class TextFontEditor ( BaseTextEditor ): """ Text style of font editor, which displays an editable text field containing a text representation of the font value (using that font if possible). """ #--------------------------------------------------------------------------- # Handles the user changing the contents of the edit control: #--------------------------------------------------------------------------- def update_object ( self, event ): """ Handles the user changing the contents of the edit control. """ self.value = self.control.GetValue() #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes external to the editor. """ super( TextFontEditor, self ).update_editor() set_font( self ) #--------------------------------------------------------------------------- # Returns the text representation of a specified font value: #--------------------------------------------------------------------------- def string_value ( self, font ): """ Returns the text representation of a specified font value. """ return self.factory.str_font( font ) #------------------------------------------------------------------------------- # 'ReadonlyFontEditor' class: #------------------------------------------------------------------------------- class ReadonlyFontEditor ( BaseReadonlyEditor ): """ Read-only style of font editor, which displays a read-only text field containing a text representation of the font value (using that font if possible). """ #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes external to the editor. """ super( ReadonlyFontEditor, self ).update_editor() set_font( self ) #--------------------------------------------------------------------------- # Returns the text representation of a specified font value: #--------------------------------------------------------------------------- def string_value ( self, font ): """ Returns the text representation of a specified font value. """ return self.factory.str_font( font ) #------------------------------------------------------------------------------- # Set the editor control's font to match a specified font: #------------------------------------------------------------------------------- def set_font ( editor ): """ Sets the editor control's font to match a specified font. """ font = editor.factory.to_wx_font( editor ) font.SetPointSize( min( 10, font.GetPointSize() ) ) editor.control.SetFont( font ) #------------------------------------------------------------------------------- # 'FontEnumerator' class: #------------------------------------------------------------------------------- class FontEnumerator ( wx.FontEnumerator ): """ An enumeration of fonts. """ #--------------------------------------------------------------------------- # Returns a list of all available font facenames: #--------------------------------------------------------------------------- def facenames ( self ): """ Returns a list of all available font facenames. """ self._facenames = [] self.EnumerateFacenames() return self._facenames #--------------------------------------------------------------------------- # Adds a facename to the list of facenames: #--------------------------------------------------------------------------- def OnFacename ( self, facename ): """ Adds a facename to the list of facenames. """ self._facenames.append( facename ) return True # Define the names SimpleEditor, CustomEditor, TextEditor and ReadonlyEditor # which are looked up by the editor factory for the font editor. SimpleEditor = SimpleFontEditor CustomEditor = CustomFontEditor TextEditor = TextFontEditor ReadonlyEditor = ReadonlyFontEditor ### EOF ####################################################################### traitsui-4.1.0/traitsui/wx/ui_live.py0000644000175100001440000004702511674463546020701 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 11/01/2004 # #------------------------------------------------------------------------------ """ Creates a wxPython user interface for a specified UI object, where the UI is "live", meaning that it immediately updates its underlying object(s). """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx from helper \ import restore_window, save_window, TraitsUIScrolledPanel from ui_base \ import BaseDialog from ui_panel \ import panel, show_help from constants \ import DefaultTitle, WindowColor, screen_dy, \ scrollbar_dx from traitsui.undo \ import UndoHistory from traitsui.menu \ import UndoButton, RevertButton, OKButton, CancelButton, HelpButton #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- # Types of supported windows: NONMODAL = 0 MODAL = 1 POPUP = 2 POPOVER = 3 INFO = 4 # Types of 'popup' dialogs: Popups = set( ( POPUP, POPOVER, INFO ) ) #------------------------------------------------------------------------------- # Creates a 'live update' wxPython user interface for a specified UI object: #------------------------------------------------------------------------------- def ui_live ( ui, parent ): """ Creates a live, non-modal wxPython user interface for a specified UI object. """ ui_dialog( ui, parent, NONMODAL ) def ui_livemodal ( ui, parent ): """ Creates a live, modal wxPython user interface for a specified UI object. """ ui_dialog( ui, parent, MODAL ) def ui_popup ( ui, parent ): """ Creates a live, temporary popup wxPython user interface for a specified UI object. """ ui_dialog( ui, parent, POPUP ) def ui_popover ( ui, parent ): """ Creates a live, temporary popup wxPython user interface for a specified UI object. """ ui_dialog( ui, parent, POPOVER ) def ui_info ( ui, parent ): """ Creates a live, temporary popup wxPython user interface for a specified UI object. """ ui_dialog( ui, parent, INFO ) def ui_dialog ( ui, parent, style ): """ Creates a live wxPython user interface for a specified UI object. """ if ui.owner is None: ui.owner = LiveWindow() ui.owner.init( ui, parent, style ) ui.control = ui.owner.control ui.control._parent = parent try: ui.prepare_ui() except: ui.control.Destroy() ui.control.ui = None ui.control = None ui.owner = None ui.result = False raise ui.handler.position( ui.info ) restore_window( ui, is_popup = (style in Popups) ) ui.control.Layout() # Check if the control is already being displayed modally. This would be # the case if after the window was displayed, some event caused the ui to # get rebuilt (typically when the user fires the 'updated' event on the ui # ). In this case, calling ShowModal again leads to the parent window # hanging even after the control has been closed by clicking OK or Cancel # (maybe the modal mode isn't ending?) if style == MODAL and not ui.control.IsModal(): ui.control.ShowModal() else: ui.control.Show() #------------------------------------------------------------------------------- # 'LiveWindow' class: #------------------------------------------------------------------------------- class LiveWindow ( BaseDialog ): """ User interface window that immediately updates its underlying object(s). """ #--------------------------------------------------------------------------- # Initializes the object: #--------------------------------------------------------------------------- def init ( self, ui, parent, style ): self.is_modal = (style == MODAL) window_style = 0 view = ui.view if view.resizable: window_style |= wx.RESIZE_BORDER title = view.title if title == '': title = DefaultTitle history = ui.history window = ui.control if window is not None: if history is not None: history.on_trait_change( self._on_undoable, 'undoable', remove = True ) history.on_trait_change( self._on_redoable, 'redoable', remove = True ) history.on_trait_change( self._on_revertable, 'undoable', remove = True ) window.SetSizer( None ) ui.reset() else: self.ui = ui if style == MODAL: if view.resizable: window_style |= (wx.MAXIMIZE_BOX | wx.MINIMIZE_BOX) window = wx.Dialog( parent, -1, title, style = window_style | wx.DEFAULT_DIALOG_STYLE ) elif style == NONMODAL: if parent is not None: window_style |= (wx.FRAME_FLOAT_ON_PARENT | wx.FRAME_NO_TASKBAR) window = wx.Frame( parent, -1, title, style = window_style | (wx.DEFAULT_FRAME_STYLE & (~wx.RESIZE_BORDER)) ) else: if window_style == 0: window_style = wx.SIMPLE_BORDER if parent is not None: window_style |= (wx.FRAME_FLOAT_ON_PARENT | wx.FRAME_NO_TASKBAR) window = wx.Frame( parent, -1, '', style = window_style ) window._kind = ui.view.kind self._monitor = MouseMonitor( ui ) # Set the correct default window background color: window.SetBackgroundColour( WindowColor ) self.control = window wx.EVT_CLOSE( window, self._on_close_page ) wx.EVT_CHAR( window, self._on_key ) self.set_icon( view.icon ) buttons = [ self.coerce_button( button ) for button in view.buttons ] nbuttons = len( buttons ) no_buttons = ((nbuttons == 1) and self.is_button( buttons[0], '' )) has_buttons = ((not no_buttons) and ((nbuttons > 0) or view.undo or view.revert or view.ok or view.cancel)) if has_buttons or (view.menubar is not None): if history is None: history = UndoHistory() else: history = None ui.history = history # Create the actual trait sheet panel and imbed it in a scrollable # window (if requested): sw_sizer = wx.BoxSizer( wx.VERTICAL ) if ui.scrollable: sizer = wx.BoxSizer( wx.VERTICAL ) sw = TraitsUIScrolledPanel( window ) trait_sheet = panel( ui, sw ) sizer.Add( trait_sheet, 1, wx.EXPAND ) tsdx, tsdy = trait_sheet.GetSize() sw.SetScrollRate( 16, 16 ) max_dy = (2 * screen_dy) / 3 sw.SetSizer( sizer ) sw.SetSize( wx.Size( tsdx + ((tsdy > max_dy) * scrollbar_dx), min( tsdy, max_dy ) ) ) else: sw = panel( ui, window ) sw_sizer.Add( sw, 1, wx.EXPAND ) sw_sizer.SetMinSize(sw.GetSize()) # Check to see if we need to add any of the special function buttons: if (not no_buttons) and (has_buttons or view.help): sw_sizer.Add( wx.StaticLine( window, -1 ), 0, wx.EXPAND ) b_sizer = wx.BoxSizer( wx.HORIZONTAL ) # Convert all button flags to actual button actions if no buttons # were specified in the 'buttons' trait: if nbuttons == 0: if view.undo: self.check_button( buttons, UndoButton ) if view.revert: self.check_button( buttons, RevertButton ) if view.ok: self.check_button( buttons, OKButton ) if view.cancel: self.check_button( buttons, CancelButton ) if view.help: self.check_button( buttons, HelpButton ) # Create a button for each button action: for raw_button, button in zip( view.buttons, buttons ): button = self.coerce_button( button ) default = raw_button == view.default_button if self.is_button( button, 'Undo' ): self.undo = self.add_button( button, b_sizer, self._on_undo, False, default = default ) self.redo = self.add_button( button, b_sizer, self._on_redo, False, 'Redo' ) history.on_trait_change( self._on_undoable, 'undoable', dispatch = 'ui' ) history.on_trait_change( self._on_redoable, 'redoable', dispatch = 'ui' ) if history.can_undo: self._on_undoable( True ) if history.can_redo: self._on_redoable( True ) elif self.is_button( button, 'Revert' ): self.revert = self.add_button( button, b_sizer, self._on_revert, False, default = default ) history.on_trait_change( self._on_revertable, 'undoable', dispatch = 'ui' ) if history.can_undo: self._on_revertable( True ) elif self.is_button( button, 'OK' ): self.ok = self.add_button( button, b_sizer, self._on_ok, default = default) ui.on_trait_change( self._on_error, 'errors', dispatch = 'ui' ) elif self.is_button( button, 'Cancel' ): self.add_button( button, b_sizer, self._on_cancel, default = default ) elif self.is_button( button, 'Help' ): self.add_button( button, b_sizer, self._on_help, default = default ) elif not self.is_button( button, '' ): self.add_button( button, b_sizer, default = default ) sw_sizer.Add( b_sizer, 0, wx.ALIGN_RIGHT | wx.ALL, 5 ) # Add the menu bar, tool bar and status bar (if any): self.add_menubar() self.add_toolbar() self.add_statusbar() # Lay all of the dialog contents out: window.SetSizer( sw_sizer ) window.Fit() #--------------------------------------------------------------------------- # Closes the dialog window: #--------------------------------------------------------------------------- def close ( self, rc = wx.ID_OK ): """ Closes the dialog window. """ ui = self.ui ui.result = (rc == wx.ID_OK) save_window( ui ) if self.is_modal: self.control.EndModal( rc ) ui.finish() self.ui = self.undo = self.redo = self.revert = self.control = None #--------------------------------------------------------------------------- # Handles the user clicking the window/dialog 'close' button/icon: #--------------------------------------------------------------------------- def _on_close_page ( self, event ): """ Handles the user clicking the window/dialog "close" button/icon. """ if self.ui.view.close_result == False: self._on_cancel( event ) else: self._on_ok( event ) #--------------------------------------------------------------------------- # Handles the user giving focus to another window for a 'popup' view: #--------------------------------------------------------------------------- def _on_close_popup ( self, event ): """ Handles the user giving focus to another window for a 'popup' view. """ if not event.GetActive(): self.close_popup() def close_popup ( self ): # Close the window if it has not already been closed: if self.ui.info is not None and self.ui.info.ui is not None: if self._on_ok(): self._monitor.Stop() #--------------------------------------------------------------------------- # Handles the user clicking the 'OK' button: #--------------------------------------------------------------------------- def _on_ok ( self, event = None ): """ Handles the user clicking the **OK** button. """ if self.ui.handler.close( self.ui.info, True ): wx.EVT_ACTIVATE( self.control, None ) self.close( wx.ID_OK ) return True return False #--------------------------------------------------------------------------- # Handles the user hitting the 'Esc'ape key: #--------------------------------------------------------------------------- def _on_key ( self, event ): """ Handles the user pressing the Escape key. """ if event.GetKeyCode() == 0x1B: self._on_close_page( event ) #--------------------------------------------------------------------------- # Handles an 'Undo' change request: #--------------------------------------------------------------------------- def _on_undo ( self, event ): """ Handles an "Undo" change request. """ self.ui.history.undo() #--------------------------------------------------------------------------- # Handles a 'Redo' change request: #--------------------------------------------------------------------------- def _on_redo ( self, event ): """ Handles a "Redo" change request. """ self.ui.history.redo() #--------------------------------------------------------------------------- # Handles a 'Revert' all changes request: #--------------------------------------------------------------------------- def _on_revert ( self, event ): """ Handles a request to revert all changes. """ ui = self.ui if ui.history is not None: ui.history.revert() ui.handler.revert( ui.info ) #--------------------------------------------------------------------------- # Handles a 'Cancel' all changes request: #--------------------------------------------------------------------------- def _on_cancel ( self, event ): """ Handles a request to cancel all changes. """ if self.ui.handler.close( self.ui.info, False ): self._on_revert( event ) self.close( wx.ID_CANCEL ) #--------------------------------------------------------------------------- # Handles editing errors: #--------------------------------------------------------------------------- def _on_error ( self, errors ): """ Handles editing errors. """ self.ok.Enable( errors == 0 ) #--------------------------------------------------------------------------- # Handles the 'Help' button being clicked: #--------------------------------------------------------------------------- def _on_help ( self, event ): """ Handles the 'user clicking the Help button. """ self.ui.handler.show_help( self.ui.info, event.GetEventObject() ) #--------------------------------------------------------------------------- # Handles the undo history 'undoable' state changing: #--------------------------------------------------------------------------- def _on_undoable ( self, state ): """ Handles a change to the "undoable" state of the undo history """ self.undo.Enable( state ) #--------------------------------------------------------------------------- # Handles the undo history 'redoable' state changing: #--------------------------------------------------------------------------- def _on_redoable ( self, state ): """ Handles a change to the "redoable state of the undo history. """ self.redo.Enable( state ) #--------------------------------------------------------------------------- # Handles the 'revert' state changing: #--------------------------------------------------------------------------- def _on_revertable ( self, state ): """ Handles a change to the "revert" state. """ self.revert.Enable( state ) #------------------------------------------------------------------------------- # 'MouseMonitor' class: #------------------------------------------------------------------------------- class MouseMonitor ( wx.Timer ): """ Monitors a specified window and closes it the first time the mouse pointer leaves the window. """ def __init__ ( self, ui ): super( MouseMonitor, self ).__init__() self.ui = ui kind = ui.view.kind self.is_activated = self.is_info = (kind == 'info') self.border = 3 if kind == 'popup': self.border = 10 self.Start( 100 ) def Notify ( self ): ui = self.ui control = ui.control if ui.control is None: # Looks like someone forgot to tell us that the ui has been closed: self.Stop() return mx, my = wx.GetMousePosition() cx, cy = control.ClientToScreenXY( 0, 0 ) cdx, cdy = control.GetSizeTuple() if self.is_activated: # Don't close the popup if any mouse buttons are currently pressed: ms = wx.GetMouseState() if ms.LeftDown() or ms.MiddleDown() or ms.RightDown(): return # Check for the special case of the mouse pointer having to be # within the original bounds of the object the popup was created # for: if self.is_info: parent = control._parent if isinstance( parent, wx.Window ): px, py, pdx, pdy = parent.GetScreenRect() else: px, py, pdx, pdy = parent if ((mx < px) or (mx >= (px + pdx)) or (my < py) or (my >= (py + pdy))): ui.owner.close_popup() self.is_activated = False else: # Allow for a 'dead zone' border around the window to allow for # small motor control problems: border = self.border if ((mx < (cx - border)) or (mx >= (cx + cdx + border)) or (my < (cy - border)) or (my >= (cy + cdy + border))): ui.owner.close_popup() self.is_activated = False elif (cx <= mx < (cx + cdx)) and (cy <= my < (cy + cdy)): self.is_activated = True traitsui-4.1.0/traitsui/wx/image_panel.py0000644000175100001440000002716111674463546021505 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2007, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 08/11/2007 # #------------------------------------------------------------------------------- """ Defines a themed panel that wraps itself around a single child widget. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx from traits.api \ import Str, Property, Instance, Bool, cached_property from themed_window \ import ThemedWindow #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- # Size of an empty text string: ZeroTextSize = ( 0, 0, 0, 0 ) #------------------------------------------------------------------------------- # 'ImagePanel' class: #------------------------------------------------------------------------------- class ImagePanel ( ThemedWindow ): # The optional text to display in the top or bottom of the image slice: text = Str( event = 'updated' ) # Can the application change the theme contents? mutable_theme = Bool( False ) # Is the image panel capable of displaying text? can_show_text = Property # The adjusted size of the panel, taking into account the size of its # current children and the image border: adjusted_size = Property # The best size of the panel, taking into account the best size of its # children and the image border: best_size = Property # The underlying wx control: control = Instance( wx.Window ) #-- Private Traits --------------------------------------------------------- # The size of the current text: text_size = Property( depends_on = 'text, control' ) #-- Public Methods --------------------------------------------------------- def create_control ( self, parent ): """ Creates the underlying wx.Panel control. """ self.control = control = wx.Panel( parent, -1, style = wx.TAB_TRAVERSAL | wx.FULL_REPAINT_ON_RESIZE ) # Set up the sizer for the control: control.SetSizer( ImageSizer( self.theme ) ) # Initialize the control (set-up event handlers, ...) self.init_control() # Attach the image slice to the control: control._image_slice = self.theme.image_slice # Set the panel's background colour to the image slice bg_color: control.SetBackgroundColour( control._image_slice.bg_color ) return control def layout ( self ): """ Lays out the contents of the image panel. """ self.control.Layout() self.control.Refresh() #-- Property Implementations ----------------------------------------------- def _get_adjusted_size ( self ): """ Returns the adjusted size of the panel taking into account the size of its current children and the image border. """ control = self.control dx, dy = 0, 0 for child in control.GetChildren(): dx, dy = child.GetSizeTuple() size = self._adjusted_size_of( dx, dy ) control.SetSize( size ) return size def _get_best_size ( self ): """ Returns the best size of the panel taking into account the best size of its current children and the image border. """ control = self.control dx, dy = 0, 0 for child in control.GetChildren(): dx, dy = child.GetBestSize() return self._adjusted_size_of( dx, dy ) @cached_property def _get_can_show_text ( self ): """ Returns whether or not the image panel is capable of displaying text. """ tdx, tdy, descent, leading = self.control.GetFullTextExtent( 'Myj' ) slice = self.theme.image_slice tdy += 4 return ((tdy <= slice.xtop) or (tdy <= slice.xbottom) or (slice.xleft >= 40) or (slice.xright >= 40)) @cached_property def _get_text_size ( self ): """ Returns the text size information for the window. """ if (self.text == '') or (self.control is None): return ZeroTextSize return self.control.GetFullTextExtent( self.text ) #-- Trait Event Handlers --------------------------------------------------- def _updated_changed ( self ): """ Handles a change that requires the control to be updated. """ if self.control is not None: self.control.Refresh() def _mutable_theme_changed ( self, state ): """ Handles a change to the 'mutable_theme' trait. """ self.on_trait_change( self._theme_modified, 'theme.[border.-,content.-,label.-,alignment,content_color,' 'label_color]', remove = not state ) def _theme_modified ( self ): if self.control is not None: self.layout() def _theme_changed ( self, theme ): """ Handles the 'theme' trait being changed. """ super( ImagePanel, self )._theme_changed() control = self.control if (control is not None) and (theme is not None): # Attach the image slice to the control: control._image_slice = theme.image_slice # Set the panel's background colour to the image slice bg_color: control.SetBackgroundColour( control._image_slice.bg_color ) #-- wx.Python Event Handlers ----------------------------------------------- def _paint_fg ( self, dc ): """ Paints the foreground into the specified device context. """ # If we have text and have room to draw it, then do so: text = self.text if (text != '') and self.can_show_text: theme = self.theme dc.SetBackgroundMode( wx.TRANSPARENT ) dc.SetTextForeground( theme.label_color ) dc.SetFont( self.control.GetFont() ) alignment = theme.alignment label = theme.label wdx, wdy = self.control.GetClientSizeTuple() tdx, tdy, descent, leading = self.text_size tx = None slice = theme.image_slice xleft = slice.xleft xright = slice.xright xtop = slice.xtop xbottom = slice.xbottom ltop = label.top lbottom = label.bottom tdyp = tdy + ltop + lbottom cl = xleft + label.left cr = wdx - xright - label.right if (tdyp <= xtop) and (xtop >= xbottom): ty = ((ltop + xtop - lbottom - tdy) / 2) + 1 elif tdy <= xbottom: ty = wdy + ((ltop - xbottom - lbottom - tdy) / 2) else: ty = (wdy + xtop + label.top - xbottom - label.bottom - tdy) / 2 if xleft >= xright: cl = label.left cr = xleft - label.right else: cl = wdx - xright + label.left cr = wdx - label.right # Calculate the x coordinate for the specified alignment type: if alignment == 'left': tx = cl elif alignment == 'right': tx = cr - tdx else: tx = (cl + cr - tdx) / 2 # Draw the (clipped) text string: dc.SetClippingRegion( cl, ty, cr - cl, tdy ) dc.DrawText( text, tx, ty ) dc.DestroyClippingRegion() #-- Private Methods -------------------------------------------------------- def _adjusted_size_of ( self, dx, dy ): """ Returns the adjusted size of its children, taking into account the image slice border. """ slice = self.theme.image_slice content = self.theme.content sizer = self.control.GetSizer() return wx.Size( dx + min( slice.left, slice.xleft ) + min( slice.right, slice.xright ) + content.left + content.right, dy + min( slice.top, slice.xtop ) + min( slice.bottom, slice.xbottom ) + content.top + content.bottom ) #------------------------------------------------------------------------------- # 'ImageSizer' class: #------------------------------------------------------------------------------- class ImageSizer ( wx.PySizer ): """ Defines a sizer that correctly sizes a window's children to fit within the borders implicitly defined by a background ImageSlice object, """ #--------------------------------------------------------------------------- # Initializes the object: #--------------------------------------------------------------------------- def __init__ ( self, theme ): """ Initializes the object. """ super( ImageSizer, self ).__init__() # Save a reference to the theme: self._theme = theme # Save the ImageSlice object which determines the inset border size: self._image_slice = theme.image_slice #--------------------------------------------------------------------------- # Calculates the minimum size needed by the sizer: #--------------------------------------------------------------------------- def CalcMin ( self ): """ Calculates the minimum size of the control by adding its contents minimum size to the ImageSlice object's border size. """ dx, dy = 0, 0 for item in self.GetChildren(): if item.IsSizer(): dx, dy = item.GetSizer().CalcMin() else: dx, dy = item.GetWindow().GetBestSize() slice = self._image_slice content = self._theme.content return wx.Size( max( slice.left + slice.right, slice.xleft + slice.xright + content.left + content.right + dx ), max( slice.top + slice.bottom, slice.xtop + slice.xbottom + content.top + content.bottom + dy ) ) #--------------------------------------------------------------------------- # Layout the contents of the sizer based on the sizer's current size and # position: #--------------------------------------------------------------------------- def RecalcSizes ( self ): """ Layout the contents of the sizer based on the sizer's current size and position. """ x, y = self.GetPositionTuple() dx, dy = self.GetSizeTuple() slice = self._image_slice content = self._theme.content left = slice.xleft + content.left top = slice.xtop + content.top ix, iy, idx, idy = ( x + left, y + top, dx - left - slice.xright - content.right, dy - top - slice.xbottom - content.bottom ) for item in self.GetChildren(): if item.IsSizer(): item.GetSizer().SetDimension( ix, iy, idx, idy ) else: item.GetWindow().SetDimensions( ix, iy, idx, idy ) traitsui-4.1.0/traitsui/wx/ui_panel.py0000644000175100001440000015103011674463546021031 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 11/01/2004 # #------------------------------------------------------------------------------ """ Creates a panel-based wxPython user interface for a specified UI object. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx import wx.html as wh import re from cgi \ import escape from traits.api \ import Instance, Undefined from traitsui.api \ import Group from traits.trait_base \ import enumerate from traitsui.undo \ import UndoHistory from traitsui.dockable_view_element \ import DockableViewElement from traitsui.help_template \ import help_template from traitsui.menu \ import UndoButton, RevertButton, HelpButton from pyface.dock.api \ import DockWindow, DockSizer, DockSection, DockRegion, DockControl from pyface.sizers.flow \ import FlowSizer from helper \ import position_window, TraitsUIPanel, TraitsUIScrolledPanel, GroupEditor from constants \ import screen_dx, screen_dy, WindowColor from ui_base \ import BaseDialog from constants import is_mac #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- # Pattern of all digits all_digits = re.compile( r'\d+' ) # Global font used for emphasis emphasis_font = None # Global color used for emphasis emphasis_color = wx.Colour( 0, 0, 127 ) #------------------------------------------------------------------------------- # Creates a panel-based wxPython user interface for a specified UI object: #------------------------------------------------------------------------------- def ui_panel ( ui, parent ): """ Creates a panel-based wxPython user interface for a specified UI object. """ ui_panel_for( ui, parent, True ) #------------------------------------------------------------------------------- # Creates a subpanel-based wxPython user interface for a specified UI object: #------------------------------------------------------------------------------- def ui_subpanel ( ui, parent ): """ Creates a subpanel-based wxPython user interface for a specified UI object. A subpanel does not allow control buttons (other than those specified in the UI object). """ ui_panel_for( ui, parent, False ) #------------------------------------------------------------------------------- # Creates a panel-based wxPython user interface for a specified UI object: #------------------------------------------------------------------------------- def ui_panel_for ( ui, parent, buttons ): """ Creates a panel-based wxPython user interface for a specified UI object. """ # Disable screen updates on the parent control while we build the view: parent.Freeze() # Build the view: ui.control = control = Panel( ui, parent, buttons ).control # Allow screen updates to occur again: parent.Thaw() control._parent = parent control._object = ui.context.get( 'object' ) control._ui = ui try: ui.prepare_ui() except: control.Destroy() ui.control = None ui.result = False raise ui.restore_prefs() ui.result = True #------------------------------------------------------------------------------- # 'Panel' class: #------------------------------------------------------------------------------- class Panel ( BaseDialog ): """ wxPython user interface panel for Traits-based user interfaces. """ #--------------------------------------------------------------------------- # Initializes the object: #--------------------------------------------------------------------------- def __init__ ( self, ui, parent, allow_buttons ): """ Initializes the object. """ self.ui = ui history = None view = ui.view title = view.title # Reset any existing history listeners: history = ui.history if history is not None: history.on_trait_change( self._on_undoable, 'undoable', remove = True ) history.on_trait_change( self._on_redoable, 'redoable', remove = True ) history.on_trait_change( self._on_revertable, 'undoable', remove = True ) # Determine if we need any buttons or an 'undo' history: buttons = [ self.coerce_button( button ) for button in view.buttons ] nbuttons = len( buttons ) if nbuttons == 0: if view.undo: self.check_button( buttons, UndoButton ) if view.revert: self.check_button( buttons, RevertButton ) if view.help: self.check_button( buttons, HelpButton ) if allow_buttons and (history is None): for button in buttons: if (self.is_button( button, 'Undo' ) or self.is_button( button, 'Revert' )): history = UndoHistory() break ui.history = history # Create a container panel to put everything in: cpanel = getattr( self, 'control', None ) if cpanel is not None: cpanel.SetSizer( None ) cpanel.DestroyChildren() else: if is_mac: # Groups with borders have a two-tone background, and the # getter is picking the wrong color. Set to transparent # and hope that the parent has been painted. bg_color = wx.Color(224, 224, 224, 0) self.control = cpanel = TraitsUIPanel( parent, -1, bg_color=bg_color ) else: self.control = cpanel = TraitsUIPanel( parent, -1 ) # Create the actual trait sheet panel and embed it in a scrollable # window (if requested): sw_sizer = wx.BoxSizer( wx.VERTICAL ) if ui.scrollable: sizer = wx.BoxSizer( wx.VERTICAL ) sw = TraitsUIScrolledPanel( cpanel ) sizer.Add( panel( ui, sw ), 1, wx.EXPAND ) sw.SetSizerAndFit( sizer ) sw.SetScrollRate( 16, 16 ) else: sw = panel( ui, cpanel ) if ((title != '') and (not isinstance( getattr( parent, 'owner', None ), DockWindow ))): sw_sizer.Add( heading_text( cpanel, text = title ).control, 0, wx.EXPAND ) self.add_toolbar( sw_sizer ) sw_sizer.Add( sw, 1, wx.EXPAND ) if (allow_buttons and ((nbuttons != 1) or (not self.is_button( buttons[0], '' )))): # Add the special function buttons: sw_sizer.Add( wx.StaticLine( cpanel, -1 ), 0, wx.EXPAND ) b_sizer = wx.BoxSizer( wx.HORIZONTAL ) for button in buttons: if self.is_button( button, 'Undo' ): self.undo = self.add_button( button, b_sizer, self._on_undo, False ) self.redo = self.add_button( button, b_sizer, self._on_redo, False, 'Redo' ) history.on_trait_change( self._on_undoable, 'undoable', dispatch = 'ui' ) history.on_trait_change( self._on_redoable, 'redoable', dispatch = 'ui' ) elif self.is_button( button, 'Revert' ): self.revert = self.add_button( button, b_sizer, self._on_revert, False ) history.on_trait_change( self._on_revertable, 'undoable', dispatch = 'ui' ) elif self.is_button( button, 'Help' ): self.add_button( button, b_sizer, self._on_help ) elif not self.is_button( button, '' ): self.add_button( button, b_sizer ) sw_sizer.Add( b_sizer, 0, wx.ALIGN_RIGHT | wx.ALL, 5 ) cpanel.SetSizerAndFit( sw_sizer ) #--------------------------------------------------------------------------- # Handles an 'Undo' change request: #--------------------------------------------------------------------------- def _on_undo ( self, event ): """ Handles a request to undo a change. """ self.ui.history.undo() #--------------------------------------------------------------------------- # Handles a 'Redo' change request: #--------------------------------------------------------------------------- def _on_redo ( self, event ): """ Handles a request to redo a change. """ self.ui.history.redo() #--------------------------------------------------------------------------- # Handles a 'Revert' all changes request: #--------------------------------------------------------------------------- def _on_revert ( self, event ): """ Handles a request to revert all changes. """ ui = self.ui ui.history.revert() ui.handler.revert( ui.info ) #--------------------------------------------------------------------------- # Handles the 'Help' button being clicked: #--------------------------------------------------------------------------- def _on_help ( self, event ): """ Handles the **Help** button being clicked. """ self.ui.handler.show_help( self.ui.info, event.GetEventObject() ) #----------------------------------------------------------------------- # Handles the undo history 'undoable' state changing: #----------------------------------------------------------------------- def _on_undoable ( self, state ): """ Handles a change to the "undoable" state of the undo history. """ self.undo.Enable( state ) #--------------------------------------------------------------------------- # Handles the undo history 'redoable' state changing: #--------------------------------------------------------------------------- def _on_redoable ( self, state ): """ Handles a change to the "redoable" state of the undo history. """ self.redo.Enable( state ) #--------------------------------------------------------------------------- # Handles the 'revert' state changing: #--------------------------------------------------------------------------- def _on_revertable ( self, state ): """ Handles a change to the "revert" state. """ self.revert.Enable( state ) #--------------------------------------------------------------------------- # Adds an optional tool bar to the dialog (base class override): #--------------------------------------------------------------------------- def add_toolbar ( self, sizer ): """ Adds an optional toolbar to the dialog. """ toolbar = self.ui.view.toolbar if toolbar is not None: self._last_group = self._last_parent = None sizer.Add( toolbar.create_tool_bar( self.control, self ), 0, wx.EXPAND ) self._last_group = self._last_parent = None #------------------------------------------------------------------------------- # Creates a panel-based wxPython user interface for a specified UI object: # # Note: This version does not modify the UI object passed to it. #------------------------------------------------------------------------------- def panel ( ui, parent ): """ Creates a panel-based wxPython user interface for a specified UI object. This function does not modify the UI object passed to it """ # Bind the context values to the 'info' object: ui.info.bind_context() # Get the content that will be displayed in the user interface: content = ui._groups # If there is 0 or 1 Groups in the content, create a single panel for it: if len( content ) <= 1: panel = TraitsUIPanel( parent, -1 ) if len( content ) == 1: # Fill the panel with the Group's content: sg_sizer, resizable, contents = fill_panel_for_group( panel, content[0], ui ) sizer = panel.GetSizer() if sizer is not sg_sizer: sizer.Add( sg_sizer, 1, wx.EXPAND ) # Make sure the panel and its contents have been laid out properly: sizer.Fit( panel ) # Return the panel that was created: return panel # Create a notebook which will contain a page for each group in the content: nb = create_notebook_for_items( content, ui, parent, None ) nb.ui = ui # Notice when the notebook page changes (to display correct help) ###wx.EVT_NOTEBOOK_PAGE_CHANGED( parent, nb.GetId(), _page_changed ) # Return the notebook as the result: return nb #------------------------------------------------------------------------------- # Creates a notebook and adds a list of groups or items to it as separate # pages: #------------------------------------------------------------------------------- def create_notebook_for_items ( content, ui, parent, group, item_handler = None, is_dock_window = False ): """ Creates a notebook and adds a list of groups or items to it as separate pages. """ if is_dock_window: nb = parent else: dw = DockWindow( parent, handler = ui.handler, handler_args = ( ui.info, ), id = ui.id ) if group is not None: dw.theme = group.dock_theme nb = dw.control pages = [] count = 0 has_theme = ((group is not None) and (group.group_theme is not None)) # Create a notebook page for each group or item in the content: active = 0 for index, item in enumerate( content ): if isinstance( item, Group ): # Create the group as a nested DockWindow item: if item.selected: active = index sg_sizer, resizable, contents = \ fill_panel_for_group( nb, item, ui, suppress_label = True, is_dock_window = True ) # If the result is a region (i.e. notebook) with only one page, # collapse it down into just the contents of the region: if (isinstance( contents, DockRegion ) and (len( contents.contents ) == 1)): contents = contents.contents[0] # Add the content to the notebook as a new page: pages.append( contents ) else: # Create the new page as a simple DockControl containing the # specified set of controls: page_name = item.get_label( ui ) count += 1 if page_name == '': page_name = 'Page %d' % count sizer = wx.BoxSizer( wx.VERTICAL ) if has_theme: image_panel, image_sizer = add_image_panel( nb, group ) panel = image_panel.control image_sizer.Add( sizer, 1, wx.EXPAND ) else: panel = TraitsUIPanel( nb, -1 ) panel.SetSizer( sizer ) pages.append( DockControl( name = page_name, image = item.image, id = item.get_id(), style = item.dock, dockable = DockableViewElement( ui = ui, element = item ), export = item.export, control = panel ) ) item_handler( item, panel, sizer ) panel.GetSizer().Fit( panel ) region = DockRegion( contents = pages, active = active ) # If the caller is a DockWindow, return the region as the result: if is_dock_window: return region nb.SetSizer( DockSizer( contents = DockSection( contents = [ region ] ) ) ) # Return the notebook as the result: return nb #------------------------------------------------------------------------------- # Creates a themed ImagePanel for the specified group and parent window: #------------------------------------------------------------------------------- def add_image_panel ( window, group ): """ Creates a themed ImagePanel for the specified group and parent window. """ from image_panel import ImagePanel image_panel = ImagePanel( theme = group.group_theme, text = group.label ) panel = image_panel.create_control( window ) return ( image_panel, panel.GetSizer() ) #------------------------------------------------------------------------------- # Handles a notebook page being 'turned': #------------------------------------------------------------------------------- def _page_changed ( event ): nb = event.GetEventObject() nb.ui._active_group = event.GetSelection() #------------------------------------------------------------------------------- # Displays a help window for the specified UI's active Group: #------------------------------------------------------------------------------- def show_help ( ui, button ): """ Displays a help window for the specified UI's active Group. """ group = ui._groups[ ui._active_group ] template = help_template() if group.help != '': header = template.group_help % escape( group.help ) else: header = template.no_group_help fields = [] for item in group.get_content( False ): if not item.is_spacer(): fields.append( template.item_help % ( escape( item.get_label( ui ) ), escape( item.get_help( ui ) ) ) ) html = template.group_html % ( header, '\n'.join( fields ) ) HTMLHelpWindow( button, html, .25, .33 ) #------------------------------------------------------------------------------- # Displays a pop-up help window for a single trait: #------------------------------------------------------------------------------- def show_help_popup ( event ): """ Displays a pop-up help window for a single trait. """ control = event.GetEventObject() template = help_template() # Note: The following check is necessary because under Linux, we get back # a control which does not have the 'help' trait defined (it is the parent # of the object with the 'help' trait): help = getattr( control, 'help', None ) if help is not None: html = template.item_html % ( control.GetLabel(), help ) HTMLHelpWindow( control, html, .25, .13 ) #------------------------------------------------------------------------------- # Builds the user interface for a specified Group within a specified Panel: #------------------------------------------------------------------------------- def fill_panel_for_group ( panel, group, ui, suppress_label = False, is_dock_window = False, create_panel = False ): """ Builds the user interface for a specified Group within a specified Panel. """ fp = FillPanel( panel, group, ui, suppress_label, is_dock_window, create_panel ) return ( fp.control or fp.sizer, fp.resizable, fp.dock_contents ) #------------------------------------------------------------------------------- # 'FillPanel' class: #------------------------------------------------------------------------------- class FillPanel ( object ): """ A subpanel for a single group of items. """ #--------------------------------------------------------------------------- # Initializes the object: #--------------------------------------------------------------------------- def __init__ ( self, panel, group, ui, suppress_label, is_dock_window, create_panel ): """ Initializes the object. """ # Get the contents of the group: content = group.get_content() # Create a group editor object if one is needed: self.control = self.sizer = editor = None self.ui = ui self.group = group self.is_horizontal = (group.orientation == 'horizontal') layout = group.layout is_scrolled_panel = group.scrollable is_splitter = (layout == 'split') is_tabbed = (layout == 'tabbed') id = group.id # Assume our contents are not resizable: self.resizable = False if is_dock_window and (is_splitter or is_tabbed): if is_splitter: self.dock_contents = self.add_dock_window_splitter_items( panel, content, group ) else: self.resizable = group.springy self.dock_contents = create_notebook_for_items( content, ui, panel, group, self.add_notebook_item, True ) return theme = group.group_theme if (is_dock_window or create_panel or is_scrolled_panel or (id != '') or (theme is not None) or (group.visible_when != '') or (group.enabled_when != '')): if theme is not None: image_panel, image_sizer = add_image_panel( panel, group ) new_panel = image_panel.control suppress_label |= image_panel.can_show_text elif is_scrolled_panel: new_panel = TraitsUIScrolledPanel( panel ) new_panel.SetMinSize( panel.GetMinSize() ) self.resizable = True else: new_panel = TraitsUIPanel( panel, -1 ) sizer = panel.GetSizer() if sizer is None: sizer = wx.BoxSizer( wx.VERTICAL ) panel.SetSizer( sizer ) self.control = panel = new_panel if is_splitter or is_tabbed: editor = DockWindowGroupEditor( control = panel, ui = ui ) else: editor = GroupEditor( control = panel ) if id != '': ui.info.bind( group.id, editor ) if group.visible_when != '': ui.add_visible( group.visible_when, editor ) if group.enabled_when != '': ui.add_enabled( group.enabled_when, editor ) self.panel = panel self.dock_contents = None # Determine the horizontal/vertical orientation of the group: if self.is_horizontal: orientation = wx.HORIZONTAL else: orientation = wx.VERTICAL # Set up a group with or without a border around its contents: label = '' if not suppress_label: label = group.label if group.show_border: box = wx.StaticBox( panel, -1, label ) self._set_owner( box, group ) self.sizer = wx.StaticBoxSizer( box, orientation ) else: if layout == 'flow': self.sizer = FlowSizer( orientation ) else: self.sizer = wx.BoxSizer( orientation ) if label != '': self.sizer.Add( heading_text( panel, text = label ).control, 0, wx.EXPAND | wx.LEFT | wx.TOP | wx.RIGHT, 4 ) # If no sizer has been specified for the panel yet, make the new sizer # the layout sizer for the panel: if panel.GetSizer() is None: panel.SetSizer( self.sizer ) # Set up scrolling now that the sizer has been set: if is_scrolled_panel: if self.is_horizontal: panel.SetupScrolling( scroll_y = False ) else: panel.SetupScrolling( scroll_x = False ) if is_splitter: dw = DockWindow( panel, handler = ui.handler, handler_args = ( ui.info, ), id = ui.id, theme = group.dock_theme ).control if editor is not None: editor.dock_window = dw dw.SetSizer( DockSizer( contents = self.add_dock_window_splitter_items( dw, content, group ) ) ) self.sizer.Add( dw, 1, wx.EXPAND ) elif len( content ) > 0: if is_tabbed: self.resizable = group.springy dw = create_notebook_for_items( content, ui, panel, group, self.add_notebook_item ) if editor is not None: editor.dock_window = dw self.sizer.Add( dw, self.resizable, wx.EXPAND ) # Check if content is all Group objects: elif layout == 'fold': self.resizable = True self.sizer.Add( self.create_fold_for_items( panel, content ), 1, wx.EXPAND ) elif isinstance( content[0], Group ): # If so, add them to the panel and exit: self.add_groups( content, panel ) else: self.add_items(content, panel, self.sizer) # If the caller is a DockWindow, we need to define the content we are # adding to it: if is_dock_window: self.dock_contents = DockRegion( contents = [ DockControl( name = group.get_label( self.ui ), image = group.image, id = group.get_id(), style = group.dock, dockable = DockableViewElement( ui = ui, element = group ), export = group.export, control = panel ) ] ) # If we are using an background image, add the sizer to the image sizer: if theme is not None: image_sizer.Add( self.sizer, 1, wx.EXPAND ) #--------------------------------------------------------------------------- # Adds a set of groups or items separated by splitter bars to a DockWindow: #--------------------------------------------------------------------------- def add_dock_window_splitter_items ( self, window, content, group ): """ Adds a set of groups or items separated by splitter bars to a DockWindow. """ contents = [ self.add_dock_window_splitter_item( window, item, group ) for item in content ] # Create a splitter group to hold the contents: result = DockSection( contents = contents, is_row = self.is_horizontal ) # If nothing is resizable, then mark each DockControl as such: if not self.resizable: for item in result.get_controls(): item.resizable = False # Return the DockSection we created: return result #--------------------------------------------------------------------------- # Adds a single group or item to a DockWindow: #--------------------------------------------------------------------------- def add_dock_window_splitter_item ( self, window, item, group ): """ Adds a single group or item to a DockWindow. """ if isinstance( item, Group ): sizer, resizable, contents = fill_panel_for_group( window, item, self.ui, suppress_label = True, is_dock_window = True ) self.resizable |= resizable return contents orientation = wx.VERTICAL if self.is_horizontal: orientation = wx.HORIZONTAL sizer = wx.BoxSizer( orientation ) if group.group_theme is not None: image_panel, image_sizer = add_image_panel( window, group ) panel = image_panel.control image_sizer.Add( sizer, 1, wx.EXPAND ) else: panel = TraitsUIPanel( window, -1 ) panel.SetSizer( sizer ) self.add_items( [ item ], panel, sizer ) return DockRegion( contents = [ DockControl( name = item.get_label( self.ui ), image = item.image, id = item.get_id(), style = item.dock, dockable = DockableViewElement( ui = self.ui, element = item ), export = item.export, control = panel ) ] ) #--------------------------------------------------------------------------- # Adds a set of groups or items as vertical notebook pages to a vertical # notebook: #--------------------------------------------------------------------------- def create_fold_for_items ( self, window, content ): """ Adds a set of groups or items as vertical notebook pages to a vertical notebook. """ from themed_vertical_notebook import ThemedVerticalNotebook # Create the vertical notebook: nb = ThemedVerticalNotebook( scrollable = True ) result = nb.create_control( window ) # Create the notebook pages: nb.pages = [ self.create_fold_for_item( nb, item ) for item in content ] # Return the notebook we created: return result #--------------------------------------------------------------------------- # Adds a single group or item to a vertical notebook: #--------------------------------------------------------------------------- def create_fold_for_item ( self, notebook, item ): """ Adds a single group or item to a vertical notebook. """ # Create a new notebook page: page = notebook.create_page() # Create the page contents: if isinstance( item, Group ): panel, resizable, contents = fill_panel_for_group( page.parent, item, self.ui, suppress_label = True, create_panel = True ) else: panel = TraitsUIPanel( page.parent, -1 ) sizer = wx.BoxSizer( wx.VERTICAL ) panel.SetSizer( sizer ) self.add_items( [ item ], panel, sizer ) # Set the page name and control: page.name = item.get_label( self.ui ) page.control = panel # Return the new notebook page: return page #--------------------------------------------------------------------------- # Adds a single Item to a notebook: #--------------------------------------------------------------------------- def add_notebook_item ( self, item, parent, sizer ): """ Adds a single Item to a notebook. """ self.add_items( [ item ], parent, sizer ) #--------------------------------------------------------------------------- # Adds a list of Group objects to the panel: #--------------------------------------------------------------------------- def add_groups ( self, content, panel ): """ Adds a list of Group objects to the panel. """ sizer = self.sizer # Process each group: for subgroup in content: # Add the sub-group to the panel: sg_sizer, sg_resizable, contents = \ fill_panel_for_group( panel, subgroup, self.ui ) # If the sub-group is resizable: if sg_resizable: # Then so are we: self.resizable = True # Add the sub-group so that it can be resized by the layout: sizer.Add( sg_sizer, 1, wx.EXPAND | wx.ALL, 2 ) else: style = wx.EXPAND | wx.ALL growable = 0 if self.is_horizontal: if subgroup.springy: growable = 1 if subgroup.orientation == 'horizontal': style |= wx.ALIGN_CENTER_VERTICAL sizer.Add( sg_sizer, growable, style, 2 ) #--------------------------------------------------------------------------- # Adds a list of Item objects to the panel: #--------------------------------------------------------------------------- def add_items ( self, content, panel, sizer ): """ Adds a list of Item objects to the panel. """ # Get local references to various objects we need: ui = self.ui info = ui.info handler = ui.handler group = self.group show_left = group.show_left padding = group.padding col = -1 col_incr = 1 self.label_flags = 0 show_labels = False for item in content: show_labels |= item.show_label if (not self.is_horizontal) and (show_labels or (group.columns > 1)): # For a vertical list of Items with labels or multiple columns, use # a 'FlexGridSizer': self.label_pad = 0 cols = group.columns if show_labels: cols *= 2 col_incr = 2 flags = wx.TOP | wx.BOTTOM border_size = 1 item_sizer = wx.FlexGridSizer( 0, cols, 0, 5 ) if show_left: self.label_flags = wx.ALIGN_RIGHT if show_labels: for i in range( 1, cols, 2 ): item_sizer.AddGrowableCol( i ) else: # Otherwise, the current sizer will work as is: self.label_pad = 4 cols = 1 flags = wx.ALL border_size = 1 item_sizer = sizer # Process each Item in the list: for item in content: # Get the item theme (if any): theme = item.item_theme # Get the name in order to determine its type: name = item.name # Check if is a label: if name == '': label = item.label if label != '': # Update the column counter: col += col_incr # If we are building a multi-column layout with labels, # just add space in the next column: if (cols > 1) and show_labels: item_sizer.Add( ( 1, 1 ) ) if theme is not None: from image_text import ImageText label = ImageText( panel, theme, label ) item_sizer.Add( label, 0, wx.EXPAND ) elif item.style == 'simple': # Add a simple text label: label = wx.StaticText( panel, -1, label, style = wx.ALIGN_LEFT ) item_sizer.Add( label, 0, wx.EXPAND ) else: # Add the label to the sizer: label = heading_text( panel, text = label ).control item_sizer.Add( label, 0, wx.TOP | wx.BOTTOM | wx.EXPAND, 3 ) if item.emphasized: self._add_emphasis( label ) # Continue on to the next Item in the list: continue # Update the column counter: col += col_incr # Check if it is a separator: if name == '_': for i in range( cols ): if self.is_horizontal: # Add a vertical separator: line = wx.StaticLine( panel, -1, style = wx.LI_VERTICAL ) item_sizer.Add( line, 0, wx.LEFT | wx.RIGHT | wx.EXPAND, 2 ) else: # Add a horizontal separator: line = wx.StaticLine( panel, -1, style = wx.LI_HORIZONTAL ) item_sizer.Add( line, 0, wx.TOP | wx.BOTTOM | wx.EXPAND, 2 ) self._set_owner( line, item ) # Continue on to the next Item in the list: continue # Convert a blank to a 5 pixel spacer: if name == ' ': name = '5' # Check if it is a spacer: if all_digits.match( name ): # If so, add the appropriate amount of space to the sizer: n = int( name ) if self.is_horizontal: item_sizer.Add( ( n, 1 ) ) else: spacer = ( 1, n ) item_sizer.Add( spacer ) if show_labels: item_sizer.Add( spacer ) # Continue on to the next Item in the list: continue # Otherwise, it must be a trait Item: object = eval( item.object_, globals(), ui.context ) trait = object.base_trait( name ) desc = trait.desc or '' label = None # If we are displaying labels on the left, add the label to the # user interface: if show_left: if item.show_label: label = self.create_label( item, ui, desc, panel, item_sizer, border=group.show_border ) elif (cols > 1) and show_labels: label = self.dummy_label( panel, item_sizer ) # Get the editor factory associated with the Item: editor_factory = item.editor if editor_factory is None: editor_factory = trait.get_editor() # If still no editor factory found, use a default text editor: if editor_factory is None: from text_editor import ToolkitEditorFactory editor_factory = ToolkitEditorFactory() # If the item has formatting traits set them in the editor # factory: if item.format_func is not None: editor_factory.format_func = item.format_func if item.format_str != '': editor_factory.format_str = item.format_str # If the item has an invalid state extended trait name, set it # in the editor factory: if item.invalid != '': editor_factory.invalid = item.invalid # Set up the background image (if used): item_panel = panel if theme is not None: from image_panel import ImagePanel text = '' if item.show_label: text = item.get_label( ui ) image_panel = ImagePanel( theme = theme, text = text ) item_panel = image_panel.create_control( panel ) # Create the requested type of editor from the editor factory: factory_method = getattr( editor_factory, item.style + '_editor' ) editor = factory_method( ui, object, name, item.tooltip, item_panel ).set( item = item, object_name = item.object ) # Tell editor to actually build the editing widget: editor.prepare( item_panel ) # Set the initial 'enabled' state of the editor from the factory: editor.enabled = editor_factory.enabled # Add emphasis to the editor control if requested: if item.emphasized: self._add_emphasis( editor.control ) # Give the editor focus if it requested it: if item.has_focus: editor.control.SetFocus() # Adjust the maximum border size based on the editor's settings: border_size = min( border_size, editor.border_size ) # Set up the reference to the correct 'control' to use in the # following section, depending upon whether we have wrapped an # ImagePanel around the editor control or not: control = editor.control if theme is None: width, height = control.GetSizeTuple() else: item_panel.GetSizer().Add( control, 1, wx.EXPAND ) control = item_panel width, height = image_panel.adjusted_size # Set the correct size on the control, as specified by the user: scrollable = editor.scrollable item_width = item.width item_height = item.height growable = 0 if (item_width != -1.0) or (item_height != -1.0): if (0.0 < item_width <= 1.0) and self.is_horizontal: growable = int( 1000.0 * item_width ) item_width = -1 item_width = int( item_width ) if item_width < -1: item_width = -item_width elif item_width != -1: item_width = max( item_width, width ) if (0.0 < item_height <= 1.0) and (not self.is_horizontal): growable = int( 1000.0 * item_height ) item_height = -1 item_height = int( item_height ) if item_height < -1: item_height = -item_height elif item_height != -1: item_height = max( item_height, height ) control.SetMinSize( wx.Size( item_width, item_height ) ) # Bind the item to the control and all of its children: self._set_owner( control, item ) # Bind the editor into the UIInfo object name space so it can be # referred to by a Handler while the user interface is active: id = item.id or name info.bind( id, editor, item.id ) # Also, add the editors to the list of editors used to construct # the user interface: ui._editors.append( editor ) # If the handler wants to be notified when the editor is created, # add it to the list of methods to be called when the UI is # complete: defined = getattr( handler, id + '_defined', None ) if defined is not None: ui.add_defined( defined ) # If the editor is conditionally visible, add the visibility # 'expression' and the editor to the UI object's list of monitored # objects: if item.visible_when != '': ui.add_visible( item.visible_when, editor ) # If the editor is conditionally enabled, add the enabling # 'expression' and the editor to the UI object's list of monitored # objects: if item.enabled_when != '': ui.add_enabled( item.enabled_when, editor ) # Add the created editor control to the sizer with the appropriate # layout flags and values: ui._scrollable |= scrollable item_resizable = ((item.resizable is True) or ((item.resizable is Undefined) and scrollable)) if item_resizable: growable = growable or 500 self.resizable = True elif item.springy: growable = growable or 500 # The following is a hack to allow 'readonly' text fields to # work correctly (wx has a bug that setting wx.EXPAND on a # StaticText control seems to cause the text to be aligned higher # than it would be otherwise, causing it to misalign with its # label). layout_style = editor.layout_style if not show_labels: layout_style |= wx.EXPAND item_sizer.Add( control, growable, flags | layout_style | wx.ALIGN_CENTER_VERTICAL, max( 0, border_size + padding + item.padding ) ) # If we are displaying labels on the right, add the label to the # user interface: if not show_left: if item.show_label: label = self.create_label( item, ui, desc, panel, item_sizer, '', wx.RIGHT ) elif (cols > 1) and show_labels: label = self.dummy_label( panel, item_sizer ) # If the Item is resizable, and we are using a multi-column grid: if item_resizable and (cols > 1): # Mark the entire row as growable: item_sizer.AddGrowableRow( col / cols ) # Save the reference to the label control (if any) in the editor: editor.label_control = label # If we created a grid sizer, add it to the original sizer: if item_sizer is not sizer: growable = 0 if self.resizable: growable = 1 sizer.Add( item_sizer, growable, wx.EXPAND | wx.ALL, 2 ) #--------------------------------------------------------------------------- # Creates an item label: #--------------------------------------------------------------------------- def create_label ( self, item, ui, desc, parent, sizer, suffix = ':', pad_side = wx.LEFT, border=False ): """ Creates an item label. """ from image_text import ImageText label = item.get_label( ui ) if (label == '') or (label[-1:] in '?=:;,.<>/\\"\'-+#|'): suffix = '' control = ImageText( parent, item.label_theme, label + suffix, border=border ) self._set_owner( control, item ) if item.emphasized: self._add_emphasis( control ) # XXX: Turning off help popups for now #wx.EVT_LEFT_UP( control, show_help_popup ) control.help = item.get_help( ui ) sizer.Add( control, 0, self.label_flags | wx.ALIGN_CENTER_VERTICAL | pad_side, self.label_pad ) if desc != '': control.SetToolTipString( 'Specifies ' + desc ) return control #--------------------------------------------------------------------------- # Creates a dummy item label: #--------------------------------------------------------------------------- def dummy_label ( self, parent, sizer ): """ Creates an item label. """ control = wx.StaticText( parent, -1, '', style = wx.ALIGN_RIGHT ) sizer.Add( control, 0 ) return control #--------------------------------------------------------------------------- # Adds 'emphasis' to a specified control: #--------------------------------------------------------------------------- def _add_emphasis ( self, control ): """ Adds emphasis to a specified control's font. """ global emphasis_font control.SetForegroundColour( emphasis_color ) if emphasis_font is None: font = control.GetFont() emphasis_font = wx.Font( font.GetPointSize() + 1, font.GetFamily(), font.GetStyle(), wx.BOLD ) control.SetFont( emphasis_font ) #--------------------------------------------------------------------------- # Sets the owner of a specified control and all of its children: #--------------------------------------------------------------------------- def _set_owner ( self, control, owner ): control._owner = owner for child in control.GetChildren(): self._set_owner( child, owner ) #------------------------------------------------------------------------------- # 'DockWindowGroupEditor' class: #------------------------------------------------------------------------------- class DockWindowGroupEditor ( GroupEditor ): """ Editor for a group which displays a DockWindow. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # DockWindow for the group dock_window = Instance( wx.Window ) #-- UI preference save/restore interface ----------------------------------- #--------------------------------------------------------------------------- # Restores any saved user preference information associated with the # editor: #--------------------------------------------------------------------------- def restore_prefs ( self, prefs ): """ Restores any saved user preference information associated with the editor. """ if isinstance( prefs, dict ): structure = prefs.get( 'structure' ) else: structure = prefs self.dock_window.GetSizer().SetStructure( self.dock_window, structure ) self.dock_window.Layout() #--------------------------------------------------------------------------- # Returns any user preference information associated with the editor: #--------------------------------------------------------------------------- def save_prefs ( self ): """ Returns any user preference information associated with the editor. """ return { 'structure': self.dock_window.GetSizer().GetStructure() } #-- End UI preference save/restore interface ------------------------------- #------------------------------------------------------------------------------- # 'HTMLHelpWindow' class: #------------------------------------------------------------------------------- class HTMLHelpWindow ( wx.Frame ): """ Window for displaying Traits-based help text with HTML formatting. """ #--------------------------------------------------------------------------- # Initializes the object: #--------------------------------------------------------------------------- def __init__ ( self, parent, html, scale_dx, scale_dy ): """ Initializes the object. """ wx.Frame.__init__( self, parent, -1, 'Help', style = wx.SIMPLE_BORDER ) self.SetBackgroundColour( WindowColor ) # Wrap the dialog around the image button panel: sizer = wx.BoxSizer( wx.VERTICAL ) html_control = wh.HtmlWindow( self ) html_control.SetBorders( 2 ) html_control.SetPage( html ) sizer.Add( html_control, 1, wx.EXPAND ) sizer.Add( wx.StaticLine( self, -1 ), 0, wx.EXPAND ) b_sizer = wx.BoxSizer( wx.HORIZONTAL ) button = wx.Button( self, -1, 'OK' ) wx.EVT_BUTTON( self, button.GetId(), self._on_ok ) b_sizer.Add( button, 0 ) sizer.Add( b_sizer, 0, wx.ALIGN_RIGHT | wx.ALL, 5 ) self.SetSizer( sizer ) self.SetSize( wx.Size( int( scale_dx * screen_dx ), int( scale_dy * screen_dy ) ) ) # Position and show the dialog: position_window( self, parent = parent ) self.Show() #--------------------------------------------------------------------------- # Handles the window being closed: #--------------------------------------------------------------------------- def _on_ok ( self, event ): """ Handles the window being closed. """ self.Destroy() #------------------------------------------------------------------------------- # Creates a PyFace HeadingText control: #------------------------------------------------------------------------------- HeadingText = None def heading_text ( *args, **kw ): """ Creates a PyFace HeadingText control. """ global HeadingText if HeadingText is None: from pyface.heading_text import HeadingText return HeadingText( *args, **kw ) traitsui-4.1.0/traitsui/wx/list_str_editor.py0000644000175100001440000010212511674463546022447 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2007, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 05/08/2007 # #------------------------------------------------------------------------------- """ Traits UI editor for editing lists of strings. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx from traits.api \ import Str, Int, List, Bool, Instance, Any, Event, TraitListEvent, \ Property # FIXME: ListStrEditor is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.list_editor file. from traitsui.editors.list_str_editor \ import ListStrEditor from traitsui.list_str_adapter \ import ListStrAdapter from traitsui.wx.editor \ import Editor from pyface.image_resource \ import ImageResource from helper \ import disconnect, disconnect_no_id try: from pyface.wx.drag_and_drop \ import PythonDropSource, PythonDropTarget except: PythonDropSource = PythonDropTarget = None #------------------------------------------------------------------------------- # 'wxListCtrl' class: #------------------------------------------------------------------------------- class wxListCtrl ( wx.ListCtrl ): """ Subclass of wx.ListCtrl to provide correct virtual list behavior. """ def OnGetItemAttr ( self, index ): """ Returns the display attributes to use for the specified list item. """ # fixme: There appears to be a bug in wx in that they do not correctly # manage the reference count for the returned object, and it seems to be # gc'ed before they finish using it. So we store an object reference to # it to prevent it from going away too soon... self._attr = attr = wx.ListItemAttr() editor = self._editor adapter = editor.adapter if editor._is_auto_add( index ): bg_color = adapter.get_default_bg_color( editor.object, editor.name ) color = adapter.get_default_text_color( editor.object, editor.name ) else: bg_color = adapter.get_bg_color( editor.object, editor.name, index ) color = adapter.get_text_color( editor.object, editor.name, index ) if bg_color is not None: attr.SetBackgroundColour( bg_color ) if color is not None: attr.SetTextColour( color ) return attr def OnGetItemImage ( self, index ): """ Returns the image index to use for the specified list item. """ editor = self._editor if editor._is_auto_add( index ): image = editor.adapter.get_default_image( editor.object, editor.name ) else: image = editor.adapter.get_image( editor.object, editor.name, index ) image = editor._get_image( image ) if image is not None: return image return -1 def OnGetItemText ( self, index, column ): """ Returns the text to use for the specified list item. """ editor = self._editor if editor._is_auto_add( index ): return editor.adapter.get_default_text( editor.object, editor.name ) return editor.adapter.get_text( editor.object, editor.name, index ) #------------------------------------------------------------------------------- # '_ListStrEditor' class: #------------------------------------------------------------------------------- class _ListStrEditor ( Editor ): """ Traits UI editor for editing lists of strings. """ #-- Trait Definitions ------------------------------------------------------ # The title of the editor: title = Str # The current set of selected items (which one is used depends upon the # initial state of the editor factory 'multi_select' trait): selected = Any multi_selected = List # The current set of selected item indices (which one is used depends upon # the initial state of the editor factory 'multi_select' trait): selected_index = Int multi_selected_indices = List( Int ) # The most recently actived item and its index: activated = Any activated_index = Int # The most recently right_clicked item and its index: right_clicked = Event right_clicked_index = Event # Is the list editor scrollable? This value overrides the default. scrollable = True # Index of item to select after rebuilding editor list: index = Any # Should the selected item be edited after rebuilding the editor list: edit = Bool( False ) # The adapter from list items to editor values: adapter = Instance( ListStrAdapter ) # Dictionaly mapping image names to wx.ImageList indices: images = Any( {} ) # Dictionary mapping ImageResource objects to wx.ImageList indices: image_resources = Any( {} ) # The current number of item currently in the list: item_count = Property # The current search string: search = Str #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ factory = self.factory # Set up the adapter to use: self.adapter = factory.adapter self.sync_value( factory.adapter_name, 'adapter', 'from' ) # Determine the style to use for the list control: style = wx.LC_REPORT | wx.LC_VIRTUAL if factory.editable: style |= wx.LC_EDIT_LABELS if factory.horizontal_lines: style |= wx.LC_HRULES if not factory.multi_select: style |= wx.LC_SINGLE_SEL if (factory.title == '') and (factory.title_name == ''): style |= wx.LC_NO_HEADER # Create the list control and link it back to us: self.control = control = wxListCtrl( parent, -1, style = style ) control._editor = self # Create the list control column: control.InsertColumn( 0, '' ) # Set up the list control's event handlers: id = control.GetId() wx.EVT_LIST_BEGIN_DRAG( parent, id, self._begin_drag ) wx.EVT_LIST_BEGIN_LABEL_EDIT( parent, id, self._begin_label_edit ) wx.EVT_LIST_END_LABEL_EDIT( parent, id, self._end_label_edit ) wx.EVT_LIST_ITEM_SELECTED( parent, id, self._item_selected ) wx.EVT_LIST_ITEM_DESELECTED( parent, id, self._item_selected ) wx.EVT_LIST_ITEM_RIGHT_CLICK( parent, id, self._right_clicked ) wx.EVT_LIST_ITEM_ACTIVATED( parent, id, self._item_activated ) wx.EVT_SIZE( control, self._size_modified ) # Handle key events: wx.EVT_CHAR( control, self._key_pressed ) # Handle mouse events: if 'edit' in factory.operations: wx.EVT_LEFT_DOWN( control, self._left_down ) # Set up the drag and drop target: if PythonDropTarget is not None: control.SetDropTarget( PythonDropTarget( self ) ) # Initialize the editor title: self.title = factory.title self.sync_value( factory.title_name, 'title', 'from' ) # Set up the selection listener (if necessary): if factory.multi_select: self.sync_value( factory.selected, 'multi_selected', 'both', is_list = True ) self.sync_value( factory.selected_index, 'multi_selected_indices', 'both', is_list = True ) else: self.sync_value( factory.selected, 'selected', 'both' ) self.sync_value( factory.selected_index, 'selected_index', 'both' ) # Synchronize other interesting traits as necessary: self.sync_value( factory.activated, 'activated', 'to' ) self.sync_value( factory.activated_index, 'activated_index', 'to' ) self.sync_value( factory.right_clicked, 'right_clicked', 'to' ) self.sync_value( factory.right_clicked_index, 'right_clicked_index', 'to' ) # Make sure we listen for 'items' changes as well as complete list # replacements: self.context_object.on_trait_change( self.update_editor, self.extended_name + '_items', dispatch = 'ui' ) # Create the mapping from user supplied images to wx.ImageList indices: for image_resource in factory.images: self._add_image( image_resource ) # Refresh the editor whenever the adapter changes: self.on_trait_change( self._refresh, 'adapter.+update', dispatch = 'ui' ) # Set the list control's tooltip: self.set_tooltip() def dispose ( self ): """ Disposes of the contents of an editor. """ disconnect( self.control, wx.EVT_LIST_BEGIN_DRAG, wx.EVT_LIST_BEGIN_LABEL_EDIT, wx.EVT_LIST_END_LABEL_EDIT, wx.EVT_LIST_ITEM_SELECTED, wx.EVT_LIST_ITEM_DESELECTED, wx.EVT_LIST_ITEM_RIGHT_CLICK, wx.EVT_LIST_ITEM_ACTIVATED ) disconnect_no_id( self.control, wx.EVT_SIZE, wx.EVT_CHAR, wx.EVT_LEFT_DOWN ) self.context_object.on_trait_change( self.update_editor, self.extended_name + '_items', remove = True ) self.on_trait_change( self._refresh, 'adapter.+update', remove = True ) super( _ListStrEditor, self ).dispose() def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ control = self.control top = control.GetTopItem() pn = control.GetCountPerPage() n = self.adapter.len( self.object, self.name ) if self.factory.auto_add: n += 1 control.DeleteAllItems() control.SetItemCount( n ) control.RefreshItems( 0, n - 1 ) control.SetColumnWidth( 0, control.GetClientSizeTuple()[0] ) edit, self.edit = self.edit, False index, self.index = self.index, None if index is not None: if index >= n: index -= 1 if index < 0: index = None if index is None: visible = top + pn - 2 if visible >= 0 and visible < control.GetItemCount(): control.EnsureVisible( visible ) return if 0 <= (index - top) < pn: control.EnsureVisible( top + pn - 2 ) elif index < top: control.EnsureVisible( index + pn - 1 ) else: control.EnsureVisible( index ) control.SetItemState( index, wx.LIST_STATE_SELECTED | wx.LIST_STATE_FOCUSED, wx.LIST_STATE_SELECTED | wx.LIST_STATE_FOCUSED ) if edit: control.EditLabel( index ) #-- Property Implementations ----------------------------------------------- def _get_item_count ( self ): return (self.control.GetItemCount() - self.factory.auto_add) #-- Trait Event Handlers --------------------------------------------------- def _title_changed ( self, title ): """ Handles the editor title being changed. """ list_item = wx.ListItem() list_item.SetText( title ) self.control.SetColumn( 0, list_item ) def _selected_changed ( self, selected ): """ Handles the editor's 'selected' trait being changed. """ if not self._no_update: try: self.control.SetItemState( self.value.index( selected ), wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED ) except: pass def _selected_index_changed ( self, selected_index ): """ Handles the editor's 'selected_index' trait being changed. """ if not self._no_update: self.control.SetItemState( selected_index, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED ) def _multi_selected_changed ( self, selected ): """ Handles the editor's 'multi_selected' trait being changed. """ if not self._no_update: values = self.value try: self._multi_selected_indices_changed( [ values.index( item ) for item in selected ] ) except: pass def _multi_selected_items_changed ( self, event ): """ Handles the editor's 'multi_selected' trait being modified. """ values = self.values try: self._multi_selected_indices_items_changed( TraitListEvent( 0, [ values.index( item ) for item in event.removed ], [ values.index( item ) for item in event.added ] ) ) except: pass def _multi_selected_indices_changed ( self, selected_indices ): """ Handles the editor's 'multi_selected_indices' trait being changed. """ if not self._no_update: control = self.control selected = self._get_selected() # Select any new items that aren't already selected: for index in selected_indices: if index in selected: selected.remove( index ) else: control.SetItemState( index, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED ) # Unselect all remaining selected items that aren't selected now: for index in selected: control.SetItemState( index, 0, wx.LIST_STATE_SELECTED ) def _multi_selected_indices_items_changed ( self, event ): """ Handles the editor's 'multi_selected_indices' trait being modified. """ control = self.control # Remove all items that are no longer selected: for index in event.removed: control.SetItemState( index, 0, wx.LIST_STATE_SELECTED ) # Select all newly added items: for index in event.added: control.SetItemState( index, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED ) #-- List Control Event Handlers -------------------------------------------- def _begin_drag ( self, event ): """ Handles the user beginning a drag operation with the left mouse button. """ if PythonDropSource is not None: adapter = self.adapter object, name = self.object, self.name index = event.GetIndex() selected = self._get_selected() drag_items = [] # Collect all of the selected items to drag: for index in selected: drag = adapter.get_drag( object, name, index ) if drag is None: return drag_items.append( drag ) # Save the drag item indices, so that we can later handle a # completed 'move' operation: self._drag_indices = selected try: # If only one item is being dragged, drag it as an item, not a # list: if len( drag_items ) == 1: drag_items = drag_items[0] # Perform the drag and drop operation: ds = PythonDropSource( self.control, drag_items ) # If moves are allowed and the result was a drag move: if ((ds.result == wx.DragMove) and (self._drag_local or self.factory.drag_move)): # Then delete all of the original items (in reverse order # from highest to lowest, so the indices don't need to be # adjusted): indices = self._drag_indices indices.reverse() for index in indices: adapter.delete( object, name, index ) finally: self._drag_indices = None self._drag_local = False def _begin_label_edit ( self, event ): """ Handles the user starting to edit an item label. """ index = event.GetIndex() if ((not self._is_auto_add( index )) and (not self.adapter.get_can_edit( self.object, self.name, index ))): event.Veto() def _end_label_edit ( self, event ): """ Handles the user finishing editing an item label. """ self._set_text_current( event.GetIndex(), event.GetText() ) def _item_selected ( self, event ): """ Handles an item being selected. """ self._no_update = True try: get_item = self.adapter.get_item object, name = self.object, self.name selected_indices = self._get_selected() if self.factory.multi_select: self.multi_selected_indices = selected_indices self.multi_selected = [ get_item( object, name, index ) for index in selected_indices] elif len( selected_indices ) == 0: self.selected_index = -1 self.selected = None else: self.selected_index = selected_indices[0] self.selected = get_item( object, name, selected_indices[0] ) finally: self._no_update = False def _item_activated ( self, event ): """ Handles an item being activated (double-clicked or enter pressed). """ self.activated_index = event.GetIndex() if 'edit' in self.factory.operations: self._edit_current() else: self.activated = self.adapter.get_item( self.object, self.name, self.activated_index ) def _right_clicked ( self, event ): """ Handles an item being right clicked. """ self.right_clicked_index = index = event.GetIndex() self.right_clicked = self.adapter.get_item( self.object, self.name, index ) def _key_pressed ( self, event ): key = event.GetKeyCode() control = event.ControlDown() if 32 <= key <= 126: self.search += chr( key ).lower() self._search_for_string() elif key in ( wx.WXK_HOME, wx.WXK_PAGEUP, wx.WXK_PAGEDOWN ): self.search = '' event.Skip() elif key == wx.WXK_END: self.search = '' self._append_new() elif (key == wx.WXK_UP) and control: self._search_for_string( -1 ) elif (key == wx.WXK_DOWN) and control: self._search_for_string( 1 ) elif key in ( wx.WXK_BACK, wx.WXK_DELETE ): self._delete_current() elif key == wx.WXK_INSERT: self._insert_current() elif key == wx.WXK_LEFT: self._move_up_current() elif key == wx.WXK_RIGHT: self._move_down_current() elif key == wx.WXK_RETURN: self._edit_current() elif key == 3: # Ctrl-C self._copy_current() elif key == 22: # Ctrl-V self._paste_current() elif key == 24: # Ctrl-X self._cut_current() else: event.Skip() def _size_modified ( self, event ): """ Handles the size of the list control being changed. """ dx, dy = self.control.GetClientSizeTuple() self.control.SetColumnWidth( 0, dx - 1 ) event.Skip() def _left_down ( self, event ): """ Handles the user pressing the left mouse button. """ index, flags = self.control.HitTest( wx.Point( event.GetX(), event.GetY() ) ) selected = self._get_selected() if (len( selected ) == 1) and (index == selected[0]): self._edit_current() else: event.Skip() #-- Drag and Drop Event Handlers ------------------------------------------- def wx_dropped_on ( self, x, y, data, drag_result ): """ Handles a Python object being dropped on the list control. """ index, flags = self.control.HitTest( wx.Point( x, y ) ) # If the user dropped it on an empty list, set the target as past the # end of the list: if ((index == -1) and ((flags & wx.LIST_HITTEST_NOWHERE) != 0) and (self.control.GetItemCount() == 0)): index = 0 # If we have a valid drop target index, proceed: if index != -1: if not isinstance( data, list ): # Handle the case of just a single item being dropped: self._wx_dropped_on( index, data ) else: # Handles the case of a list of items being dropped, being # careful to preserve the original order of the source items if # possible: data.reverse() for item in data: self._wx_dropped_on( index, item ) # If this was an inter-list drag, mark it as 'local': if self._drag_indices is not None: self._drag_local = True # Return a successful drop result: return drag_result # Indicate we could not process the drop: return wx.DragNone def _wx_dropped_on ( self, index, item ): """ Helper method for handling a single item dropped on the list control. """ adapter = self.adapter object, name = self.object, self.name # Obtain the destination of the dropped item relative to the target: destination = adapter.get_dropped( object, name, index, item ) # Adjust the target index accordingly: if destination == 'after': index += 1 # Insert the dropped item at the requested position: adapter.insert( object, name, index, item ) # If the source for the drag was also this list control, we need to # adjust the original source indices to account for their new position # after the drag operation: indices = self._drag_indices if indices is not None: for i in range( len( indices ) - 1, -1, -1 ): if indices[i] < index: break indices[i] += 1 def wx_drag_over ( self, x, y, data, drag_result ): """ Handles a Python object being dragged over the tree. """ if isinstance( data, list ): rc = wx.DragNone for item in data: rc = self.wx_drag_over( x, y, item, drag_result ) if rc == wx.DragNone: break return rc index, flags = self.control.HitTest( wx.Point( x, y ) ) # If the user is dragging over an empty list, set the target to the end # of the list: if ((index == -1) and ((flags & wx.LIST_HITTEST_NOWHERE) != 0) and (self.control.GetItemCount() == 0)): index = 0 # If the drag target index is valid and the adapter says it is OK to # drop the data here, then indicate the data can be dropped: if ((index != -1) and self.adapter.get_can_drop( self.object, self.name, index, data )): return drag_result # Else indicate that we will not accept the data: return wx.DragNone #-- Private Methods -------------------------------------------------------- def _refresh ( self ): """ Refreshes the contents of the editor's list control. """ self.control.RefreshItems( 0, len( self.value ) - 1 ) def _add_image ( self, image_resource ): """ Adds a new image to the wx.ImageList and its associated mapping. """ bitmap = image_resource.create_image().ConvertToBitmap() image_list = self._image_list if image_list is None: self._image_list = image_list = wx.ImageList( bitmap.GetWidth(), bitmap.GetHeight() ) self.control.AssignImageList( image_list, wx.IMAGE_LIST_SMALL ) self.image_resources[image_resource] = \ self.images[ image_resource.name ] = index = image_list.Add( bitmap ) return index def _get_image ( self, image ): """ Converts a user specified image to a wx.ListCtrl image index. """ if isinstance( image, ImageResource ): result = self.image_resources.get( image ) if result is not None: return result return self._add_image( image ) return self.images.get( image ) def _get_selected ( self ): """ Returns a list of the indices of all currently selected list items. """ selected = [] item = -1 control = self.control while True: item = control.GetNextItem( item, wx.LIST_NEXT_ALL, wx.LIST_STATE_SELECTED ) if item == -1: break; selected.append( item ) return selected def _search_for_string ( self, increment = 0 ): """ Searches for the next occurrence of the current search string. """ selected = self._get_selected() if len( selected ) > 1: return start = 0 if len( selected ) == 1: start = selected[0] + increment get_text = self.adapter.get_text search = self.search object = self.object name = self.name if increment >= 0: items = xrange( start, self.item_count ) else: items = xrange( start, -1, -1 ) for index in items: if search in get_text( object, name, index ).lower(): self.index = index self.update_editor() break def _append_new ( self ): """ Append a new item to the end of the list control. """ if 'append' in self.factory.operations: self.edit = True adapter = self.adapter index = self.control.GetItemCount() if self.factory.auto_add: self.index = index - 1 self.update_editor() else: self.index = index adapter.insert( self.object, self.name, self.index, adapter.get_default_value( self.object, self.name ) ) def _copy_current ( self ): """ Copies the currently selected list control item to the clipboard. """ selected = self._get_selected() if len( selected ) == 1: index = selected[0] if index < self.item_count: try: from pyface.wx.clipboard import clipboard clipboard.data = self.adapter.get_text( self.object, self.name, index ) except: # Handle the traits.util package not being installed by # just ignoring the request: pass def _cut_current ( self ): """ Cuts the currently selected list control item and places its value in the clipboard. """ ops = self.factory.operations if ('insert' in ops) and ('delete' in ops): selected = self._get_selected() if len( selected ) == 1: index = selected[0] if index < self.item_count: try: from pyface.wx.clipboard import clipboard clipboard.data = self.adapter.get_text( self.object, self.name, index ) self.index = index self.adapter.delete( self.object, self.name, index ) except: # Handle the traits.util package not being installed # by just ignoring the request: pass def _paste_current ( self ): """ Pastes the clipboard contents into the currently selected list control item. """ if 'insert' in self.factory.operations: selected = self._get_selected() if len( selected ) == 1: try: from pyface.wx.clipboard import clipboard self._set_text_current( selected[0], clipboard.text_data, insert = True ) except: # Handle the traits.util package not being installed by # just ignoring the request: pass def _insert_current ( self ): """ Inserts a new item after the currently selected list control item. """ if 'insert' in self.factory.operations: selected = self._get_selected() if len( selected ) == 1: self.index = selected[0] self.edit = True adapter = self.adapter adapter.insert( self.object, self.name, selected[0], adapter.get_default_value( self.object, self.name ) ) def _delete_current ( self ): """ Deletes the currently selected items from the list control. """ if 'delete' in self.factory.operations: selected = self._get_selected() if len( selected ) == 0: return n = self.item_count delete = self.adapter.delete selected.reverse() self.index = selected[-1] for index in selected: if index < n: delete( self.object, self.name, index ) def _move_up_current ( self ): """ Moves the currently selected item up one line in the list control. """ if 'move' in self.factory.operations: selected = self._get_selected() if len( selected ) == 1: index = selected[0] n = self.item_count if 0 < index < n: adapter = self.adapter object, name = self.object, self.name item = adapter.get_item( object, name, index ) adapter.delete( object, name, index ) self.index = index - 1 adapter.insert( object, name, index - 1, item ) def _move_down_current ( self ): """ Moves the currently selected item down one line in the list control. """ if 'move' in self.factory.operations: selected = self._get_selected() if len( selected ) == 1: index = selected[0] n = self.item_count - 1 if index < n: adapter = self.adapter object, name = self.object, self.name item = adapter.get_item( object, name, index ) adapter.delete( object, name, index ) self.index = index + 1 adapter.insert( object, name, index + 1, item ) def _edit_current ( self ): """ Allows the user to edit the current item in the list control. """ if 'edit' in self.factory.operations: selected = self._get_selected() if len( selected ) == 1: self.control.EditLabel( selected[0] ) def _is_auto_add ( self, index ): """ Returns whether or not the index is the special 'auto add' item at the end of the list. """ return (self.factory.auto_add and (index >= self.adapter.len( self.object, self.name ))) def _set_text_current ( self, index, text, insert = False ): """ Sets the text value of the specified list control item. """ if text.strip() != '': object, name, adapter = self.object, self.name, self.adapter if insert or self._is_auto_add( index ): adapter.insert( object, name, index, adapter.get_default_value( object, name ) ) self.edit = (not insert) self.index = index + 1 adapter.set_text( object, name, index, text ) #--EOF------------------------------------------------------------------------- traitsui-4.1.0/traitsui/wx/directory_editor.py0000644000175100001440000001032711674463546022612 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/21/2004 # #------------------------------------------------------------------------------ """ Defines various directory editors for the wxPython user interface toolkit. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx from os.path \ import isdir # FIXME: ToolkitEditorFactory is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.custom_editor file. from traitsui.editors.directory_editor \ import ToolkitEditorFactory from file_editor \ import SimpleEditor as SimpleFileEditor, \ CustomEditor as CustomFileEditor, \ PopupFile #------------------------------------------------------------------------------- # 'SimpleEditor' class: #------------------------------------------------------------------------------- class SimpleEditor ( SimpleFileEditor ): """ Simple style of editor for directories, which displays a text field and a **Browse** button that opens a directory-selection dialog box. """ #--------------------------------------------------------------------------- # Creates the correct type of file dialog or popup: #--------------------------------------------------------------------------- def _create_file_dialog ( self ): """ Creates the correct type of file dialog. """ dlg = wx.DirDialog( self.control, message = 'Select a Directory' ) dlg.SetPath( self._file_name.GetValue() ) return dlg def _create_file_popup ( self ): """ Creates the correct type of file popup. """ return PopupDirectory( control = self.control, file_name = self.str_value, filter = self.factory.filter, height = 300 ) #------------------------------------------------------------------------------- # 'CustomEditor' class: #------------------------------------------------------------------------------- class CustomEditor ( CustomFileEditor ): """ Custom style of editor for directories, which displays a tree view of the file system. """ #--------------------------------------------------------------------------- # Returns the basic style to use for the control: #--------------------------------------------------------------------------- def get_style ( self ): """ Returns the basic style to use for the control. """ return (wx.DIRCTRL_DIR_ONLY | wx.DIRCTRL_EDIT_LABELS) #--------------------------------------------------------------------------- # Handles the user changing the contents of the edit control: #--------------------------------------------------------------------------- def update_object ( self, event ): """ Handles the user changing the contents of the edit control. """ if self.control is not None: path = self.control.GetPath() if isdir( path ): self.value = path #------------------------------------------------------------------------------- # 'PopupDirectory' class: #------------------------------------------------------------------------------- class PopupDirectory ( PopupFile ): def get_style ( self ): """ Returns the basic style to use for the popup. """ return (wx.DIRCTRL_DIR_ONLY | wx.DIRCTRL_EDIT_LABELS) def is_valid ( self, path ): """ Returns whether or not the path is valid. """ return isdir( path ) ### EOF ######################################################################## traitsui-4.1.0/traitsui/wx/font_trait.py0000644000175100001440000001532311674463546021412 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 12/22/2004 # #------------------------------------------------------------------------------ """ Trait definition for a wxPython-based font. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx from traits.api \ import Trait, TraitHandler, TraitError #------------------------------------------------------------------------------- # Convert a string into a valid 'wxFont' object (if possible): #------------------------------------------------------------------------------- # Mapping of strings to valid wxFont families font_families = { 'default': wx.DEFAULT, 'decorative': wx.DECORATIVE, 'roman': wx.ROMAN, 'script': wx.SCRIPT, 'swiss': wx.SWISS, 'modern': wx.MODERN } # Mapping of strings to wxFont styles font_styles = { 'slant': wx.SLANT, 'italic': wx.ITALIC } # Mapping of strings wxFont weights font_weights = { 'light': wx.LIGHT, 'bold': wx.BOLD } # Strings to ignore in text representations of fonts font_noise = [ 'pt', 'point', 'family' ] #------------------------------------------------------------------------------- # Converts a wx.Font into a string description of itself: #------------------------------------------------------------------------------- def font_to_str ( font ): """ Converts a wx.Font into a string description of itself. """ weight = { wx.LIGHT: ' Light', wx.BOLD: ' Bold' }.get( font.GetWeight(), '' ) style = { wx.SLANT: ' Slant', wx.ITALIC: ' Italic' }.get( font.GetStyle(), '' ) underline = '' if font.GetUnderlined(): underline = ' underline' return '%s point %s%s%s%s' % ( font.GetPointSize(), font.GetFaceName(), style, weight, underline ) #------------------------------------------------------------------------------- # Create a TraitFont object from a string description: #------------------------------------------------------------------------------- def create_traitsfont ( value ): """ Create a TraitFont object from a string description. """ if isinstance( value, wx.Font ): value = font_to_str( value ) point_size = None family = wx.DEFAULT style = wx.NORMAL weight = wx.NORMAL underline = 0 facename = [] for word in value.split(): lword = word.lower() if font_families.has_key( lword ): family = font_families[ lword ] elif font_styles.has_key( lword ): style = font_styles[ lword ] elif font_weights.has_key( lword ): weight = font_weights[ lword ] elif lword == 'underline': underline = 1 elif lword not in font_noise: if point_size is None: try: point_size = int( lword ) continue except: pass facename.append( word ) return TraitsFont( point_size or 10, family, style, weight, underline, ' '.join( facename ) ) #------------------------------------------------------------------------------- # 'TraitsFont' class: #------------------------------------------------------------------------------- class TraitsFont ( wx.Font ): """ A Traits-specific wx.Font. """ #--------------------------------------------------------------------------- # Returns the pickleable form of a TraitsFont object: #--------------------------------------------------------------------------- def __reduce_ex__ ( self, protocol ): """ Returns the pickleable form of a TraitsFont object. """ return ( create_traitsfont, ( font_to_str( self ), ) ) #--------------------------------------------------------------------------- # Returns a printable form of the font: #--------------------------------------------------------------------------- def __str__ ( self ): """ Returns a printable form of the font. """ return font_to_str( self ) #------------------------------------------------------------------------------- # 'TraitWXFont' class' #------------------------------------------------------------------------------- class TraitWXFont ( TraitHandler ): """ Ensures that values assigned to a trait attribute are valid font descriptor strings; the value actually assigned is the corresponding TraitsFont. """ #--------------------------------------------------------------------------- # Validates that the value is a valid font: #--------------------------------------------------------------------------- def validate ( self, object, name, value ): """ Validates that the value is a valid font descriptor string. If so, it returns the corresponding TraitsFont; otherwise, it raises a TraitError. """ if value is None: return None try: return create_traitsfont( value ) except: pass raise TraitError, ( object, name, 'a font descriptor string', repr( value ) ) def info ( self ): return ( "a string describing a font (e.g. '12 pt bold italic " "swiss family Arial' or 'default 12')" ) #------------------------------------------------------------------------------- # Define a wxPython specific font trait: #------------------------------------------------------------------------------- ### Note: Declare the editor to be a function which returns the FontEditor # class from traits ui to avoid circular import issues. For backwards # compatibility with previous Traits versions, the 'editors' folder in Traits # project declares 'from api import *' in its __init__.py. The 'api' in turn # can contain classes that have a Font trait which lead to this file getting # imported. This leads to a circular import when declaring a Font trait. def get_font_editor(*args, **traits): from font_editor import ToolkitEditorFactory return ToolkitEditorFactory(*args, **traits) fh = TraitWXFont() WxFont = Trait( wx.SystemSettings_GetFont( wx.SYS_DEFAULT_GUI_FONT ), fh, editor = get_font_editor ) traitsui-4.1.0/traitsui/wx/rgb_color_trait.py0000644000175100001440000001105511674463546022412 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 12/22/2004 # #------------------------------------------------------------------------------ """ Trait definition for an RGB-based color, which is a tuple of the form (*red*, *green*, *blue*), where *red*, *green* and *blue* are floats in the range from 0.0 to 1.0. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx from traits.api \ import Trait, TraitError from traits.trait_base \ import SequenceTypes ### Note: Import from the source rather than the api to avoid circular imports # since some classes declared in the traits UI api define Color traits which # will end up importing this file. from traitsui.editors.rgb_color_editor \ import RGBColorEditor from traitsui.wx.color_trait \ import standard_colors, w3c_color_database #------------------------------------------------------------------------------- # Convert a number into an RGB tuple: #------------------------------------------------------------------------------- def range_check ( value ): """ Checks that *value* can be converted to a value in the range 0.0 to 1.0. If so, it returns the floating point value; otherwise, it raises a TraitError. """ value = float( value ) if 0.0 <= value <= 1.0: return value raise TraitError def convert_to_color ( object, name, value ): """ Converts a tuple or an integer to an RGB color value, or raises a TraitError if that is not possible. """ if (type( value ) in SequenceTypes) and (len( value ) == 3): return ( range_check( value[0] ), range_check( value[1] ), range_check( value[2] ) ) if type( value ) is int: num = int( value ) return ( (num / 0x10000) / 255.0 ((num / 0x100) & 0xFF) / 255.0, (num & 0xFF) / 255.0 ) if isinstance(value, wx.Colour): return (value.Red()/255.0, value.Green()/255.0, value.Blue()/255.0) raise TraitError convert_to_color.info = ('a tuple of the form (r,g,b), where r, g, and b ' 'are floats in the range from 0.0 to 1.0, or an integer which in hex is of ' 'the form 0xRRGGBB, where RR is red, GG is green, and BB is blue') #------------------------------------------------------------------------------- # Standard colors: #------------------------------------------------------------------------------- # RGB versions of standard colors: rgb_standard_colors = {} for name, color in standard_colors.items(): rgb_standard_colors[ name ] = ( color.Red() / 255.0, color.Green() / 255.0, color.Blue() / 255.0 ) # Add the W3C colors for color_name in w3c_color_database._color_names: color = w3c_color_database.Find(color_name) rgb_standard_colors[color_name] = (color.Red() / 255.0, color.Green() / 255.0, color.Blue() / 255.0) #------------------------------------------------------------------------------- # Define wxPython specific color traits: #------------------------------------------------------------------------------- ### Note: Declare the editor to be a function which returns the RGBColorEditor # class from traits ui to avoid circular import issues. For backwards # compatibility with previous Traits versions, the 'editors' folder in Traits # project declares 'from api import *' in its __init__.py. The 'api' in turn # can contain classes that have a RGBColor trait which lead to this file getting # imported. This will lead to a circular import when declaring a RGBColor trait. def get_rgb_color_editor(*args, **traits): from rgb_color_editor import ToolkitEditorFactory return ToolkitEditorFactory(*args, **traits) # Trait whose value must be an RGB color: RGBColor = Trait( 'white', convert_to_color, rgb_standard_colors, editor = get_rgb_color_editor ) traitsui-4.1.0/traitsui/wx/time_editor.py0000644000175100001440000000743411674463546021551 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2008, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: Judah De Paula # Date: 10/7/2008 # #------------------------------------------------------------------------------ """ A Traits UI editor that wraps a WX timer control. Future Work ----------- The only editor provided is an editable and constrained "XX:XX:XX XM" field. At the minimum, a spinner should be provided so the time can be changed without the need for a keyboard. In addition we need to extend to provide all four of the basic editor types, Simple, Custom, Text, and Readonly. """ import datetime import wx.lib.masked as masked from traitsui.wx.editor import Editor from traitsui.wx.text_editor \ import ReadonlyEditor as TextReadonlyEditor class SimpleEditor (Editor): """ Traits UI time editor. """ def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ tctl = masked.TimeCtrl( parent, -1, name="12 hour control" ) self.control = tctl self.control.Bind(masked.EVT_TIMEUPDATE, self.time_updated) return def time_updated(self, event): """ Event for when the wx time control is updated. """ time = self.control.GetValue(as_wxDateTime=True) hour = time.GetHour() minute = time.GetMinute() second = time.GetSecond() self.value = datetime.time(hour, minute, second) return def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ if self.value: time = self.control.GetValue(as_wxDateTime=True) time.SetHour(self.value.hour) time.SetMinute(self.value.minute) time.SetSecond(self.value.second) self.control.SetValue(time) return #-- end SimpleEditor definition ------------------------------------------------ #------------------------------------------------------------------------------ #-- Text Editor #------------------------------------------------------------------------------ # TODO: Write me. Possibly use TextEditor as a model to show a string # representation of the time, and have enter-set do a time evaluation. class TextEditor (SimpleEditor): pass #-- end TextEditor definition ------------------------------------------------- #------------------------------------------------------------------------------ #-- Custom Editor #------------------------------------------------------------------------------ # TODO: Write me. class CustomEditor (SimpleEditor): pass #-- end TextEditor definition ------------------------------------------------- #------------------------------------------------------------------------------ #-- Readonly Editor #------------------------------------------------------------------------------ class ReadonlyEditor (TextReadonlyEditor): """ Use a TextEditor for the view. """ def _get_str_value(self): """ Replace the default string value with our own time version. """ if self.value is None: return self.factory.message else: return self.value.strftime(self.factory.strftime) #-- end ReadonlyEditor definition --------------------------------------------- #-- eof ----------------------------------------------------------------------- traitsui-4.1.0/traitsui/wx/compound_editor.py0000644000175100001440000001100611674463546022425 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/21/2004 # #------------------------------------------------------------------------------ """ Defines the compound editor and the compound editor factory for the wxPython user interface toolkit. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx from traits.api \ import Str # FIXME: ToolkitEditorFactory is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.compound_editor file. from traitsui.editors.compound_editor \ import ToolkitEditorFactory from editor \ import Editor from helper \ import TraitsUIPanel #------------------------------------------------------------------------------- # 'CompoundEditor' class: #------------------------------------------------------------------------------- class CompoundEditor ( Editor ): """ Editor for compound traits, which displays editors for each of the combined traits, in the appropriate style. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # The kind of editor to create for each list item kind = Str #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ # Create a panel to hold all of the component trait editors: self.control = panel = TraitsUIPanel( parent, -1 ) sizer = wx.BoxSizer( wx.VERTICAL ) # Add all of the component trait editors: self._editors = editors = [] for factory in self.factory.editors: editor = getattr( factory, self.kind )( self.ui, self.object, self.name, self.description, panel ) editor.prepare( panel ) sizer.Add( editor.control, 1, wx.TOP | wx.BOTTOM | editor.layout_style, 3 ) editors.append( editor ) # Set-up the layout: panel.SetSizerAndFit( sizer ) self.set_tooltip() #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ pass #--------------------------------------------------------------------------- # Disposes of the contents of an editor: #--------------------------------------------------------------------------- def dispose ( self ): """ Disposes of the contents of an editor. """ for editor in self._editors: editor.dispose() super( CompoundEditor, self ).dispose() #------------------------------------------------------------------------------- # 'SimpleEditor' class: #------------------------------------------------------------------------------- class SimpleEditor(CompoundEditor): # The kind of editor to create for each list item. This value overrides # the default. kind = 'simple_editor' #------------------------------------------------------------------------------- # 'CustomEditor' class: #------------------------------------------------------------------------------- class CustomEditor(CompoundEditor): # The kind of editor to create for each list item. This value overrides # the default. kind = 'custom_editor' #-- EOF ---------------------------------------------------------------------- traitsui-4.1.0/traitsui/wx/color_trait.py0000644000175100001440000001644411674463546021567 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 12/22/2004 # #------------------------------------------------------------------------------ """ Trait definition for a wxPython-based color. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx from traits.api \ import Trait, TraitError # Version dependent imports (ColourPtr not defined in wxPython 2.5): try: ColourPtr = wx.ColourPtr except: class ColourPtr ( object ): pass #------------------------------------------------------------------------------- # W3CColourDatabase #------------------------------------------------------------------------------- class W3CColourDatabase(object): """ Proxy for the ColourDatabase which allows for finding W3C colors. This class is necessary because the wx 'green' is the W3C 'lime', and we need some means to lookup the color names since wx has only a few hardcoded. This class is a proxy because AddColour expects a wx.ColourDatabase instance, not an instance of a subclass """ _database = wx.ColourDatabase() def __init__(self): self._color_names = ['aqua', 'black', 'blue', 'fuchsia', 'gray', 'green', 'lime', 'maroon', 'navy', 'olive', 'purple', 'red', 'silver', 'teal', 'white', 'yellow'] self.AddColour('aqua', wx.Colour(0, 0xff, 0xff, 255)) self.AddColour('fuchsia', wx.Colour(0xff, 0, 0xff, 255)) self.AddColour('green', wx.Colour(0, 0x80, 0, 255)) self.AddColour('lime', wx.Colour(0, 0xff, 0, 255)) self.AddColour('maroon', wx.Colour(0x80, 0x0, 0, 255)) self.AddColour('navy', wx.Colour(0x00, 0x0, 0x80, 255)) self.AddColour('olive', wx.Colour(0x80, 0x80, 0, 255)) self.AddColour('purple', wx.Colour(0x80, 0x00, 0x80, 255)) self.AddColour('silver', wx.Colour(0xc0, 0xc0, 0xc0, 255)) self.AddColour('teal', wx.Colour(0, 0x80, 0x80, 255)) def AddColour(self, name, color): if name not in self._color_names: self._color_names.append(name) return self._database.AddColour(name, color) def Find(self, color_name): return self._database.Find(color_name) def FindName(self, color): for color_name in self._color_names: if self.Find(color_name) == color: return color_name return '' w3c_color_database = W3CColourDatabase() #------------------------------------------------------------------------------- # Convert a number into a wxColour object: #------------------------------------------------------------------------------- def tuple_to_wxcolor(tup): if 3 <= len(tup) <= 4: for c in tup: if not isinstance(c, int): raise TraitError return wx.Colour(*tup) else: raise TraitError def convert_to_color ( object, name, value ): """ Converts a number into a wxColour object. """ if isinstance( value, tuple ): return tuple_to_wxcolor(value) elif isinstance( value, ColourPtr ): return wx.Colour( value.Red(), value.Green(), value.Blue() ) elif isinstance( value, wx.Colour ): return value elif isinstance( value, str ): if value in standard_colors: return standard_colors[value] # Check for tuple-ness tmp = value.strip() if tmp.startswith("(") and tmp.endswith(")") and tmp.count(",") in (2,3): tup = eval(tmp) return tuple_to_wxcolor(tup) elif isinstance( value, int ): num = int( value ) return wx.Colour( num / 0x10000, (num / 0x100) & 0xFF, num & 0xFF ) raise TraitError convert_to_color.info = ('a string of the form (r,g,b) or (r,g,b,a) where r, ' 'g, b, and a are integers from 0 to 255, a wx.Colour ' 'instance, an integer which in hex is of the form ' '0xRRGGBB, where RR is red, GG is green, and BB is ' 'blue') #------------------------------------------------------------------------------- # Standard colors: #------------------------------------------------------------------------------- standard_colors = {} for name in [ 'aquamarine', 'black', 'blue', 'blue violet', 'brown', 'cadet blue', 'coral', 'cornflower blue', 'cyan', 'dark grey', 'dark green', 'dark olive green', 'dark orchid', 'dark slate blue', 'dark slate grey', 'dark turquoise', 'dim grey', 'firebrick', 'forest green', 'gold', 'goldenrod', 'grey', 'green', 'green yellow', 'indian red', 'khaki', 'light blue', 'light grey', 'light steel blue', 'lime green', 'magenta', 'maroon', 'medium aquamarine', 'medium blue', 'medium forest green', 'medium goldenrod', 'medium orchid', 'medium sea green', 'medium slate blue', 'medium spring green', 'medium turquoise', 'medium violet red', 'midnight blue', 'navy', 'orange', 'orange red', 'orchid', 'pale green', 'pink', 'plum', 'purple', 'red', 'salmon', 'sea green', 'sienna', 'sky blue', 'slate blue', 'spring green', 'steel blue', 'tan', 'thistle', 'turquoise', 'violet', 'violet red', 'wheat', 'white', 'yellow', 'yellow green' ]: try: wx_color = w3c_color_database.Find(name) standard_colors[ name ] = convert_to_color( None, None, wx_color ) except: pass #------------------------------------------------------------------------------- # Define wxPython specific color traits: #------------------------------------------------------------------------------- ### Note: Declare the editor to be a function which returns the ColorEditor # class from traits ui to avoid circular import issues. For backwards # compatibility with previous Traits versions, the 'editors' folder in Traits # project declares 'from api import *' in its __init__.py. The 'api' in turn # can contain classes that have a Color trait which lead to this file getting # imported. This leads to a circular import when declaring a Color trait. def get_color_editor(*args, **traits): from color_editor import ToolkitEditorFactory return ToolkitEditorFactory(*args, **traits) def WxColor ( default = 'white', allow_none = False, **metadata ): """ Defines wxPython-specific color traits. """ if allow_none: return Trait( default, None, standard_colors, convert_to_color, editor = get_color_editor, **metadata ) return Trait( default, standard_colors, convert_to_color, editor = get_color_editor, **metadata ) traitsui-4.1.0/traitsui/wx/button_editor.py0000644000175100001440000001400711674463546022120 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/21/2004 # #------------------------------------------------------------------------------ """ Defines the various button editors for the wxPython user interface toolkit. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx from traits.api \ import Str # FIXME: ToolkitEditorFactory is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.button_editor file. from traitsui.editors.button_editor \ import ToolkitEditorFactory from editor \ import Editor #------------------------------------------------------------------------------- # 'SimpleEditor' class: #------------------------------------------------------------------------------- class SimpleEditor ( Editor ): """ Simple style editor for a button. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # The button label label = Str #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ label = self.factory.label or self.item.get_label( self.ui ) self.control = wx.Button( parent, -1, self.string_value( label ) ) self.sync_value( self.factory.label_value, 'label', 'from' ) wx.EVT_BUTTON( parent, self.control.GetId(), self.update_object ) self.set_tooltip() #--------------------------------------------------------------------------- # Handles the 'label' trait being changed: #--------------------------------------------------------------------------- def _label_changed ( self, label ): self.control.SetLabel( self.string_value( label ) ) #--------------------------------------------------------------------------- # Handles the user clicking the button by setting the value on the object: #--------------------------------------------------------------------------- def update_object ( self, event ): """ Handles the user clicking the button by setting the factory value on the object. """ factory = self.factory self.value = factory.value # If there is an associated view, then display it: if factory.view is not None: self.object.edit_traits( view = factory.view, parent = self.control ) #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ pass #--------------------------------------------------------------------------- # Disposes of the contents of an editor: #--------------------------------------------------------------------------- def dispose ( self ): """ Disposes of the contents of an editor. """ wx.EVT_BUTTON( self.control.GetParent(), self.control.GetId(), None ) super( SimpleEditor, self ).dispose() #------------------------------------------------------------------------------- # 'CustomEditor' class: #------------------------------------------------------------------------------- class CustomEditor ( SimpleEditor ): """ Custom style editor for a button, which can contain an image. """ #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ from pyface.image_button import ImageButton factory = self.factory self._control = ImageButton( parent, label = self.string_value( factory.label ), image = factory.image, style = factory.style, orientation = factory.orientation, width_padding = factory.width_padding, height_padding = factory.height_padding ) self.control = self._control.control self._control.on_trait_change( self.update_object, 'clicked', dispatch = 'ui' ) self.set_tooltip() #--------------------------------------------------------------------------- # Disposes of the contents of an editor: #--------------------------------------------------------------------------- def dispose ( self ): """ Disposes of the contents of an editor. """ self._control.on_trait_change( self.update_object, 'clicked', remove = True ) super( CustomEditor, self ).dispose() ### EOF ####################################################################### traitsui-4.1.0/traitsui/wx/__init__.py0000644000175100001440000000205511674463546020776 0ustar ischnellusers00000000000000#---------------------------------------------------------------------------- # # Copyright (c) 2005-2011, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/21/2004 # #---------------------------------------------------------------------------- """ Defines the concrete implementations of the traits Toolkit interface for the wxPython user interface toolkit. """ #------------------------------------------------------------------------------- # Define the reference to the exported GUIToolkit object: #------------------------------------------------------------------------------- import toolkit # Reference to the GUIToolkit object for wxPython toolkit = toolkit.GUIToolkit() traitsui-4.1.0/traitsui/wx/themed_slider_editor.py0000644000175100001440000003731611674463546023425 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2007, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 06/22/2007 # #------------------------------------------------------------------------------- """ Traits UI simple, themed slider-based integer or float value editor. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx from math \ import log10, pow from traits.api \ import HasPrivateTraits, Instance, Enum, Range, Str, Float, Bool, Color, \ TraitError from traitsui.ui_traits \ import Alignment from traitsui.wx.editor \ import Editor from traitsui.basic_editor_factory \ import BasicEditorFactory from pyface.timer.api \ import do_after from constants \ import ErrorColor from helper \ import disconnect, disconnect_no_id, BufferDC #------------------------------------------------------------------------------- # '_ThemedSliderEditor' class: #------------------------------------------------------------------------------- class _ThemedSliderEditor ( Editor ): """ Traits UI simple, themed slider-based integer or float value editor. """ # The low end of the slider range: low = Float # The high end of the slider range: high = Float # The smallest allowed increment: increment = Float # The current text being displayed: text = Str #-- Class Variables -------------------------------------------------------- text_styles = { 'left': wx.TE_LEFT, 'center': wx.TE_CENTRE, 'right': wx.TE_RIGHT } #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ factory = self.factory # Establish the range of the slider: low, high = factory.low, factory.high if high <= low: low = high = None range = self.object.trait( self.name ).handler if isinstance( range, Range ): low, high = range._low, range._high if low is None: if high is None: high = 1.0 low = high - 1.0 elif high is None: high = low + 1.0 # Establish the slider increment: increment = factory.increment if increment <= 0.0: if isinstance( low, int ): increment = 1.0 else: increment = pow( 10, int( log10( (high - low) / 1000.0 ) ) ) # Save the values we calculated: self.set( low = low, high = high, increment = increment ) # Create the control: self.control = control = wx.Window( parent, -1, size = wx.Size( 70, 20 ), style = wx.FULL_REPAINT_ON_RESIZE | wx.TAB_TRAVERSAL ) # Set up the painting event handlers: wx.EVT_ERASE_BACKGROUND( control, self._erase_background ) wx.EVT_PAINT( control, self._on_paint ) wx.EVT_SET_FOCUS( control, self._set_focus ) # Set up mouse event handlers: wx.EVT_LEFT_DOWN( control, self._left_down ) wx.EVT_LEFT_UP( control, self._left_up ) wx.EVT_MOTION( control, self._motion ) wx.EVT_MOUSEWHEEL( control, self._mouse_wheel ) wx.EVT_ENTER_WINDOW( control, self._enter_window ) wx.EVT_LEAVE_WINDOW( control, self._leave_window ) # Set up the control resize handler: wx.EVT_SIZE( control, self._resize ) # Set the tooltip: if not self.set_tooltip(): control.SetToolTipString( '[%g..%g]' % ( low, high ) ) #--------------------------------------------------------------------------- # Disposes of the contents of an editor: #--------------------------------------------------------------------------- def dispose ( self ): """ Disposes of the contents of an editor. """ disconnect_no_id( self.control, wx.EVT_ERASE_BACKGROUND, wx.EVT_PAINT, wx.EVT_SET_FOCUS, wx.EVT_LEFT_DOWN, wx.EVT_LEFT_UP, wx.EVT_MOTION, wx.EVT_MOUSEWHEEL, wx.EVT_ENTER_WINDOW, wx.EVT_LEAVE_WINDOW, wx.EVT_SIZE ) if self._text is not None: disconnect( self._text, wx.EVT_TEXT_ENTER ) disconnect_no_id( self._text, wx.EVT_KILL_FOCUS, wx.EVT_ENTER_WINDOW, wx.EVT_LEAVE_WINDOW, wx.EVT_CHAR ) super( _ThemedSliderEditor, self ).dispose() #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ self.text = '%g' % self.value self._text_size = None self._refresh() if self._text is not None: self._text.SetValue( self.text ) #--------------------------------------------------------------------------- # Updates the object when the control slider value changes: #--------------------------------------------------------------------------- def update_object ( self, value ): """ Updates the object when the control slider value changes. """ try: self.value = value except TraitError: self.value = int( value ) self.update_editor() #--------------------------------------------------------------------------- # Handles an error that occurs while setting the object's trait value: #--------------------------------------------------------------------------- def error ( self, excp ): """ Handles an error that occurs while setting the object's trait value. """ pass #-- Private Methods -------------------------------------------------------- def _get_text_bounds ( self ): """ Get the window bounds of where the current text should be displayed. """ tdx, tdy, descent, leading = self._get_text_size() wdx, wdy = self.control.GetClientSizeTuple() ty = ((wdy - (tdy - descent)) / 2) - 2 alignment = self.factory.alignment if alignment == 'left': tx = 4 elif alignment == 'center': tx = (wdx - tdx) / 2 else: tx = wdx - tdx - 4 return ( tx, ty, tdx, tdy ) def _get_text_size ( self ): """ Returns the text size information for the window. """ if self._text_size is None: self._text_size = self.control.GetFullTextExtent( self.text.strip() or 'M' ) return self._text_size def _refresh ( self ): """ Refreshes the contents of the control. """ if self.control is not None: self.control.Refresh() def _set_slider_position ( self, x ): """ Calculates a new slider value for a specified (x,y) coordinate. """ wdx, wdy = self.control.GetSizeTuple() if 3 <= x < wdx: value = self.low + (((x - 3) * (self.high - self.low)) / (wdx - 4)) increment = self.increment if increment > 0: value = round( value / increment ) * increment self.update_object( value ) def _delayed_click ( self ): """ Handle a delayed click response. """ if self._pending: self._pending = False self._set_slider_position( self._x ) def _pop_up_text ( self ): """ Pop-up a text control to allow the user to enter a value using the keyboard. """ control = self.control self._text = text = wx.TextCtrl( control, -1, self.text, size = control.GetSize(), style = self.text_styles[ self.factory.alignment ] | wx.TE_PROCESS_ENTER ) text.SetSelection( -1, -1 ) text.SetFocus() wx.EVT_TEXT_ENTER( control, text.GetId(), self._text_completed ) wx.EVT_KILL_FOCUS( text, self._text_completed ) wx.EVT_ENTER_WINDOW( text, self._enter_text ) wx.EVT_LEAVE_WINDOW( text, self._leave_text ) wx.EVT_CHAR( text, self._key_entered ) def _destroy_text ( self ): """ Destroys the current text control. """ self._ignore_focus = self._in_text_window disconnect( self._text, wx.EVT_TEXT_ENTER ) disconnect_no_id( self._text, wx.EVT_KILL_FOCUS, wx.EVT_ENTER_WINDOW, wx.EVT_LEAVE_WINDOW, wx.EVT_CHAR ) self.control.DestroyChildren() self._text = None #--- wxPython Event Handlers ----------------------------------------------- def _erase_background ( self, event ): """ Do not erase the background here (do it in the 'on_paint' handler). """ pass def _on_paint ( self, event ): """ Paint the background using the associated ImageSlice object. """ control = self.control dc = BufferDC( control ) # Draw the slider bar: wdx, wdy = control.GetClientSize() dx = max( 0, min( wdx - 2, int( round( ((wdx - 3) * (self.value - self.low)) / (self.high - self.low) ) ) ) ) factory = self.factory dc.SetBrush( wx.Brush( factory.slider_color_ ) ) dc.SetPen( wx.TRANSPARENT_PEN ) dc.DrawRectangle( 0, 0, dx + 3, wdy ) # Draw the rest of the background: dc.SetBrush( wx.Brush( factory.bg_color_ ) ) dc.DrawRectangle( dx + 3, 0, wdx - dx - 3, wdy ) # Draw the slider tip: dc.SetBrush( wx.Brush( factory.tip_color_ ) ) dc.DrawRectangle( dx, 0, 3, wdy ) # Draw the current text value (if requested): if factory.show_value: dc.SetBackgroundMode( wx.TRANSPARENT ) dc.SetTextForeground( factory.text_color_ ) dc.SetFont( control.GetFont() ) tx, ty, tdx, tdy = self._get_text_bounds() dc.DrawText( self.text, tx, ty ) # Copy the buffer to the display: dc.copy() def _resize ( self, event ): """ Handles the control being resized. """ if self._text is not None: self._text.SetSize( self.control.GetSize() ) def _set_focus ( self, event ): """ Handle the control getting the keyboard focus. """ if ((not self._ignore_focus) and (self._x is None) and (self._text is None)): self._pop_up_text() event.Skip() def _left_down ( self, event ): """ Handles the left mouse being pressed. """ self._x, self._y = event.GetX(), event.GetY() self._pending = True self.control.CaptureMouse() do_after( 150, self._delayed_click ) def _left_up ( self, event ): """ Handles the left mouse button being released. """ if self._x is not None: self.control.ReleaseMouse() if self._pending: self._pop_up_text() self._x = self._y = self._pending = None def _motion ( self, event ): """ Handles the mouse moving. """ if self._x is not None: x, y = event.GetX(), event.GetY() if self._pending: if (abs( x - self._x ) + abs( y - self._y )) < 3: return self._pending = False self._set_slider_position( x ) def _mouse_wheel ( self, event ): """ Handles the mouse wheel rotating. """ if self._in_window: increment = event.GetWheelRotation() / event.GetWheelDelta() delta = (self.high - self.low) / 100.0 if isinstance( self.value, int ) and (abs( delta ) < 1): delta = int( abs( delta ) / delta ) self.update_object( min( max( self.value + increment * delta, self.low ), self.high ) ) def _enter_window ( self, event ): """ Handles the mouse pointer entering the control. """ self._in_window = True if not self._ignore_focus: self._ignore_focus = True self.control.SetFocus() self._ignore_focus = False def _leave_window ( self, event ): """ Handles the mouse pointer leaving the control. """ self._in_window = False def _update_value ( self, event ): """ Updates the object value from the current text control value. """ control = event.GetEventObject() try: self.update_object( float( control.GetValue() ) ) return True except TraitError: control.SetBackgroundColour( ErrorColor ) control.Refresh() return False def _enter_text ( self, event ): """ Handles the mouse entering the pop-up text control. """ self._in_text_window = True def _leave_text ( self, event ): """ Handles the mouse leaving the pop-up text control. """ self._in_text_window = False def _text_completed ( self, event ): """ Handles the user pressing the 'Enter' key in the text control. """ if self._update_value( event ): self._destroy_text() def _key_entered ( self, event ): """ Handles individual key strokes while the text control is active. """ key_code = event.GetKeyCode() if key_code == wx.WXK_ESCAPE: self._destroy_text() return if key_code == wx.WXK_TAB: if self._update_value( event ): if event.ShiftDown(): self.control.Navigate( 0 ) else: self.control.Navigate() return event.Skip() #------------------------------------------------------------------------------- # Create the editor factory object: #------------------------------------------------------------------------------- # wxPython editor factory for themed slider editors: class ThemedSliderEditor ( BasicEditorFactory ): # The editor class to be created: klass = _ThemedSliderEditor # The low end of the slider range: low = Float # The high end of the slider range: high = Float # The smallest allowed increment: increment = Float # Should the current value be displayed as text? show_value = Bool( True ) # The alignment of the text within the slider: alignment = Alignment( 'center' ) # The color to use for the slider bar: slider_color = Color( 0xC0C0C0 ) # The background color for the slider: bg_color = Color( 'white' ) # The color of the slider tip: tip_color = Color( 0xFF7300 ) # The color to use for the value text: text_color = Color( 'black' ) traitsui-4.1.0/traitsui/wx/search_editor.py0000644000175100001440000000520511674463546022052 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2009, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: Evan Patterson # Date: 06/25/09 # #------------------------------------------------------------------------------- # System library imports import wx # Local imports from editor import Editor class SearchEditor(Editor): def init(self, parent): """ Finishes initializing the editor by creating the underlying toolkit widget. """ style = 0 if self.factory.enter_set: style = wx.TE_PROCESS_ENTER self.control = wx.SearchCtrl(parent, -1, value=self.value, style=style) self.control.SetDescriptiveText(self.factory.text) self.control.ShowSearchButton(self.factory.search_button) self.control.ShowCancelButton(self.factory.cancel_button) if self.factory.auto_set: wx.EVT_TEXT(parent, self.control.GetId(), self.update_object) if self.factory.enter_set: wx.EVT_TEXT_ENTER(parent, self.control.GetId(), self.update_object) wx.EVT_SEARCHCTRL_SEARCH_BTN(parent, self.control.GetId(), self.update_object) wx.EVT_SEARCHCTRL_CANCEL_BTN(parent, self.control.GetId(), self.clear_text) def update_object(self, event): """ Handles the user entering input data in the edit control. """ if not self._no_update: self.value = self.control.GetValue() if self.factory.search_event_trait != '': setattr(self.object, self.factory.search_event_trait, True) def clear_text(self, event): """ Handles the user pressing the cancel search button. """ if not self._no_update: self.control.SetValue("") self.value = "" if self.factory.search_event_trait != '': setattr(self.object, self.factory.search_event_trait, True) def update_editor(self): """ Updates the editor when the object trait changes externally to the editor. """ if self.control.GetValue() != self.value: self._no_update = True self.control.SetValue(self.str_value) self._no_update = False traitsui-4.1.0/traitsui/wx/enum_editor.py0000644000175100001440000005260311674463546021555 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/21/2004 # #------------------------------------------------------------------------------ """ Defines the various editors for single-selection enumerations, for the wxPython user interface toolkit. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx from string \ import capitalize from traits.api \ import Property # FIXME: ToolkitEditorFactory is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.drop_editor file. from traitsui.editors.enum_editor \ import ToolkitEditorFactory from editor \ import Editor from constants \ import OKColor, ErrorColor from helper \ import enum_values_changed, TraitsUIPanel, disconnect, disconnect_no_id #------------------------------------------------------------------------------- # 'BaseEditor' class: #------------------------------------------------------------------------------- class BaseEditor ( Editor ): """ Base class for enumeration editors. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Current set of enumeration names: names = Property # Current mapping from names to values: mapping = Property # Current inverse mapping from values to names: inverse_mapping = Property #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ factory = self.factory if factory.name != '': self._object, self._name, self._value = \ self.parse_extended_name( factory.name ) self.values_changed() self._object.on_trait_change( self._values_changed, ' ' + self._name, dispatch = 'ui' ) else: factory.on_trait_change( self.rebuild_editor, 'values_modified', dispatch = 'ui' ) #--------------------------------------------------------------------------- # Gets the current set of enumeration names: #--------------------------------------------------------------------------- def _get_names ( self ): """ Gets the current set of enumeration names. """ if self._object is None: return self.factory._names return self._names #--------------------------------------------------------------------------- # Gets the current mapping: #--------------------------------------------------------------------------- def _get_mapping ( self ): """ Gets the current mapping. """ if self._object is None: return self.factory._mapping return self._mapping #--------------------------------------------------------------------------- # Gets the current inverse mapping: #--------------------------------------------------------------------------- def _get_inverse_mapping ( self ): """ Gets the current inverse mapping. """ if self._object is None: return self.factory._inverse_mapping return self._inverse_mapping #--------------------------------------------------------------------------- # Rebuilds the contents of the editor whenever the original factory # object's 'values' trait changes: #--------------------------------------------------------------------------- def rebuild_editor ( self ): """ Rebuilds the contents of the editor whenever the original factory object's **values** trait changes. """ raise NotImplementedError #--------------------------------------------------------------------------- # Recomputes the cached data based on the underlying enumeration model: #--------------------------------------------------------------------------- def values_changed ( self ): """ Recomputes the cached data based on the underlying enumeration model. """ self._names, self._mapping, self._inverse_mapping = \ enum_values_changed( self._value() ) #--------------------------------------------------------------------------- # Handles the underlying object model's enumeration set being changed: #--------------------------------------------------------------------------- def _values_changed ( self ): """ Handles the underlying object model's enumeration set being changed. """ self.values_changed() self.rebuild_editor() #--------------------------------------------------------------------------- # Disposes of the contents of an editor: #--------------------------------------------------------------------------- def dispose ( self ): """ Disposes of the contents of an editor. """ if self._object is not None: self._object.on_trait_change( self._values_changed, ' ' + self._name, remove = True ) else: self.factory.on_trait_change( self.rebuild_editor, 'values_modified', remove = True ) super( BaseEditor, self ).dispose() #------------------------------------------------------------------------------- # 'SimpleEditor' class: #------------------------------------------------------------------------------- class SimpleEditor ( BaseEditor ): """ Simple style of enumeration editor, which displays a combo box. """ #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ super( SimpleEditor, self ).init( parent ) factory = self.factory if factory.evaluate is None: self.control = control = wx.Choice( parent, -1, wx.Point( 0, 0 ), wx.Size( -1, -1 ), self.names ) wx.EVT_CHOICE( parent, self.control.GetId(), self.update_object ) else: self.control = control = wx.ComboBox( parent, -1, '', wx.Point( 0, 0 ), wx.Size( -1, -1 ), self.names, style = wx.CB_DROPDOWN ) wx.EVT_COMBOBOX( parent, control.GetId(), self.update_object ) wx.EVT_TEXT_ENTER( parent, control.GetId(), self.update_text_object ) wx.EVT_KILL_FOCUS( control, self.on_kill_focus ) if (not factory.is_grid_cell) and factory.auto_set: wx.EVT_TEXT( parent, control.GetId(), self.update_text_object ) self._no_enum_update = 0 self.set_tooltip() def dispose ( self ): """ Disposes of the contents of an editor. """ disconnect( self.control, wx.EVT_COMBOBOX, wx.EVT_TEXT_ENTER, wx.EVT_TEXT ) disconnect_no_id( self.control, wx.EVT_KILL_FOCUS ) super( SimpleEditor, self ).dispose() #--------------------------------------------------------------------------- # Handles the user selecting a new value from the combo box: #--------------------------------------------------------------------------- def update_object ( self, event ): """ Handles the user selecting a new value from the combo box. """ self._no_enum_update += 1 try: new_value = self.mapping[ event.GetString() ] if new_value == self.value and self.factory.is_grid_cell: # If the enum editor is in a grid cell and the value did not # change, we want the enum editor to go away, reverting back to # the normal cell appearance. This is for 2 reasons: # 1. it looks nicer # 2. if the grid id suddenly closed, wx freaks & causes a # segfault grid = self.control.Parent.Parent grid.EnableEditing(False) grid.EnableEditing(True) self.value = new_value except: from traitsui.api import raise_to_debug raise_to_debug() self._no_enum_update -= 1 #--------------------------------------------------------------------------- # Handles the user typing text into the combo box text entry field: #--------------------------------------------------------------------------- def update_text_object ( self, event ): """ Handles the user typing text into the combo box text entry field. """ if self._no_enum_update == 0: value = self.control.GetValue() try: value = self.mapping[ value ] except: try: value = self.factory.evaluate( value ) except Exception, excp: self.error( excp ) return self._no_enum_update += 1 try: self.value = value self.control.SetBackgroundColour( OKColor ) self.control.Refresh() except: pass self._no_enum_update -= 1 #--------------------------------------------------------------------------- # Handles the control losing the keyboard focus: #--------------------------------------------------------------------------- def on_kill_focus ( self, event ): """ Handles the control losing the keyboard focus. """ self.update_text_object( event ) event.Skip() #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ if self._no_enum_update == 0: if self.factory.evaluate is None: try: self.control.SetStringSelection( self.inverse_mapping[ self.value ] ) except: pass else: try: self.control.SetValue( self.str_value ) except: pass #--------------------------------------------------------------------------- # Handles an error that occurs while setting the object's trait value: #--------------------------------------------------------------------------- def error ( self, excp ): """ Handles an error that occurs while setting the object's trait value. """ self.control.SetBackgroundColour( ErrorColor ) self.control.Refresh() #--------------------------------------------------------------------------- # Rebuilds the contents of the editor whenever the original factory # object's 'values' trait changes: #--------------------------------------------------------------------------- def rebuild_editor ( self ): """ Rebuilds the contents of the editor whenever the original factory object's **values** trait changes. """ # Note: This code is unnecessarily complex due to a strange bug in # wxWidgets implementation of the wx.Combobox control that has strange # behavior when the current text field value is one of the selection # values when 'Clear' is called. In this case, even saving and # restoring the text field value does not work, so we go to great # lengths to detect this case and avoid using 'Clear', but still get # the equivalent visual results. Modify this code at your own risk... control = self.control clear = True cur_name = None if self.factory.evaluate is not None: n = control.GetCount() cur_names = [ control.GetString( i ) for i in range( n ) ] cur_name = control.GetValue() if cur_name in self.names: clear = False include = True for i in range( n - 1, -1, -1 ): if cur_name == cur_names[i]: include = False else: control.Delete( i ) for name in self.names: if include or (name != cur_name): control.Append( name ) cur_name = None else: point = control.GetInsertionPoint() if clear: control.Clear() control.AppendItems( self.names ) if cur_name is not None: self._no_enum_update += 1 control.SetValue( cur_name ) control.SetInsertionPoint( point ) self._no_enum_update -= 1 self.update_editor() #------------------------------------------------------------------------------- # 'RadioEditor' class: #------------------------------------------------------------------------------- class RadioEditor ( BaseEditor ): """ Enumeration editor, used for the "custom" style, that displays radio buttons. """ #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ super( RadioEditor, self ).init( parent ) # Create a panel to hold all of the radio buttons: self.control = TraitsUIPanel( parent, -1 ) self.rebuild_editor() #--------------------------------------------------------------------------- # Handles the user clicking one of the 'custom' radio buttons: #--------------------------------------------------------------------------- def update_object ( self, event ): """ Handles the user clicking one of the custom radio buttons. """ try: self.value = event.GetEventObject().value except: pass #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ value = self.value for button in self.control.GetChildren(): state = (button.value == value) button.SetValue( state ) if state: button.SetFocus() #--------------------------------------------------------------------------- # Rebuilds the contents of the editor whenever the original factory # object's 'values' trait changes: #--------------------------------------------------------------------------- def rebuild_editor ( self ): """ Rebuilds the contents of the editor whenever the original factory object's **values** trait changes. """ # Clear any existing content: panel = self.control panel.SetSizer( None ) panel.DestroyChildren() # Get the current trait value: cur_name = self.str_value # Create a sizer to manage the radio buttons: names = self.names mapping = self.mapping n = len( names ) cols = self.factory.cols rows = (n + cols - 1) / cols incr = [ n / cols ] * cols rem = n % cols for i in range( cols ): incr[i] += (rem > i) incr[-1] = -(reduce( lambda x, y: x + y, incr[:-1], 0 ) - 1) if cols > 1: sizer = wx.GridSizer( 0, cols, 2, 4 ) else: sizer = wx.BoxSizer( wx.VERTICAL ) # Add the set of all possible choices: style = wx.RB_GROUP index = 0 for i in range( rows ): for j in range( cols ): if n > 0: name = label = names[ index ] label = self.string_value( label, capitalize ) control = wx.RadioButton( panel, -1, label, style = style ) control.value = mapping[ name ] style = 0 control.SetValue( name == cur_name ) wx.EVT_RADIOBUTTON( panel, control.GetId(), self.update_object ) self.set_tooltip( control ) index += incr[j] n -= 1 else: control = wx.RadioButton( panel, -1, '' ) control.value = '' control.Show( False ) sizer.Add( control, 0, wx.NORTH, 5 ) # Set-up the layout: panel.SetSizerAndFit( sizer ) #------------------------------------------------------------------------------- # 'ListEditor' class: #------------------------------------------------------------------------------- class ListEditor ( BaseEditor ): """ Enumeration editor, used for the "custom" style, that displays a list box. """ #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ super( ListEditor, self ).init( parent ) # Create a panel to hold all of the radio buttons: self.control = wx.ListBox( parent, -1, wx.Point( 0, 0 ), wx.Size( -1, -1 ), self.names, style = wx.LB_SINGLE | wx.LB_NEEDED_SB ) wx.EVT_LISTBOX( parent, self.control.GetId(), self.update_object ) self.set_tooltip() def dispose ( self ): """ Disposes of the contents of an editor. """ disconnect( self.control, wx.EVT_LISTBOX ) super( ListEditor, self ).dispose() #--------------------------------------------------------------------------- # Handles the user selecting a list box item: #--------------------------------------------------------------------------- def update_object ( self, event ): """ Handles the user selecting a list box item. """ if not self._ignore_update: value = self.control.GetStringSelection() try: value = self.mapping[ value ] except: try: value = self.factory.evaluate( value ) except: pass try: self.value = value except: pass #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ control = self.control try: index = control.FindString( self.inverse_mapping[ self.value ] ) if index >= 0: control.SetSelection( index ) except: pass #--------------------------------------------------------------------------- # Rebuilds the contents of the editor whenever the original factory # object's 'values' trait changes: #--------------------------------------------------------------------------- def rebuild_editor ( self ): """ Rebuilds the contents of the editor whenever the original factory object's **values** trait changes. """ self._ignore_update = True self.control.Clear() self.control.AppendItems( self.names ) self._ignore_update = False # fixme: Is this line necessary? self.update_editor() ### EOF ####################################################################### traitsui-4.1.0/traitsui/wx/ui_base.py0000644000175100001440000003423511674463546020653 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 12/18/2004 # #------------------------------------------------------------------------------ """ Defines the base class for the wxPython-based Traits UI modal and non-modal dialogs. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx from traits.api \ import HasStrictTraits, HasPrivateTraits, Instance, List, Event from traitsui.api \ import UI from traitsui.menu \ import Action from editor \ import Editor #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- # List of all predefined system button names: SystemButtons = [ 'Undo', 'Redo', 'Apply', 'Revert', 'OK', 'Cancel', 'Help' ] # List of alternative context items that might handle an Action 'perform': PerformHandlers = ( 'object', 'model' ) #------------------------------------------------------------------------------- # 'RadioGroup' class: #------------------------------------------------------------------------------- class RadioGroup ( HasStrictTraits ): """ A group of mutually-exclusive menu or toolbar actions. """ # List of menu or tool bar items items = List #--------------------------------------------------------------------------- # Handles a menu item in the group being checked: #--------------------------------------------------------------------------- def menu_checked ( self, menu_item ): """ Handles a menu item in the group being checked. """ for item in self.items: if item is not menu_item: item.control.Check( False ) item.item.action.checked = False #--------------------------------------------------------------------------- # Handles a tool bar item in the group being checked: #--------------------------------------------------------------------------- def toolbar_checked ( self, toolbar_item ): """ Handles a tool bar item in the group being checked. """ for item in self.items: if item is not toolbar_item: item.tool_bar.ToggleTool( item.control_id, False ) item.item.action.checked = False #------------------------------------------------------------------------------- # 'ButtonEditor' class: #------------------------------------------------------------------------------- class ButtonEditor ( Editor ): """ Editor for buttons. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Action associated with the button action = Instance( Action ) #--------------------------------------------------------------------------- # Initializes the object: #--------------------------------------------------------------------------- def __init__ ( self, **traits ): self.set( **traits ) #--------------------------------------------------------------------------- # Handles the associated button being clicked: #--------------------------------------------------------------------------- def perform ( self, event ): """ Handles the associated button being clicked. """ self.ui.do_undoable( self._perform, event ) def _perform ( self, event ): method_name = self.action.action if method_name == '': method_name = '_%s_clicked' % (self.action.name.lower()) method = getattr( self.ui.handler, method_name, None ) if method is not None: method( self.ui.info ) else: self.action.perform( event ) #------------------------------------------------------------------------------- # 'BaseDialog' class: #------------------------------------------------------------------------------- class BaseDialog ( object ): """ Base class for Traits UI dialog boxes. """ #--------------------------------------------------------------------------- # Sets the frame's icon: #--------------------------------------------------------------------------- def set_icon ( self, icon = None ): """ Sets the frame's icon. """ from pyface.image_resource import ImageResource if not isinstance( icon, ImageResource ): icon = ImageResource( 'frame.ico' ) self.control.SetIcon( icon.create_icon() ) #--------------------------------------------------------------------------- # Adds a status bar to the dialog: #--------------------------------------------------------------------------- def add_statusbar ( self ): """ Adds a status bar to the dialog. """ ui = self.ui statusbar = ui.view.statusbar context = ui.context if statusbar is not None: widths = [] listeners = [] control = wx.StatusBar( self.control ) control.SetFieldsCount( len( statusbar ) ) for i, item in enumerate( statusbar ): width = abs( item.width ) if width <= 1.0: widths.append( -max( 1, int( 1000 * width ) ) ) else: widths.append( int( width ) ) set_text = self._set_status_text( control, i ) name = item.name set_text( ui.get_extended_value( name ) ) col = name.find( '.' ) object = 'object' if col >= 0: object = name[ : col ] name = name[ col + 1: ] object = context[ object ] object.on_trait_change( set_text, name, dispatch = 'ui' ) listeners.append( ( object, set_text, name ) ) control.SetStatusWidths( widths ) self.control.SetStatusBar( control ) ui._statusbar = listeners def _set_status_text ( self, control, i ): def set_status_text ( text ): control.SetStatusText( text, i ) return set_status_text #--------------------------------------------------------------------------- # Adds a menu bar to the dialog: #--------------------------------------------------------------------------- def add_menubar ( self ): """ Adds a menu bar to the dialog. """ menubar = self.ui.view.menubar if menubar is not None: self._last_group = self._last_parent = None self.control.SetMenuBar( menubar.create_menu_bar( self.control, self ) ) self._last_group = self._last_parent = None #--------------------------------------------------------------------------- # Adds a tool bar to the dialog: #--------------------------------------------------------------------------- def add_toolbar ( self ): """ Adds a toolbar to the dialog. """ toolbar = self.ui.view.toolbar if toolbar is not None: self._last_group = self._last_parent = None self.control.SetToolBar( toolbar.create_tool_bar( self.control, self ) ) self._last_group = self._last_parent = None #--------------------------------------------------------------------------- # Adds a menu item to the menu bar being constructed: #--------------------------------------------------------------------------- def add_to_menu ( self, menu_item ): """ Adds a menu item to the menu bar being constructed. """ item = menu_item.item action = item.action if action.id != '': self.ui.info.bind( action.id, menu_item ) if action.style == 'radio': if ((self._last_group is None) or (self._last_parent is not item.parent)): self._last_group = RadioGroup() self._last_parent = item.parent self._last_group.items.append( menu_item ) menu_item.group = self._last_group if action.enabled_when != '': self.ui.add_enabled( action.enabled_when, menu_item ) if action.checked_when != '': self.ui.add_checked( action.checked_when, menu_item ) #--------------------------------------------------------------------------- # Adds a tool bar item to the tool bar being constructed: #--------------------------------------------------------------------------- def add_to_toolbar ( self, toolbar_item ): """ Adds a toolbar item to the toolbar being constructed. """ self.add_to_menu( toolbar_item ) #--------------------------------------------------------------------------- # Returns whether the menu action should be defined in the user interface: #--------------------------------------------------------------------------- def can_add_to_menu ( self, action, action_event = None ): """ Returns whether the action should be defined in the user interface. """ if action.defined_when == '': return True return self.ui.eval_when( action.defined_when ) #--------------------------------------------------------------------------- # Returns whether the toolbar action should be defined in the user # interface: #--------------------------------------------------------------------------- def can_add_to_toolbar ( self, action ): """ Returns whether the toolbar action should be defined in the user interface. """ return self.can_add_to_menu( action ) #--------------------------------------------------------------------------- # Performs the action described by a specified Action object: #--------------------------------------------------------------------------- def perform ( self, action ): """ Performs the action described by a specified Action object. """ self.ui.do_undoable( self._perform, action ) def _perform ( self, action ): method = getattr( self.ui.handler, action.action, None ) if method is not None: method( self.ui.info ) else: context = self.ui.context for item in PerformHandlers: handler = context.get( item, None ) if handler is not None: method = getattr( handler, action.action, None ) if method is not None: method() break else: action.perform() #--------------------------------------------------------------------------- # Check to see if a specified 'system' button is in the buttons list, and # add it if it is not: #--------------------------------------------------------------------------- def check_button ( self, buttons, action ): """ Adds *action* to the system buttons list for this dialog, if it is not already in the list. """ name = action.name for button in buttons: if self.is_button( button, name ): return buttons.append( action ) #--------------------------------------------------------------------------- # Check to see if a specified Action button is a 'system' button: #--------------------------------------------------------------------------- def is_button ( self, action, name ): """ Returns whether a specified action button is a system button. """ if isinstance(action, basestring): return (action == name) return (action.name == name) #--------------------------------------------------------------------------- # Coerces a string to an Action if necessary: #--------------------------------------------------------------------------- def coerce_button ( self, action ): """ Coerces a string to an Action if necessary. """ if isinstance(action, basestring): return Action( name = action, action = '?'[ (not action in SystemButtons): ] ) return action #--------------------------------------------------------------------------- # Creates a user specified button: #--------------------------------------------------------------------------- def add_button ( self, action, sizer, method = None, enabled = True, name = None, default = False ): """ Creates a button. """ ui = self.ui if ((action.defined_when != '') and (not ui.eval_when( action.defined_when ))): return None if name is None: name = action.name id = action.id button = wx.Button( self.control, -1, name ) button.Enable( enabled ) if default: button.SetDefault() if (method is None) or (action.enabled_when != '') or (id != ''): editor = ButtonEditor( ui = ui, action = action, control = button ) if id != '': ui.info.bind( id, editor ) if action.visible_when != '': ui.add_visible( action.visible_when, editor ) if action.enabled_when != '': ui.add_enabled( action.enabled_when, editor ) if method is None: method = editor.perform wx.EVT_BUTTON( self.control, button.GetId(), method ) sizer.Add( button, 0, wx.LEFT, 5 ) if action.tooltip != '': button.SetToolTipString( action.tooltip ) return button traitsui-4.1.0/traitsui/wx/themed_button_editor.py0000644000175100001440000001460511674463546023452 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2007, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 06/26/2007 # #------------------------------------------------------------------------------- """ Traits UI themed button editor. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx from traits.api \ import Instance, Str, on_trait_change from traitsui.api \ import Theme from traitsui.ui_traits \ import ATheme, AView, Image, Position, Spacing from traitsui.wx.editor \ import Editor from traitsui.basic_editor_factory \ import BasicEditorFactory from themed_control \ import ThemedControl #------------------------------------------------------------------------------- # '_ThemedButtonEditor' class: #------------------------------------------------------------------------------- class _ThemedButtonEditor ( Editor ): """ Traits UI themed button editor. """ # The ThemedControl used for the button: button = Instance( ThemedControl ) #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ # Create the button and its control: factory = self.factory label = factory.label if (label == '') and (factory.image is None): label = self.item.get_label( self.ui ) label = self.string_value( label ) self.button = button = ThemedControl( **factory.get( 'theme', 'image', 'position', 'spacing' ) ).set( text = label, controller = self, default_alignment = 'center', min_size = ( 80, 0 ) ) self.control = button.create_control( parent ) # Set the tooltip: self.set_tooltip() #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ pass #-- Trait Event Handlers --------------------------------------------------- @on_trait_change( 'button.enabled' ) def _on_enabled_changed ( self ): """ Handles the button 'enabled' state changing. """ if self.button.enabled: self.button.set( state = 'normal', offset = ( 0, 0 ), theme = self.factory.theme ) else: self.button.set( state = 'disabled', offset = ( 0, 0 ), theme = self.factory.disabled_theme or self.factory.theme ) #-- ThemedControl Event Handlers ------------------------------------------- def normal_left_down ( self, x, y, event ): if self.control.IsEnabled(): self.button.set( state = 'down', offset = ( 1, 1 ), theme = self.factory.down_theme or self.factory.theme ) def normal_motion ( self, x, y, event ): hover = self.factory.hover_theme if self.control.IsEnabled() and (hover is not None): self.button.set( state = 'hover', theme = hover ) self.control.CaptureMouse() def hover_left_down ( self, x, y, event ): self.control.ReleaseMouse() self.normal_left_down( x, y, event ) def hover_motion ( self, x, y, event ): if not self.button.in_control( x, y ): self.control.ReleaseMouse() self.button.set( state = 'normal', theme = self.factory.theme ) def down_left_up ( self, x, y, event ): if self.button.in_control( x, y ): self.value = True # If there is an associated view, display it: if self.factory.view is not None: self.object.edit_traits( view = self.factory.view, parent = self.control ) self.button.set( state = 'normal', offset = ( 0, 0 ), theme = self.factory.theme ) def down_motion ( self, x, y, event ): theme = self.factory.down_theme or self.factory.theme is_in = self.button.in_control( x, y ) if not is_in: theme = self.factory.theme self.button.set( offset = ( is_in, is_in ), theme = theme ) #------------------------------------------------------------------------------- # Create the editor factory object: #------------------------------------------------------------------------------- # wxPython editor factory for themed button editors: class ThemedButtonEditor ( BasicEditorFactory ): # The editor class to be created: klass = _ThemedButtonEditor # The button label: label = Str # The basic theme for the button (i.e. the 'up' state): theme = ATheme( '@std:BG5' ) # The optional 'down' state theme for the button: down_theme = ATheme( '@std:BE5' ) # The optional 'hover' state theme for the button: hover_theme = ATheme( '@std:BG6' ) # The optional 'disabled' state theme for the button: disabled_theme = ATheme( '@std:GG3' ) # The optional image to display in the button: image = Image # The position of the image relative to the text: position = Position # The amount of space between the image and the text: spacing = Spacing # The optional view to display when the button is clicked: view = AView traitsui-4.1.0/traitsui/wx/array_view_editor.py0000644000175100001440000000121211674463546022747 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from traitsui.ui_editors.array_view_editor \ import _ArrayViewEditor as BaseArrayViewEditor from ui_editor \ import UIEditor #------------------------------------------------------------------------------- # '_ArrayViewEditor' class: #------------------------------------------------------------------------------- class _ArrayViewEditor ( BaseArrayViewEditor, UIEditor ): pass #--EOF------------------------------------------------------------------------- traitsui-4.1.0/traitsui/wx/value_editor.py0000644000175100001440000000315711674463546021725 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2006, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 01/05/2006 # #------------------------------------------------------------------------------ """ Defines the tree-based Python value editor and the value editor factory, for the wxPython user interface toolkit. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- # FIXME: ToolkitEditorFactory is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.value_editor file. from traitsui.editors.value_editor \ import _ValueEditor, ToolkitEditorFactory from editor import Editor class SimpleEditor( _ValueEditor, Editor): """ Returns the editor to use for simple style views. """ # Override the value of the readonly trait. readonly = False class ReadonlyEditor( _ValueEditor, Editor): """ Returns the editor to use for readonly style views. """ # Override the value of the readonly trait. readonly = True ### EOF ####################################################################### traitsui-4.1.0/traitsui/wx/view_application.py0000644000175100001440000001244011674463546022573 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 11/10/2004 # #------------------------------------------------------------------------------ """ Creates a wxPython specific modal dialog user interface that runs as a complete application, using information from the specified UI object. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- # Standard library imports. import os import sys # System library imports. import wx # ETS imports. from pyface.util.guisupport import is_event_loop_running_wx, \ start_event_loop_wx #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- # File to redirect output to. If '', output goes to stdout. redirect_filename = '' #------------------------------------------------------------------------------- # Creates a 'stand-alone' wx Application to display a specified traits UI View: #------------------------------------------------------------------------------- def view_application ( context, view, kind, handler, id, scrollable, args ): """ Creates a stand-alone wx Application to display a specified traits UI View. Parameters ---------- context : object or dictionary A single object or a dictionary of string/object pairs, whose trait attributes are to be edited. If not specified, the current object is used. view : view object A View object that defines a user interface for editing trait attribute values. kind : string The type of user interface window to create. See the **traitsui.view.kind_trait** trait for values and their meanings. If *kind* is unspecified or None, the **kind** attribute of the View object is used. handler : Handler object A handler object used for event handling in the dialog box. If None, the default handler for Traits UI is used. scrollable : Boolean Indicates whether the dialog box should be scrollable. When set to True, scroll bars appear on the dialog box if it is not large enough to display all of the items in the view at one time. """ if (kind == 'panel') or ((kind is None) and (view.kind == 'panel')): kind = 'modal' app = wx.GetApp() if app is None or not is_event_loop_running_wx(app): return ViewApplication( context, view, kind, handler, id, scrollable, args ).ui.result return view.ui( context, kind = kind, handler = handler, id = id, scrollable = scrollable, args = args ).result #------------------------------------------------------------------------------- # 'ViewApplication' class: #------------------------------------------------------------------------------- class ViewApplication ( wx.PySimpleApp ): """ Modal window that contains a stand-alone application. """ #--------------------------------------------------------------------------- # Initializes the object: #--------------------------------------------------------------------------- def __init__ ( self, context, view, kind, handler, id, scrollable, args ): """ Initializes the object. """ self.context = context self.view = view self.kind = kind self.handler = handler self.id = id self.scrollable = scrollable self.args = args wx.InitAllImageHandlers() if os.environ.get( 'ENABLE_FBI' ) is not None: try: from etsdevtools.developer.helper.fbi import enable_fbi enable_fbi() except: pass if redirect_filename.strip() != '': super( ViewApplication, self ).__init__( 1, redirect_filename ) else: super( ViewApplication, self ).__init__() # Start the event loop in an IPython-conforming manner. start_event_loop_wx(self) #--------------------------------------------------------------------------- # Handles application initialization: #--------------------------------------------------------------------------- def OnInit ( self ): """ Handles application initialization. """ self.ui = self.view.ui( self.context, kind = self.kind, handler = self.handler, id = self.id, scrollable = self.scrollable, args = self.args ) return True traitsui-4.1.0/traitsui/wx/dnd_editor.py0000644000175100001440000003300611674463546021352 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2006, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 06/25/2006 # #------------------------------------------------------------------------------ """ Defines the various editors for a drag-and-drop editor, for the wxPython user interface toolkit. A drag-and-drop editor represents its value as a simple image which, depending upon the editor style, can be a drag source only, a drop target only, or both a drag source and a drop target. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx import numpy from cPickle \ import load from traits.api \ import Bool # FIXME: ToolkitEditorFactory is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.dnd_editor file. from traitsui.editors.dnd_editor \ import ToolkitEditorFactory from pyface.wx.drag_and_drop \ import PythonDropSource, PythonDropTarget, clipboard try: from apptools.io import File except ImportError: File = None try: from apptools.naming.api import Binding except ImportError: Binding = None from pyface.image_resource \ import ImageResource from editor \ import Editor #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- # The image to use when the editor accepts files: file_image = ImageResource( 'file' ).create_image() # The image to use when the editor accepts objects: object_image = ImageResource( 'object' ).create_image() # The image to use when the editor is disabled: inactive_image = ImageResource( 'inactive' ).create_image() # String types: string_type = ( str, unicode ) #------------------------------------------------------------------------------- # 'SimpleEditor' class: #------------------------------------------------------------------------------- class SimpleEditor ( Editor ): """ Simply style of editor for a drag-and-drop editor, which is both a drag source and a drop target. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Is the editor a drop target? drop_target = Bool( True ) # Is the editor a drag source? drag_source = Bool( True ) #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ # Determine the drag/drop type: value = self.value self._is_list = isinstance( value, list ) self._is_file = (isinstance( value, string_type ) or (self._is_list and (len( value ) > 0) and isinstance( value[0], string_type ))) # Get the right image to use: image = self.factory.image if image is not None: image = image.create_image() disabled_image = self.factory.disabled_image if disabled_image is not None: disabled_image = disabled_image.create_image() else: disabled_image = inactive_image image = object_image if self._is_file: image = file_image self._image = image.ConvertToBitmap() if disabled_image is not None: self._disabled_image = disabled_image.ConvertToBitmap() else: data = numpy.reshape( numpy.fromstring( image.GetData(), numpy.uint8 ), ( -1, 3 ) ) * numpy.array( [ [ 0.297, 0.589, 0.114 ] ] ) g = data[ :, 0 ] + data[ :, 1 ] + data[ :, 2 ] data[ :, 0 ] = data[ :, 1 ] = data[ :, 2 ] = g image.SetData( numpy.ravel( data.astype(numpy.uint8) ).tostring() ) image.SetMaskColour( 0, 0, 0 ) self._disabled_image = image.ConvertToBitmap() # Create the control and set up the event handlers: self.control = control = wx.Window( parent, -1, size = wx.Size( image.GetWidth(), image.GetHeight() ) ) self.set_tooltip() if self.drop_target: control.SetDropTarget( PythonDropTarget( self ) ) wx.EVT_LEFT_DOWN( control, self._left_down ) wx.EVT_LEFT_UP( control, self._left_up ) wx.EVT_MOTION( control, self._mouse_move ) wx.EVT_PAINT( control, self._on_paint ) #--------------------------------------------------------------------------- # Disposes of the contents of an editor: #--------------------------------------------------------------------------- def dispose ( self ): """ Disposes of the contents of an editor. """ control = self.control wx.EVT_LEFT_DOWN( control, None ) wx.EVT_LEFT_UP( control, None ) wx.EVT_MOTION( control, None ) wx.EVT_PAINT( control, None ) super( SimpleEditor, self ).dispose() #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ return #-- Private Methods ------------------------------------------------------------ #--------------------------------------------------------------------------- # Returns the processed version of a drag request's data: #--------------------------------------------------------------------------- def _get_drag_data ( self, data ): """ Returns the processed version of a drag request's data. """ if isinstance( data, list ): if Binding is not None and isinstance( data[0], Binding ): data = [ item.obj for item in data ] if File is not None and isinstance( data[0], File ): data = [ item.absolute_path for item in data ] if not self._is_file: result = [] for file in data: item = self._unpickle( file ) if item is not None: result.append( item ) data = result else: if Binding is not None and isinstance( data, Binding ): data = data.obj if File is not None and isinstance( data, File ): data = data.absolute_path if not self._is_file: object = self._unpickle( data ) if object is not None: data = object return data #--------------------------------------------------------------------------- # Returns the unpickled version of a specified file (if possible): #--------------------------------------------------------------------------- def _unpickle ( self, file_name ): """ Returns the unpickled version of a specified file (if possible). """ fh = None try: fh = file( file_name, 'rb' ) object = load( fh ) except: object = None if fh is not None: fh.close() return object #-- wxPython Event Handlers ---------------------------------------------------- def _on_paint ( self, event ): """ Called when the control needs repainting. """ image = self._image control = self.control if not control.IsEnabled(): image = self._disabled_image wdx, wdy = control.GetClientSizeTuple() wx.PaintDC( control ).DrawBitmap( image, (wdx - image.GetWidth()) / 2, (wdy - image.GetHeight()) / 2, True ) def _left_down ( self, event ): """ Handles the left mouse button being pressed. """ if self.control.IsEnabled() and self.drag_source: self._x, self._y = event.GetX(), event.GetY() self.control.CaptureMouse() event.Skip() def _left_up ( self, event ): """ Handles the left mouse button being released. """ if self._x is not None: self._x = None self.control.ReleaseMouse() event.Skip() def _mouse_move ( self, event ): """ Handles the mouse being moved. """ if self._x is not None: if ((abs( self._x - event.GetX() ) + abs( self._y - event.GetY() )) >= 3): self.control.ReleaseMouse() self._x = None if self._is_file: FileDropSource( self.control, self.value ) else: PythonDropSource( self.control, self.value ) event.Skip() #----- Drag and drop event handlers: ------------------------------------------- #--------------------------------------------------------------------------- # Handles a Python object being dropped on the control: #--------------------------------------------------------------------------- def wx_dropped_on ( self, x, y, data, drag_result ): """ Handles a Python object being dropped on the tree. """ try: self.value = self._get_drag_data( data ) return drag_result except: return wx.DragNone #--------------------------------------------------------------------------- # Handles a Python object being dragged over the control: #--------------------------------------------------------------------------- def wx_drag_over ( self, x, y, data, drag_result ): """ Handles a Python object being dragged over the tree. """ try: self.object.base_trait( self.name ).validate( self.object, self.name, self._get_drag_data( data ) ) return drag_result except: return wx.DragNone #------------------------------------------------------------------------------- # 'CustomEditor' class: #------------------------------------------------------------------------------- class CustomEditor ( SimpleEditor ): """ Custom style of drag-and-drop editor, which is not a drag source. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Is the editor a drag source? This value overrides the default. drag_source = False #------------------------------------------------------------------------------- # 'ReadonlyEditor' class: #------------------------------------------------------------------------------- class ReadonlyEditor ( SimpleEditor ): """ Read-only style of drag-and-drop editor, which is not a drop target. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Is the editor a drop target? This value overrides the default. drop_target = False #------------------------------------------------------------------------------- # 'FileDropSource' class: #------------------------------------------------------------------------------- class FileDropSource ( wx.DropSource ): """ Represents a draggable file. """ #--------------------------------------------------------------------------- # Initializes the object: #--------------------------------------------------------------------------- def __init__ ( self, source, files ): """ Initializes the object. """ self.handler = None self.allow_move = True # Put the data to be dragged on the clipboard: clipboard.data = files clipboard.source = source clipboard.drop_source = self data_object = wx.FileDataObject() if isinstance( files, string_type ): files = [ files ] for file in files: data_object.AddFile( file ) # Create the drop source and begin the drag and drop operation: super( FileDropSource, self ).__init__( source ) self.SetData( data_object ) self.result = self.DoDragDrop( True ) #--------------------------------------------------------------------------- # Called when the data has been dropped: #--------------------------------------------------------------------------- def on_dropped ( self, drag_result ): """ Called when the data has been dropped. """ return ## EOF ######################################################################## traitsui-4.1.0/traitsui/wx/image_editor.py0000644000175100001440000000540511674463546021671 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2007, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 06/05/2007 # #------------------------------------------------------------------------------- """ Traits UI 'display only' image editor. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from pyface.image_resource \ import ImageResource from traitsui.ui_traits \ import convert_bitmap # FIXME: ImageEditor is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.image_editor file. from traitsui.editors.image_editor \ import ImageEditor from editor \ import Editor from image_control \ import ImageControl #------------------------------------------------------------------------------- # '_ImageEditor' class: #------------------------------------------------------------------------------- class _ImageEditor ( Editor ): """ Traits UI 'display only' image editor. """ #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ image = self.factory.image if image is None: image = self.value self.control = ImageControl( parent, convert_bitmap( image ), padding = 0 ) self.set_tooltip() #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ if self.factory.image is None: value = self.value if isinstance( value, ImageResource ): self.control.Bitmap( convert_bitmap( value ) ) ### EOF ####################################################################### traitsui-4.1.0/traitsui/wx/list_editor.py0000644000175100001440000010464711674463546021572 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/21/2004 # #------------------------------------------------------------------------------ """ Defines the various list editors for the wxPython user interface toolkit. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx import wx.lib.scrolledpanel as wxsp from traits.api \ import Str, Any, Instance, Property, Bool, cached_property from traits.trait_base \ import user_name_for, enumerate, xgetattr from traitsui.ui_traits \ import Image, convert_bitmap from traitsui.editors.list_editor \ import ListItemProxy, ToolkitEditorFactory from traitsui.dockable_view_element \ import DockableViewElement from pyface.dock.api \ import DockWindow, DockSizer, DockSection, DockRegion, DockControl from constants \ import scrollbar_dx from editor \ import Editor from menu \ import MakeMenu from image_control \ import ImageControl #------------------------------------------------------------------------------- # 'SimpleEditor' class: #------------------------------------------------------------------------------- class SimpleEditor ( Editor ): """ Simple style of editor for lists, which displays a scrolling list box with only one item visible at a time. A icon next to the list box displays a menu of operations on the list. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # The kind of editor to create for each list item kind = Str # Is the list of items being edited mutable? mutable = Bool # The image used by the editor: image = Image( 'list_editor' ) # The bitmap used by the editor: bitmap = Property #--------------------------------------------------------------------------- # Class constants: #--------------------------------------------------------------------------- # Whether the list is displayed in a single row single_row = True #--------------------------------------------------------------------------- # Normal list item menu: #--------------------------------------------------------------------------- # Menu for modifying the list list_menu = """ Add Before [_menu_before]: self.add_before() Add After [_menu_after]: self.add_after() --- Delete [_menu_delete]: self.delete_item() --- Move Up [_menu_up]: self.move_up() Move Down [_menu_down]: self.move_down() Move to Top [_menu_top]: self.move_top() Move to Bottom [_menu_bottom]: self.move_bottom() """ #--------------------------------------------------------------------------- # Empty list item menu: #--------------------------------------------------------------------------- empty_list_menu = """ Add: self.add_empty() """ #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ # Initialize the trait handler to use: trait_handler = self.factory.trait_handler if trait_handler is None: trait_handler = self.object.base_trait( self.name ).handler self._trait_handler = trait_handler # Create a scrolled window to hold all of the list item controls: self.control = wxsp.ScrolledPanel( parent, -1 ) self.control.SetBackgroundColour( parent.GetBackgroundColour() ) self.control.SetAutoLayout( True ) # Remember the editor to use for each individual list item: editor = self.factory.editor if editor is None: editor = trait_handler.item_trait.get_editor() self._editor = getattr( editor, self.kind ) # Set up the additional 'list items changed' event handler needed for # a list based trait. Note that we want to fire the update_editor_item # only when the items in the list change and not when intermediate # traits change. Therefore, replace "." by ":" in the extended_name # when setting up the listener. extended_name = self.extended_name.replace('.', ':') self.context_object.on_trait_change( self.update_editor_item, extended_name + '_items?', dispatch = 'ui' ) self.set_tooltip() #--------------------------------------------------------------------------- # Disposes of the contents of an editor: #--------------------------------------------------------------------------- def dispose ( self ): """ Disposes of the contents of an editor. """ extended_name = self.extended_name.replace('.', ':') self.context_object.on_trait_change( self.update_editor_item, extended_name + '_items?', remove = True ) self._dispose_items() super( SimpleEditor, self ).dispose() #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ # Disconnect the editor from any control about to be destroyed: self._dispose_items() # Get rid of any previous contents: list_pane = self.control list_pane.SetSizer( None ) list_pane.DestroyChildren() # Create all of the list item trait editors: trait_handler = self._trait_handler resizable = ((trait_handler.minlen != trait_handler.maxlen) and self.mutable) item_trait = trait_handler.item_trait factory = self.factory list_sizer = wx.FlexGridSizer( len(self.value), (1 + resizable) * factory.columns, 0, 0 ) j = resizable for i in range( factory.columns ): list_sizer.AddGrowableCol( j ) j += (1 + resizable) values = self.value index = 0 width, height = 0, 0 is_fake = (resizable and (values is None or len( values ) == 0)) if is_fake: values = [ item_trait.default_value()[1] ] panel_height = 0 editor = self._editor for value in values: width1 = height = 0 if resizable: control = ImageControl( list_pane, self.bitmap, -1, self.popup_menu ) width1, height = control.GetSize() width1 += 4 try: proxy = ListItemProxy( self.object, self.name, index, item_trait, value ) if resizable: control.proxy = proxy peditor = editor( self.ui, proxy, 'value', self.description, list_pane ).set( object_name = '' ) peditor.prepare( list_pane ) pcontrol = peditor.control pcontrol.proxy = proxy except: if not is_fake: raise pcontrol = wx.Button( list_pane, -1, 'sample' ) pcontrol.Fit() width2, height2 = size = pcontrol.GetSize() pcontrol.SetMinSize( size ) width = max( width, width1 + width2 ) height = max( height, height2 ) panel_height += height if resizable: list_sizer.Add( control, 0, wx.LEFT | wx.RIGHT, 2 ) list_sizer.Add( pcontrol, 0, wx.EXPAND ) index += 1 list_pane.SetSizer( list_sizer ) if not self.mutable: #list_sizer.SetDimension(0,0,width, panel_height) list_pane.SetInitialSize(list_sizer.GetSize()) if is_fake: self._cur_control = control self.empty_list() control.Destroy() pcontrol.Destroy() rows = 1 if not self.single_row: rows = self.factory.rows # Make sure we have valid values set for width and height (in case there # was no data to base them on): if width == 0: width = 100 if panel_height == 0: panel_height = 20 list_pane.SetMinSize( wx.Size( width + ((trait_handler.maxlen > rows) * scrollbar_dx), panel_height) ) list_pane.SetupScrolling() list_pane.GetParent().Layout() #--------------------------------------------------------------------------- # Updates the editor when an item in the object trait changes external to # the editor: #--------------------------------------------------------------------------- def update_editor_item ( self, obj, name, event ): """ Updates the editor when an item in the object trait changes externally to the editor. """ # If this is not a simple, single item update, rebuild entire editor: if (len( event.removed ) != 1) or (len( event.added ) != 1): self.update_editor() return # Otherwise, find the proxy for this index and update it with the # changed value: for control in self.control.GetChildren(): proxy = control.proxy if proxy.index == event.index: proxy.value = event.added[0] break #--------------------------------------------------------------------------- # Creates an empty list entry (so the user can add a new item): #--------------------------------------------------------------------------- def empty_list ( self ): """ Creates an empty list entry (so the user can add a new item). """ control = ImageControl( self.control, self.bitmap, -1, self.popup_empty_menu ) control.is_empty = True proxy = ListItemProxy( self.object, self.name, -1, None, None ) pcontrol = wx.StaticText( self.control, -1, ' (Empty List)' ) pcontrol.proxy = control.proxy = proxy self.reload_sizer( [ ( control, pcontrol ) ] ) #--------------------------------------------------------------------------- # Reloads the layout from the specified list of ( button, proxy ) pairs: #--------------------------------------------------------------------------- def reload_sizer ( self, controls, extra = 0 ): """ Reloads the layout from the specified list of ( button, proxy ) pairs. """ sizer = self.control.GetSizer() for i in xrange( 2 * len( controls ) + extra ): sizer.Remove( 0 ) index = 0 for control, pcontrol in controls: sizer.Add( control, 0, wx.LEFT | wx.RIGHT, 2 ) sizer.Add( pcontrol, 1, wx.EXPAND ) control.proxy.index = index index += 1 sizer.Layout() self.control.SetVirtualSize( sizer.GetMinSize() ) #--------------------------------------------------------------------------- # Returns the associated object list and current item index: #--------------------------------------------------------------------------- def get_info ( self ): """ Returns the associated object list and current item index. """ proxy = self._cur_control.proxy return ( proxy.list, proxy.index ) #--------------------------------------------------------------------------- # Displays the empty list editor popup menu: #--------------------------------------------------------------------------- def popup_empty_menu ( self, control ): """ Displays the empty list editor popup menu. """ self._cur_control = control menu = MakeMenu( self.empty_list_menu, self, True, self.control ).menu self.control.PopupMenu( menu, control.GetPosition() ) menu.Destroy() #--------------------------------------------------------------------------- # Displays the list editor popup menu: #--------------------------------------------------------------------------- def popup_menu ( self, control ): """ Displays the list editor popup menu. """ self._cur_control = control # Makes sure that any text that was entered get's added (Pressure #145): control.SetFocus() proxy = control.proxy index = proxy.index menu = MakeMenu( self.list_menu, self, True, self.control ).menu len_list = len( proxy.list ) not_full = (len_list < self._trait_handler.maxlen) self._menu_before.enabled( not_full ) self._menu_after.enabled( not_full ) self._menu_delete.enabled( len_list > self._trait_handler.minlen ) self._menu_up.enabled( index > 0 ) self._menu_top.enabled( index > 0 ) self._menu_down.enabled( index < (len_list - 1) ) self._menu_bottom.enabled( index < (len_list - 1) ) self.control.PopupMenu( menu, control.GetPosition() ) menu.Destroy() #--------------------------------------------------------------------------- # Adds a new value at the specified list index: #--------------------------------------------------------------------------- def add_item ( self, offset ): """ Adds a new value at the specified list index. """ list, index = self.get_info() index += offset item_trait = self._trait_handler.item_trait value = item_trait.default_value_for( self.object, self.name ) self.value = list[:index] + [ value ] + list[index:] self.update_editor() #--------------------------------------------------------------------------- # Inserts a new item before the current item: #--------------------------------------------------------------------------- def add_before ( self ): """ Inserts a new item before the current item. """ self.add_item( 0 ) #--------------------------------------------------------------------------- # Inserts a new item after the current item: #--------------------------------------------------------------------------- def add_after ( self ): """ Inserts a new item after the current item. """ self.add_item( 1 ) #--------------------------------------------------------------------------- # Adds a new item when the list is empty: #--------------------------------------------------------------------------- def add_empty ( self ): """ Adds a new item when the list is empty. """ list, index = self.get_info() self.add_item( 0 ) #--------------------------------------------------------------------------- # Delete the current item: #--------------------------------------------------------------------------- def delete_item ( self ): """ Delete the current item. """ list, index = self.get_info() self.value = list[:index] + list[index+1:] self.update_editor() #--------------------------------------------------------------------------- # Move the current item up one in the list: #--------------------------------------------------------------------------- def move_up ( self ): """ Move the current item up one in the list. """ list, index = self.get_info() self.value = (list[:index-1] + [ list[index], list[index-1] ] + list[index+1:]) self.update_editor() #--------------------------------------------------------------------------- # Moves the current item down one in the list: #--------------------------------------------------------------------------- def move_down ( self ): """ Moves the current item down one in the list. """ list, index = self.get_info() self.value = (list[:index] + [ list[index+1], list[index] ] + list[index+2:]) self.update_editor() #--------------------------------------------------------------------------- # Moves the current item to the top of the list: #--------------------------------------------------------------------------- def move_top ( self ): """ Moves the current item to the top of the list. """ list, index = self.get_info() self.value = [ list[index] ] + list[:index] + list[index+1:] self.update_editor() #--------------------------------------------------------------------------- # Moves the current item to the bottom of the list: #--------------------------------------------------------------------------- def move_bottom ( self ): """ Moves the current item to the bottom of the list. """ list, index = self.get_info() self.value = list[:index] + list[index+1:] + [ list[index] ] self.update_editor() #-- Property Implementations ----------------------------------------------- @cached_property def _get_bitmap ( self ): return convert_bitmap( self.image ) #-- Private Methods -------------------------------------------------------- def _dispose_items ( self ): """ Disposes of each current list item. """ for control in self.control.GetChildren(): editor = getattr( control, '_editor', None ) if editor is not None: editor.dispose() editor.control = None #-- Trait initializers ---------------------------------------------------- def _kind_default(self): """ Returns a default value for the 'kind' trait. """ return self.factory.style + '_editor' def _mutable_default(self): """ Trait handler to set the mutable trait from the factory. """ return self.factory.mutable #------------------------------------------------------------------------------- # 'CustomEditor' class: #------------------------------------------------------------------------------- class CustomEditor ( SimpleEditor ): """ Custom style of editor for lists, which displays the items as a series of text fields. If the list is editable, an icon next to each item displays a menu of operations on the list. """ #--------------------------------------------------------------------------- # Class constants: #--------------------------------------------------------------------------- # Whether the list is displayed in a single row. This value overrides the # default. single_row = False #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Is the list editor is scrollable? This values overrides the default. scrollable = True #------------------------------------------------------------------------------- # 'TextEditor' class: #------------------------------------------------------------------------------- class TextEditor(CustomEditor): # The kind of editor to create for each list item. This value overrides the # default. kind = 'text_editor' #------------------------------------------------------------------------------- # 'ReadonlyEditor' class: #------------------------------------------------------------------------------- class ReadonlyEditor(CustomEditor): # Is the list of items being edited mutable? This value overrides the # default. mutable = False #------------------------------------------------------------------------------- # 'NotebookEditor' class: #------------------------------------------------------------------------------- class NotebookEditor ( Editor ): """ An editor for lists that displays the list as a "notebook" of tabbed pages. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Is the notebook editor scrollable? This values overrides the default: scrollable = True # The currently selected notebook page object: selected = Any #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self._uis = [] # Create a DockWindow to hold each separate object's view: theme = self.factory.dock_theme or self.item.container.dock_theme dw = DockWindow( parent, theme = theme ) self.control = dw.control self._sizer = DockSizer( DockSection( dock_window = dw ) ) self.control.SetSizer( self._sizer ) # Set up the additional 'list items changed' event handler needed for # a list based trait: self.context_object.on_trait_change( self.update_editor_item, self.extended_name + '_items?', dispatch = 'ui' ) # Set of selection synchronization: self.sync_value( self.factory.selected, 'selected' ) #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ # Make sure the DockWindow is in a correct state: self._sizer.Reset( self. control ) # Destroy the views on each current notebook page: self.close_all() # Create a DockControl for each object in the trait's value: uis = self._uis dock_controls = [] for object in self.value: dock_control, view_object, monitoring = self._create_page( object ) # Remember the DockControl for later deletion processing: uis.append( [ dock_control, object, view_object, monitoring ] ) dock_controls.append( dock_control ) # Add the new items to the DockWindow: self.add_controls( dock_controls ) if self.ui.info.initialized: self.update_layout() #--------------------------------------------------------------------------- # Handles some subset of the trait's list being updated: #--------------------------------------------------------------------------- def update_editor_item ( self, event ): """ Handles an update to some subset of the trait's list. """ # Make sure the DockWindow is in a correct state: self._sizer.Reset( self.control ) index = event.index # Delete the page corresponding to each removed item: layout = ((len( event.removed ) + len( event.added )) <= 1) for i in range( len( event.removed ) ): dock_control, object, view_object, monitoring = self._uis[ index ] if monitoring: view_object.on_trait_change( self.update_page_name, self.factory.page_name[1:], remove = True ) dock_control.close( layout = layout, force = True ) del self._uis[ index ] # Add a page for each added object: dock_controls = [] for object in event.added: dock_control, view_object, monitoring = self._create_page( object ) self._uis[ index: index ] = [ [ dock_control, object, view_object, monitoring ] ] dock_controls.append( dock_control ) index += 1 # Add the new items to the DockWindow: self.add_controls( dock_controls ) self.update_layout() #--------------------------------------------------------------------------- # Closes all currently open notebook pages: #--------------------------------------------------------------------------- def close_all ( self ): """ Closes all currently open notebook pages. """ page_name = self.factory.page_name[1:] for dock_control, object, view_object, monitoring in self._uis: if monitoring: view_object.on_trait_change( self.update_page_name, page_name, remove = True ) dock_control.close( layout = False, force = True ) # Reset the list of ui's and dictionary of page name counts: self._uis = [] self._pages = {} #--------------------------------------------------------------------------- # Disposes of the contents of an editor: #--------------------------------------------------------------------------- def dispose ( self ): """ Disposes of the contents of an editor. """ self.context_object.on_trait_change( self.update_editor_item, self.name + '_items?', remove = True ) self.close_all() super( NotebookEditor, self ).dispose() #--------------------------------------------------------------------------- # Adds a group of new DockControls to the view: #--------------------------------------------------------------------------- def add_controls ( self, controls ): """ Adds a group of new DockControls to the view. """ if len( controls ) > 0: section = self.control.GetSizer().GetContents() if ((len( section.contents ) == 0) or (not isinstance( section.contents[-1], DockRegion ))): section.contents.append( DockRegion( contents = controls ) ) else: for control in controls: section.contents[-1].add(control, activate=False) # Fire this event to activate the dock control corresponding # to the selected object, if any. self._selected_changed(None, self.selected) #--------------------------------------------------------------------------- # Updates the layout of the DockWindow: #--------------------------------------------------------------------------- def update_layout ( self ): """ Updates the layout of the DockWindow. """ self.control.Layout() self.control.Refresh() #--------------------------------------------------------------------------- # Handles the trait defining a particular page's name being changed: #--------------------------------------------------------------------------- def update_page_name ( self ): """ Handles the trait defining a particular page's name being changed. """ changed = False for i, value in enumerate( self._uis ): dock_control, user_object, view_object, monitoring = value if dock_control.control is not None: name = None handler = getattr( self.ui.handler, '%s_%s_page_name' % ( self.object_name, self.name ), None ) if handler is not None: name = handler( self.ui.info, user_object ) if name is None: name = str( xgetattr( view_object, self.factory.page_name[1:], '???' ) ) changed |= (dock_control.name != name) dock_control.name = name if changed: self.update_layout() #--------------------------------------------------------------------------- # Creates a DockControl for a specified object: #--------------------------------------------------------------------------- def _create_page ( self, object ): """ Creates a DockControl for a specified object. """ # Create the view for the object: view_object = object factory = self.factory if factory.factory is not None: view_object = factory.factory( object ) ui = view_object.edit_traits( parent = self.control, view = factory.view, kind = factory.ui_kind ).set( parent = self.ui ) # Get the name of the page being added to the notebook: name = '' monitoring = False prefix = '%s_%s_page_' % ( self.object_name, self.name ) page_name = self.factory.page_name if page_name[0:1] == '.': name = xgetattr( view_object, page_name[1:], None ) monitoring = (name is not None) if monitoring: handler_name = None method = getattr( self.ui.handler, prefix + 'name', None ) if method is not None: handler_name = method( self.ui.info, object ) if handler_name is not None: name = handler_name else: name = str( name ) or '???' view_object.on_trait_change( self.update_page_name, page_name[1:], dispatch = 'ui' ) else: name = '' elif page_name != '': name = page_name if name == '': name = user_name_for( view_object.__class__.__name__ ) # Make sure the name is not a duplicate: if not monitoring: self._pages[ name ] = count = self._pages.get( name, 0 ) + 1 if count > 1: name += (' %d' % count) # Return a new DockControl for the ui, and whether or not its name is # being monitored: image = None method = getattr( self.ui.handler, prefix + 'image', None ) if method is not None: image = method( self.ui.info, object ) dock_control = DockControl( control = ui.control, id = str( id( ui.control ) ), name = name, style = factory.dock_style, image = image, export = factory.export, closeable = factory.deletable, dockable = DockableListElement( ui = ui, editor = self ) ) return ( dock_control, view_object, monitoring ) #--------------------------------------------------------------------------- # Activates the corresponding dock window when the 'selected' trait of # the editor is changed. #--------------------------------------------------------------------------- def _selected_changed(self, old, new): """ Activates the corresponding dock window when the 'selected' trait of the editor is changed. """ for i, value in enumerate(self._uis): if new == value[1]: value[0].activate() break return #------------------------------------------------------------------------------- # 'DockableListElement' class: #------------------------------------------------------------------------------- class DockableListElement ( DockableViewElement ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # The editor this dockable item is associated with: editor = Instance( NotebookEditor ) #--------------------------------------------------------------------------- # Returns whether or not it is OK to close the control, and if it is OK, # then it closes the DockControl itself: #--------------------------------------------------------------------------- def dockable_close ( self, dock_control, force ): """ Returns whether it is OK to close the control. """ return self.close_dock_control( dock_control, force ) #--------------------------------------------------------------------------- # Closes a DockControl: #--------------------------------------------------------------------------- def close_dock_control ( self, dock_control, abort ): """ Closes a DockControl. """ if abort: return super( DockableListElement, self ).close_dock_control( dock_control, False ) view_object = self.ui.context[ 'object' ] for i, value in enumerate( self.editor._uis ): if view_object is value[2]: del self.editor.value[ i ] return False #--------------------------------------------------------------------------- # Handles a notebook tab being activated or deactivated. #--------------------------------------------------------------------------- def dockable_tab_activated ( self, dock_control, activated ): """ Handles a notebook tab being activated or deactivated. Sets the value of the editor's selected trait to the activated dock_control's object. """ for i, value in enumerate( self.editor._uis ): if dock_control is value[0] and activated: self.editor.selected = value[1] break ### EOF ####################################################################### traitsui-4.1.0/traitsui/wx/animated_gif_editor.py0000644000175100001440000000207311674463546023214 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 03/02/2007 # #------------------------------------------------------------------------------- """ Defines an editor for playing animated GIF files. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx # Define the wx version dependent version of the editor: if wx.__version__[:3] == '2.6': from animated_gif_editor_26 import AnimatedGIFEditor else: from animated_gif_editor_28 import AnimatedGIFEditor traitsui-4.1.0/traitsui/wx/set_editor.py0000644000175100001440000005307611674463546021411 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/21/2004 # # fixme: Add undo/redo support # fixme: Allow factory to handle a TraitListObject for the 'values' trait. # #------------------------------------------------------------------------------ """ Defines the set editors for the wxPython user interface toolkit. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx from traits.api \ import Property # FIXME: ToolkitEditorFactory is a proxy class defined here just for backward # compatibility. The class has been moved to the # traitsui.editors.set_editor file. from traitsui.editors.set_editor \ import ToolkitEditorFactory from editor \ import Editor from helper \ import enum_values_changed, TraitsUIPanel #------------------------------------------------------------------------------- # 'SimpleEditor' class: #------------------------------------------------------------------------------- class SimpleEditor ( Editor ): """ Simple style of editor for sets. The editor displays two list boxes, with buttons for moving the selected items from left to right, or vice versa. If **can_move_all** on the factory is True, then buttons are displayed for moving all the items to one box or the other. If the set is ordered, buttons are displayed for moving the selected item up or down in right-side list box. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Current set of enumeration names: names = Property # Current mapping from names to values: mapping = Property # Current inverse mapping from values to names: inverse_mapping = Property # Is set editor scrollable? This value overrides the default. scrollable = True #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ factory = self.factory if factory.name != '': self._object, self._name, self._value = \ self.parse_extended_name( factory.name ) self.values_changed() self._object.on_trait_change( self._values_changed, self._name, dispatch = 'ui' ) else: factory.on_trait_change( self.update_editor, 'values_modified', dispatch = 'ui' ) self.control = panel = TraitsUIPanel( parent, -1 ) hsizer = wx.BoxSizer( wx.HORIZONTAL ) vsizer = wx.BoxSizer( wx.VERTICAL ) self._unused = self._create_listbox( panel, hsizer, self._on_unused, self._on_use, factory.left_column_title ) self._use_all = self._unuse_all = self._up = self._down = None if factory.can_move_all: self._use_all = self._create_button( '>>', panel, vsizer, 15, self._on_use_all) self._use = self._create_button( '>', panel, vsizer, 15, self._on_use ) self._unuse = self._create_button( '<', panel, vsizer, 0, self._on_unuse ) if factory.can_move_all: self._unuse_all = self._create_button('<<', panel, vsizer, 15, self._on_unuse_all) if factory.ordered: self._up = self._create_button( 'Move Up', panel, vsizer, 30, self._on_up ) self._down = self._create_button( 'Move Down', panel, vsizer, 0, self._on_down ) hsizer.Add( vsizer, 0, wx.LEFT | wx.RIGHT, 8 ) self._used = self._create_listbox( panel, hsizer, self._on_value, self._on_unuse, factory.right_column_title ) panel.SetSizer( hsizer ) self.context_object.on_trait_change( self.update_editor, self.extended_name + '_items?', dispatch = 'ui' ) self.set_tooltip() #--------------------------------------------------------------------------- # Gets the current set of enumeration names: #--------------------------------------------------------------------------- def _get_names ( self ): """ Gets the current set of enumeration names. """ if self._object is None: return self.factory._names return self._names #--------------------------------------------------------------------------- # Gets the current mapping: #--------------------------------------------------------------------------- def _get_mapping ( self ): """ Gets the current mapping. """ if self._object is None: return self.factory._mapping return self._mapping #--------------------------------------------------------------------------- # Gets the current inverse mapping: #--------------------------------------------------------------------------- def _get_inverse_mapping ( self ): """ Gets the current inverse mapping. """ if self._object is None: return self.factory._inverse_mapping return self._inverse_mapping #--------------------------------------------------------------------------- # Creates a list box: #--------------------------------------------------------------------------- def _create_listbox ( self, parent, sizer, handler1, handler2, title ): """ Creates a list box. """ column_sizer = wx.BoxSizer( wx.VERTICAL ) # Add the column title in emphasized text: title_widget = wx.StaticText( parent, -1, title ) font = title_widget.GetFont() emphasis_font = wx.Font( font.GetPointSize() + 1, font.GetFamily(), font.GetStyle(), wx.BOLD ) title_widget.SetFont(emphasis_font) column_sizer.Add( title_widget, 0, 0) # Create the list box and add it to the column: list = wx.ListBox(parent, -1, style = wx.LB_EXTENDED | wx.LB_NEEDED_SB) column_sizer.Add( list, 1, wx.EXPAND ) # Add the column to the SetEditor widget: sizer.Add( column_sizer, 1, wx.EXPAND ) # Hook up the event handlers: wx.EVT_LISTBOX( parent, list.GetId(), handler1 ) wx.EVT_LISTBOX_DCLICK( parent, list.GetId(), handler2 ) return list #--------------------------------------------------------------------------- # Creates a button: #--------------------------------------------------------------------------- def _create_button ( self, label, parent, sizer, space_before, handler ): """ Creates a button. """ button = wx.Button( parent, -1, label, style=wx.BU_EXACTFIT ) sizer.AddSpacer( ( space_before, space_before ) ) sizer.Add( button, 0, wx.EXPAND | wx.BOTTOM, 8 ) wx.EVT_BUTTON( parent, button.GetId(), handler ) return button #--------------------------------------------------------------------------- # Recomputes the cached data based on the underlying enumeration model: #--------------------------------------------------------------------------- def values_changed ( self ): """ Recomputes the cached data based on the underlying enumeration model. """ self._names, self._mapping, self._inverse_mapping = \ enum_values_changed( self._value() ) #--------------------------------------------------------------------------- # Handles the underlying object model's enumeration set being changed: #--------------------------------------------------------------------------- def _values_changed ( self ): """ Handles the underlying object model's enumeration set being changed. """ self.values_changed() self.update_editor() #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ # Check for any items having been deleted from the enumeration that are # still present in the object value: mapping = self.inverse_mapping.copy() values = [ v for v in self.value if v in mapping ] if len( values ) < len( self.value ): self.value = values return # Get a list of the selected items in the right box: used = self._used used_labels = self._get_selected_strings( used ) # Get a list of the selected items in the left box: unused = self._unused unused_labels = self._get_selected_strings( unused ) # Empty list boxes in preparation for rebuilding from current values: used.Clear() unused.Clear() # Ensure right list box is kept alphabetized unless insertion # order is relevant: if not self.factory.ordered: values = values[:] values.sort() # Rebuild the right listbox: used_selections = [] for i, value in enumerate( values ): label = mapping[ value ] used.Append( label ) del mapping[ value ] if label in used_labels: used_selections.append(i) # Rebuild the left listbox: unused_selections = [] unused_items = mapping.values() unused_items.sort() mapping = self.mapping self._unused_items = [ mapping[ ui ] for ui in unused_items ] for i, unused_item in enumerate( unused_items ): unused.Append( unused_item ) if unused_item in unused_labels: unused_selections.append( i ) # If nothing is selected, default selection should be top of left box, # or of right box if left box is empty: if (len( used_selections ) == 0) and (len( unused_selections ) == 0): if unused.GetCount() == 0: used_selections.append( 0 ) else: unused_selections.append( 0 ) used_count = used.GetCount() for i in used_selections: if i < used_count: used.SetSelection( i ) unused_count = unused.GetCount() for i in unused_selections: if i < unused_count: unused.SetSelection( i ) self._check_up_down() self._check_left_right() #--------------------------------------------------------------------------- # Disposes of the contents of an editor: #--------------------------------------------------------------------------- def dispose ( self ): """ Disposes of the contents of an editor. """ if self._object is not None: self._object.on_trait_change( self._values_changed, self._name, remove = True ) else: self.factory.on_trait_change( self.update_editor, 'values_modified', remove = True ) self.context_object.on_trait_change( self.update_editor, self.extended_name + '_items?', remove = True ) super( SimpleEditor, self ).dispose() #--------------------------------------------------------------------------- # Returns the editor's control for indicating error status: #--------------------------------------------------------------------------- def get_error_control ( self ): """ Returns the editor's control for indicating error status. """ return [ self._unused, self._used ] #--------------------------------------------------------------------------- # Event handlers: #--------------------------------------------------------------------------- def _on_value ( self, event ): if not self.factory.ordered: self._clear_selection( self._unused ) self._check_left_right() self._check_up_down() def _on_unused ( self, event ): if not self.factory.ordered: self._clear_selection( self._used ) self._check_left_right() self._check_up_down() def _on_use ( self, event ): self._unused_items, self.value = self._transfer_items( self._unused, self._used, self._unused_items, self.value ) def _on_unuse ( self, event ): self.value, self._unused_items = self._transfer_items( self._used, self._unused, self.value, self._unused_items ) def _on_use_all ( self, event ): self._unused_items, self.value = self._transfer_all( self._unused, self._used, self._unused_items, self.value ) def _on_unuse_all (self, event): self.value, self._unused_items = self._transfer_all( self._used, self._unused, self.value, self._unused_items ) def _on_up ( self, event ): self._move_item( -1 ) def _on_down ( self, event ): self._move_item( 1 ) #--------------------------------------------------------------------------- # Private methods: #--------------------------------------------------------------------------- #--------------------------------------------------------------------------- # Unselects all items in the given ListBox #--------------------------------------------------------------------------- def _clear_selection( self, box ): """ Unselects all items in the given ListBox """ for i in box.GetSelections(): box.SetSelection( i, False ) #--------------------------------------------------------------------------- # Transfers all items from one list to another: #--------------------------------------------------------------------------- def _transfer_all ( self, list_from, list_to, values_from, values_to ): """ Transfers all items from one list to another. """ values_from = values_from[:] values_to = values_to[:] self._clear_selection( list_from ) while list_from.GetCount() > 0: index_to = list_to.GetCount() list_from.SetSelection( 0 ) list_to.InsertItems( self._get_selected_strings( list_from ), index_to ) list_from.Delete( 0 ) values_to.append( values_from[0] ) del values_from[ 0 ] list_to.SetSelection( 0 ) self._check_left_right() self._check_up_down() return ( values_from, values_to ) #--------------------------------------------------------------------------- # Transfers the selected item from one list to another: #--------------------------------------------------------------------------- def _transfer_items ( self, list_from, list_to, values_from, values_to ): """ Transfers the selected item from one list to another. """ values_from = values_from[:] values_to = values_to[:] indices_from = list_from.GetSelections() index_from = max( self._get_first_selection( list_from ), 0 ) index_to = max( self._get_first_selection( list_to ), 0 ) self._clear_selection( list_to ) # Get the list of strings in the "from" box to be moved: selected_list = self._get_selected_strings( list_from ) # fixme: I don't know why I have to reverse the list to get # correct behavior from the ordered list box. Investigate -- LP selected_list.reverse() list_to.InsertItems( selected_list, index_to ) # Delete the transferred items from the left box: for i in range( len( indices_from ) - 1, -1, -1 ): list_from.Delete( indices_from[i] ) # Delete the transferred items from the "unused" value list: for item_label in selected_list: val_index_from = values_from.index( self.mapping[ item_label ] ) values_to.insert( index_to, values_from[ val_index_from ] ) del values_from[ val_index_from ] # If right list is ordered, keep moved items selected: if self.factory.ordered: list_to.SetSelection( list_to.FindString( item_label ) ) # Reset the selection in the left box: count = list_from.GetCount() if count > 0: if index_from >= count: index_from -= 1 list_from.SetSelection( index_from ) self._check_left_right() self._check_up_down() return ( values_from, values_to ) #--------------------------------------------------------------------------- # Moves an item up or down with the 'used' list: #--------------------------------------------------------------------------- def _move_item ( self, direction ): """ Moves an item up or down within the "used" list. """ # Move the item up/down within the list: listbox = self._used index_from = self._get_first_selection(listbox) index_to = index_from + direction label = listbox.GetString(index_from) listbox.Delete( index_from ) listbox.Insert( label, index_to ) listbox.SetSelection( index_to ) # Enable the up/down buttons appropriately: self._check_up_down() # Move the item up/down within the editor's trait value: value = self.value if direction < 0: index = index_to values = [ value[ index_from ], value[ index_to ] ] else: index = index_from values = [ value[ index_to ], value[ index_from ] ] self.value = value[ : index ] + values + value[ index + 2: ] #--------------------------------------------------------------------------- # Sets the proper enable state for the up and down buttons: #--------------------------------------------------------------------------- def _check_up_down ( self ): """ Sets the proper enabled state for the up and down buttons. """ if self.factory.ordered: index_selected = self._used.GetSelections() self._up.Enable( (len( index_selected ) == 1) and (index_selected[0] > 0) ) self._down.Enable( (len( index_selected ) == 1) and (index_selected[0] < (self._used.GetCount() - 1) ) ) #--------------------------------------------------------------------------- # Sets the proper enable state for the left and right buttons: #--------------------------------------------------------------------------- def _check_left_right ( self ): """ Sets the proper enabled state for the left and right buttons. """ self._use.Enable(self._unused.GetCount() > 0 and self._get_first_selection(self._unused) >= 0) self._unuse.Enable( self._used.GetCount() > 0 and self._get_first_selection(self._used) >= 0) if self.factory.can_move_all: self._use_all.Enable( (self._unused.GetCount() > 0) and (self._get_first_selection( self._unused ) >= 0) ) self._unuse_all.Enable( (self._used.GetCount() > 0) and (self._get_first_selection( self._used ) >= 0) ) #--------------------------------------------------------------------------- # Returns a list of the selected strings in the listbox #--------------------------------------------------------------------------- def _get_selected_strings ( self, listbox ): """ Returns a list of the selected strings in the given *listbox*. """ stringlist = [] for label_index in listbox.GetSelections(): stringlist.append( listbox.GetString( label_index ) ) return stringlist #--------------------------------------------------------------------------- # Returns the index of the first (or only) selected item. #--------------------------------------------------------------------------- def _get_first_selection ( self, listbox ): """ Returns the index of the first (or only) selected item. """ select_list = listbox.GetSelections() if len( select_list ) == 0: return -1 return select_list[0] ### EOF ####################################################################### traitsui-4.1.0/traitsui/wx/progress_editor.py0000644000175100001440000000411411674463546022447 0ustar ischnellusers00000000000000import wx from traits.api import Instance from traitsui.wx.editor import Editor from pyface.ui.wx.progress_dialog import ProgressDialog class SimpleEditor(Editor): """ Show a progress bar with all the optional goodies """ progress = Instance(ProgressDialog) #-- Editor interface ------------------------------------------------------ def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self.control = self.create_control( parent ) self.set_tooltip() def create_control (self, parent): """ Finishes initializing the editor by creating the underlying widget. """ self.progress = ProgressDialog( title=self.factory.title, message=self.factory.message, min=self.factory.min, max=self.factory.max, can_cancel=self.factory.can_cancel, show_time=self.factory.show_time, show_percent=self.factory.show_percent) panel = wx.Panel(parent, -1) sizer = wx.BoxSizer(wx.VERTICAL) panel.SetSizer(sizer) panel.SetAutoLayout(True) panel.SetBackgroundColour(wx.NullColor) self.progress.dialog_size = wx.Size() # The 'guts' of the dialog. self.progress._create_message(panel, sizer) self.progress._create_gauge(panel, sizer) self.progress._create_percent(panel, sizer) self.progress._create_timer(panel, sizer) self.progress._create_buttons(panel, sizer) panel.SetClientSize(self.progress.dialog_size) panel.CentreOnParent() self.control = panel return self.control def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ if self.value: self.progress.update(self.value) return traitsui-4.1.0/traitsui/wx/editors_gen.py0000644000175100001440000000601011674463546021534 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2008, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the GPL v2 # license. # # Author: Vibha Srinivasan #------------------------------------------------------------------------------ """ Generates a file containing definitions for all of the editors defined in the WX backend. """ import os, glob, sys from traitsui.api import Editor from traitsui.editor_factory import EditorFactory def gen_editor_definitions(target_filename): """ Generates a file containing definitions for all of the editors defined in the Qt backend. """ target_file = open(target_filename, 'w') dirpath = os.path.dirname(os.path.abspath(__file__)) # Find all the files which define a TraitsUIEditor editor_files = [] for (root, dirs, files) in os.walk(dirpath): if '.svn' in dirs: dirs.remove('.svn') editor_files.extend(glob.glob(os.path.join(root, '*_editor.py'))) for absfilename in editor_files: (dirname, filename) = (os.path.dirname(absfilename), os.path.basename(absfilename).rstrip('.py')) import_path = 'traitsui.wx' + \ dirname.replace(dirpath, '').replace(os.sep, '.') +\ '.' + filename __import__(import_path) module = sys.modules[import_path] class_names = [] for name in dir(module): try: if issubclass(getattr(module, name), EditorFactory) and \ name not in ['EditorFactory', 'BasicEditorFactory']: class_names.append(name) elif issubclass(getattr(module, name), Editor) and \ name != 'Editor': class_names.append(name) except: try: if isinstance(getattr(module, name), EditorFactory) or \ isinstance(getattr(module, name), Editor): class_names.insert(0, name) except: pass if len(class_names) > 0: # FIXME: Is there a better way to sort these names? if 'ToolkitEditorFactory' in class_names: class_name = 'ToolkitEditorFactory' else: class_name = ''.join([name.capitalize() for name in filename.split('_')]) if class_name not in class_names: class_name = class_names[0] function = "def %(filename)s(*args, **traits):"%locals() target_file.write(function) target_file.write('\n') func_code = ' '*4 + "import %(import_path)s as editor"%locals()+'\n' func_code+= ' '*4 + "return editor.%(class_name)s(*args, **traits)" \ % locals() target_file.write(func_code) target_file.write('\n\n') target_file.close() traitsui-4.1.0/traitsui/wx/ui_editor.py0000644000175100001440000000261311674463546021222 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 03/03/2006 # #------------------------------------------------------------------------------ """ Defines the BasicUIEditor class, which allows creating editors that define their function by creating an embedded Traits UI. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from traitsui.ui_editor \ import UIEditor as BaseUIEditor from editor \ import Editor #------------------------------------------------------------------------------- # 'UIEditor' base class: #------------------------------------------------------------------------------- class UIEditor ( BaseUIEditor, Editor ): """ An editor that creates an embedded Traits UI. """ pass #-- End UI preference save/restore interface ----------------------------------- traitsui-4.1.0/traitsui/wx/image_text.py0000644000175100001440000001307011674463546021364 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2007, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 08/11/2007 # #------------------------------------------------------------------------------- """ Defines a themed read-only text string. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx from image_slice \ import paint_parent from helper \ import BufferDC #------------------------------------------------------------------------------- # Class 'ImageText' #------------------------------------------------------------------------------- class ImageText ( wx.PyWindow ): """ Defines a text control that displays an ImageSlice in its background. """ #-- wx.PyWindow Method Overrides ------------------------------------------- def __init__ ( self, parent, theme, text = '', border=False ): """ Initializes the object. """ self._theme = theme self._border = border if theme is not None: self._image_slice = theme.image_slice super( ImageText, self ).__init__( parent, -1, style = wx.FULL_REPAINT_ON_RESIZE ) self._text_size = None self._text = text # Set up the painting event handlers: wx.EVT_ERASE_BACKGROUND( self, self._erase_background ) wx.EVT_PAINT( self, self._on_paint ) size = self.GetMinSize() self.SetMinSize( size ) self.SetSize( size ) def AcceptsFocus ( self ): """ Indicate that we are a static control that does not accept focus. """ return False #-- wxPython Event Handlers ------------------------------------------------ def _erase_background ( self, event ): """ Do not erase the background here (do it in the 'on_paint' handler). """ pass def _on_paint ( self, event ): """ Paint the background using the associated ImageSlice object. """ dc = BufferDC( self ) paint_parent( dc, self ) if self._theme is not None: wdx, wdy = self.GetClientSize() self._image_slice.fill( dc, 0, 0, wdx, wdy, True ) dc.SetTextForeground( self._image_slice.content_color ) dc.SetBackgroundMode( wx.TRANSPARENT ) dc.SetFont( self.GetFont() ) tx, ty, tdx, tdy = self._get_text_bounds() dc.DrawText( self._text, tx, ty ) dc.copy() def GetMinSize ( self ): """ Returns the minimum size for the window. """ tdx, tdy, descent, leading = self._get_text_size() if self._theme is None: return wx.Size( tdx + 8, tdy + 4 ) content = self._theme.content tdx += (content.left + content.right) tdy += (content.top + content.bottom) slice = self._image_slice return wx.Size( max( slice.left + slice.right, slice.xleft + slice.xright + tdx + 8 ), max( slice.top + slice.bottom, slice.xtop + slice.xbottom + tdy + 4 ) ) def SetFont ( self, font ): """ Set the window font. """ super( ImageText, self ).SetFont( font ) self._refresh() def SetLabel ( self, label ): """ Set the window label. """ self._text = label self._refresh() def _refresh ( self ): """ Refreshes the contents of the control. """ if self._text_size is not None: self.RefreshRect( wx.Rect( *self._get_text_bounds() ), False ) self._text_size = None self.SetMinSize( self.GetMinSize() ) self.RefreshRect( wx.Rect( *self._get_text_bounds() ), False ) def _get_text_size ( self, text = None ): """ Returns the text size information for the window. """ if self._text_size is None: if text is None: text = self._text if text.strip() == '': text = 'M' self._text_size = self.GetFullTextExtent( text ) return self._text_size def _get_text_bounds ( self ): """ Get the window bounds of where the current text should be displayed. """ tdx, tdy, descent, leading = self._get_text_size() wdx, wdy = self.GetClientSize() theme = self._theme if theme is None: return ( wdx - tdx, (wdy - tdy) / 2, tdx, tdy ) slice = self._image_slice content = theme.content ady = wdy - slice.xtop - slice.xbottom ty = (wdy + slice.xtop + content.top - slice.xtop - slice.xbottom - tdy) / 2 alignment = theme.alignment if alignment == 'left': tx = slice.xleft + content.left elif alignment == 'center': adx = wdx - slice.xleft - slice.xright tx = slice.xleft + content.left + 4 + ((adx - tdx) / 2) else: tx = wdx - tdx - slice.xright - content.right return ( tx + theme.label.left, ty + theme.label.top, tdx, tdy ) traitsui-4.1.0/traitsui/wx/popup_editor.py0000644000175100001440000000147411674463546021754 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- # FIXME: PopupEditor is a proxy class defined here just for backward # compatibility. The class (which represents the editor factory) has been moved # to the traitsui.editors.list_editor file. from traitsui.editors.popup_editor \ import _PopupEditor as BasePopupEditor, PopupEditor from ui_editor \ import UIEditor #------------------------------------------------------------------------------- # '_PopupEditor' class: #------------------------------------------------------------------------------- class _PopupEditor ( BasePopupEditor, UIEditor ): pass #--EOF------------------------------------------------------------------------- traitsui-4.1.0/traitsui/wx/tabular_editor.py0000644000175100001440000012417511674463546022247 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2007, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 05/20/2007 # #------------------------------------------------------------------------------- """ A traits UI editor for editing tabular data (arrays, list of tuples, lists of objects, etc). """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx import wx.lib.mixins.listctrl as listmix from traits.api \ import HasStrictTraits, Int, \ List, Bool, Instance, Any, Event, \ Property, TraitListEvent # FIXME: TabularEditor (the editor factory for tabular editors) is a proxy class # defined here just for backward compatibility. The class has been moved to the # traitsui.editors.tabular_editor file. from traitsui.editors.tabular_editor \ import TabularEditor from traitsui.ui_traits \ import Image from traitsui.tabular_adapter \ import TabularAdapter from traitsui.wx.editor \ import Editor from pyface.image_resource \ import ImageResource from pyface.timer.api \ import do_later from constants \ import is_mac, scrollbar_dx try: from pyface.wx.drag_and_drop \ import PythonDropSource, PythonDropTarget except: PythonDropSource = PythonDropTarget = None #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- # Mapping for trait alignment values to wx alignment values: alignment_map = { 'left': wx.LIST_FORMAT_LEFT, 'center': wx.LIST_FORMAT_CENTRE, 'right': wx.LIST_FORMAT_RIGHT } class TextEditMixin(listmix.TextEditMixin): def __init__(self, edit_labels): """ edit_labels controls whether the first column is editable """ self.edit_labels = edit_labels listmix.TextEditMixin.__init__(self) def OpenEditor(self, col, row): if col == 0 and not self.edit_labels: return else: return listmix.TextEditMixin.OpenEditor(self, col, row) #------------------------------------------------------------------------------- # 'wxListCtrl' class: #------------------------------------------------------------------------------- class wxListCtrl ( wx.ListCtrl, TextEditMixin ): """ Subclass of wx.ListCtrl to provide correct virtual list behavior. """ def __init__(self, parent, ID, pos=wx.DefaultPosition, size=wx.DefaultSize, style=0, can_edit = False, edit_labels=False): wx.ListCtrl.__init__(self, parent, ID, pos, size, style) # if the selected is editable, then we have to init the mixin if can_edit: TextEditMixin.__init__(self, edit_labels) def SetVirtualData(self, row, col, text): # this method is called but the job is already done by # the _end_label_edit method. Commmented code is availabed # if needed pass #edit = self._editor #return editor.adapter.set_text( editor.object, editor.name, # row, col, text ) def OnGetItemAttr ( self, row ): """ Returns the display attributes to use for the specified list item. """ # fixme: There appears to be a bug in wx in that they do not correctly # manage the reference count for the returned object, and it seems to be # gc'ed before they finish using it. So we store an object reference to # it to prevent it from going away too soon... self._attr = attr = wx.ListItemAttr() editor = self._editor object, name = editor.object, editor.name color = editor.adapter.get_bg_color( object, name, row ) if color is not None: attr.SetBackgroundColour( color ) color = editor.adapter.get_text_color( object, name, row ) if color is not None: attr.SetTextColour( color ) font = editor.adapter.get_font( object, name, row ) if font is not None: attr.SetFont( font ) return attr def OnGetItemImage ( self, row ): """ Returns the image index to use for the specified list item. """ editor = self._editor image = editor._get_image( editor.adapter.get_image( editor.object, editor.name, row, 0 ) ) if image is not None: return image return -1 def OnGetItemColumnImage ( self, row, column ): """ Returns the image index to use for the specified list item. """ editor = self._editor image = editor._get_image( editor.adapter.get_image( editor.object, editor.name, row, column ) ) if image is not None: return image return -1 def OnGetItemText ( self, row, column ): """ Returns the text to use for the specified list item. """ editor = self._editor return editor.adapter.get_text( editor.object, editor.name, row, column ) #------------------------------------------------------------------------------- # 'TabularEditor' class: #------------------------------------------------------------------------------- class TabularEditor ( Editor ): """ A traits UI editor for editing tabular data (arrays, list of tuples, lists of objects, etc). """ #-- Trait Definitions ------------------------------------------------------ # The event fired when a table update is needed: update = Event # The current set of selected items (which one is used depends upon the # initial state of the editor factory 'multi_select' trait): selected = Any multi_selected = List # The current set of selected item indices (which one is used depends upon # the initial state of the editor factory 'multi_select' trait): selected_row = Int( -1 ) multi_selected_rows = List( Int ) # The most recently actived item and its index: activated = Any activated_row = Int # The most recent left click data: clicked = Instance( 'TabularEditorEvent' ) # The most recent left double click data: dclicked = Instance( 'TabularEditorEvent' ) # The most recent right click data: right_clicked = Instance( 'TabularEditorEvent' ) # The most recent right double click data: right_dclicked = Instance( 'TabularEditorEvent' ) # The most recent column click data: column_clicked = Instance( 'TabularEditorEvent' ) # Is the tabular editor scrollable? This value overrides the default. scrollable = True # Row index of item to select after rebuilding editor list: row = Any # Should the selected item be edited after rebuilding the editor list: edit = Bool( False ) # The adapter from trait values to editor values: adapter = Instance( TabularAdapter ) # Dictionary mapping image names to wx.ImageList indices: images = Any( {} ) # Dictionary mapping ImageResource objects to wx.ImageList indices: image_resources = Any( {} ) # An image being converted: image = Image # Flag for marking whether the update was within the visible area _update_visible = Bool(False) #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ factory = self.factory # Set up the adapter to use: self.adapter = factory.adapter # Determine the style to use for the list control: style = wx.LC_REPORT | wx.LC_VIRTUAL | wx.BORDER_NONE if factory.editable_labels: style |= wx.LC_EDIT_LABELS if factory.horizontal_lines: style |= wx.LC_HRULES if factory.vertical_lines: style |= wx.LC_VRULES if not factory.multi_select: style |= wx.LC_SINGLE_SEL if not factory.show_titles: style |= wx.LC_NO_HEADER # Create the list control and link it back to us: self.control = control = wxListCtrl( parent, -1, style = style, can_edit = factory.editable, edit_labels = factory.editable_labels) control._editor = self # Create the list control column: #fixme: what do we do here? #control.InsertColumn( 0, '' ) # Set up the list control's event handlers: id = control.GetId() wx.EVT_LIST_BEGIN_DRAG( parent, id, self._begin_drag ) wx.EVT_LIST_BEGIN_LABEL_EDIT( parent, id, self._begin_label_edit ) wx.EVT_LIST_END_LABEL_EDIT( parent, id, self._end_label_edit ) wx.EVT_LIST_ITEM_SELECTED( parent, id, self._item_selected ) wx.EVT_LIST_ITEM_DESELECTED( parent, id, self._item_selected ) wx.EVT_LIST_KEY_DOWN( parent, id, self._key_down ) wx.EVT_LIST_ITEM_ACTIVATED( parent, id, self._item_activated ) wx.EVT_LIST_COL_END_DRAG( parent, id, self._size_modified ) wx.EVT_LIST_COL_RIGHT_CLICK( parent, id, self._column_right_clicked ) wx.EVT_LIST_COL_CLICK( parent, id, self._column_clicked ) wx.EVT_LEFT_DOWN( control, self._left_down ) wx.EVT_LEFT_DCLICK( control, self._left_dclick ) wx.EVT_RIGHT_DOWN( control, self._right_down ) wx.EVT_RIGHT_DCLICK( control, self._right_dclick ) wx.EVT_MOTION( control, self._motion ) wx.EVT_SIZE( control, self._size_modified ) # Set up the drag and drop target: if PythonDropTarget is not None: control.SetDropTarget( PythonDropTarget( self ) ) # Set up the selection listener (if necessary): if factory.multi_select: self.sync_value( factory.selected, 'multi_selected', 'both', is_list = True ) self.sync_value( factory.selected_row, 'multi_selected_rows', 'both', is_list = True ) else: self.sync_value( factory.selected, 'selected', 'both' ) self.sync_value( factory.selected_row, 'selected_row', 'both' ) # Synchronize other interesting traits as necessary: self.sync_value( factory.update, 'update', 'from' ) self.sync_value( factory.activated, 'activated', 'to' ) self.sync_value( factory.activated_row, 'activated_row', 'to' ) self.sync_value( factory.clicked, 'clicked', 'to' ) self.sync_value( factory.dclicked, 'dclicked', 'to' ) self.sync_value( factory.right_clicked, 'right_clicked', 'to' ) self.sync_value( factory.right_dclicked, 'right_dclicked', 'to' ) self.sync_value( factory.column_clicked, 'column_clicked', 'to' ) # Make sure we listen for 'items' changes as well as complete list # replacements: try: self.context_object.on_trait_change( self.update_editor, self.extended_name + '_items', dispatch = 'ui' ) except: pass # If the user has requested automatic update, attempt to set up the # appropriate listeners: if factory.auto_update: self.context_object.on_trait_change( self.refresh_editor, self.extended_name + '.-', dispatch = 'ui' ) # Create the mapping from user supplied images to wx.ImageList indices: for image_resource in factory.images: self._add_image( image_resource ) # Refresh the editor whenever the adapter changes: self.on_trait_change( self._refresh, 'adapter.+update', dispatch = 'ui' ) # Rebuild the editor columns and headers whenever the adapter's # 'columns' changes: self.on_trait_change( self._rebuild_all, 'adapter.columns', dispatch = 'ui' ) # Make sure the tabular view gets initialized: self._rebuild() # Set the list control's tooltip: self.set_tooltip() def dispose ( self ): """ Disposes of the contents of an editor. """ # Remove all of the wx event handlers: control = self.control parent = control.GetParent() id = control.GetId() wx.EVT_LIST_BEGIN_DRAG( parent, id, None ) wx.EVT_LIST_BEGIN_LABEL_EDIT( parent, id, None ) wx.EVT_LIST_END_LABEL_EDIT( parent, id, None ) wx.EVT_LIST_ITEM_SELECTED( parent, id, None ) wx.EVT_LIST_ITEM_DESELECTED( parent, id, None ) wx.EVT_LIST_KEY_DOWN( parent, id, None ) wx.EVT_LIST_ITEM_ACTIVATED( parent, id, None ) wx.EVT_LIST_COL_END_DRAG( parent, id, None ) wx.EVT_LIST_COL_RIGHT_CLICK( parent, id, None ) wx.EVT_LIST_COL_CLICK( parent, id, None ) wx.EVT_LEFT_DOWN( control, None ) wx.EVT_LEFT_DCLICK( control, None ) wx.EVT_RIGHT_DOWN( control, None ) wx.EVT_RIGHT_DCLICK( control, None ) wx.EVT_MOTION( control, None ) wx.EVT_SIZE( control, None ) self.context_object.on_trait_change( self.update_editor, self.extended_name + '_items', remove = True ) if self.factory.auto_update: self.context_object.on_trait_change( self.refresh_editor, self.extended_name + '.-', remove = True ) self.on_trait_change( self._refresh, 'adapter.+update', remove = True ) self.on_trait_change( self._rebuild_all, 'adapter.columns', remove = True ) super( TabularEditor, self ).dispose() def _update_changed ( self, event ): """ Handles the 'update' event being fired. """ if event is True: self.update_editor() elif isinstance( event, int ): self._refresh_row( event ) else: self._refresh_editor( event ) def refresh_editor ( self, item, name, old, new ): """ Handles a table item attribute being changed. """ self._refresh_editor( item ) def _refresh_editor ( self, item ): """ Handles a table item being changed. """ adapter = self.adapter object, name = self.object, self.name agi = adapter.get_item for row in xrange( adapter.len( object, name ) ): if item is agi( object, name, row ): self._refresh_row( row ) return self.update_editor() def _refresh_row ( self, row ): """ Updates the editor control when a specified table row changes. """ self.control.RefreshRect( self.control.GetItemRect( row, wx.LIST_RECT_BOUNDS ) ) def _update_editor ( self, object, name, old_value, new_value ): """ Performs updates when the object trait changes. Overloads traitsui.editor.UIEditor """ self._update_visible = True super(TabularEditor, self)._update_editor(object, name, old_value, new_value) def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ control = self.control n = self.adapter.len( self.object, self.name ) top = control.GetTopItem() pn = control.GetCountPerPage() bottom = min(top + pn - 1, n) control.SetItemCount( n ) if self._update_visible: control.RefreshItems( 0, n-1 ) self._update_visible = False if len( self.multi_selected_rows ) > 0: self._multi_selected_rows_changed( self.multi_selected_rows ) if len( self.multi_selected ) > 0: self._multi_selected_changed( self.multi_selected ) edit, self.edit = self.edit, False row, self.row = self.row, None if row is not None: if row >= n: row -= 1 if row < 0: row = None if row is None: visible = bottom if visible >= 0 and visible < control.GetItemCount(): control.EnsureVisible( visible ) return if 0 <= (row - top) < pn: control.EnsureVisible( top + pn - 2 ) elif row < top: control.EnsureVisible( row + pn - 1 ) else: control.EnsureVisible( row ) control.SetItemState( row, wx.LIST_STATE_SELECTED | wx.LIST_STATE_FOCUSED, wx.LIST_STATE_SELECTED | wx.LIST_STATE_FOCUSED ) if edit: control.EditLabel( row ) #-- Trait Event Handlers --------------------------------------------------- def _selected_changed ( self, selected ): """ Handles the editor's 'selected' trait being changed. """ if not self._no_update: if selected is None: for row in self._get_selected(): self.control.SetItemState( row, 0, wx.LIST_STATE_SELECTED ) else: try: self.control.SetItemState( self.value.index( selected ), wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED ) except: pass def _selected_row_changed ( self, old, new ): """ Handles the editor's 'selected_index' trait being changed. """ if not self._no_update: if new < 0: if old >= 0: self.control.SetItemState( old, 0, wx.LIST_STATE_SELECTED ) else: self.control.SetItemState( new, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED ) def _multi_selected_changed ( self, selected ): """ Handles the editor's 'multi_selected' trait being changed. """ if not self._no_update: values = self.value try: self._multi_selected_rows_changed( [ values.index( item ) for item in selected ] ) except: pass def _multi_selected_items_changed ( self, event ): """ Handles the editor's 'multi_selected' trait being modified. """ values = self.values try: self._multi_selected_rows_items_changed( TraitListEvent( 0, [ values.index( item ) for item in event.removed ], [ values.index( item ) for item in event.added ] ) ) except: pass def _multi_selected_rows_changed ( self, selected_rows ): """ Handles the editor's 'multi_selected_rows' trait being changed. """ if not self._no_update: control = self.control selected = self._get_selected() # Select any new items that aren't already selected: for row in selected_rows: if row in selected: selected.remove( row ) else: control.SetItemState( row, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED ) # Unselect all remaining selected items that aren't selected now: for row in selected: control.SetItemState( row, 0, wx.LIST_STATE_SELECTED ) def _multi_selected_rows_items_changed ( self, event ): """ Handles the editor's 'multi_selected_rows' trait being modified. """ control = self.control # Remove all items that are no longer selected: for row in event.removed: control.SetItemState( row, 0, wx.LIST_STATE_SELECTED ) # Select all newly added items: for row in event.added: control.SetItemState( row, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED ) #-- List Control Event Handlers -------------------------------------------- def _left_down ( self, event ): """ Handles the left mouse button being pressed. """ self._mouse_click( event, 'clicked' ) def _left_dclick ( self, event ): """ Handles the left mouse button being double clicked. """ self._mouse_click( event, 'dclicked' ) def _right_down ( self, event ): """ Handles the right mouse button being pressed. """ self._mouse_click( event, 'right_clicked' ) def _right_dclick ( self, event ): """ Handles the right mouse button being double clicked. """ self._mouse_click( event, 'right_dclicked' ) def _begin_drag ( self, event ): """ Handles the user beginning a drag operation with the left mouse button. """ if PythonDropSource is not None: adapter = self.adapter object, name = self.object, self.name selected = self._get_selected() drag_items = [] # Collect all of the selected items to drag: for row in selected: drag = adapter.get_drag( object, name, row ) if drag is None: return drag_items.append( drag ) # Save the drag item indices, so that we can later handle a # completed 'move' operation: self._drag_rows = selected try: # If only one item is being dragged, drag it as an item, not a # list: if len( drag_items ) == 1: drag_items = drag_items[0] # Perform the drag and drop operation: ds = PythonDropSource( self.control, drag_items ) # If moves are allowed and the result was a drag move: if ((ds.result == wx.DragMove) and (self._drag_local or self.factory.drag_move)): # Then delete all of the original items (in reverse order # from highest to lowest, so the indices don't need to be # adjusted): rows = self._drag_rows rows.reverse() for row in rows: adapter.delete( object, name, row ) finally: self._drag_rows = None self._drag_local = False def _begin_label_edit ( self, event ): """ Handles the user starting to edit an item label. """ if not self.adapter.get_can_edit( self.object, self.name, event.GetIndex() ): event.Veto() def _end_label_edit ( self, event ): """ Handles the user finishing editing an item label. """ self.adapter.set_text( self.object, self.name, event.GetIndex(), event.GetColumn(), event.GetText() ) self.row = event.GetIndex() + 1 def _item_selected ( self, event ): """ Handles an item being selected. """ self._no_update = True try: get_item = self.adapter.get_item object, name = self.object, self.name selected_rows = self._get_selected() if self.factory.multi_select: self.multi_selected_rows = selected_rows self.multi_selected = [ get_item( object, name, row ) for row in selected_rows ] elif len( selected_rows ) == 0: self.selected_row = -1 self.selected = None else: self.selected_row = selected_rows[0] self.selected = get_item( object, name, selected_rows[0] ) finally: self._no_update = False def _item_activated ( self, event ): """ Handles an item being activated (double-clicked or enter pressed). """ self.activated_row = event.GetIndex() self.activated = self.adapter.get_item( self.object, self.name, self.activated_row ) def _key_down ( self, event ): """ Handles the user pressing a key in the list control. """ key = event.GetKeyCode() if key == wx.WXK_NEXT: self._append_new() elif key in ( wx.WXK_BACK, wx.WXK_DELETE ): self._delete_current() elif key == wx.WXK_INSERT: self._insert_current() elif key == wx.WXK_LEFT: self._move_up_current() elif key == wx.WXK_RIGHT: self._move_down_current() elif key in ( wx.WXK_RETURN, wx.WXK_ESCAPE ): self._edit_current() else: event.Skip() def _column_right_clicked ( self, event ): """ Handles the user right-clicking a column header. """ column = event.GetColumn() if ((self._cached_widths is not None) and (0 <= column < len( self._cached_widths ))): self._cached_widths[ column ] = None self._size_modified( event ) def _column_clicked ( self, event ): """ Handles the right mouse button being double clicked. """ editor_event = TabularEditorEvent( editor = self, row = 0, column = event.GetColumn() ) setattr( self, 'column_clicked', editor_event) event.Skip() def _size_modified ( self, event ): """ Handles the size of the list control being changed. """ control = self.control n = control.GetColumnCount() if n == 1: dx, dy = control.GetClientSizeTuple() control.SetColumnWidth( 0, dx - 1 ) elif n > 1: do_later( self._set_column_widths ) event.Skip() def _motion ( self, event ): """ Handles the user moving the mouse. """ x = event.GetX() column = self._get_column( x ) row, flags = self.control.HitTest( wx.Point( x, event.GetY() ) ) if (row != self._last_row) or (column != self._last_column): self._last_row, self._last_column = row, column if (row == -1) or (column is None): tooltip = '' else: tooltip = self.adapter.get_tooltip( self.object, self.name, row, column ) if tooltip != self._last_tooltip: self._last_tooltip = tooltip wx.ToolTip.Enable( False ) wx.ToolTip.Enable( True ) self.control.SetToolTip( wx.ToolTip( tooltip ) ) #-- Drag and Drop Event Handlers ------------------------------------------- def wx_dropped_on ( self, x, y, data, drag_result ): """ Handles a Python object being dropped on the list control. """ row, flags = self.control.HitTest( wx.Point( x, y ) ) # If the user dropped it on an empty list, set the target as past the # end of the list: if ((row == -1) and ((flags & wx.LIST_HITTEST_NOWHERE) != 0) and (self.control.GetItemCount() == 0)): row = 0 # If we have a valid drop target row, proceed: if row != -1: if not isinstance( data, list ): # Handle the case of just a single item being dropped: self._wx_dropped_on( row, data ) else: # Handles the case of a list of items being dropped, being # careful to preserve the original order of the source items if # possible: data.reverse() for item in data: self._wx_dropped_on( row, item ) # If this was an inter-list drag, mark it as 'local': if self._drag_indices is not None: self._drag_local = True # Return a successful drop result: return drag_result # Indicate we could not process the drop: return wx.DragNone def _wx_dropped_on ( self, row, item ): """ Helper method for handling a single item dropped on the list control. """ adapter = self.adapter object, name = self.object, self.name # Obtain the destination of the dropped item relative to the target: destination = adapter.get_dropped( object, name, row, item ) # Adjust the target index accordingly: if destination == 'after': row += 1 # Insert the dropped item at the requested position: adapter.insert( object, name, row, item ) # If the source for the drag was also this list control, we need to # adjust the original source indices to account for their new position # after the drag operation: rows = self._drag_rows if rows is not None: for i in range( len( rows ) - 1, -1, -1 ): if rows[i] < row: break rows[i] += 1 def wx_drag_over ( self, x, y, data, drag_result ): """ Handles a Python object being dragged over the tree. """ if isinstance( data, list ): rc = wx.DragNone for item in data: rc = self.wx_drag_over( x, y, item, drag_result ) if rc == wx.DragNone: break return rc row, flags = self.control.HitTest( wx.Point( x, y ) ) # If the user is dragging over an empty list, set the target to the end # of the list: if ((row == -1) and ((flags & wx.LIST_HITTEST_NOWHERE) != 0) and (self.control.GetItemCount() == 0)): row = 0 # If the drag target index is valid and the adapter says it is OK to # drop the data here, then indicate the data can be dropped: if ((row != -1) and self.adapter.get_can_drop( self.object, self.name, row, data )): return drag_result # Else indicate that we will not accept the data: return wx.DragNone #-- UI preference save/restore interface ----------------------------------- def restore_prefs ( self, prefs ): """ Restores any saved user preference information associated with the editor. """ self._cached_widths = cws = prefs.get( 'cached_widths' ) if cws is not None: set_column_width = self.control.SetColumnWidth for i, width in enumerate( cws ): if width is not None: set_column_width( i, width ) def save_prefs ( self ): """ Returns any user preference information associated with the editor. """ cws = self._cached_widths if cws is not None: cws = [ ( None, cw )[ cw >= 0 ] for cw in cws ] return { 'cached_widths': cws } #-- Private Methods -------------------------------------------------------- def _refresh ( self ): """ Refreshes the contents of the editor's list control. """ n = self.adapter.len( self.object, self.name ) if n > 0: self.control.RefreshItems( 0, n - 1) def _rebuild ( self ): """ Rebuilds the contents of the editor's list control. """ control = self.control control.ClearAll() adapter, object, name = self.adapter, self.object, self.name adapter.object, adapter.name = object, name get_alignment = adapter.get_alignment get_width = adapter.get_width for i, label in enumerate( adapter.label_map ): control.InsertColumn( i, label, alignment_map.get( get_alignment( object, name, i ), wx.LIST_FORMAT_LEFT ) ) self._set_column_widths() def _rebuild_all ( self ): """ Rebuilds the structure of the list control, then refreshes its contents. """ self._rebuild() self.update_editor() def _set_column_widths ( self ): """ Set the column widths for the current set of columns. """ control = self.control if control is None: return object, name = self.object, self.name dx, dy = control.GetClientSize() if is_mac: dx -= scrollbar_dx n = control.GetColumnCount() get_width = self.adapter.get_width pdx = 0 wdx = 0.0 widths = [] cached = self._cached_widths current = [ control.GetColumnWidth( i ) for i in xrange( n ) ] if (cached is None) or (len( cached ) != n): self._cached_widths = cached = [ None ] * n for i in xrange( n ): cw = cached[i] if (cw is None) or (-cw == current[i]): width = float( get_width( object, name, i ) ) if width <= 0.0: width = 0.1 if width <= 1.0: wdx += width cached[i] = -1 else: width = int( width ) pdx += width if cw is None: cached[i] = width else: cached[i] = width = current[i] pdx += width widths.append( width ) adx = max( 0, dx - pdx ) control.Freeze() for i in range( n ): width = cached[i] if width < 0: width = widths[i] if width <= 1.0: widths[i] = w = max( 30, int( round( (adx * width)/wdx ) ) ) wdx -= width width = w adx -= width cached[i] = -w control.SetColumnWidth( i, width ) control.Thaw() def _add_image ( self, image_resource ): """ Adds a new image to the wx.ImageList and its associated mapping. """ bitmap = image_resource.create_image().ConvertToBitmap() image_list = self._image_list if image_list is None: self._image_list = image_list = wx.ImageList( bitmap.GetWidth(), bitmap.GetHeight() ) self.control.AssignImageList( image_list, wx.IMAGE_LIST_SMALL ) self.image_resources[image_resource] = \ self.images[ image_resource.name ] = row = image_list.Add( bitmap ) return row def _get_image ( self, image ): """ Converts a user specified image to a wx.ListCtrl image index. """ if isinstance( image, basestring ): self.image = image image = self.image if isinstance( image, ImageResource ): result = self.image_resources.get( image ) if result is not None: return result return self._add_image( image ) return self.images.get( image ) def _get_selected ( self ): """ Returns a list of the rows of all currently selected list items. """ selected = [] item = -1 control = self.control # Handle case where the list is cleared if len( self.value ) == 0: return selected while True: item = control.GetNextItem( item, wx.LIST_NEXT_ALL, wx.LIST_STATE_SELECTED ) if item == -1: break; selected.append( item ) return selected def _append_new ( self ): """ Append a new item to the end of the list control. """ if 'append' in self.factory.operations: adapter = self.adapter self.row = self.control.GetItemCount() self.edit = True adapter.insert( self.object, self.name, self.row, adapter.get_default_value( self.object, self.name ) ) def _insert_current ( self ): """ Inserts a new item after the currently selected list control item. """ if 'insert' in self.factory.operations: selected = self._get_selected() if len( selected ) == 1: adapter = self.adapter adapter.insert( self.object, self.name, selected[0], adapter.get_default_value( self.object, self.name ) ) self.row = selected[0] self.edit = True def _delete_current ( self ): """ Deletes the currently selected items from the list control. """ if 'delete' in self.factory.operations: selected = self._get_selected() if len( selected ) == 0: return delete = self.adapter.delete selected.reverse() for row in selected: delete( self.object, self.name, row ) n = self.adapter.len( self.object, self.name ) if not self.factory.multi_select: self.selected_row = self.row = n-1 if row>=n else row else: #FIXME: What should the selection be? self.multi_selected = [] self.multi_selected_rows = [] def _move_up_current ( self ): """ Moves the currently selected item up one line in the list control. """ if 'move' in self.factory.operations: selected = self._get_selected() if len( selected ) == 1: row = selected[0] if row > 0: adapter = self.adapter object, name = self.object, self.name item = adapter.get_item( object, name, row ) adapter.delete( object, name, row ) adapter.insert( object, name, row - 1, item ) self.row = row - 1 def _move_down_current ( self ): """ Moves the currently selected item down one line in the list control. """ if 'move' in self.factory.operations: selected = self._get_selected() if len( selected ) == 1: row = selected[0] if row < (self.control.GetItemCount() - 1): adapter = self.adapter object, name = self.object, self.name item = adapter.get_item( object, name, row ) adapter.delete( object, name, row ) adapter.insert( object, name, row + 1, item ) self.row = row + 1 def _edit_current ( self ): """ Allows the user to edit the current item in the list control. """ if 'edit' in self.factory.operations and self.factory.editable_labels: selected = self._get_selected() if len( selected ) == 1: self.control.EditLabel( selected[0] ) def _get_column ( self, x, translate = False ): """ Returns the column index corresponding to a specified x position. """ if x >= 0: control = self.control for i in range( control.GetColumnCount() ): x -= control.GetColumnWidth( i ) if x < 0: if translate: return self.adapter.get_column( self.object, self.name, i ) return i return None def _mouse_click ( self, event, trait ): """ Generate a TabularEditorEvent event for a specified mouse event and editor trait name. """ x = event.GetX() row, flags = self.control.HitTest( wx.Point( x, event.GetY() ) ) if row == wx.NOT_FOUND: if self.factory.multi_select: self.multi_selected = [] self.multi_selected_rows = [] else: self.selected = None self.selected_row = -1 else: if self.factory.multi_select and event.ShiftDown(): # Handle shift-click multi-selections because the wx.ListCtrl # does not (by design, apparently). # We must append this to the event queue because the # multi-selection will not be recorded until this event handler # finishes and lets the widget actually handle the event. do_later( self._item_selected, None ) setattr( self, trait, TabularEditorEvent( editor = self, row = row, column = self._get_column( x, translate = True ) ) ) # wx should continue with additional event handlers. Skip(False) # actually means to skip looking, skip(True) means to keep looking. # This seems backwards to me... event.Skip(True) #------------------------------------------------------------------------------- # 'TabularEditorEvent' class: #------------------------------------------------------------------------------- class TabularEditorEvent ( HasStrictTraits ): # The index of the row: row = Int # The id of the column (either a string or an integer): column = Any # The row item: item = Property #-- Private Traits --------------------------------------------------------- # The editor the event is associated with: editor = Instance( TabularEditor ) #-- Property Implementations ----------------------------------------------- def _get_item ( self ): editor = self.editor return editor.adapter.get_item( editor.object, editor.name, self.row ) traitsui-4.1.0/traitsui/wx/ui_modal.py0000644000175100001440000003411711674463546021034 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 11/01/2004 # #------------------------------------------------------------------------------ """ Creates a wxPython user interface for a specified UI object. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx from helper \ import restore_window, save_window, TraitsUIScrolledPanel from ui_base \ import BaseDialog from ui_panel \ import panel, show_help from constants \ import DefaultTitle, WindowColor, screen_dy, scrollbar_dx from traitsui.menu \ import ApplyButton, RevertButton, OKButton, CancelButton, HelpButton #------------------------------------------------------------------------------- # Creates a modal wxPython user interface for a specified UI object: #------------------------------------------------------------------------------- def ui_modal ( ui, parent ): """ Creates a modal wxPython user interface for a specified UI object. """ ui_dialog( ui, parent, True ) #------------------------------------------------------------------------------- # Creates a non-modal wxPython user interface for a specified UI object: #------------------------------------------------------------------------------- def ui_nonmodal ( ui, parent ): """ Creates a non-modal wxPython user interface for a specified UI object. """ ui_dialog( ui, parent, False ) #------------------------------------------------------------------------------- # Creates a wxPython dialog-based user interface for a specified UI object: #------------------------------------------------------------------------------- def ui_dialog ( ui, parent, is_modal ): """ Creates a wxPython dialog box for a specified UI object. Changes are not immediately applied to the underlying object. The user must click **Apply** or **OK** to apply changes. The user can revert changes by clicking **Revert** or **Cancel**. """ if ui.owner is None: ui.owner = ModalDialog() ui.owner.init( ui, parent, is_modal ) ui.control = ui.owner.control ui.control._parent = parent try: ui.prepare_ui() except: ui.control.Destroy() ui.control.ui = None ui.control = None ui.owner = None ui.result = False raise ui.handler.position( ui.info ) restore_window( ui ) if is_modal: ui.control.ShowModal() else: ui.control.Show() #------------------------------------------------------------------------------- # 'ModalDialog' class: #------------------------------------------------------------------------------- class ModalDialog ( BaseDialog ): """ Modal dialog box for Traits-based user interfaces. """ #--------------------------------------------------------------------------- # Initializes the object: #--------------------------------------------------------------------------- def init ( self, ui, parent, is_modal ): self.is_modal = is_modal style = 0 view = ui.view if view.resizable: style |= wx.RESIZE_BORDER title = view.title if title == '': title = DefaultTitle revert = apply = False window = ui.control if window is not None: window.SetSizer( None ) ui.reset() if hasattr( self, 'revert' ): revert = self.revert.IsEnabled() if hasattr( self, 'apply' ): apply = self.apply.IsEnabled() else: self.ui = ui if is_modal: window = wx.Dialog( parent, -1, title, style = style | wx.DEFAULT_DIALOG_STYLE ) else: window = wx.Frame( parent, -1, title, style = style | (wx.DEFAULT_FRAME_STYLE & (~wx.RESIZE_BORDER) ) ) window.SetBackgroundColour( WindowColor ) self.control = window self.set_icon( view.icon ) wx.EVT_CLOSE( window, self._on_close_page ) wx.EVT_CHAR( window, self._on_key ) # Create the 'context' copies we will need while editing: context = ui.context ui._context = context ui.context = self._copy_context( context ) ui._revert = self._copy_context( context ) # Create the actual trait sheet panel and imbed it in a scrollable # window (if requested): sw_sizer = wx.BoxSizer( wx.VERTICAL ) if ui.scrollable: sizer = wx.BoxSizer( wx.VERTICAL ) sw = TraitsUIScrolledPanel( window ) trait_sheet = panel( ui, sw ) sizer.Add( trait_sheet, 1, wx.EXPAND | wx.ALL, 4 ) tsdx, tsdy = trait_sheet.GetSizeTuple() tsdx += 8 tsdy += 8 sw.SetScrollRate( 16, 16 ) max_dy = (2 * screen_dy) / 3 sw.SetSizer( sizer ) sw.SetSize( wx.Size( tsdx + ((tsdy > max_dy) * scrollbar_dx), min( tsdy, max_dy ) ) ) else: sw = panel( ui, window ) sw_sizer.Add( sw, 1, wx.EXPAND ) buttons = [ self.coerce_button( button ) for button in view.buttons ] nbuttons = len( buttons ) if (nbuttons != 1) or (not self.is_button( buttons[0], '' )): # Create the necessary special function buttons: sw_sizer.Add( wx.StaticLine( window, -1 ), 0, wx.EXPAND ) b_sizer = wx.BoxSizer( wx.HORIZONTAL ) if nbuttons == 0: if view.apply: self.check_button( buttons, ApplyButton ) if view.revert: self.check_button( buttons, RevertButton ) if view.ok: self.check_button( buttons, OKButton ) if view.cancel: self.check_button( buttons, CancelButton ) if view.help: self.check_button( buttons, HelpButton ) for raw_button, button in zip( view.buttons, buttons ): default = raw_button == view.default_button if self.is_button( button, 'Apply' ): self.apply = self.add_button( button, b_sizer, self._on_apply, apply, default = default ) ui.on_trait_change( self._on_applyable, 'modified', dispatch = 'ui' ) elif self.is_button( button, 'Revert' ): self.revert = self.add_button( button, b_sizer, self._on_revert, revert, default = default ) elif self.is_button( button, 'OK' ): self.ok = self.add_button( button, b_sizer, self._on_ok, default = default ) ui.on_trait_change( self._on_error, 'errors', dispatch = 'ui' ) elif self.is_button( button, 'Cancel' ): self.add_button( button, b_sizer, self._on_cancel, default = default) elif self.is_button( button, 'Help' ): self.add_button( button, b_sizer, self._on_help, default = default) elif not self.is_button( button, '' ): self.add_button( button, b_sizer, default = default ) sw_sizer.Add( b_sizer, 0, wx.ALIGN_RIGHT | wx.ALL, 5 ) # Add the menu bar, tool bar and status bar (if any): self.add_menubar() self.add_toolbar() self.add_statusbar() # Lay all of the dialog contents out: window.SetSizerAndFit( sw_sizer ) #--------------------------------------------------------------------------- # Closes the dialog window: #--------------------------------------------------------------------------- def close ( self, rc = wx.ID_OK ): """ Closes the dialog window. """ ui = self.ui ui.result = (rc == wx.ID_OK) save_window( ui ) if self.is_modal: self.control.EndModal( rc ) ui.finish() self.ui = self.apply = self.revert = self.help = self.control = None #--------------------------------------------------------------------------- # Creates a copy of a 'context' dictionary: #--------------------------------------------------------------------------- def _copy_context ( self, context ): """ Creates a copy of a *context* dictionary. """ result = {} for name, value in context.items(): if value is not None: result[ name ] = value.clone_traits() else: result[ name ] = None return result #--------------------------------------------------------------------------- # Applies the traits in the 'from' context to the 'to' context: #--------------------------------------------------------------------------- def _apply_context ( self, from_context, to_context ): """ Applies the traits in the *from_context* to the *to_context*. """ for name, value in from_context.items(): if value is not None: to_context[ name ].copy_traits( value ) else: to_context[ name ] = None if to_context is self.ui._context: on_apply = self.ui.view.on_apply if on_apply is not None: on_apply() #--------------------------------------------------------------------------- # Handles the user clicking the window/dialog 'close' button/icon: #--------------------------------------------------------------------------- def _on_close_page ( self, event ): """ Handles the user clicking the window/dialog "close" button/icon. """ if self.ui.view.close_result == True: self._on_ok( event ) else: self._on_cancel( event ) #--------------------------------------------------------------------------- # Closes the window and saves changes (if allowed by the handler): #--------------------------------------------------------------------------- def _on_ok ( self, event = None ): """ Closes the window and saves changes (if allowed by the handler). """ if self.ui.handler.close( self.ui.info, True ): self._apply_context( self.ui.context, self.ui._context ) self.close( wx.ID_OK ) #--------------------------------------------------------------------------- # Closes the window and discards changes (if allowed by the handler): #--------------------------------------------------------------------------- def _on_cancel ( self, event = None ): """ Closes the window and discards changes (if allowed by the handler). """ if self.ui.handler.close( self.ui.info, False ): self._apply_context( self.ui._revert, self.ui._context ) self.close( wx.ID_CANCEL ) #--------------------------------------------------------------------------- # Handles the 'Help' button being clicked: #--------------------------------------------------------------------------- def _on_help ( self, event ): """ Handles the **Help** button being clicked. """ self.ui.handler.show_help( self.ui.info, event.GetEventObject() ) #--------------------------------------------------------------------------- # Handles the user hitting the 'Esc'ape key: #--------------------------------------------------------------------------- def _on_key ( self, event ): """ Handles the user pressing the Escape key. """ if event.GetKeyCode() == 0x1B: self._on_close_page( event ) #--------------------------------------------------------------------------- # Handles an 'Apply' all changes request: #--------------------------------------------------------------------------- def _on_apply ( self, event ): """ Handles a request to apply changes. """ ui = self.ui self._apply_context( ui.context, ui._context ) if hasattr(self, 'revert'): self.revert.Enable( True ) ui.handler.apply( ui.info ) ui.modified = False #--------------------------------------------------------------------------- # Handles a 'Revert' all changes request: #--------------------------------------------------------------------------- def _on_revert ( self, event ): """ Handles a request to revert changes. """ ui = self.ui self._apply_context( ui._revert, ui.context ) self._apply_context( ui._revert, ui._context ) self.revert.Enable( False ) ui.handler.revert( ui.info ) ui.modified = False #--------------------------------------------------------------------------- # Handles the user interface 'modified' state changing: #--------------------------------------------------------------------------- def _on_applyable ( self, state ): """ Handles a change to the "modified" state of the user interface . """ self.apply.Enable( state ) #--------------------------------------------------------------------------- # Handles editing errors: #--------------------------------------------------------------------------- def _on_error ( self, errors ): """ Handles editing errors. """ self.ok.Enable( errors == 0 ) traitsui-4.1.0/traitsui/wx/history_control.py0000644000175100001440000001447211674463546022506 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/21/2004 # #------------------------------------------------------------------------------ """ Defines the a text entry field (actually a combo-box) with a drop-down list of values previously entered into the control. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import wx from traits.api \ import HasPrivateTraits, Instance, Str, List, Int, Bool from pyface.timer.api \ import do_later from constants \ import OKColor, ErrorColor #------------------------------------------------------------------------------- # 'HistoryControl' class: #------------------------------------------------------------------------------- class HistoryControl ( HasPrivateTraits ): # The UI control: control = Instance( wx.Window ) # The current value of the control: value = Str # Should 'value' be updated on every keystroke? auto_set = Bool( False ) # The current history of the control: history = List( Str ) # The maximum number of history entries allowed: entries = Int( 10 ) # Is the current value valid? error = Bool( False ) #-- Public Methods --------------------------------------------------------- def create_control ( self, parent ): """ Creates the control. """ self.control = control = wx.ComboBox( parent, -1, self.value, wx.Point( 0, 0 ), wx.Size( -1, -1 ), self.history, style = wx.CB_DROPDOWN ) wx.EVT_COMBOBOX( parent, control.GetId(), self._update_value ) wx.EVT_KILL_FOCUS( control, self._kill_focus ) wx.EVT_TEXT_ENTER( parent, control.GetId(), self._update_text_value ) if self.auto_set: wx.EVT_TEXT( parent, control.GetId(), self._update_value_only ) return control def dispose ( self ): """ Disposes of the control at the end of its life cycle. """ control, self.control = self.control, None parent = control.GetParent() wx.EVT_COMBOBOX( parent, control.GetId(), None ) wx.EVT_TEXT_ENTER( parent, control.GetId(), None ) wx.EVT_KILL_FOCUS( control, None ) def set_value ( self, value ): """ Sets the specified value and adds it to the history. """ self._update( value ) #-- Traits Event Handlers -------------------------------------------------- def _value_changed ( self, value ): """ Handles the 'value' trait being changed. """ if not self._no_update: control = self.control if control is not None: control.SetValue( value ) self._restore = False def _history_changed ( self ): """ Handles the 'history' being changed. """ if not self._no_update: if self._first_time is None: self._first_time = False if (self.value == '') and (len( self.history ) > 0): self.value = self.history[0] self._load_history( select = False ) def _error_changed ( self, error ): """ Handles the 'error' trait being changed. """ if error: self.control.SetBackgroundColour( ErrorColor ) else: self.control.SetBackgroundColour( OKColor ) self.control.Refresh() #-- Wx Event Handlers ------------------------------------------------------ def _update_value ( self, event ): """ Handles the user selecting something from the drop-down list of the combobox. """ self._update( event.GetString() ) def _update_value_only ( self, event ): """ Handles the user typing into the text field in 'auto_set' mode. """ self._no_update = True self.value = event.GetString() self._no_update = False def _update_text_value ( self, event, select = True ): """ Handles the user typing something into the text field of the combobox. """ if not self._no_update: self._update( self.control.GetValue(), select ) def _kill_focus ( self, event ): """ Handles the combobox losing focus. """ self._update_text_value( event, False ) event.Skip() #-- Private Methods -------------------------------------------------------- def _update ( self, value, select = True ): """ Updates the value and history list based on a specified value. """ self._no_update = True if value.strip() != '': history = self.history if (len( history ) == 0) or (value != history[0]): if value in history: history.remove( value ) history.insert( 0, value ) del history[ self.entries: ] self._load_history( value, select ) self.value = value self._no_update = False def _load_history ( self, restore = None, select = True ): """ Loads the current history list into the control. """ control = self.control control.Freeze() if restore is None: restore = control.GetValue() control.Clear() for value in self.history: control.Append( value ) self._restore = True do_later( self._thaw_value, restore, select ) def _thaw_value ( self, restore, select ): """ Restores the value of the combobox control. """ control = self.control if control is not None: if self._restore: control.SetValue( restore ) if select: control.SetMark( 0, len( restore ) ) control.Thaw() traitsui-4.1.0/traitsui/view.py0000644000175100001440000004512711674463546017562 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/07/2004 # #------------------------------------------------------------------------------ """ Defines the View class used to represent the structural content of a Traits-based user interface. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import (Any, Bool, Callable, Enum, Event, Float, Instance, List, Str, Trait, TraitPrefixList) from .view_element import ViewElement, ViewSubElement from .ui import UI from .ui_traits import (AButton, ATheme, AnObject, Buttons, DockStyle, EditorStyle, ExportType, HelpId, Image, SequenceTypes, ViewStatus) from .handler import Handler, default_handler from .group import Group from .item import Item from .include import Include #------------------------------------------------------------------------------- # Trait definitions: #------------------------------------------------------------------------------- # Name of the view trait: AnId = Str( desc = 'the name of the view' ) # Contents of the view trait (i.e., a single Group object): Content = Instance( Group, desc = 'the content of the view' ) # An optional model/view factory for converting the model into a viewable # 'model_view' object AModelView = Callable( desc = 'the factory function for converting a model ' 'into a model/view object' ) # Reference to a Handler object trait: AHandler = Any( desc = 'the handler for the view' ) # Dialog window title trait: ATitle = Str( desc = 'the window title for the view' ) # Dialog window icon trait #icon_trait = Instance( 'pyface.image_resource.ImageResource', # desc = 'the ImageResource of the icon file for the view' ) # User interface 'kind' trait. The values have the following meanings: # # * 'panel': An embeddable panel. This type of window is intended to be used as # part of a larger interface. # * 'subpanel': An embeddable panel that does not display command buttons, # even if the View specifies them. # * 'modal': A modal dialog box that operates on a clone of the object until # the user commits the change. # * 'nonmodal': A nonmodal dialog box that operates on a clone of the object # until the user commits the change # * 'live': A nonmodal dialog box that immediately updates the object. # * 'livemodal': A modal dialog box that immediately updates the object. # * 'popup': A temporary, frameless popup dialog that immediately updates the # object and is active only while the mouse pointer is in the dialog. # * 'info': A temporary, frameless popup dialog that immediately updates the # object and is active only while the dialog is still over the invoking # control. # * 'wizard': A wizard modal dialog box. A wizard contains a sequence of # pages, which can be accessed by clicking **Next** and **Back** buttons. # Changes to attribute values are applied only when the user clicks the # **Finish** button on the last page. AKind = Trait( 'live', TraitPrefixList( 'panel', 'subpanel', 'modal', 'nonmodal', 'livemodal', 'live', 'popup', 'popover', 'info', 'wizard' ), desc = 'the kind of view window to create', cols = 4 ) # Apply changes handler: OnApply = Callable( desc = 'the routine to call when modal changes are applied ' 'or reverted' ) # Is the dialog window resizable? IsResizable = Bool( False, desc = 'whether dialog can be resized or not' ) # Is the view scrollable? IsScrollable = Bool( False, desc = 'whether view should be scrollable or not' ) # The valid categories of imported elements that can be dragged into the view: ImportTypes = List( Str, desc = 'the categories of elements that can be ' 'dragged into the view' ) # The view position and size traits: Width = Float( -1E6, desc = 'the width of the view window' ) Height = Float( -1E6, desc = 'the height of the view window' ) XCoordinate = Float( -1E6, desc = 'the x coordinate of the view window' ) YCoordinate = Float( -1E6, desc = 'the y coordinate of the view window' ) # The result that should be returned if the user clicks the window or dialog # close button or icon CloseResult = Enum( None, True, False, desc = 'the result to return when the user clicks the ' 'window or dialog close button or icon' ) # The KeyBindings trait: AKeyBindings = Instance( 'traitsui.key_bindings.KeyBindings', desc = 'the global key bindings for the view' ) #------------------------------------------------------------------------------- # 'View' class: #------------------------------------------------------------------------------- class View ( ViewElement ): """ A Traits-based user interface for one or more objects. The attributes of the View object determine the contents and layout of an attribute-editing window. A View object contains a set of Group, Item, and Include objects. A View object can be an attribute of an object derived from HasTraits, or it can be a standalone object. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # A unique identifier for the view: id = AnId # The top-level Group object for the view: content = Content # The menu bar for the view. Usually requires a custom **handler**: menubar = Any # Instance( pyface.action.MenuBarManager ) # The toolbar for the view. Usually requires a custom **handler**: toolbar = Any # Instance( pyface.action.ToolBarManager ) # Status bar items to add to the view's status bar. The value can be: # # - **None**: No status bar for the view (the default). # - string: Same as [ StatusItem( name = string ) ]. # - StatusItem: Same as [ StatusItem ]. # - [ [StatusItem|string], ... ]: Create a status bar with one field for # each StatusItem in the list (or tuple). The status bar fields are # defined from left to right in the order specified. A string value is # converted to: StatusItem( name = string ): statusbar = ViewStatus # List of button actions to add to the view. The **traitsui.menu** # module defines standard buttons, such as **OKButton**, and standard sets # of buttons, such as **ModalButtons**, which can be used to define a value # for this attribute. This value can also be a list of button name strings, # such as ``['OK', 'Cancel', 'Help']``. If set to the empty list, the # view contains a default set of buttons (equivalent to **LiveButtons**: # Undo/Redo, Revert, OK, Cancel, Help). To suppress buttons in the view, # use the **NoButtons** variable, defined in **traitsui.menu**. buttons = Buttons # The default button to activate when Enter is pressed. If not specified, # pressing Enter will not activate any button. default_button = AButton # The set of global key bindings for the view. Each time a key is pressed # while the view has keyboard focus, the key is checked to see if it is one # of the keys recognized by the KeyBindings object. If it is, the matching # KeyBinding's method name is checked to see if it is defined on any of the # object's in the view's context. If it is, the method is invoked. If the # result of the method is **False**, then the search continues with the # next object in the context. If any invoked method returns a non-False # value, processing stops and the key is marked as having been handled. If # all invoked methods return **False**, or no matching KeyBinding object is # found, the key is processed normally. If the view has a non-empty *id* # trait, the contents of the **KeyBindings** object will be saved as part # of the view's persistent data: key_bindings = AKeyBindings # The Handler object that provides GUI logic for handling events in the # window. Set this attribute only if you are using a custom Handler. If # not set, the default Traits UI Handler is used. handler = AHandler # The factory function for converting a model into a model/view object: model_view = AModelView # Title for the view, displayed in the title bar when the view appears as a # secondary window (i.e., dialog or wizard). If not specified, "Edit # properties" is used as the title. title = ATitle # The name of the icon to display in the dialog window title bar: icon = Any # The kind of user interface to create: kind = AKind # The default object being edited: object = AnObject # The default editor style of elements in the view: style = EditorStyle # The default docking style to use for sub-groups of the view. The following # values are possible: # # * 'fixed': No rearrangement of sub-groups is allowed. # * 'horizontal': Moveable elements have a visual "handle" to the left by # which the element can be dragged. # * 'vertical': Moveable elements have a visual "handle" above them by # which the element can be dragged. # * 'tabbed': Moveable elements appear as tabbed pages, which can be # arranged within the window or "stacked" so that only one appears at # at a time. dock = DockStyle # The image to display on notebook tabs: image = Image # Called when modal changes are applied or reverted: on_apply = OnApply # Can the user resize the window? resizable = IsResizable # Can the user scroll the view? If set to True, window-level scroll bars # appear whenever the window is too small to show all of its contents at # one time. If set to False, the window does not scroll, but individual # widgets might still contain scroll bars. scrollable = IsScrollable # The category of exported elements: export = ExportType # The valid categories of imported elements: imports = ImportTypes # External help context identifier, which can be used by a custom help # handler. This attribute is ignored by the default help handler. help_id = HelpId # Requested x-coordinate (horizontal position) for the view window. This # attribute can be specified in the following ways: # # * A positive integer: indicates the number of pixels from the left edge # of the screen to the left edge of the window. # * A negative integer: indicates the number of pixels from the right edge # of the screen to the right edge of the window. # * A floating point value between 0 and 1: indicates the fraction of the # total screen width between the left edge of the screen and the left edge # of the window. # * A floating point value between -1 and 0: indicates the fraction of the # total screen width between the right edge of the screen and the right # edge of the window. x = XCoordinate # Requested y-coordinate (vertical position) for the view window. This # attribute behaves exactly like the **x** attribute, except that its value # indicates the position of the top or bottom of the view window relative # to the top or bottom of the screen. y = YCoordinate # Requested width for the view window, as an (integer) number of pixels, or # as a (floating point) fraction of the screen width. width = Width # Requested height for the view window, as an (integer) number of pixels, or # as a (floating point) fraction of the screen height. height = Height # Class of dropped objects that can be added: drop_class = Any # Event when the view has been updated: updated = Event # What result should be returned if the user clicks the window or dialog # close button or icon? close_result = CloseResult # The default theme to use for a contained item: item_theme = ATheme # The default theme to use for a contained item's label: label_theme = ATheme # Note: Group objects delegate their 'object' and 'style' traits to the View #-- Deprecated Traits (DO NOT USE) ----------------------------------------- ok = Bool( False ) cancel = Bool( False ) undo = Bool( False ) redo = Bool( False ) apply = Bool( False ) revert = Bool( False ) help = Bool( False ) #--------------------------------------------------------------------------- # Initializes the object: #--------------------------------------------------------------------------- def __init__ ( self, *values, **traits ): """ Initializes the object. """ ViewElement.__init__( self, **traits ) self.set_content( *values ) #--------------------------------------------------------------------------- # Sets the content of a view: #--------------------------------------------------------------------------- def set_content ( self, *values ): """ Sets the content of a view. """ content = [] accum = [] for value in values: if isinstance( value, ViewSubElement ): content.append( value ) elif type( value ) in SequenceTypes: content.append( Group( *value ) ) elif (isinstance( value, basestring ) and (value[:1] == '<') and (value[-1:] == '>')): # Convert string to an Include value: content.append( Include( value[1:-1].strip() ) ) else: content.append( Item( value ) ) # If there are any 'Item' objects in the content, wrap the content in a # Group: for item in content: if isinstance( item, Item ): content = [ Group( *content ) ] break # Wrap all of the content up into a Group and save it as our content: self.content = Group( container = self, *content ) #--------------------------------------------------------------------------- # Creates a UI user interface object: #--------------------------------------------------------------------------- def ui ( self, context, parent = None, kind = None, view_elements = None, handler = None, id = '', scrollable = None, args = None ): """ Creates a **UI** object, which generates the actual GUI window or panel from a set of view elements. Parameters ---------- context : object or dictionary A single object or a dictionary of string/object pairs, whose trait attributes are to be edited. If not specified, the current object is used. parent : window component The window parent of the View object's window kind : string The kind of window to create. See the **AKind** trait for details. If *kind* is unspecified or None, the **kind** attribute of the View object is used. view_elements : ViewElements object The set of Group, Item, and Include objects contained in the view. Do not use this parameter when calling this method directly. handler : Handler object A handler object used for event handling in the dialog box. If None, the default handler for Traits UI is used. id : string A unique ID for persisting preferences about this user interface, such as size and position. If not specified, no user preferences are saved. scrollable : Boolean Indicates whether the dialog box should be scrollable. When set to True, scroll bars appear on the dialog box if it is not large enough to display all of the items in the view at one time. """ handler = handler or self.handler or default_handler() if not isinstance( handler, Handler ): handler = handler() if args is not None: handler.set( **args ) if not isinstance( context, dict ): context = context.trait_context() context.setdefault( 'handler', handler ) handler = context[ 'handler' ] if self.model_view is not None: context[ 'object' ] = self.model_view( context[ 'object' ] ) self_id = self.id if self_id != '': if id != '': id = '%s:%s' % ( self_id, id ) else: id = self_id if scrollable is None: scrollable = self.scrollable ui = UI( view = self, context = context, handler = handler, view_elements = view_elements, title = self.title, id = id, scrollable = scrollable ) if kind is None: kind = self.kind ui.ui( parent, kind ) return ui #--------------------------------------------------------------------------- # Replaces any items which have an 'id' with an Include object with the # same 'id', and puts the object with the 'id' into the specified # ViewElements object: #--------------------------------------------------------------------------- def replace_include ( self, view_elements ): """ Replaces any items that have an ID with an Include object with the same ID, and puts the object with the ID into the specified ViewElements object. """ if self.content is not None: self.content.replace_include( view_elements ) #--------------------------------------------------------------------------- # Returns a 'pretty print' version of the View: #--------------------------------------------------------------------------- def __repr__ ( self ): """ Returns a "pretty print" version of the View. """ if self.content is None: return '()' return "( %s )" % ', '.join( [ item.__repr__() for item in self.content.content ] ) traitsui-4.1.0/traitsui/api.py0000644000175100001440000000717611674463546017363 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/07/2004 # #------------------------------------------------------------------------------ """ Exports the symbols defined by the traits.ui package. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from .basic_editor_factory import BasicEditorFactory from .context_value import CV, CVFloat, CVInt, CVStr, CVType, ContextValue from .editor import Editor from .editor_factory import EditorFactory from .editors.api import (ArrayEditor, BooleanEditor, ButtonEditor, CheckListEditor, CodeEditor, ColorEditor, CompoundEditor, CustomEditor, CSVListEditor, DNDEditor, StyledDateEditor, DateEditor, DefaultOverride, DirectoryEditor, DropEditor, EnumEditor, FileEditor, FontEditor, HTMLEditor, HistoryEditor, ImageEditor, ImageEnumEditor, InstanceEditor, KeyBindingEditor, ListEditor, ListStrEditor, NullEditor, PopupEditor, ProgressEditor, RGBColorEditor, RangeEditor, ScrubberEditor, SearchEditor, SetEditor, ShellEditor, TableEditor, TabularEditor, TextEditor, TimeEditor, TitleEditor, TreeEditor, TupleEditor, ValueEditor) from .group import (Group, HFlow, HGroup, HSplit, Tabbed, VFlow, VFold, VGrid, VGroup, VSplit) from .handler import Controller, Handler, ModelView, ViewHandler, default_handler from .help import on_help_call from .help_template import help_template from .include import Include from .item import (Custom, Heading, Item, Label, Readonly, Spring, UCustom, UItem, UReadonly, spring) from .menu import (Action, ActionGroup, ApplyButton, CancelButton, CloseAction, HelpAction, HelpButton, LiveButtons, Menu, MenuBar, ModalButtons, NoButton, NoButtons, OKButton, OKCancelButtons, PyFaceAction, RedoAction, RevertAction, RevertButton, Separator, StandardMenuBar, ToolBar, UndoAction, UndoButton) from .message import auto_close_message, error, message from .table_column import (ExpressionColumn, ListColumn, NumericColumn, ObjectColumn, TableColumn) from .table_filter import (EvalTableFilter, MenuTableFilter, RuleTableFilter, TableFilter) from .theme import Theme, default_theme from .toolkit import toolkit from .toolkit_traits import ColorTrait, FontTrait, RGBColorTrait from .tree_node import (ITreeNode, ITreeNodeAdapter, MultiTreeNode, ObjectTreeNode, TreeNode, TreeNodeObject) from .ui import UI from .ui_info import UIInfo from .ui_traits import (ATheme, Border, HasBorder, HasMargin, Image, Margin, StatusItem) from .undo import (AbstractUndoItem, ListUndoItem, UndoHistory, UndoHistoryUndoItem, UndoItem) from .view import View from .view_element import ViewElement, ViewSubElement from . import view_elements _constants = toolkit().constants() WindowColor = _constants.get( 'WindowColor', 0xFFFFFF ) def raise_to_debug() : """ When we would otherwise silently swallow an exception, call this instead to allow people to set the TRAITS_DEBUG environment variable and get the exception. """ import os if os.getenv('TRAITS_DEBUG') is not None : raise traitsui-4.1.0/traitsui/include.py0000644000175100001440000000706111674463546020226 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/18/2004 # #------------------------------------------------------------------------------ """ Defines the Include class, which is used to represent a substitutable element within a user interface View. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import Str from .view_element import ViewSubElement #------------------------------------------------------------------------------- # 'Include' class: #------------------------------------------------------------------------------- class Include ( ViewSubElement ): """ A substitutable user interface element, i.e., a placeholder in a view definition. When a view object constructs an attribute-editing window, any Include objects within the view definition are replaced with a group or item defined elsewhere in the object's inheritance tree, based on matching of the name of the element. If no matching element is found, the Include object is ignored. An Include object can reference a group or item attribute on a parent class or on a subclass. For example, the following class contains a view definition that provides for the possibility that a subclass might add "extra" attributes in the middle of the view:: class Person(HasTraits): name = Str age = Int person_view = View('name', Include('extra'), 'age', kind='modal') If you directly create an instance of Person, and edit its attributes, the Include object is ignored. The following class extends Person, and defines a group of "extra" attributes to add to the view defined on Person:: class LocatedPerson(Person): street = Str city = Str state = Str zip = Int extra = Group('street', 'city', 'state', 'zip') The attribute-editing window for an instance of LocatedPerson displays editors for these extra attributes. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # The name of the substitutable content id = Str #--------------------------------------------------------------------------- # Initializes the object: #--------------------------------------------------------------------------- def __init__ ( self, id, **traits ): """ Initializes the Include object. """ super( ViewSubElement, self ).__init__( **traits ) self.id = id #--------------------------------------------------------------------------- # Returns a 'pretty print' version of the Include: #--------------------------------------------------------------------------- def __repr__ ( self ): """ Returns a "pretty print" version of the Include object. """ return "<%s>" % self.id traitsui-4.1.0/traitsui/key_bindings.py0000644000175100001440000003211011674463546021241 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 05/20/2005 # #------------------------------------------------------------------------------- """ Defines KeyBinding and KeyBindings classes, which manage the mapping of keystroke events into method calls on controller objects that are supplied by the application. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import (Any, Event, HasPrivateTraits, HasStrictTraits, Instance, List, Property, Str, cached_property, on_trait_change) from .api import HGroup, Item, KeyBindingEditor, ListEditor, View, toolkit from traits.trait_base import SequenceTypes #------------------------------------------------------------------------------- # Key binding trait definition: #------------------------------------------------------------------------------- # Trait definition for key bindings Binding = Str( event = 'binding', editor = KeyBindingEditor() ) #------------------------------------------------------------------------------- # 'KeyBinding' class: #------------------------------------------------------------------------------- class KeyBinding ( HasStrictTraits ): """ Binds one or two keystrokes to a method. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # First key binding binding1 = Binding # Second key binding binding2 = Binding # Description of what application function the method performs description = Str # Name of controller method the key is bound to method_name = Str # KeyBindings object that "owns" the KeyBinding owner = Instance( 'KeyBindings' ) #--------------------------------------------------------------------------- # Traits view definitions: #--------------------------------------------------------------------------- traits_view = View( HGroup( Item( 'binding1' ), Item( 'binding2' ), Item( 'description', style = 'readonly' ), show_labels = False ) ) #--------------------------------------------------------------------------- # Handles a binding trait being changed: #--------------------------------------------------------------------------- def _binding_changed ( self ): if self.owner is not None: self.owner.binding_modified = self #------------------------------------------------------------------------------- # 'KeyBindings' class: #------------------------------------------------------------------------------- class KeyBindings ( HasPrivateTraits ): """ A set of key bindings. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Set of defined key bindings (redefined dynamically) bindings = List( KeyBinding ) # Optional prefix to add to each method name prefix = Str # Optional suffix to add to each method name suffix = Str #-- Private Traits --------------------------------------------------------- # The (optional) list of controllers associated with this KeyBindings # object. The controllers may also be provided with the 'do' method: controllers = List( transient = True ) # The 'parent' KeyBindings object of this one (if any): parent = Instance( 'KeyBindings', transient = True ) # The root of the KeyBindings tree this object is part of: root = Property( depends_on = 'parent' ) # The child KeyBindings of this object (if any): children = List( transient = True ) # Event fired when one of the contained KeyBinding objects is changed binding_modified = Event( KeyBinding ) # Control that currently has the focus (if any) focus_owner = Any( transient = True ) #--------------------------------------------------------------------------- # Traits view definitions: #--------------------------------------------------------------------------- traits_view = View( [ Item( 'bindings', style = 'custom', show_label = False, editor = ListEditor( style = 'custom' ) ), '|{Click on an entry field, then press the key to ' 'assign. Double-click a field to clear it.}<>' ], title = 'Update Key Bindings', kind = 'livemodal', resizable = True, width = 0.4, height = 0.4 ) #--------------------------------------------------------------------------- # Initializes the object: #--------------------------------------------------------------------------- def __init__ ( self, *bindings, **traits ): super( KeyBindings, self ).__init__( **traits ) if (len( bindings ) == 1) and isinstance( bindings[0], SequenceTypes ): bindings = bindings[0] n = len( bindings ) self.add_trait( 'bindings', List( KeyBinding, minlen = n, maxlen = n, mode = 'list' ) ) self.bindings = [ binding.set( owner = self ) for binding in bindings ] #--------------------------------------------------------------------------- # Processes a keyboard event: #--------------------------------------------------------------------------- def do ( self, event, controllers = [], *args, **kw ): """ Processes a keyboard event. """ if isinstance( controllers, dict ): controllers = controllers.values() elif not isinstance( controllers, SequenceTypes ): controllers = [ controllers ] else: controllers = list( controllers ) return self._do( toolkit().key_event_to_name( event ), controllers, args, kw.get( 'recursive', False ) ) #--------------------------------------------------------------------------- # Merges another set of key bindings into this set: #--------------------------------------------------------------------------- def merge ( self, key_bindings ): """ Merges another set of key bindings into this set. """ binding_dic = {} for binding in self.bindings: binding_dic[ binding.method_name ] = binding for binding in key_bindings.bindings: binding2 = binding_dic.get( binding.method_name ) if binding2 is not None: binding2.binding1 = binding.binding1 binding2.binding2 = binding.binding2 #--------------------------------------------------------------------------- # Returns a clone of the KeyBindings object: #--------------------------------------------------------------------------- def clone ( self, **traits ): """ Returns a clone of the KeyBindings object. """ return self.__class__( *self.bindings, **traits ).set( **self.get( 'prefix', 'suffix' ) ) #--------------------------------------------------------------------------- # Dispose of the object: #--------------------------------------------------------------------------- def dispose ( self ): """ Dispose of the object. """ if self.parent is not None: self.parent.children.remove( self ) del self.controllers del self.children del self.bindings self.parent = self._root = self.focus_owner = None #--------------------------------------------------------------------------- # Edits a possibly hierarchical set of KeyBindings: #--------------------------------------------------------------------------- def edit ( self ): """ Edits a possibly hierarchical set of KeyBindings. """ bindings = list( set( self.root._get_bindings( [] ) ) ) bindings.sort( lambda l, r: cmp( '%s%02d' % ( l.binding1[-1:], len( l.binding1 ) ), '%s%02d' % ( r.binding1[-1:], len( r.binding1 ) ) ) ) KeyBindings( bindings ).edit_traits() #--------------------------------------------------------------------------- # Returns the current binding for a specified key (if any): #--------------------------------------------------------------------------- def key_binding_for ( self, binding, key_name ): """ Returns the current binding for a specified key (if any). """ if key_name != '': for a_binding in self.bindings: if ((a_binding is not binding) and ((key_name == a_binding.binding1) or (key_name == a_binding.binding2))): return a_binding return None #-- Property Implementations ----------------------------------------------- @cached_property def _get_root ( self ): root = self while root.parent is not None: root = root.parent return root #-- Event Handlers --------------------------------------------------------- def _binding_modified_changed ( self, binding ): """ Handles a binding being changed. """ binding1 = binding.binding1 binding2 = binding.binding2 for a_binding in self.bindings: if binding is not a_binding: if binding1 == a_binding.binding1: a_binding.binding1 = '' if binding1 == a_binding.binding2: a_binding.binding2 = '' if binding2 == a_binding.binding1: a_binding.binding1 = '' if binding2 == a_binding.binding2: a_binding.binding2 = '' def _focus_owner_changed ( self, old, new ): """ Handles the focus owner being changed. """ if old is not None: old.border_size = 0 @on_trait_change( 'children[]' ) def _children_modified ( self, removed, added ): """ Handles child KeyBindings being added to the object. """ for item in added: item.parent = self #-- object Method Overrides ------------------------------------------------ #--------------------------------------------------------------------------- # Restores the state of a previously pickled object: #--------------------------------------------------------------------------- def __setstate__ ( self, state ): """ Restores the state of a previously pickled object. """ n = len( state[ 'bindings' ] ) self.add_trait( 'bindings', List( KeyBinding, minlen = n, maxlen = n ) ) self.__dict__.update( state ) self.bindings = self.bindings[:] #-- Private Methods -------------------------------------------------------- def _get_bindings ( self, bindings ): """ Returns all of the bindings of this object and all of its children. """ bindings.extend( self.bindings ) for child in self.children: child._get_bindings( bindings ) return bindings def _do ( self, key_name, controllers, args, recursive ): """ Process the specified key for the specified set of controllers for this KeyBindings object and all of its children. """ # Search through our own bindings for a match: for binding in self.bindings: if (key_name == binding.binding1) or (key_name == binding.binding2): method_name = '%s%s%s' % ( self.prefix, binding.method_name, self.suffix ) for controller in (controllers + self.controllers): method = getattr( controller, method_name, None ) if method is not None: result = method( *args ) if result is not False: return True if binding.method_name == 'edit_bindings': self.edit() return True # If recursive, continue searching through a children's bindings: if recursive: for child in self.children: if child._do( key_name, controllers, args, recursive ): return True # Indicate no one processed the key: return False traitsui-4.1.0/traitsui/file_dialog.py0000644000175100001440000005520311674463546021042 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/07/2004 # #------------------------------------------------------------------------------ """ Defines functions and classes used to create pop-up file dialogs for opening and saving files. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from os import R_OK, W_OK, access, mkdir from os.path import (basename, dirname, exists, getatime, getctime, getmtime, getsize, isdir, isfile, join, split, splitext) from time import localtime, strftime from traits.api import (Bool, Button, CList, Event, File, HasPrivateTraits, Instance, Int, Interface, Property, Str, cached_property, implements) from traits.trait_base import user_name_for from .api import (CodeEditor, FileEditor, HGroup, HSplit, Handler, HistoryEditor, ImageEditor, InstanceEditor, Item, UIInfo, VGroup, VSplit, View, spring) from .ui_traits import AView from pyface.api import ImageResource from pyface.timer.api import do_later from .helper import commatize from .toolkit import toolkit #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- # Maximum text file size to process: MAX_SIZE = 16 * 1024 * 1024 #------------------------------------------------------------------------------- # 'IFileDialogModel' interface: #------------------------------------------------------------------------------- class IFileDialogModel ( Interface ): """ Defines a model extension to a file dialog. """ # The name of the currently selected file: file_name = File #------------------------------------------------------------------------------- # 'IFileDialogView' interface: #------------------------------------------------------------------------------- class IFileDialogView ( Interface ): """ Defines a visual extension to a file dialog. """ # The view to display: view = AView # Is the view fixed or variable width? is_fixed = Bool #------------------------------------------------------------------------------- # 'IFileDialogExtension' interface: #------------------------------------------------------------------------------- class IFileDialogExtension ( IFileDialogModel, IFileDialogView ): """ Defines a (convenience) union of the IFileDialogModel and IFileDialogView interfaces. """ #------------------------------------------------------------------------------- # 'MFileDialogModel' mix-in class: #------------------------------------------------------------------------------- class MFileDialogModel ( HasPrivateTraits ): implements( IFileDialogModel ) # The name of the currently selected file: file_name = File #------------------------------------------------------------------------------- # 'MFileDialogView' mix-in class: #------------------------------------------------------------------------------- class MFileDialogView ( HasPrivateTraits ): """ Defines a visual extension to a file dialog. """ # The view to display: view = AView # Is the view fixed or variable width? is_fixed = Bool( False ) # Create a default implementation: default_view = MFileDialogView() #------------------------------------------------------------------------------- # 'MFileDialogExtension' mix-in class: #------------------------------------------------------------------------------- class MFileDialogExtension ( MFileDialogModel, MFileDialogView ): """ Defines a (convenience) union of the MFileDialogModel and MFileDialogView mix-in classes. """ #------------------------------------------------------------------------------- # 'FileInfo' class: #------------------------------------------------------------------------------- class FileInfo ( MFileDialogModel ): """ Defines a file dialog extension that display various file information. """ # The size of the file: size = Property( depends_on = 'file_name' ) # Last file access time: atime = Property( depends_on = 'file_name' ) # List file modification time: mtime = Property( depends_on = 'file_name' ) # File creation time (or last metadata change time): ctime = Property( depends_on = 'file_name' ) #-- Traits View Definitions ------------------------------------------------ view = View( VGroup( Item( 'size', label = 'File size', style = 'readonly' ), Item( 'atime', label = 'Last access', style = 'readonly' ), Item( 'mtime', label = 'Last modified', style = 'readonly' ), Item( 'ctime', label = 'Created at', style = 'readonly' ), label = 'File Information', show_border = True ) ) #-- Property Implementations ----------------------------------------------- @cached_property def _get_size ( self ): try: return commatize( getsize( self.file_name ) ) + ' bytes' except: return '' @cached_property def _get_atime ( self ): try: return strftime( '%m/%d/%Y %I:%M:%S %p', localtime( getatime( self.file_name ) ) ) except: return '' @cached_property def _get_mtime ( self ): try: return strftime( '%m/%d/%Y %I:%M:%S %p', localtime( getmtime( self.file_name ) ) ) except: return '' @cached_property def _get_ctime ( self ): try: return strftime( '%m/%d/%Y %I:%M:%S %p', localtime( getctime( self.file_name ) ) ) except: return '' #------------------------------------------------------------------------------- # 'TextInfo' class: #------------------------------------------------------------------------------- class TextInfo ( MFileDialogModel ): """ Defines a file dialog extension that displays a file's contents as text. """ # The file's text content: text = Property( depends_on = 'file_name' ) #-- Traits View Definitions ------------------------------------------------ view = View( Item( 'text', style = 'readonly', show_label = False, editor = CodeEditor() ) ) #-- Property Implementations ----------------------------------------------- @cached_property def _get_text ( self ): try: if getsize( self.file_name ) > MAX_SIZE: return 'File too big...' fh = file( self.file_name, 'rb' ) data = fh.read() fh.close() except: return '' if (data.find( '\x00' ) >= 0) or (data.find( '\xFF' ) >= 0): return 'File contains binary data...' return data #------------------------------------------------------------------------------- # 'ImageInfo' class: #------------------------------------------------------------------------------- class ImageInfo ( MFileDialogModel ): """ Defines a file dialog extension that display an image file's dimensions and content. """ # The ImageResource object for the current file: image = Property( depends_on = 'file_name' ) # The width of the current image: width = Property( depends_on = 'image' ) # The height of the current image: height = Property( depends_on = 'image' ) #-- Traits View Definitions ------------------------------------------------ view = View( VGroup( VGroup( Item( 'width', style = 'readonly' ), Item( 'height', style = 'readonly' ), label = 'Image Dimensions', show_border = True ), VGroup( Item( 'image', show_label = False, editor = ImageEditor() ), label = 'Image', show_border = True, springy = True ) ) ) #-- Property Implementations ----------------------------------------------- @cached_property def _get_image ( self ): path, name = split( self.file_name ) if splitext( name )[1] in ( '.png', '.gif', '.jpg', '.jpeg' ): image = ImageResource( name, search_path = [ path ] ) else: image = ImageResource( 'unknown' ) self._cur_image = image.create_image() return image @cached_property def _get_width ( self ): try: return str( toolkit().image_size( self._cur_image )[0] ) + ' pixels' except: return '---' @cached_property def _get_height ( self ): try: return str( toolkit().image_size( self._cur_image )[1] ) + ' pixels' except: return '---' #------------------------------------------------------------------------------- # 'CreateDirHandler' class: #------------------------------------------------------------------------------- class CreateDirHandler ( Handler ): """ Controller for the 'create new directory' popup. """ # The name for the new directory to be created: dir_name = Str # The current status message: message = Str # The OK and Cancel buttons: ok = Button( 'OK' ) cancel = Button( 'Cancel' ) #-- Traits View Definitions ------------------------------------------------ view = View( VGroup( HGroup( Item( 'handler.dir_name', label = 'Name' ), Item( 'handler.ok', show_label = False, enabled_when = "handler.dir_name.strip() != ''" ), Item( 'handler.cancel', show_label = False ), ), HGroup( Item( 'handler.message', show_label = False, style = 'readonly', springy = True ), show_border = True ) ), kind = 'popup' ) #-- Handler Event Handlers ------------------------------------------------- def handler_ok_changed ( self, info ): """ Handles the user clicking the OK button. """ dir = info.object.file_name if not isdir( dir ): dir = dirname( dir ) path = join( dir, self.dir_name ) try: # Try to create the requested directory: mkdir( path ) # Force the file tree view to be refreshed: info.object.reload = True # set the new directory as the currently selected file name: info.object.file_name = path # Close this view: info.ui.dispose( True ) except: self.message = "Could not create the '%s' directory" % self.dir_name def handler_cancel_changed ( self, info ): """ Handles the user clicking the Cancel button. """ info.ui.dispose( False ) #------------------------------------------------------------------------------- # 'FileExistsHandler' class: #------------------------------------------------------------------------------- class FileExistsHandler ( Handler ): """ Controller for the 'file already exists' popup. """ # The current status message: message = Str # The OK and Cancel buttons: ok = Button( 'OK' ) cancel = Button( 'Cancel' ) #-- Traits View Definitions ------------------------------------------------ view = View( VGroup( HGroup( Item( 'handler.message', editor = ImageEditor( image = '@icons:dialog-warning' ) ), Item( 'handler.message', style = 'readonly' ), show_labels = False ), HGroup( spring, Item( 'handler.ok' ), Item( 'handler.cancel' ), show_labels = False ) ), kind = 'popup' ) #-- Handler Event Handlers ------------------------------------------------- def handler_ok_changed ( self, info ): """ Handles the user clicking the OK button. """ parent = info.ui.parent info.ui.dispose( True ) parent.dispose( True ) def handler_cancel_changed ( self, info ): """ Handles the user clicking the Cancel button. """ info.ui.dispose( False ) #------------------------------------------------------------------------------- # 'OpenFileDialog' class: #------------------------------------------------------------------------------- class OpenFileDialog ( Handler ): """ Defines the model and handler for the open file dialog. """ # The starting and current file path: file_name = File # The list of file filters to apply: filter = CList( Str ) # Number of history entries to allow: entries = Int( 10 ) # The file dialog title: title = Str( 'Open File' ) # The Traits UI persistence id to use: id = Str( 'traitsui.file_dialog.OpenFileDialog' ) # A list of optional file dialog extensions: extensions = CList( IFileDialogModel ) #-- Private Traits --------------------------------------------------------- # The UIInfo object for the view: info = Instance( UIInfo ) # Event fired when the file tree view should be reloaded: reload = Event # Event fired when the user double-clicks on a file name: dclick = Event # Allow extension models to be added dynamically: extension__ = Instance( IFileDialogModel ) # Is the file dialog for saving a file (or opening a file)? is_save_file = Bool( False ) # Is the currently specified file name valid? is_valid_file = Property( depends_on = 'file_name' ) # Can a directory be created now? can_create_dir = Property( depends_on = 'file_name' ) # The OK, Cancel and create directory buttons: ok = Button( 'OK' ) cancel = Button( 'Cancel' ) create = Button( image = '@icons:folder-new', style = 'toolbar' ) #-- Handler Class Method Overrides ----------------------------------------- def init_info ( self, info ): """ Handles the UIInfo object being initialized during view start-up. """ self.info = info #-- Property Implementations ----------------------------------------------- def _get_is_valid_file ( self ): if self.is_save_file: return (isfile( self.file_name ) or (not exists( self.file_name ))) return isfile( self.file_name ) def _get_can_create_dir ( self ): dir = dirname( self.file_name ) return (isdir( dir ) and access( dir, R_OK | W_OK )) #-- Handler Event Handlers ------------------------------------------------- def object_ok_changed ( self, info ): """ Handles the user clicking the OK button. """ if self.is_save_file and exists( self.file_name ): do_later( self._file_already_exists ) else: info.ui.dispose( True ) def object_cancel_changed ( self, info ): """ Handles the user clicking the Cancel button. """ info.ui.dispose( False ) def object_create_changed ( self, info ): """ Handles the user clicking the create directory button. """ if not isdir( self.file_name ): self.file_name = dirname( self.file_name ) CreateDirHandler().edit_traits( context = self, parent = info.create.control ) #-- Traits Event Handlers -------------------------------------------------- def _dclick_changed ( self ): """ Handles the user double-clicking a file name in the file tree view. """ if self.is_valid_file: self.object_ok_changed( self.info ) #-- Private Methods -------------------------------------------------------- def open_file_view ( self ): """ Returns the file dialog view to use. """ # Set up the default file dialog view and size information: item = Item( 'file_name', id = 'file_tree', style = 'custom', show_label = False, width = 0.5, editor = FileEditor( filter = self.filter, allow_dir = True, reload_name = 'reload', dclick_name = 'dclick' ) ) width = height = 0.20 # Check to see if we have any extensions being added: if len( self.extensions ) > 0: # fixme: We should use the actual values of the view's Width and # height traits here to adjust the overall width and height... width *= 2.0 # Assume we can used a fixed width Group: klass = HGroup # Set up to build a list of view Item objects: items = [] # Add each extension to the dialog: for i, extension in enumerate( self.extensions ): # Save the extension in a new trait (for use by the View): name = 'extension_%d' % i setattr( self, name, extension ) extension_view = extension # Sync up the 'file_name' trait with the extension: self.sync_trait( 'file_name', extension, mutual = True ) # Check to see if it also defines the optional IFileDialogView # interface, and if not, use the default view information: if not extension.has_traits_interface( IFileDialogView ): extension_view = default_view # Get the view that the extension wants to use: view = extension.trait_view( extension_view.view ) # Determine if we should use a splitter for the dialog: if not extension_view.is_fixed: klass = HSplit # Add the extension as a new view item: items.append( Item( name, label = user_name_for( extension.__class__.__name__ ), show_label = False, style = 'custom', width = 0.5, height = 0.5, dock = 'horizontal', resizable = True, editor = InstanceEditor( view = view, id = name ) ) ) # Finally, combine the normal view element with the extensions: item = klass( item, VSplit( id = 'splitter2', springy = True, *items ), id = 'splitter' ) # Return the resulting view: return View( VGroup( VGroup( item ), HGroup( Item( 'create', id = 'create', show_label = False, style = 'custom', defined_when = 'is_save_file', enabled_when = 'can_create_dir', tooltip = 'Create a new directory' ), Item( 'file_name', id = 'history', editor = HistoryEditor( entries = self.entries, auto_set = True ), springy = True ), Item( 'ok', id = 'ok', show_label = False, enabled_when = 'is_valid_file' ), Item( 'cancel', show_label = False ) ) ), title = self.title, id = self.id, kind = 'livemodal', width = width, height = height, close_result = False, resizable = True ) def _file_already_exists ( self ): """ Handles prompting the user when the selected file already exists, and the dialog is a 'save file' dialog. """ FileExistsHandler( message = ("The file '%s' already exists.\nDo " "you wish to overwrite it?") % basename( self.file_name ) ).edit_traits( context = self, parent = self.info.ok.control ).set( parent = self.info.ui ) #------------------------------------------------------------------------------- # Returns a file name to open or an empty string if the user cancels the # operation: #------------------------------------------------------------------------------- def open_file ( **traits ): """ Returns a file name to open or an empty string if the user cancels the operation. """ fd = OpenFileDialog( **traits ) if fd.edit_traits( view = 'open_file_view' ).result: return fd.file_name return '' def save_file ( **traits ): """ Returns a file name to save to or an empty string if the user cancels the operation. In the case where the file selected already exists, the user will be prompted if they want to overwrite the file before the selected file name is returned. """ traits.setdefault( 'title', 'Save File' ) traits[ 'is_save_file' ] = True fd = OpenFileDialog( **traits ) if fd.edit_traits( view = 'open_file_view' ).result: return fd.file_name return '' #-- Test Case ------------------------------------------------------------------ if __name__ == '__main__': print save_file( extensions = [ FileInfo(), TextInfo(), ImageInfo() ], filter = 'Python file (*.py)|*.py' ) traitsui-4.1.0/traitsui/group.py0000644000175100001440000007366711674463546017756 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/07/2004 # #------------------------------------------------------------------------------ """ Defines the Group class used to represent a group of items used in a Traits-based user interface. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from string \ import find from traits.api import (Bool, Delegate, Float, Instance, List, Property, Range, ReadOnly, Str, TraitError, cached_property) from traits.trait_base import enumerate from .view_element import ViewSubElement from .item import Item from .include import Include from .ui_traits import SequenceTypes, ATheme, ContainerDelegate, Orientation, Layout from .dock_window_theme import dock_window_theme, DockWindowTheme #------------------------------------------------------------------------------- # Trait definitions: #------------------------------------------------------------------------------- # Delegate trait to the object being "shadowed" ShadowDelegate = Delegate( 'shadow' ) # Amount of padding to add around item Padding = Range( 0, 15, desc = 'amount of padding to add around each item' ) #------------------------------------------------------------------------------- # 'Group' class: #------------------------------------------------------------------------------- class Group ( ViewSubElement ): """ Represents a grouping of items in a user interface view. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # A list of Group, Item, and Include objects in this group. content = List( ViewSubElement ) # A unique identifier for the group. id = Str # User interface label for the group. How the label is displayed depends # on the **show_border** attribute, and on the **layout** attribute of # the group's parent group or view. label = Str style_sheet = Str # Default context object for group items. object = ContainerDelegate # Default editor style of items in the group. style = ContainerDelegate # Default docking style of items in group. dock = ContainerDelegate # Default image to display on notebook tabs. image = ContainerDelegate # The theme to use for a DockWindow: dock_theme = Instance( DockWindowTheme, allow_none = False ) # The theme to use for the group itself: group_theme = ATheme # The theme to use for items contained in the group: item_theme = ContainerDelegate # The theme to use for the labels of items contained in the group: label_theme = ContainerDelegate # Category of elements dragged from view. export = ContainerDelegate # Spatial orientation of the group's elements. Can be 'vertical' (default) # or 'horizontal'. orientation = Orientation # Layout style of the group, which can be one of the following: # # * 'normal' (default): Sub-groups are displayed sequentially in a single # panel. # * 'flow': Sub-groups are displayed sequentially, and then "wrap" when # they exceed the available space in the **orientation** direction. # * 'split': Sub-groups are displayed in a single panel, separated by # "splitter bars", which the user can drag to adjust the amount of space # for each sub-group. # * 'tabbed': Each sub-group appears on a separate tab, labeled with the # sub-group's *label* text, if any. # # This attribute is ignored for groups that contain only items, or contain # only one sub-group. layout = Layout # Should the group be scrollable along the direction of orientation? scrollable = Bool( False ) # The number of columns in the group columns = Range( 1, 50 ) # Should a border be drawn around group? If set to True, the **label** text # is embedded in the border. If set to False, the label appears as a banner # above the elements of the group. show_border = Bool( False ) # Should labels be added to items in group? Only items that are directly # contained in the group are affected. That is, if the group contains # a sub-group, the display of labels in the sub-group is not affected by # the attribute on this group. show_labels = Bool( True ) # Should labels be shown to the left of items (True) or the right (False)? # Only items that are directly contained in the group are affected. That is, # if the group contains a sub-group, the display of labels in the sub-group # is not affected by the attribute in this group. If **show_labels** is # False, this attribute is irrelevant. show_left = Bool( True ) # Is this group the tab that is initially selected? If True, the group's # tab is displayed when the view is opened. If the **layout** of the group's # parent is not 'tabbed', this attribute is ignored. selected = Bool( False ) # Should the group use extra space along its parent group's layout # orientation? springy = Bool( False ) # Optional help text (for top-level group). This help text appears in the # View-level help window (created by the default help handler), for any # View that contains *only* this group. Group-level help is ignored for # nested groups and multiple top-level groups help = Str # Pre-condition for including the group in the display. If the expression # evaluates to False, the group is not defined in the display. Conditions # for **defined_when** are evaluated only once, when the display is first # constructed. Use this attribute for conditions based on attributes that # vary from object to object, but that do not change over time. defined_when = Str # Pre-condition for showing the group. If the expression evaluates to False, # the group and its items are not visible (and they disappear if they were # previously visible). If the value evaluates to True, the group and items # become visible. All **visible_when** conditions are checked each time # that any trait value is edited in the display. Therefore, you can use # **visible_when** conditions to hide or show groups in response to user # input. visible_when = Str # Pre-condition for enabling the group. If the expression evaluates to False, # the group is disabled, that is, none of the widgets accept input. All # **enabled_when** conditions are checked each time that any trait value # is edited in the display. Therefore, you can use **enabled_when** # conditions to enable or disable groups in response to user input. enabled_when = Str # Amount of padding (in pixels) to add around each item in the group. The # value must be an integer between 0 and 15. (Unlike the Item class, the # Group class does not support negative padding.) The padding for any # individual widget is the sum of the padding for its Group, the padding # for its Item, and the default spacing determined by the toolkit. padding = Padding # Requested width of the group (calculated from widths of contents) width = Property( Float, depends_on='content' ) # Requested height of the group (calculated from heights of contents) height = Property( Float, depends_on='content' ) #--------------------------------------------------------------------------- # Initializes the object: #--------------------------------------------------------------------------- def __init__ ( self, *values, **traits ): """ Initializes the group object. """ super( ViewSubElement, self ).__init__( **traits ) content = self.content # Process any embedded Group options first: for value in values: if (isinstance(value, basestring)) and (value[0:1] in '-|'): # Parse Group trait options if specified as a string: self._parse( value ) # Process all of the data passed to the constructor: for value in values: if isinstance( value, ViewSubElement ): content.append( value ) elif type( value ) in SequenceTypes: # Map (...) or [...] to a Group(): content.append( Group( *value ) ) elif isinstance( value, basestring ): if value[0:1] in '-|': # We've already parsed Group trait options above: pass elif (value[:1] == '<') and (value[-1:] == '>'): # Convert string to an Include value: content.append( Include( value[1:-1].strip() ) ) else: # Else let the Item class try to make sense of it: content.append( Item( value ) ) else: raise TypeError, "Unrecognized argument type: %s" % value # Make sure this Group is the container for all its children: self.set_container() #-- Default Trait Values --------------------------------------------------- def _dock_theme_default ( self ): return dock_window_theme() #--------------------------------------------------------------------------- # Gets the label to use for a specified Group in a specified UI: #--------------------------------------------------------------------------- def get_label ( self, ui ): """ Gets the label to use this group. """ if self.label != '': return self.label return 'Group' #--------------------------------------------------------------------------- # Returns whether or not the object is replacable by an Include object: #--------------------------------------------------------------------------- def is_includable ( self ): """ Returns a Boolean value indicating whether the object is replacable by an Include object. """ return (self.id != '') #--------------------------------------------------------------------------- # Replaces any items which have an 'id' with an Include object with the # same 'id', and puts the object with the 'id' into the specified # ViewElements object: #--------------------------------------------------------------------------- def replace_include ( self, view_elements ): """ Replaces any items that have an **id** attribute with an Include object with the same ID value, and puts the object with the ID into the specified ViewElements object. Parameters ---------- view_elements : ViewElements object A set of Group, Item, and Include objects """ for i, item in enumerate( self.content ): if item.is_includable(): id = item.id if id in view_elements.content: raise TraitError, \ "Duplicate definition for view element '%s'" % id self.content[ i ] = Include( id ) view_elements.content[ id ] = item item.replace_include( view_elements ) #--------------------------------------------------------------------------- # Returns a ShadowGroup for the Group which recursively resolves all # imbedded Include objects and which replaces all imbedded Group objects # with a corresponding ShadowGroup: #--------------------------------------------------------------------------- def get_shadow ( self, ui ): """ Returns a ShadowGroup object for the current Group object, which recursively resolves all embedded Include objects and which replaces each embedded Group object with a corresponding ShadowGroup. """ content = [] groups = 0 level = ui.push_level() for value in self.content: # Recursively replace Include objects: while isinstance( value, Include ): value = ui.find( value ) # Convert Group objects to ShadowGroup objects, but include Item # objects as is (ignore any 'None' values caused by a failed # Include): if isinstance( value, Group ): if self._defined_when( ui, value ): content.append( value.get_shadow( ui ) ) groups += 1 elif isinstance( value, Item ): if self._defined_when( ui, value ): content.append( value ) ui.pop_level( level ) # Return the ShadowGroup: return ShadowGroup( shadow = self, content = content, groups = groups ) #--------------------------------------------------------------------------- # Sets the correct container for the content: #--------------------------------------------------------------------------- def set_container ( self ): """ Sets the correct container for the content. """ for item in self.content: item.container = self #--------------------------------------------------------------------------- # Returns whether the object should be defined in the user interface: #--------------------------------------------------------------------------- def _defined_when ( self, ui, value ): """ Should the object be defined in the user interface? """ if value.defined_when == '': return True return ui.eval_when( value.defined_when ) #--------------------------------------------------------------------------- # Parses Group options specified as a string: #--------------------------------------------------------------------------- def _parse ( self, value ): """ Parses Group options specified as a string. """ # Override the defaults, since we only allow 'True' values to be # specified: self.show_border = self.show_labels = self.show_left = False # Parse all of the single or multi-character options: value, empty = self._parse_label( value ) value = self._parse_style( value ) value = self._option( value, '-', 'orientation', 'horizontal' ) value = self._option( value, '|', 'orientation', 'vertical' ) value = self._option( value, '=', 'layout', 'split' ) value = self._option( value, '^', 'layout', 'tabbed' ) value = self._option( value, '>', 'show_labels', True ) value = self._option( value, '<', 'show_left', True ) value = self._option( value, '!', 'selected', True ) show_labels = not (self.show_labels and self.show_left) self.show_left = not self.show_labels self.show_labels = show_labels # Parse all of the punctuation based sub-string options: value = self._split( 'id', value, ':', find, 0, 1 ) if value != '': self.object = value #--------------------------------------------------------------------------- # Handles a label being found in the string definition: #--------------------------------------------------------------------------- def _parsed_label ( self ): """ Handles a label being found in the string definition. """ self.show_border = True #--------------------------------------------------------------------------- # Returns a 'pretty print' version of the Group: #--------------------------------------------------------------------------- def __repr__ ( self ): """ Returns a "pretty print" version of the Group. """ result = [] items = ',\n'.join( [ item.__repr__() for item in self.content ] ) if len( items ) > 0: result.append( items ) options = self._repr_options( 'orientation', 'show_border', 'show_labels', 'show_left', 'selected', 'id', 'object', 'label', 'style', 'layout', 'style_sheet' ) if options is not None: result.append( options ) content = ',\n'.join( result ) if len( content ) == 0: return self.__class__.__name__ + '()' return '%s(\n%s\n)' % ( self.__class__.__name__, self._indent( content ) ) #--------------------------------------------------------------------------- # Property getters/setters for width/height attributes #--------------------------------------------------------------------------- @cached_property def _get_width ( self ): """ Returns the requested width of the Group. """ width = 0.0 for item in self.content: if item.width >= 1: if self.orientation == 'horizontal': width += item.width elif self.orientation == 'vertical': width = max( width, item.width ) if width == 0: width = -1.0 return width @cached_property def _get_height ( self ): """ Returns the requested height of the Group. """ height = 0.0 for item in self.content: if item.height >= 1: if self.orientation == 'horizontal': height = max( height, item.height ) elif self.orientation == 'vertical': height += item.height if height == 0: height = -1.0 return height #------------------------------------------------------------------------------- # 'HGroup' class: #------------------------------------------------------------------------------- class HGroup ( Group ): """ A group whose items are laid out horizontally. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Override standard Group trait defaults to give it horizontal group # behavior: orientation = 'horizontal' #------------------------------------------------------------------------------- # 'VGroup' class: #------------------------------------------------------------------------------- class VGroup ( Group ): """ A group whose items are laid out vertically. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Override standard Group trait defaults to give it vertical group behavior: orientation = 'vertical' #------------------------------------------------------------------------------- # 'VGrid' class: #------------------------------------------------------------------------------- class VGrid ( VGroup ): """ A group whose items are laid out in 2 columns. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Override standard Group trait defaults to give it grid behavior: columns = 2 #------------------------------------------------------------------------------- # 'HFlow' class: #------------------------------------------------------------------------------- class HFlow ( HGroup ): """ A group in which items are laid out horizontally, and "wrap" when they exceed the available horizontal space.. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Override standard Group trait defaults to give it horizontal flow # behavior: layout = 'flow' show_labels = False #------------------------------------------------------------------------------- # 'VFlow' class: #------------------------------------------------------------------------------- class VFlow ( VGroup ): """ A group in which items are laid out vertically, and "wrap" when they exceed the available vertical space. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Override standard Group trait defaults to give it vertical flow behavior: layout = 'flow' show_labels = False #------------------------------------------------------------------------------- # 'VFold' class: #------------------------------------------------------------------------------- class VFold ( VGroup ): """ A group in which items are laid out vertically and can be collapsed (i.e. 'folded') by clicking their title. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Override standard Group trait defaults to give it vertical folding group # behavior: layout = 'fold' show_labels = False #------------------------------------------------------------------------------- # 'HSplit' class: #------------------------------------------------------------------------------- class HSplit ( Group ): """ A horizontal group with splitter bars to separate it from other groups. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Override standard Group trait defaults to give it horizontal splitter # behavior: layout = 'split' orientation = 'horizontal' #------------------------------------------------------------------------------- # 'VSplit' class: #------------------------------------------------------------------------------- class VSplit ( Group ): """ A vertical group with splitter bars to separate it from other groups. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Override standard Group trait defaults to give it vertical splitter # behavior: layout = 'split' orientation = 'vertical' #------------------------------------------------------------------------------- # 'Tabbed' class: #------------------------------------------------------------------------------- class Tabbed ( Group ): """ A group that is shown as a tabbed notebook. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Override standard Group trait defaults to give it tabbed notebook # behavior: layout = 'tabbed' springy = True #------------------------------------------------------------------------------- # 'ShadowGroup' class: #------------------------------------------------------------------------------- class ShadowGroup ( Group ): """ Corresponds to a Group object, but with all embedded Include objects resolved, and with all embedded Group objects replaced by corresponding ShadowGroup objects. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Group object this is a "shadow" for shadow = ReadOnly # Number of ShadowGroups in **content** groups = ReadOnly # Name of the group id = ShadowDelegate # User interface label for the group label = ShadowDelegate # Default context object for group items object = ShadowDelegate # Default style of items in the group style = ShadowDelegate # Default docking style of items in the group dock = ShadowDelegate # Default image to display on notebook tabs image = ShadowDelegate # The theme to use for a DockWindow: dock_theme = ShadowDelegate # The theme to use for the group itself: group_theme = ShadowDelegate # The theme to use for item's contained in the group: item_theme = ShadowDelegate # The theme to use for the labels of items contained in the group: label_theme = ShadowDelegate # Category of elements dragged from the view export = ShadowDelegate # Spatial orientation of the group orientation = ShadowDelegate # Layout style of the group layout = ShadowDelegate # Should the group be scrollable along the direction of orientation? scrollable = ShadowDelegate # The number of columns in the group columns = ShadowDelegate # Should a border be drawn around group? show_border = ShadowDelegate # Should labels be added to items in group? show_labels = ShadowDelegate # Should labels be shown to the left of items (vs. the right)? show_left = ShadowDelegate # Is group the initially selected page? selected = ShadowDelegate # Should the group use extra space along its parent group's layout # orientation? springy = ShadowDelegate # Optional help text (for top-level group) help = ShadowDelegate # Pre-condition for defining the group defined_when = ShadowDelegate # Pre-condition for showing the group visible_when = ShadowDelegate # Pre-condition for enabling the group enabled_when = ShadowDelegate # Amount of padding to add around each item padding = ShadowDelegate # Style sheet for the panel style_sheet = ShadowDelegate #--------------------------------------------------------------------------- # Returns the contents of the ShadowGroup within a specified user interface # building context. This makes sure that all Group types are of the same # type (i.e. Group or Item) and that all Include objects have been replaced # by their substituted values: #--------------------------------------------------------------------------- def get_content ( self, allow_groups = True ): """ Returns the contents of the Group within a specified context for building a user interface. This method makes sure that all Group types are of the same type (i.e., Group or Item) and that all Include objects have been replaced by their substituted values. """ # Make a copy of the content: result = self.content[:] # If result includes any ShadowGroups and they are not allowed, # replace them: if self.groups != 0: if not allow_groups: i = 0 while i < len( result ): value = result[i] if isinstance( value, ShadowGroup ): items = value.get_content( False ) result[i:i+1] = items i += len( items ) else: i += 1 elif (self.groups != len( result )) and (self.layout == 'normal'): items = [] content = [] for item in result: if isinstance( item, ShadowGroup ): self._flush_items( content, items ) content.append( item ) else: items.append( item ) self._flush_items( content, items ) result = content # Return the resulting list of objects: return result #--------------------------------------------------------------------------- # Returns an id used to identify the group: #--------------------------------------------------------------------------- def get_id ( self ): """ Returns an ID for the group. """ if self.id != '': return self.id return ':'.join( [ item.get_id() for item in self.get_content() ] ) #--------------------------------------------------------------------------- # Sets the correct container for the content: #--------------------------------------------------------------------------- def set_container ( self ): """ Sets the correct container for the content. """ pass #--------------------------------------------------------------------------- # Creates a sub-Group for any items contained in a specified list: #--------------------------------------------------------------------------- def _flush_items ( self, content, items ): """ Creates a sub-group for any items contained in a specified list. """ if len( items ) > 0: content.append( ShadowGroup( shadow = self.shadow, groups = 0, label = '', show_border = False, content = items ).set( show_labels = self.show_labels, show_left = self.show_left, springy = self.springy, orientation = self.orientation ) ) del items[:] #--------------------------------------------------------------------------- # Returns a 'pretty print' version of the Group: #--------------------------------------------------------------------------- def __repr__ ( self ): """ Returns a "pretty print" version of the Group. """ return repr( self.shadow ) traitsui-4.1.0/traitsui/editor.py0000644000175100001440000006042311674463546020072 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/07/2004 # #------------------------------------------------------------------------------ """ Defines the abstract Editor class, which represents an editing control for an object trait in a Traits-based user interface. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import (Any, Bool, HasPrivateTraits, HasTraits, Instance, Property, ReadOnly, Str, Trait, TraitError, TraitListEvent, Undefined, cached_property) from traits.trait_base import not_none from .editor_factory import EditorFactory from .context_value import ContextValue from .undo import UndoItem from .item import Item #------------------------------------------------------------------------------- # Trait definitions: #------------------------------------------------------------------------------- # Reference to an EditorFactory object factory_trait = Trait( EditorFactory ) #------------------------------------------------------------------------------- # 'Editor' abstract base class: #------------------------------------------------------------------------------- class Editor ( HasPrivateTraits ): """ Represents an editing control for an object trait in a Traits-based user interface. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # The UI (user interface) this editor is part of: ui = Instance( 'traitsui.ui.UI' ) # Full name of the object the editor is editing (e.g. 'object.link1.link2'): object_name = Str( 'object' ) # The object this editor is editing (e.g. object.link1.link2): object = Instance( HasTraits ) # The name of the trait this editor is editing (e.g. 'value'): name = ReadOnly # The context object the editor is editing (e.g. object): context_object = Property # The extended name of the object trait being edited. That is, # 'object_name.name' minus the context object name at the beginning. For # example: 'link1.link2.value': extended_name = Property # Original value of object.name (e.g. object.link1.link2.value): old_value = Any # Text description of the object trait being edited: description = ReadOnly # The Item object used to create this editor: item = Instance( Item, () ) # The GUI widget defined by this editor: control = Any # The GUI label (if any) defined by this editor: label_control = Any # Is the underlying GUI widget enabled? enabled = Bool( True ) # Is the underlying GUI widget visible? visible = Bool( True ) # Is the underlying GUI widget scrollable? scrollable = Bool( False ) # The EditorFactory used to create this editor: factory = factory_trait # Is the editor updating the object.name value? updating = Bool( False ) # Current value for object.name: value = Property # Current value of object trait as a string: str_value = Property # The trait the editor is editing (not its value, but the trait itself): value_trait = Property # The current editor invalid state status: invalid = Bool( False ) #--------------------------------------------------------------------------- # Initializes the object: #--------------------------------------------------------------------------- def __init__ ( self, parent, **traits ): """ Initializes the editor object. """ HasPrivateTraits.__init__( self, **traits ) try: self.old_value = getattr( self.object, self.name ) except AttributeError, ex: if ex.args[0].endswith("instance is an 'event', which is write only.") or self.name == 'spring' : # Getting the attribute will fail for 'Event' traits: self.old_value = Undefined else : raise # Synchronize the application invalid state status with the editor's: self.sync_value( self.factory.invalid, 'invalid', 'from' ) #--------------------------------------------------------------------------- # Finishes editor set-up: #--------------------------------------------------------------------------- def prepare ( self, parent ): """ Finishes setting up the editor. """ name = self.extended_name if name != 'None': self.context_object.on_trait_change( self._update_editor, name, dispatch = 'ui' ) self.init( parent ) self._sync_values() self.update_editor() #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ raise NotImplementedError #--------------------------------------------------------------------------- # Assigns focus to the editor's underlying toolkit widget: #--------------------------------------------------------------------------- def set_focus ( self ): """ Assigns focus to the editor's underlying toolkit widget. """ raise NotImplementedError #--------------------------------------------------------------------------- # Disposes of the contents of an editor: #--------------------------------------------------------------------------- def dispose ( self ): """ Disposes of the contents of an editor. """ if self.ui is None: return name = self.extended_name if name != 'None': self.context_object.on_trait_change( self._update_editor, name, remove = True ) if self._user_from is not None: for name, handler in self._user_from: self.on_trait_change( handler, name, remove = True ) if self._user_to is not None: for object, name, handler in self._user_to: object.on_trait_change( handler, name, remove = True ) # Break linkages to references we no longer need: self.object = self.ui = self.item = self.factory = self.control = \ self.label_control = self.old_value = self._context_object = None #--------------------------------------------------------------------------- # Returns the context object the editor is using (Property implementation): #--------------------------------------------------------------------------- @cached_property def _get_context_object ( self ): """ Returns the context object the editor is using (Property implementation). """ object_name = self.object_name context_key = object_name.split( '.', 1 )[0] if (object_name != '') and (context_key in self.ui.context): return self.ui.context[ context_key ] # This handles the case of a 'ListItemProxy', which is not in the # ui.context, but is the editor 'object': return self.object #--------------------------------------------------------------------------- # Returns the extended trait name being edited (Property implementation): #--------------------------------------------------------------------------- @cached_property def _get_extended_name ( self ): """ Returns the extended trait name being edited (Property implementation). """ return ('%s.%s' % ( self.object_name, self.name )).split( '.', 1 )[1] #--------------------------------------------------------------------------- # Returns the trait the editor is editing (Property implementation): #--------------------------------------------------------------------------- def _get_value_trait ( self ): """ Returns the trait the editor is editing (Property implementation). """ return self.object.trait( self.name ) #--------------------------------------------------------------------------- # Gets/Sets the associated object trait's value: #--------------------------------------------------------------------------- def _get_value ( self ): return getattr( self.object, self.name, Undefined ) def _set_value ( self, value ): if self.name != 'None': self.ui.do_undoable( self.__set_value, value ) def __set_value ( self, value ): self._no_update = True try: try: handler = self.ui.handler obj_name = self.object_name name = self.name method = (getattr( handler, '%s_%s_setattr' % ( obj_name, name ), None ) or getattr( handler, '%s_setattr' % name, None ) or getattr( handler, 'setattr' )) method( self.ui.info, self.object, name, value ) except TraitError, excp: self.error( excp ) raise finally: self._no_update = False #--------------------------------------------------------------------------- # Returns the text representation of a specified object trait value: #--------------------------------------------------------------------------- def string_value ( self, value, format_func = None ): """ Returns the text representation of a specified object trait value. If the **format_func** attribute is set on the editor factory, then this method calls that function to do the formatting. If the **format_str** attribute is set on the editor factory, then this method uses that string for formatting. If neither attribute is set, then this method just calls the built-in unicode() function. """ factory = self.factory if factory.format_func is not None: return factory.format_func( value ) if factory.format_str != '': return factory.format_str % value if format_func is not None: return format_func( value ) return unicode( value ) #--------------------------------------------------------------------------- # Returns the text representation of the object trait: #--------------------------------------------------------------------------- def _get_str_value ( self ): """ Returns the text representation of the object trait. """ return self.string_value( getattr( self.object, self.name, Undefined ) ) #--------------------------------------------------------------------------- # Returns the text representation of a specified value: #--------------------------------------------------------------------------- def _str ( self, value ): """ Returns the text representation of a specified value. """ # In Unicode! return unicode( value ) #--------------------------------------------------------------------------- # Handles an error that occurs while setting the object's trait value: # # (Should normally be overridden in a subclass) #--------------------------------------------------------------------------- def error ( self, excp ): """ Handles an error that occurs while setting the object's trait value. """ pass #--------------------------------------------------------------------------- # Performs updates when the object trait changes: #--------------------------------------------------------------------------- def _update_editor ( self, object, name, old_value, new_value ): """ Performs updates when the object trait changes. """ # If background threads have modified the trait the editor is bound to, # their trait notifications are queued to the UI thread. It is possible # that by the time the UI thread dispatches these events, the UI the # editor is part of has already been closed. So we need to check if we # are still bound to a live UI, and if not, exit immediately: if self.ui is None: return # If the notification is for an object different than the one actually # being edited, it is due to editing an item of the form: # object.link1.link2.name, where one of the 'link' objects may have # been modified. In this case, we need to rebind the current object # being edited: if object is not self.object: self.object = eval( self.object_name, globals(), self.ui.context ) # If the editor has gone away for some reason, disconnect and exit: if self.control is None: self.context_object.on_trait_change( self._update_editor, self.extended_name, remove = True ) return # Log the change that was made (as long as it is not for an event): if object.base_trait( name ).type != 'event': self.log_change( self.get_undo_item, object, name, old_value, new_value ) # If the change was not caused by the editor itself: if not self._no_update: # Update the editor control to reflect the current object state: self.update_editor() #--------------------------------------------------------------------------- # Logs a change made in the editor: #--------------------------------------------------------------------------- def log_change ( self, undo_factory, *undo_args ): """ Logs a change made in the editor. """ # Indicate that the contents of the user interface have been changed: ui = self.ui ui.modified = True # Create an undo history entry if we are maintaining a history: undoable = ui._undoable if undoable >= 0: history = ui.history if history is not None: item = undo_factory( *undo_args ) if item is not None: if undoable == history.now: # Create a new undo transaction: history.add( item ) else: # Extend the most recent undo transaction: history.extend( item ) #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: # # (Should normally be overridden in a subclass) #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ pass #--------------------------------------------------------------------------- # Creates an undo history entry: # # (Can be overridden in a subclass for special value types) #--------------------------------------------------------------------------- def get_undo_item ( self, object, name, old_value, new_value ): """ Creates an undo history entry. """ return UndoItem( object = object, name = name, old_value = old_value, new_value = new_value ) #--------------------------------------------------------------------------- # Returns a tuple of the form ( context_object, name[.name...], callable ) # for a specified extended name of the form: name or # context_object_name.name[.name...]: #--------------------------------------------------------------------------- def parse_extended_name ( self, name ): """ Returns a tuple of the form ( context_object, 'name[.name...], callable ) for a specified extended name of the form: 'name' or 'context_object_name.name[.name...]'. """ col = name.find( '.' ) if col < 0: object = self.context_object else: object, name = self.ui.context[ name[ : col ] ], name[ col + 1: ] return ( object, name, eval( "lambda obj=object: obj." + name ) ) #--------------------------------------------------------------------------- # Initializes and synchronizes (as needed) editor traits with the value of # corresponding factory traits: #--------------------------------------------------------------------------- def _sync_values ( self ): """ Initializes and synchronizes (as needed) editor traits with the value of corresponding factory traits. """ factory = self.factory for name, trait in factory.traits( sync_value = not_none ): value = getattr( factory, name ) if isinstance( value, ContextValue ): self_trait = self.trait( name ) self.sync_value( value.name, name, self_trait.sync_value or trait.sync_value, self_trait.is_list is True ) elif value is not Undefined: setattr( self, name, value ) #--------------------------------------------------------------------------- # Sets/Unsets synchronization between an editor trait and a user object # trait: #--------------------------------------------------------------------------- def sync_value ( self, user_name, editor_name, mode = 'both', is_list = False ): """ Sets or unsets synchronization between an editor trait and a user object trait. """ if user_name != '': key = '%s:%s' % ( user_name, editor_name ) if self._no_trait_update is None: self._no_trait_update = {} user_ref = 'user_object' col = user_name.find( '.' ) if col < 0: user_object = self.context_object xuser_name = user_name else: user_object = self.ui.context[ user_name[ : col ] ] user_name = xuser_name = user_name[ col + 1: ] col = user_name.rfind( '.' ) if col >= 0: user_ref += ('.' + user_name[ : col ]) user_name = user_name[ col + 1: ] user_value = compile( '%s.%s' % ( user_ref, user_name ), '', 'eval' ) user_ref = compile( user_ref, '', 'eval' ) if mode in ( 'from', 'both' ): def user_trait_modified ( new ): # Need this to include 'user_object' in closure: user_object if key not in self._no_trait_update: self._no_trait_update[ key ] = None try: setattr( self, editor_name, new ) except: from traitsui.api import raise_to_debug raise_to_debug() del self._no_trait_update[ key ] user_object.on_trait_change( user_trait_modified, xuser_name ) if self._user_to is None: self._user_to = [] self._user_to.append( ( user_object, xuser_name, user_trait_modified ) ) if is_list: def user_list_modified ( event ): if isinstance( event, TraitListEvent ): if key not in self._no_trait_update: self._no_trait_update[ key ] = None n = event.index try: getattr( self, editor_name )[ n: n + len(event.removed)] = event.added except: from traitsui.api import raise_to_debug raise_to_debug() del self._no_trait_update[ key ] user_object.on_trait_change( user_list_modified, xuser_name + '_items' ) self._user_to.append( ( user_object, xuser_name + '_items', user_list_modified ) ) try: setattr( self, editor_name, eval( user_value ) ) except: from traitsui.api import raise_to_debug raise_to_debug() if mode in ( 'to', 'both' ): def editor_trait_modified ( new ): # Need this to include 'user_object' in closure: user_object if key not in self._no_trait_update: self._no_trait_update[ key ] = None try: setattr( eval( user_ref ), user_name, new ) except: from traitsui.api import raise_to_debug raise_to_debug() del self._no_trait_update[ key ] self.on_trait_change( editor_trait_modified, editor_name ) if self._user_from is None: self._user_from = [] self._user_from.append( ( editor_name, editor_trait_modified ) ) if is_list: def editor_list_modified ( event ): # Need this to include 'user_object' in closure: user_object if key not in self._no_trait_update: self._no_trait_update[ key ] = None n = event.index try: eval( user_value )[ n: n + len( event.removed ) ] = event.added except: from traitsui.api import raise_to_debug raise_to_debug() del self._no_trait_update[ key ] self.on_trait_change( editor_list_modified, editor_name + '_items' ) self._user_from.append( ( editor_name + '_items', editor_list_modified ) ) if mode == 'to': try: setattr( eval( user_ref ), user_name, getattr( self, editor_name ) ) except: from traitsui.api import raise_to_debug raise_to_debug() #-- UI preference save/restore interface ----------------------------------- #--------------------------------------------------------------------------- # Restores any saved user preference information associated with the # editor: #--------------------------------------------------------------------------- def restore_prefs ( self, prefs ): """ Restores any saved user preference information associated with the editor. """ pass #--------------------------------------------------------------------------- # Returns any user preference information associated with the editor: #--------------------------------------------------------------------------- def save_prefs ( self ): """ Returns any user preference information associated with the editor. """ return None traitsui-4.1.0/traitsui/toolkit.py0000644000175100001440000004606411674463546020276 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/07/2004 # #------------------------------------------------------------------------------ """ Defines the stub functions used for creating concrete implementations of the standard EditorFactory subclasses supplied with the Traits package. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import HasPrivateTraits, TraitError from traits.trait_base import ETSConfig #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- # List of implemented UI toolkits: TraitUIToolkits = [ 'wx', 'qt4', 'null' ] #------------------------------------------------------------------------------- # Data: #------------------------------------------------------------------------------- # The current GUI toolkit object being used: _toolkit = None #------------------------------------------------------------------------------- # Low-level GUI toolkit selection function: #------------------------------------------------------------------------------- def _import_toolkit ( name ): return __import__( name, globals=globals(), level=1 ).toolkit def assert_toolkit_import(name): """ Raise an error if a toolkit with the given name should not be allowed to be imported. """ if ETSConfig.toolkit and ETSConfig.toolkit != name: raise RuntimeError, "Importing from %s backend after selecting %s " \ "backend!" % (name, ETSConfig.toolkit) def toolkit_object(name, raise_exceptions=False): """ Return the toolkit specific object with the given name. The name consists of the relative module path and the object name separated by a colon. """ mname, oname = name.split(':') class Unimplemented ( object ): """ This is returned if an object isn't implemented by the selected toolkit. It raises an exception if it is ever instantiated. """ def __init__( self, *args, **kwargs ): raise NotImplementedError( "The %s traits backend doesn't " "implement %s" % ( ETSConfig.toolkit, oname ) ) be_obj = Unimplemented be_mname = toolkit().__module__.split('.')[-2] + '.' + mname try: module = __import__( be_mname, globals=globals(), fromlist=[oname], level=1 ) try: be_obj = getattr(module, oname) except AttributeError, e: if raise_exceptions: raise e except ImportError, e: if raise_exceptions: raise e return be_obj def toolkit ( *toolkits ): """ Selects and returns a low-level GUI toolkit. Use this function to get a reference to the current toolkit. """ global _toolkit # If _toolkit has already been set, simply return it. if _toolkit is not None: return _toolkit if ETSConfig.toolkit: # If a toolkit has already been set for ETSConfig, then use it: _toolkit = _import_toolkit(ETSConfig.toolkit) return _toolkit else: if len( toolkits ) == 0: toolkits = TraitUIToolkits for toolkit_name in toolkits: try: _toolkit = _import_toolkit( toolkit_name ) # In case we have just decided on a toolkit, tell everybody else: ETSConfig.toolkit = toolkit_name return _toolkit except (AttributeError, ImportError): pass else: # Try using the null toolkit and printing a warning try: _toolkit = _import_toolkit( 'null' ) import warnings warnings.warn( "Unable to import the '%s' backend for traits UI; " "using the 'null' toolkit instead." % toolkit_name ) return _toolkit except ImportError: raise TraitError( "Could not find any UI toolkit called '%s'" % toolkit_name ) #------------------------------------------------------------------------------- # 'Toolkit' class (abstract base class): #------------------------------------------------------------------------------- class Toolkit ( HasPrivateTraits ): """ Abstract base class for GUI toolkits. """ #--------------------------------------------------------------------------- # Create GUI toolkit specific user interfaces using information from the # specified UI object: #--------------------------------------------------------------------------- def ui_panel ( self, ui, parent ): """ Creates a GUI-toolkit-specific panel-based user interface using information from the specified UI object. """ raise NotImplementedError def ui_subpanel ( self, ui, parent ): """ Creates a GUI-toolkit-specific subpanel-based user interface using information from the specified UI object. """ raise NotImplementedError def ui_livemodal ( self, ui, parent ): """ Creates a GUI-toolkit-specific modal "live update" dialog user interface using information from the specified UI object. """ raise NotImplementedError def ui_live ( self, ui, parent ): """ Creates a GUI-toolkit-specific non-modal "live update" window user interface using information from the specified UI object. """ raise NotImplementedError def ui_modal ( self, ui, parent ): """ Creates a GUI-toolkit-specific modal dialog user interface using information from the specified UI object. """ raise NotImplementedError def ui_nonmodal ( self, ui, parent ): """ Creates a GUI-toolkit-specific non-modal dialog user interface using information from the specified UI object. """ raise NotImplementedError def ui_popup ( self, ui, parent ): """ Creates a GUI-toolkit-specific temporary "live update" popup dialog user interface using information from the specified UI object. """ raise NotImplementedError def ui_popover ( self, ui, parent ): """ Creates a GUI-toolkit-specific temporary "live update" popup dialog user interface using information from the specified UI object. """ raise NotImplementedError def ui_info ( self, ui, parent ): """ Creates a GUI-toolkit-specific temporary "live update" popup dialog user interface using information from the specified UI object. """ raise NotImplementedError def ui_wizard ( self, ui, parent ): """ Creates a GUI-toolkit-specific wizard dialog user interface using information from the specified UI object. """ raise NotImplementedError def view_application ( self, context, view, kind = None, handler = None, id = '', scrollable = None, args = None ): """ Creates a GUI-toolkit-specific modal dialog user interface that runs as a complete application using information from the specified View object. Parameters ---------- context : object or dictionary A single object or a dictionary of string/object pairs, whose trait attributes are to be edited. If not specified, the current object is used. view : view or string A View object that defines a user interface for editing trait attribute values. kind : string The type of user interface window to create. See the **traitsui.view.kind_trait** trait for values and their meanings. If *kind* is unspecified or None, the **kind** attribute of the View object is used. handler : Handler object A handler object used for event handling in the dialog box. If None, the default handler for Traits UI is used. id : string A unique ID for persisting preferences about this user interface, such as size and position. If not specified, no user preferences are saved. scrollable : Boolean Indicates whether the dialog box should be scrollable. When set to True, scroll bars appear on the dialog box if it is not large enough to display all of the items in the view at one time. """ raise NotImplementedError #--------------------------------------------------------------------------- # Positions the associated dialog window on the display: #--------------------------------------------------------------------------- def position ( self, ui ): """ Positions the associated dialog window on the display. """ raise NotImplementedError #--------------------------------------------------------------------------- # Shows a 'Help' window for a specified UI and control: #--------------------------------------------------------------------------- def show_help ( self, ui, control ): """ Shows a Help window for a specified UI and control. """ raise NotImplementedError #--------------------------------------------------------------------------- # Sets the title for the UI window: #--------------------------------------------------------------------------- def set_title ( self, ui ): """ Sets the title for the UI window. """ raise NotImplementedError #--------------------------------------------------------------------------- # Sets the icon for the UI window: #--------------------------------------------------------------------------- def set_icon ( self, ui ): """ Sets the icon for the UI window. """ raise NotImplementedError #--------------------------------------------------------------------------- # Saves user preference information associated with a UI window: #--------------------------------------------------------------------------- def save_window ( self, ui ): """ Saves user preference information associated with a UI window. """ raise NotImplementedError #--------------------------------------------------------------------------- # Rebuilds a UI after a change to the content of the UI: #--------------------------------------------------------------------------- def rebuild_ui ( self, ui ): """ Rebuilds a UI after a change to the content of the UI. """ raise NotImplementedError #--------------------------------------------------------------------------- # Converts a keystroke event into a corresponding key name: #--------------------------------------------------------------------------- def key_event_to_name ( self, event ): """ Converts a keystroke event into a corresponding key name. """ raise NotImplementedError #--------------------------------------------------------------------------- # Hooks all specified events for all controls in a ui so that they can be # routed to the corrent event handler: #--------------------------------------------------------------------------- def hook_events ( self, ui, control, events = None, handler = None ): """ Hooks all specified events for all controls in a UI so that they can be routed to the correct event handler. """ raise NotImplementedError #--------------------------------------------------------------------------- # Routes a 'hooked' event to the corrent handler method: #--------------------------------------------------------------------------- def route_event ( self, ui, event ): """ Routes a "hooked" event to the corrent handler method. """ raise NotImplementedError #--------------------------------------------------------------------------- # Indicates that an event should continue to be processed by the toolkit #--------------------------------------------------------------------------- def skip_event ( self, event ): """ Indicates that an event should continue to be processed by the toolkit. """ raise NotImplementedError #--------------------------------------------------------------------------- # Destroys a specified GUI toolkit control: #--------------------------------------------------------------------------- def destroy_control ( self, control ): """ Destroys a specified GUI toolkit control. """ raise NotImplementedError #--------------------------------------------------------------------------- # Destroys all of the child controls of a specified GUI toolkit control: #--------------------------------------------------------------------------- def destroy_children ( self, control ): """ Destroys all of the child controls of a specified GUI toolkit control. """ raise NotImplementedError #--------------------------------------------------------------------------- # Returns a ( width, height ) tuple containing the size of a specified # toolkit image: #--------------------------------------------------------------------------- def image_size ( self, image ): """ Returns a ( width, height ) tuple containing the size of a specified toolkit image. """ raise NotImplementedError #--------------------------------------------------------------------------- # Returns a dictionary of useful constants: #--------------------------------------------------------------------------- def constants ( self ): """ Returns a dictionary of useful constants. Currently, the dictionary should have the following key/value pairs: - WindowColor': the standard window background color in the toolkit specific color format. """ raise NotImplementedError #--------------------------------------------------------------------------- # Returns a renderer used to render 'themed' table cells for a specified # TableColumn object: #--------------------------------------------------------------------------- def themed_cell_renderer ( self, column ): """ Returns a renderer used to render 'themed' table cells for a specified TableColum object. """ raise NotImplementedError #--------------------------------------------------------------------------- # GUI toolkit dependent trait definitions: #--------------------------------------------------------------------------- def color_trait ( self, *args, **traits ): raise NotImplementedError def rgb_color_trait ( self, *args, **traits ): raise NotImplementedError def rgba_color_trait ( self, *args, **traits ): raise NotImplementedError def font_trait ( self, *args, **traits ): raise NotImplementedError def kiva_font_trait ( self, *args, **traits ): raise NotImplementedError #--------------------------------------------------------------------------- # 'Editor' class methods: #--------------------------------------------------------------------------- def ui_editor ( self ): raise NotImplementedError #--------------------------------------------------------------------------- # 'EditorFactory' factory methods: #--------------------------------------------------------------------------- def array_editor ( self, *args, **traits ): raise NotImplementedError def boolean_editor ( self, *args, **traits ): raise NotImplementedError def button_editor ( self, *args, **traits ): raise NotImplementedError def check_list_editor ( self, *args, **traits ): raise NotImplementedError def code_editor ( self, *args, **traits ): raise NotImplementedError def color_editor ( self, *args, **traits ): raise NotImplementedError def compound_editor ( self, *args, **traits ): raise NotImplementedError def custom_editor ( self, *args, **traits ): raise NotImplementedError def directory_editor ( self, *args, **traits ): raise NotImplementedError def drop_editor ( self, *args, **traits ): raise NotImplementedError def dnd_editor ( self, *args, **traits ): raise NotImplementedError def enum_editor ( self, *args, **traits ): raise NotImplementedError def file_editor ( self, *args, **traits ): raise NotImplementedError def font_editor ( self, *args, **traits ): raise NotImplementedError def key_binding_editor ( self, *args, **traits ): raise NotImplementedError def history_editor ( self, *args, **traits ): raise NotImplementedError def html_editor ( self, *args, **traits ): raise NotImplementedError def image_editor ( self, *args, **traits ): raise NotImplementedError def image_enum_editor ( self, *args, **traits ): raise NotImplementedError def instance_editor ( self, *args, **traits ): raise NotImplementedError def list_editor ( self, *args, **traits ): raise NotImplementedError def list_str_editor ( self, *args, **traits ): raise NotImplementedError def null_editor ( self, *args, **traits ): raise NotImplementedError def ordered_set_editor ( self, *args, **traits ): raise NotImplementedError def plot_editor ( self, *args, **traits ): raise NotImplementedError def range_editor ( self, *args, **traits ): raise NotImplementedError def rgb_color_editor ( self, *args, **traits ): raise NotImplementedError def rgba_color_editor ( self, *args, **traits ): raise NotImplementedError def shell_editor ( self, *args, **traits ): raise NotImplementedError def table_editor ( self, *args, **traits ): raise NotImplementedError def tabular_editor ( self, *args, **traits ): raise NotImplementedError def text_editor ( self, *args, **traits ): raise NotImplementedError def title_editor ( self, *args, **traits ): raise NotImplementedError def tree_editor ( self, *args, **traits ): raise NotImplementedError def tuple_editor ( self, *args, **traits ): raise NotImplementedError def value_editor ( self, *args, **traits ): raise NotImplementedError traitsui-4.1.0/traitsui/null/0000755000175100001440000000000011674463546017177 5ustar ischnellusers00000000000000traitsui-4.1.0/traitsui/null/tests/0000755000175100001440000000000011674463546020341 5ustar ischnellusers00000000000000traitsui-4.1.0/traitsui/null/tests/test_font_trait.py0000644000175100001440000000222711674463546024126 0ustar ischnellusers00000000000000 from nose.tools import assert_equals from traits.api import HasTraits, Font from traits.etsconfig.api import ETSConfig ETSConfig.toolkit = 'null' def test_font_trait_default(): class Foo(HasTraits): font = Font() f = Foo() assert_equals(f.font, '10 pt Arial') def test_font_trait_examples(): """ An assigned font string is parsed, and the substrings are put in the order: point size, family, style, weight, underline, facename The words 'pt, 'point' and 'family' are ignored. """ class Foo(HasTraits): font = Font f = Foo(font='Qwerty 10') assert_equals(f.font, '10 pt Qwerty') f = Foo(font='nothing') assert_equals(f.font, 'nothing') f = Foo(font='swiss family arial') assert_equals(f.font, 'swiss arial') f = Foo(font='12 pt bold italic') assert_equals(f.font, '12 pt italic bold') f = Foo(font='123 Foo bar slant') assert_equals(f.font, '123 pt slant Foo bar') f = Foo(font='123 point Foo family bar slant') assert_equals(f.font, '123 pt slant Foo bar') f = Foo(font='16 xyzzy underline slant') assert_equals(f.font, '16 pt slant underline xyzzy') traitsui-4.1.0/traitsui/null/toolkit.py0000644000175100001440000000611411674463546021240 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 02/14/2005 # #------------------------------------------------------------------------------ """ Defines the concrete implementations of the traits Toolkit interface for the 'null' (do nothing) user interface toolkit. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from ..toolkit import Toolkit from ..editor_factory import EditorFactory #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- # Create a dummy singleton editor factory: null_editor_factory = EditorFactory() #------------------------------------------------------------------------------- # 'GUIToolkit' class: #------------------------------------------------------------------------------- class GUIToolkit ( Toolkit ): #--------------------------------------------------------------------------- # GUI toolkit dependent trait definitions: #--------------------------------------------------------------------------- def color_trait ( self, *args, **traits ): from . import color_trait as ct return ct.NullColor( *args, **traits ) def rgb_color_trait ( self, *args, **traits ): from . import rgb_color_trait as rgbct return rgbct.RGBColor( *args, **traits ) def font_trait ( self, *args, **traits ): from . import font_trait as ft return ft.NullFont( *args, **traits ) def kiva_font_trait ( self, *args, **traits ): from . import font_trait as ft return ft.NullFont( *args, **traits ) def constants ( self, *args, **traits ): constants = {'WindowColor': ( 236 / 255.0, 233 / 255.0, 216 / 255.0, 1.0 )} return constants #--------------------------------------------------------------------------- # 'EditorFactory' factory methods: #--------------------------------------------------------------------------- def __getattribute__(self, attr): """ Return a method that returns null_editor_factory for any request to an unimplemented ``*_editor()`` method. This must be __getattribute__ to make sure that we override the definitions in the superclass which raise NotImplementedError. """ if attr.endswith('_editor'): return lambda *args, **kwds: null_editor_factory else: return super(GUIToolkit, self).__getattribute__(attr) traitsui-4.1.0/traitsui/null/font_trait.py0000644000175100001440000001052411674463546021724 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 02/14/2005 # #------------------------------------------------------------------------------ """ Trait definition for a null-based (i.e., no UI) font. """ #------------------------------------------------------------------------------ # Imports: #------------------------------------------------------------------------------ from __future__ import absolute_import from traits.api import Trait, TraitHandler, TraitError #------------------------------------------------------------------------------ # Convert a string into a valid 'wxFont' object (if possible): #------------------------------------------------------------------------------ # Mapping of strings to valid wxFont families font_families = [ 'default', 'decorative', 'roman', 'script', 'swiss', 'modern' ] # Mapping of strings to wxFont styles font_styles = [ 'slant', 'italic' ] # Mapping of strings wxFont weights font_weights = [ 'light', 'bold' ] # Strings to ignore in text representations of fonts font_noise = ['pt', 'point', 'family'] #------------------------------------------------------------------------------ # 'TraitFont' class' #------------------------------------------------------------------------------ class TraitFont(TraitHandler): """ Ensures that values assigned to a trait attribute are valid font descriptor strings; the value actually assigned is the corresponding canonical font descriptor string. """ #-------------------------------------------------------------------------- # Validates that the value is a valid font: #-------------------------------------------------------------------------- def validate(self, object, name, value): """ Validates that the value is a valid font descriptor string. """ try: point_size = family = style = weight = underline = '' facename = [''] for word in value.split(): lword = word.lower() if lword in font_families: family = ' ' + lword elif lword in font_styles: style = ' ' + lword elif lword in font_weights: weight = ' ' + lword elif lword == 'underline': underline = ' ' + lword elif lword not in font_noise: try: int(lword) point_size = lword + ' pt' except: facename.append(word) fontstr = ('%s%s%s%s%s%s' % (point_size, family, style, weight, underline, ' '.join(facename))).strip() return fontstr except Exception: pass raise TraitError(object, name, 'a font descriptor string', repr(value)) def info(self): return ("a string describing a font (e.g. '12 pt bold italic " "swiss family Arial' or 'default 12')") #------------------------------------------------------------------------------ # Define a 'null' specific font trait: #------------------------------------------------------------------------------ ### Note: Declare the editor to be a function which returns the FontEditor # class from traits ui to avoid circular import issues. For backwards # compatibility with previous Traits versions, the 'editors' folder in Traits # project declares 'from api import *' in its __init__.py. The 'api' in turn # can contain classes that have a Font trait which lead to this file getting # imported. This leads to a circular import when declaring a Font trait. def get_font_editor(*args, **traits): from ..api import FontEditor return FontEditor(*args, **traits) fh = TraitFont() NullFont = Trait(fh.validate(None, None, 'Arial 10'), fh, editor=get_font_editor) traitsui-4.1.0/traitsui/null/rgb_color_trait.py0000644000175100001440000001674311674463546022737 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Data: 02/14/2005 # #------------------------------------------------------------------------------ """ Trait definitions for an RGB-based color, which is a tuple of the form (*red*, *green*, *blue*), where *red*, *green* and *blue* are floats in the range from 0.0 to 1.0. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import Trait, TraitError from traits.trait_base import SequenceTypes #------------------------------------------------------------------------------- # Convert a number into an RGB tuple: #------------------------------------------------------------------------------- def range_check ( value ): """ Checks that *value* can be converted to a value in the range 0.0 to 1.0. If so, it returns the floating point value; otherwise, it raises a TraitError. """ value = float( value ) if 0.0 <= value <= 1.0: return value raise TraitError def convert_to_color ( object, name, value ): """ Converts a tuple or an integer to an RGB color value, or raises a TraitError if that is not possible. """ if (type( value ) in SequenceTypes) and (len( value ) == 3): return ( range_check( value[0] ), range_check( value[1] ), range_check( value[2] ) ) if type( value ) is int: num = int( value ) return ( (num / 0x10000) / 255.0 ((num / 0x100) & 0xFF) / 255.0, (num & 0xFF) / 255.0 ) raise TraitError convert_to_color.info = ('a tuple of the form (r,g,b), where r, g, and b ' 'are floats in the range from 0.0 to 1.0, or an integer which in hex is of ' 'the form 0xRRGGBB, where RR is red, GG is green, and BB is blue') #------------------------------------------------------------------------------- # Standard colors: #------------------------------------------------------------------------------- # RGB versions of standard colors rgb_standard_colors = { 'aquamarine': ( 0.439216, 0.858824, 0.576471 ), 'black': ( 0.0, 0.0, 0.0 ), 'blue': ( 0.0, 0.0, 1.0 ), 'blue violet': ( 0.623529, 0.372549, 0.623529 ), 'brown': ( 0.647059, 0.164706, 0.164706 ), 'cadet blue': ( 0.372549, 0.623529, 0.623529 ), 'coral': ( 1.0, 0.498039, 0.0 ), 'cornflower blue': ( 0.258824, 0.258824, 0.435294 ), 'cyan': ( 0.0, 1.0, 1.0 ), 'dark grey': ( 0.184314, 0.184314, 0.184314 ), 'dark green': ( 0.184314, 0.309804, 0.184314 ), 'dark olive green': ( 0.309804, 0.309804, 0.184314 ), 'dark orchid': ( 0.6, 0.196078, 0.8 ), 'dark slate blue': ( 0.419608, 0.137255, 0.556863 ), 'dark slate grey': ( 0.184314, 0.309804, 0.309804 ), 'dark turquoise': ( 0.439216, 0.576471, 0.858824 ), 'dim grey': ( 0.329412, 0.329412, 0.329412 ), 'firebrick': ( 0.556863, 0.137255, 0.137255 ), 'forest green': ( 0.137255, 0.556863, 0.137255 ), 'gold': ( 0.8, 0.498039, 0.196078 ), 'goldenrod': ( 0.858824, 0.858824, 0.439216 ), 'grey': ( 0.501961, 0.501961, 0.501961 ), 'green': ( 0.0, 1.0, 0.0 ), 'green yellow': ( 0.576471, 0.858824, 0.439216 ), 'indian red': ( 0.309804, 0.184314, 0.184314 ), 'khaki': ( 0.623529, 0.623529, 0.372549 ), 'light blue': ( 0.74902, 0.847059, 0.847059 ), 'light grey': ( 0.752941, 0.752941, 0.752941 ), 'light steel': ( 0.0, 0.0, 0.0 ), 'blue': ( 0.0, 0.0, 1.0 ), 'lime green': ( 0.196078, 0.8, 0.196078 ), 'magenta': ( 1.0, 0.0, 1.0 ), 'maroon': ( 0.556863, 0.137255, 0.419608 ), 'medium aquamarine': ( 0.196078, 0.8, 0.6 ), 'medium blue': ( 0.196078, 0.196078, 0.8 ), 'medium forest green': ( 0.419608, 0.556863, 0.137255 ), 'medium goldenrod': ( 0.917647, 0.917647, 0.678431 ), 'medium orchid': ( 0.576471, 0.439216, 0.858824 ), 'medium sea green': ( 0.258824, 0.435294, 0.258824 ), 'medium slate blue': ( 0.498039, 0.0, 1.0 ), 'medium spring green': ( 0.498039, 1.0, 0.0 ), 'medium turquoise': ( 0.439216, 0.858824, 0.858824 ), 'medium violet red': ( 0.858824, 0.439216, 0.576471 ), 'midnight blue': ( 0.184314, 0.184314, 0.309804 ), 'navy': ( 0.137255, 0.137255, 0.556863 ), 'orange': ( 0.8, 0.196078, 0.196078 ), 'orange red': ( 1.0, 0.0, 0.498039 ), 'orchid': ( 0.858824, 0.439216, 0.858824 ), 'pale green': ( 0.560784, 0.737255, 0.560784 ), 'pink': ( 0.737255, 0.560784, 0.917647 ), 'plum': ( 0.917647, 0.678431, 0.917647 ), 'purple': ( 0.690196, 0.0, 1.0 ), 'red': ( 1.0, 0.0, 0.0 ), 'salmon': ( 0.435294, 0.258824, 0.258824 ), 'sea green': ( 0.137255, 0.556863, 0.419608 ), 'sienna': ( 0.556863, 0.419608, 0.137255 ), 'sky blue': ( 0.196078, 0.6, 0.8 ), 'slate blue': ( 0.0, 0.498039, 1.0 ), 'spring green': ( 0.0, 1.0, 0.498039 ), 'steel blue': ( 0.137255, 0.419608, 0.556863 ), 'tan': ( 0.858824, 0.576471, 0.439216 ), 'thistle': ( 0.847059, 0.74902, 0.847059 ), 'turquoise': ( 0.678431, 0.917647, 0.917647 ), 'violet': ( 0.309804, 0.184314, 0.309804 ), 'violet red': ( 0.8, 0.196078, 0.6 ), 'wheat': ( 0.847059, 0.847059, 0.74902 ), 'white': ( 1.0, 1.0, 1.0 ), 'yellow': ( 1.0, 1.0, 0.0 ), 'yellow green': ( 0.6, 0.8, 0.196078 ) } #------------------------------------------------------------------------------- # Define 'null' specific color trait: #------------------------------------------------------------------------------- ### Note: Declare the editor to be a function which returns the RGBColorEditor # class from traits ui to avoid circular import issues. For backwards # compatibility with previous Traits versions, the 'editors' folder in Traits # project declares 'from api import *' in its __init__.py. The 'api' in turn # can contain classes that have a RGBColor trait which lead to this file getting # imported. This will lead to a circular import when declaring a RGBColor trait. def get_rgb_color_editor(*args, **traits): from ..editors.rgb_color_editor import ToolkitEditorFactory as RGBColorEditor return RGBColorEditor(*args, **traits) # Trait whose value must be an RGB color RGBColor = Trait( 'white', convert_to_color, rgb_standard_colors, editor = get_rgb_color_editor ) traitsui-4.1.0/traitsui/null/color_trait.py0000644000175100001440000001217611674463546022101 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 02/14/2005 # #------------------------------------------------------------------------------ """ Trait definition for a null-based (i.e., no UI) color. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import Trait, TraitError #------------------------------------------------------------------------------- # Convert a number into a wxColour object: #------------------------------------------------------------------------------- def convert_to_color ( object, name, value ): """ Converts a number into a wxColour object. """ if type( value ) is int: return value & 0xFFFFFF elif isinstance( value, tuple ): return (value[0]/255., value[1]/255., value[2]/255.) raise TraitError convert_to_color.info = ('an integer which in hex is of the form 0xRRGGBB, ' 'where RR is red, GG is green, and BB is blue') #------------------------------------------------------------------------------- # Standard colors: #------------------------------------------------------------------------------- standard_colors = { 'aquamarine': 0x70DB93, 'black': 0x000000, 'blue': 0x0000FF, 'blue violet': 0x9F5F9F, 'brown': 0xA52A2A, 'cadet blue': 0x5F9F9F, 'coral': 0xFF7F00, 'cornflower blue': 0x42426F, 'cyan': 0x00FFFF, 'dark grey': 0x2F2F2F, 'dark green': 0x2F4F2F, 'dark olive green': 0x4F4F2F, 'dark orchid': 0x9932CC, 'dark slate blue': 0x6B238E, 'dark slate grey': 0x2F4F4F, 'dark turquoise': 0x7093DB, 'dim grey': 0x545454, 'firebrick': 0x8E2323, 'forest green': 0x238E23, 'gold': 0xCC7F32, 'goldenrod': 0xDBDB70, 'grey': 0x808080, 'green': 0x00FF00, 'green yellow': 0x93DB70, 'indian red': 0x4F2F2F, 'khaki': 0x9F9F5F, 'light blue': 0xBFD8D8, 'light grey': 0xC0C0C0, 'light steel': 0x000000, 'blue': 0x0000FF, 'lime green': 0x32CC32, 'magenta': 0xFF00FF, 'maroon': 0x8E236B, 'medium aquamarine': 0x32CC99, 'medium blue': 0x3232CC, 'medium forest green': 0x6B8E23, 'medium goldenrod': 0xEAEAAD, 'medium orchid': 0x9370DB, 'medium sea green': 0x426F42, 'medium slate blue': 0x7F00FF, 'medium spring green': 0x7FFF00, 'medium turquoise': 0x70DBDB, 'medium violet red': 0xDB7093, 'midnight blue': 0x2F2F4F, 'navy': 0x23238E, 'orange': 0xCC3232, 'orange red': 0xFF007F, 'orchid': 0xDB70DB, 'pale green': 0x8FBC8F, 'pink': 0xBC8FEA, 'plum': 0xEAADEA, 'purple': 0xB000FF, 'red': 0xFF0000, 'salmon': 0x6F4242, 'sea green': 0x238E6B, 'sienna': 0x8E6B23, 'sky blue': 0x3299CC, 'slate blue': 0x007FFF, 'spring green': 0x00FF7F, 'steel blue': 0x236B8E, 'tan': 0xDB9370, 'thistle': 0xD8BFD8, 'turquoise': 0xADEAEA, 'violet': 0x4F2F4F, 'violet red': 0xCC3299, 'wheat': 0xD8D8BF, 'white': 0xFFFFFF, 'yellow': 0xFFFF00, 'yellow green': 0x99CC32 } #------------------------------------------------------------------------------- # Define 'null' specific color traits: #------------------------------------------------------------------------------- ### Note: Declare the editor to be a function which returns the ColorEditor # class from traits ui to avoid circular import issues. For backwards # compatibility with previous Traits versions, the 'editors' folder in Traits # project declares 'from api import *' in its __init__.py. The 'api' in turn # can contain classes that have a Color trait which lead to this file getting # imported. This leads to a circular import when declaring a Color trait. def get_color_editor(*args, **traits): from ..api import ColorEditor return ColorEditor(*args, **traits) # Color traits NullColor = Trait( 'white', convert_to_color, standard_colors, editor = get_color_editor ) traitsui-4.1.0/traitsui/null/__init__.py0000644000175100001440000000234511674463546021314 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 02/14/2005 # #------------------------------------------------------------------------------ """ Define the concrete implementations of the traits Toolkit interface for the 'null' (do nothing) user interface toolkit. This toolkit is provided to handle situations where no recognized traits-compatible UI toolkit is installed, but users still want to use traits for non-UI related tasks. """ #------------------------------------------------------------------------------- # Define the reference to the exported GUIToolkit object: #------------------------------------------------------------------------------- from __future__ import absolute_import from . import toolkit toolkit = toolkit.GUIToolkit() traitsui-4.1.0/traitsui/basic_editor_factory.py0000644000175100001440000000577211674463546022770 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2008, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/21/2004 # #------------------------------------------------------------------------------ """ Defines the BasicEditorFactory class, which allows creating editor factories that use the same class for creating all editor styles. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import Any from .editor_factory import EditorFactory #------------------------------------------------------------------------------- # 'BasicEditorFactory' base class: #------------------------------------------------------------------------------- class BasicEditorFactory ( EditorFactory ): """ Base class for editor factories that use the same class for creating all editor styles. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Editor class to be instantiated klass = Any #--------------------------------------------------------------------------- # Property getters. #--------------------------------------------------------------------------- def _get_simple_editor_class ( self ): """ Returns the editor class to use for "simple" style views. Overridden to return the value of the 'klass' trait. """ return self.klass def _get_custom_editor_class ( self ): """ Returns the editor class to use for "custom" style views. Overridden to return the value of the 'klass' trait. """ return self.klass def _get_text_editor_class ( self ): """ Returns the editor class to use for "text" style views. Overridden to return the value of the 'klass' trait. """ return self.klass def _get_readonly_editor_class ( self ): """ Returns the editor class to use for "readonly" style views. Overridden to return the value of the 'klass' trait. """ return self.klass #--------------------------------------------------------------------------- # Allow an instance to be called: #--------------------------------------------------------------------------- def __call__ ( self, *args, **traits ): return self.set( **traits ) ## EOF ######################################################################## traitsui-4.1.0/traitsui/help.py0000644000175100001440000000501511674463546017530 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 02/04/2005 # #------------------------------------------------------------------------------ """ Defines the help interface for displaying the help associated with a Traits UI View object. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from .toolkit import toolkit #------------------------------------------------------------------------------- # Default handler for showing the help associated with a view: #------------------------------------------------------------------------------- def default_show_help ( info, control ): """ Default handler for showing the help associated with a view. """ toolkit().show_help( info.ui, control ) # The default handler for showing help show_help = default_show_help #------------------------------------------------------------------------------- # Allows an application to change the default show help handler: #------------------------------------------------------------------------------- def on_help_call ( new_show_help = None ): """ Sets a new global help provider function. Parameters ---------- new_show_help : function The function to set as the new global help provider Returns ------- The previous global help provider function Description ----------- The help provider function must have a signature of *function*(*info*, *control*), where *info* is a UIInfo object for the current view, and *control* is the UI control that invokes the function (typically, a **Help** button). It is provided in case the help provider needs to position the help window relative to the **Help** button. To retrieve the current help provider function, call this function with no arguments. """ global show_help result = show_help if new_show_help is not None: show_help = new_show_help return result traitsui-4.1.0/traitsui/table_column.py0000644000175100001440000010310111674463546021237 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 07/01/2005 # #------------------------------------------------------------------------------ """ Defines the table column descriptor used by the editor and editor factory classes for numeric and table editors. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import (Any, Bool, Callable, Color, Constant, Either, Enum, Expression, Float, Font, HasPrivateTraits, Instance, Int, Property, Str) from traits.trait_base import user_name_for, xgetattr from .editor_factory import EditorFactory from .menu import Menu from .ui_traits import Image, AView, EditorStyle from .view import View # Set up a logger: import logging logger = logging.getLogger( __name__ ) #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- # Flag used to indicate user has not specified a column label UndefinedLabel = '???' #------------------------------------------------------------------------------- # 'TableColumn' class: #------------------------------------------------------------------------------- class TableColumn ( HasPrivateTraits ): """ Represents a column in a table editor. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Column label to use for this column: label = Str( UndefinedLabel ) # Type of data contained by the column: type = Enum( 'text' ) # Text color for this column: text_color = Color( 'black' ) # Text font for this column: text_font = Font # Cell background color for this column: cell_color = Either(Color( 'white' ), None) # Cell background color for non-editable columns: read_only_cell_color = Either(Color( 0xF4F3EE ), None) # Cell graph color: graph_color = Color( 0xDDD9CC ) # Horizontal alignment of text in the column: horizontal_alignment = Enum( 'left', [ 'left', 'center', 'right' ] ) # Vertical alignment of text in the column: vertical_alignment = Enum( 'center', [ 'top', 'center', 'bottom' ] ) # Horizontal cell margin horizontal_margin = Int(4) # Vertical cell margin vertical_margin = Int(3) # The image to display in the cell: image = Image # Renderer used to render the contents of this column: renderer = Any # A toolkit specific renderer # Is the table column visible (i.e., viewable)? visible = Bool( True ) # Is this column editable? editable = Bool( True ) # Is the column automatically edited/viewed (i.e. should the column editor # or popup be activated automatically on mouse over)? auto_editable = Bool( False ) # Should a checkbox be displayed instead of True/False? show_checkbox = Bool( True ) # Can external objects be dropped on the column? droppable = Bool( False ) # Context menu to display when this column is right-clicked: menu = Instance( Menu ) # The tooltip to display when the mouse is over the column: tooltip = Str # The width of the column (< 0.0: Default, 0.0..1.0: fraction of total table # width, > 1.0: absolute width in pixels): width = Float( -1.0 ) # The width of the column while it is being edited (< 0.0: Default, # 0.0..1.0: fraction of total table width, > 1.0: absolute width in pixels): edit_width = Float( -1.0 ) # The height of the column cell's row while it is being edited # (< 0.0: Default, 0.0..1.0: fraction of total table height, # > 1.0: absolute height in pixels): edit_height = Float( -1.0 ) # The resize mode for this column. This takes precedence over other settings # (like **width**, above). # "interactive": column can be resized by users or programmatically # "fixed": users cannot resize the column, but it can be set programmatically # "stretch": the column will be resized to fill the available space # "resize_to_contents": column will be sized to fit the contents, but then cannot be resized resize_mode = Enum("interactive", "fixed", "stretch", "resize_to_contents") # The view (if any) to display when clicking a non-editable cell: view = AView # Optional maximum value a numeric cell value can have: maximum = Float( trait_value = True ) #--------------------------------------------------------------------------- # Returns the actual object being edited: #--------------------------------------------------------------------------- def get_object ( self, object ): """ Returns the actual object being edited. """ return object #--------------------------------------------------------------------------- # Gets the label of the column: #--------------------------------------------------------------------------- def get_label ( self ): """ Gets the label of the column. """ return self.label #--------------------------------------------------------------------------- # Returns the width of the column: #--------------------------------------------------------------------------- def get_width ( self ): """ Returns the width of the column. """ return self.width #--------------------------------------------------------------------------- # Returns the edit width of the column: #--------------------------------------------------------------------------- def get_edit_width ( self, object ): """ Returns the edit width of the column. """ return self.edit_width #--------------------------------------------------------------------------- # Returns the height of the column cell's row while it is being edited: #--------------------------------------------------------------------------- def get_edit_height ( self, object ): """ Returns the height of the column cell's row while it is being edited. """ return self.edit_height #--------------------------------------------------------------------------- # Gets the type of data for the column for a specified object: #--------------------------------------------------------------------------- def get_type ( self, object ): """ Gets the type of data for the column for a specified object. """ return self.type #--------------------------------------------------------------------------- # Returns the text color for the column for a specified object: #--------------------------------------------------------------------------- def get_text_color ( self, object ): """ Returns the text color for the column for a specified object. """ return self.text_color_ #--------------------------------------------------------------------------- # Returns the text font for the column for a specified object: #--------------------------------------------------------------------------- def get_text_font ( self, object ): """ Returns the text font for the column for a specified object. """ return self.text_font #--------------------------------------------------------------------------- # Returns the cell background color for the column for a specified object: #--------------------------------------------------------------------------- def get_cell_color ( self, object ): """ Returns the cell background color for the column for a specified object. """ if self.is_editable( object ): return self.cell_color_ return self.read_only_cell_color_ #--------------------------------------------------------------------------- # Returns the cell background graph color for the column for a specified # object: #--------------------------------------------------------------------------- def get_graph_color ( self, object ): """ Returns the cell background graph color for the column for a specified object. """ return self.graph_color_ #--------------------------------------------------------------------------- # Returns the horizontal alignment for the column for a specified object: #--------------------------------------------------------------------------- def get_horizontal_alignment ( self, object ): """ Returns the horizontal alignment for the column for a specified object. """ return self.horizontal_alignment #--------------------------------------------------------------------------- # Returns the vertical alignment for the column for a specified object: #--------------------------------------------------------------------------- def get_vertical_alignment ( self, object ): """ Returns the vertical alignment for the column for a specified object. """ return self.vertical_alignment #--------------------------------------------------------------------------- # Returns the image to display for the column for a specified object: #--------------------------------------------------------------------------- def get_image ( self, object ): """ Returns the image to display for the column for a specified object. """ return self.image #--------------------------------------------------------------------------- # Returns the renderer for the column of a specified object: #--------------------------------------------------------------------------- def get_renderer ( self, object ): """ Returns the renderer for the column of a specified object. """ return self.renderer #--------------------------------------------------------------------------- # Returns whether the column is editable for a specified object: #--------------------------------------------------------------------------- def is_editable ( self, object ): """ Returns whether the column is editable for a specified object. """ return self.editable #--------------------------------------------------------------------------- # Returns whether the column is autoamtically edited/viewed for a specified # object: #--------------------------------------------------------------------------- def is_auto_editable ( self, object ): """ Returns whether the column is automatically edited/viewed for a specified object. """ return self.auto_editable #--------------------------------------------------------------------------- # Returns whether a specified value is valid for dropping on the column # for a specified object: #--------------------------------------------------------------------------- def is_droppable ( self, object, value ): """ Returns whether a specified value is valid for dropping on the column for a specified object. """ return self.droppable #--------------------------------------------------------------------------- # Returns the context menu to display when the user right-clicks on the # column for a specified object: #--------------------------------------------------------------------------- def get_menu ( self, object ): """ Returns the context menu to display when the user right-clicks on the column for a specified object. """ return self.menu #--------------------------------------------------------------------------- # Returns the tooltip to display when the user mouses over the column for # a specified object: #--------------------------------------------------------------------------- def get_tooltip ( self, object ): """ Returns the tooltip to display when the user mouses over the column for a specified object. """ return self.tooltip #--------------------------------------------------------------------------- # Returns the view to display when clicking a non-editable cell: #--------------------------------------------------------------------------- def get_view ( self, object ): """ Returns the view to display when clicking a non-editable cell. """ return self.view #--------------------------------------------------------------------------- # Returns the maximum value a numeric column can have: #--------------------------------------------------------------------------- def get_maximum ( self, object ): """ Returns the maximum value a numeric column can have. """ return self.maximum #--------------------------------------------------------------------------- # Called when the user clicks on the column: #--------------------------------------------------------------------------- def on_click ( self, object ): """ Called when the user clicks on the column. """ pass #--------------------------------------------------------------------------- # Called when the user double-clicks on the column: #--------------------------------------------------------------------------- def on_dclick ( self, object ): """ Called when the user clicks on the column. """ pass #--------------------------------------------------------------------------- # Returns the string representation of the table column: #--------------------------------------------------------------------------- def __str__ ( self ): """ Returns the string representation of the table column. """ return self.get_label() #------------------------------------------------------------------------------- # 'ObjectColumn' class: #------------------------------------------------------------------------------- class ObjectColumn ( TableColumn ): """ A column for editing objects. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Name of the object trait associated with this column: name = Str # Column label to use for this column: label = Property # Trait editor used to edit the contents of this column: editor = Instance( EditorFactory ) # The editor style to use to edit the contents of this column: style = EditorStyle # Format string to apply to column values: format = Str( '%s' ) # Format function to apply to column values: format_func = Callable #--------------------------------------------------------------------------- # Trait view definitions: #--------------------------------------------------------------------------- traits_view = View( [ [ 'name', 'label', 'type', '|[Column Information]' ], [ 'horizontal_alignment{Horizontal}@', 'vertical_alignment{Vertical}@', '|[Alignment]' ], [ 'editable', '9', 'droppable', '9', 'visible', '-[Options]>' ], '|{Column}' ], [ [ 'text_color@', 'cell_color@', 'read_only_cell_color@', '|[UI Colors]' ], '|{Colors}' ], [ [ 'text_font@', '|[Font]<>' ], '|{Font}' ], [ 'menu@', '|{Menu}' ], [ 'editor@', '|{Editor}' ] ) #--------------------------------------------------------------------------- # Implementation of the 'label' property: #--------------------------------------------------------------------------- def _get_label ( self ): """ Gets the label of the column. """ if self._label is not None: return self._label return user_name_for( self.name ) def _set_label ( self, label ): old, self._label = self._label, label if old != label: self.trait_property_changed( 'label', old, label ) #--------------------------------------------------------------------------- # Gets the value of the column for a specified object: #--------------------------------------------------------------------------- def get_raw_value ( self, object ): """ Gets the unformatted value of the column for a specified object. """ try: return xgetattr( self.get_object( object ), self.name ) except: return None def get_value ( self, object ): """ Gets the formatted value of the column for a specified object. """ try: if self.format_func is not None: return self.format_func( self.get_raw_value( object ) ) return self.format % ( self.get_raw_value( object ), ) except: logger.exception( 'Error occurred trying to format a %s value' % self.__class__.__name__ ) return 'Format!' #--------------------------------------------------------------------------- # Returns the drag value for the column: #--------------------------------------------------------------------------- def get_drag_value ( self, object ): """Returns the drag value for the column. """ return self.get_raw_value( object ) #--------------------------------------------------------------------------- # Sets the value of the column for a specified object: #--------------------------------------------------------------------------- def set_value ( self, object, value ): """ Sets the value of the column for a specified object. """ target, name = self.target_name( object ) setattr( target, name, value ) #--------------------------------------------------------------------------- # Gets the editor for the column of a specified object: #--------------------------------------------------------------------------- def get_editor ( self, object ): """ Gets the editor for the column of a specified object. """ if self.editor is not None: return self.editor target, name = self.target_name( object ) return target.base_trait( name ).get_editor() #--------------------------------------------------------------------------- # Gets the editor style for the column of a specified object: #--------------------------------------------------------------------------- def get_style ( self, object ): """ Gets the editor style for the column of a specified object. """ return self.style #--------------------------------------------------------------------------- # Returns the result of comparing the column of two different objects: #--------------------------------------------------------------------------- def cmp ( self, object1, object2 ): """ Returns the result of comparing the column of two different objects. """ return cmp( self.get_raw_value( object1 ), self.get_raw_value( object2 ) ) #--------------------------------------------------------------------------- # Returns whether a specified value is valid for dropping on the column # for a specified object: #--------------------------------------------------------------------------- def is_droppable ( self, object, value ): """ Returns whether a specified value is valid for dropping on the column for a specified object. """ if self.droppable: try: target, name = self.target_name( object ) target.base_trait( name ).validate( target, name, value ) return True except: pass return False #--------------------------------------------------------------------------- # Returns the target object and name for the column: #--------------------------------------------------------------------------- def target_name ( self, object ): """ Returns the target object and name for the column. """ object = self.get_object( object ) name = self.name col = name.rfind( '.' ) if col < 0: return ( object, name ) return ( xgetattr( object, name[ :col ] ), name[ col + 1: ] ) #------------------------------------------------------------------------------- # 'ExpressionColumn' class: #------------------------------------------------------------------------------- class ExpressionColumn ( ObjectColumn ): """ A column for displaying computed values. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # The Python expression used to return the value of the column: expression = Expression # Is this column editable? editable = Constant( False ) # The globals dictionary that should be passed to the expression evaluation: globals = Any( {} ) #--------------------------------------------------------------------------- # Gets the value of the column for a specified object: #--------------------------------------------------------------------------- def get_raw_value ( self, object ): """ Gets the unformatted value of the column for a specified object. """ try: return eval( self.expression_, self.globals, { 'object': object } ) except: logger.exception( 'Error evaluating table column expression: %s' % self.expression ) return None #------------------------------------------------------------------------------- # 'NumericColumn' class: #------------------------------------------------------------------------------- class NumericColumn ( ObjectColumn ): """ A column for editing Numeric arrays. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Column label to use for this column label = Property # Text color this column when selected selected_text_color = Color( 'black' ) # Text font for this column when selected selected_text_font = Font # Cell background color for this column when selected selected_cell_color = Color( 0xD8FFD8 ) # Formatting string for the cell value format = Str( '%s' ) # Horizontal alignment of text in the column; this value overrides the # default. horizontal_alignment = 'center' #--------------------------------------------------------------------------- # Implementation of the 'label' property: #--------------------------------------------------------------------------- def _get_label ( self ): """ Gets the label of the column. """ if self._label is not None: return self._label return self.name def _set_label ( self, label ): old, self._label = self._label, label if old != label: self.trait_property_changed( 'label', old, label ) #--------------------------------------------------------------------------- # Gets the type of data for the column for a specified object row: #--------------------------------------------------------------------------- def get_type ( self, object ): """ Gets the type of data for the column for a specified object row. """ return self.type #--------------------------------------------------------------------------- # Returns the text color for the column for a specified object row: #--------------------------------------------------------------------------- def get_text_color ( self, object ): """ Returns the text color for the column for a specified object row. """ if self._is_selected( object ): return self.selected_text_color_ return self.text_color_ #--------------------------------------------------------------------------- # Returns the text font for the column for a specified object row: #--------------------------------------------------------------------------- def get_text_font ( self, object ): """ Returns the text font for the column for a specified object row. """ if self._is_selected( object ): return self.selected_text_font return self.text_font #--------------------------------------------------------------------------- # Returns the cell background color for the column for a specified object # row: #--------------------------------------------------------------------------- def get_cell_color ( self, object ): """ Returns the cell background color for the column for a specified object row. """ if self.is_editable( object ): if self._is_selected( object ): return self.selected_cell_color_ return self.cell_color_ return self.read_only_cell_color_ #--------------------------------------------------------------------------- # Returns the horizontal alignment for the column for a specified object # row: #--------------------------------------------------------------------------- def get_horizontal_alignment ( self, object ): """ Returns the horizontal alignment for the column for a specified object row. """ return self.horizontal_alignment #--------------------------------------------------------------------------- # Returns the vertical alignment for the column for a specified object row: #--------------------------------------------------------------------------- def get_vertical_alignment ( self, object ): """ Returns the vertical alignment for the column for a specified object row. """ return self.vertical_alignment #--------------------------------------------------------------------------- # Returns whether the column is editable for a specified object row: #--------------------------------------------------------------------------- def is_editable ( self, object ): """ Returns whether the column is editable for a specified object row. """ return self.editable #--------------------------------------------------------------------------- # Returns whether a specified value is valid for dropping on the column # for a specified object row: #--------------------------------------------------------------------------- def is_droppable ( self, object, row, value ): """ Returns whether a specified value is valid for dropping on the column for a specified object row. """ return self.droppable #--------------------------------------------------------------------------- # Returns the context menu to display when the user right-clicks on the # column for a specified object row: #--------------------------------------------------------------------------- def get_menu ( self, object, row ): """ Returns the context menu to display when the user right-clicks on the column for a specified object row. """ return self.menu #--------------------------------------------------------------------------- # Gets the value of the column for a specified object row: #--------------------------------------------------------------------------- def get_value ( self, object ): """ Gets the value of the column for a specified object row. """ try: value = getattr( object, self.name ) try: return self.format % ( value, ) except: return 'Format!' except: return 'Undefined!' #--------------------------------------------------------------------------- # Sets the value of the column for a specified object row: #--------------------------------------------------------------------------- def set_value ( self, object, row, value ): """ Sets the value of the column for a specified object row. """ column = self.get_data_column( object ) column[ row ] = type( column[ row ] )( value ) #--------------------------------------------------------------------------- # Gets the editor for the column of a specified object row: #--------------------------------------------------------------------------- def get_editor ( self, object ): """ Gets the editor for the column of a specified object row. """ return super( NumericColumn, self ).get_editor( object ) #--------------------------------------------------------------------------- # Gets the entire contents of the specified object column: #--------------------------------------------------------------------------- def get_data_column ( self, object ): """ Gets the entire contents of the specified object column. """ return getattr( object, self.name ) #--------------------------------------------------------------------------- # Returns whether a specified object row is selected or not: #--------------------------------------------------------------------------- def _is_selected ( self, object ): """ Returns whether a specified object row is selected. """ if hasattr(object, 'model_selection') \ and object.model_selection is not None: return True return False #------------------------------------------------------------------------------- # 'ListColumn' class: #------------------------------------------------------------------------------- class ListColumn ( TableColumn ): """ A column for editing lists. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- #Label to use for this column label = Property # Index of the list element associated with this column index = Int # Is this column editable? This value overrides the base class default. editable = False #--------------------------------------------------------------------------- # Trait view definitions: #--------------------------------------------------------------------------- traits_view = View( [ [ 'index', 'label', 'type', '|[Column Information]' ], [ 'text_color@', 'cell_color@', '|[UI Colors]' ] ] ) #--------------------------------------------------------------------------- # Implementation of the 'label' property: #--------------------------------------------------------------------------- def _get_label ( self ): """ Gets the label of the column. """ if self._label is not None: return self._label return 'Column %d' % (self.index + 1) def _set_label ( self, label ): old, self._label = self._label, label if old != label: self.trait_property_changed( 'label', old, label ) #--------------------------------------------------------------------------- # Gets the value of the column for a specified object: #--------------------------------------------------------------------------- def get_value ( self, object ): """ Gets the value of the column for a specified object. """ return unicode( object[ self.index ] ) #--------------------------------------------------------------------------- # Sets the value of the column for a specified object: #--------------------------------------------------------------------------- def set_value ( self, object, value ): """ Sets the value of the column for a specified object. """ object[ self.index ] = value #--------------------------------------------------------------------------- # Gets the editor for the column of a specified object: #--------------------------------------------------------------------------- def get_editor ( self, object ): """ Gets the editor for the column of a specified object. """ return None #--------------------------------------------------------------------------- # Returns the result of comparing the column of two different objects: #--------------------------------------------------------------------------- def cmp ( self, object1, object2 ): """ Returns the result of comparing the column of two different objects. """ return cmp( object1[ self.index ], object2[ self.index ] ) traitsui-4.1.0/traitsui/table_filter.py0000644000175100001440000007071311674463546021243 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 07/01/2005 # #------------------------------------------------------------------------------ """ Defines the filter object used to filter items displayed in a table editor. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import (Any, Bool, Callable, Enum, Event, Expression, HasPrivateTraits, Instance, List, Str, Trait) from .editor_factory import EditorFactory from .editors.api import EnumEditor from .group import Group from .include import Include from .item import Item from .menu import Action from .table_column import ObjectColumn from .view import View #------------------------------------------------------------------------------- # Trait definitions: #------------------------------------------------------------------------------- GenericTableFilterRuleOperation = Trait( '=', { '=': 'eq', '<>': 'ne', '<': 'lt', '<=': 'le', '>': 'gt', '>=': 'ge', 'contains': 'contains', 'starts with': 'starts_with', 'ends with': 'ends_with' } ) #------------------------------------------------------------------------------- # 'TableFilter' class: #------------------------------------------------------------------------------- class TableFilter ( HasPrivateTraits ): """ Filter for items displayed in a table. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # UI name of this filter (so the user can identify it in the UI) name = Str( 'Default filter' ) # Default name that can be automatically overridden _name = Str( 'Default filter' ) # A user-readable description of what kind of object satisfies the filter desc = Str( 'All items' ) # A callable function that returns whether the passed object is allowed # by the filter allowed = Callable( lambda object: True, transient = True ) # Is the filter a template (i.e., non-deletable, non-editable)? template = Bool( False ) #--------------------------------------------------------------------------- # Class constants: #--------------------------------------------------------------------------- # Traits that are ignored by the _anytrait_changed() handler ignored_traits = [ '_name', 'template', 'desc' ] #--------------------------------------------------------------------------- # Traits view definitions: #--------------------------------------------------------------------------- traits_view = View( 'name{Filter name}', '_', Include( 'filter_view' ), title = 'Edit Filter', width = 0.2, buttons = [ 'OK', 'Cancel', Action( name = 'Help', action = 'show_help', defined_when = "ui.view_elements.content['filter_view']" ".help_id != ''" ) ] ) searchable_view = View( [ [ Include( 'search_view' ), '|[]' ], [ 'handler.status~', '|[]<>' ], [ 'handler.find_next`Find the next matching item`', 'handler.find_previous`Find the previous matching item`', 'handler.select`Select all matching items`', 'handler.OK`Exit search`', '-<>' ], '|<>' ], title = 'Search for', kind = 'livemodal', width = 0.25 ) search_view = Group( Include( 'filter_view' ) ) filter_view = Group() #--------------------------------------------------------------------------- # Returns whether a specified object meets the filter/search criteria: # (Should normally be overridden) #--------------------------------------------------------------------------- def filter ( self, object ): """ Returns whether a specified object meets the filter or search criteria. """ return self.allowed( object ) #--------------------------------------------------------------------------- # Returns a user readable description of what kind of object will # satisfy the filter: # (Should normally be overridden): #--------------------------------------------------------------------------- def description ( self ): """ Returns a user-readable description of what kind of object satisfies the filter. """ return self.desc #--------------------------------------------------------------------------- # Edits the contents of the filter: #--------------------------------------------------------------------------- def edit ( self, object ): """ Edits the contents of the filter. """ return self.edit_traits( view = self.edit_view( object ), kind = 'livemodal' ) def edit_view ( self, object ): """ Return a view to use for editing the filter. The ''object'' parameter is a sample object for the table that the filter will be applied to. It is supplied in case the filter needs to extract data or metadata from the object. If the table is empty, the ''object'' argument is None. """ return None #--------------------------------------------------------------------------- # 'object' interface: #--------------------------------------------------------------------------- def __str__ ( self ): return self.name #--------------------------------------------------------------------------- # Event handlers: #--------------------------------------------------------------------------- def _anytrait_changed ( self, name, old, new ): if ((name not in self.ignored_traits) and ((self.name == self._name) or (self.name == ''))): self.name = self._name = self.description() #------------------------------------------------------------------------------- # 'EvalTableFilter' class: #------------------------------------------------------------------------------- class EvalTableFilter ( TableFilter ): """ A table filter based on evaluating an expression. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Override the standard **name** trait name = 'Default evaluation filter' # Python expression which will be applied to each table item expression = Expression #--------------------------------------------------------------------------- # Traits view definitions: #--------------------------------------------------------------------------- filter_view = Group( 'expression' ) #--------------------------------------------------------------------------- # Returns whether a specified object meets the filter/search criteria: # (Should normally be overridden) #--------------------------------------------------------------------------- def filter ( self, object ): """ Returns whether a specified object meets the filter or search criteria. """ if self._traits is None: self._traits = object.trait_names() try: return eval( self.expression_, globals(), object.get( *self._traits ) ) except: return False #--------------------------------------------------------------------------- # Returns a user readable description of what kind of object will # satisfy the filter: # (Should normally be overridden): #--------------------------------------------------------------------------- def description ( self ): """ Returns a user readable description of what kind of object satisfies the filter. """ return self.expression #------------------------------------------------------------------------------- # 'GenericTableFilterRule' class: #------------------------------------------------------------------------------- class GenericTableFilterRule ( HasPrivateTraits ): """ A general rule used by a table filter. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Filter this rule is part of filter = Instance( 'RuleTableFilter' ) # Is this rule enabled? enabled = Bool( False ) # Is this rule an 'and' rule or an 'or' rule? and_or = Enum( 'and', 'or' ) # EnumEditor used to edit the **name** trait: name_editor = Instance( EditorFactory ) # Name of the object trait that this rule applies to name = Str # Operation to be applied in the rule operation = GenericTableFilterRuleOperation # Editor used to edit the **value** trait value_editor = Instance( EditorFactory ) # Value to use in the operation when applying the rule to an object value = Any #--------------------------------------------------------------------------- # Class constants: #--------------------------------------------------------------------------- # Traits that are ignored by the _anytrait_changed() handler ignored_traits = [ 'filter', 'name_editor', 'value_editor' ] #--------------------------------------------------------------------------- # Initializes the object: #--------------------------------------------------------------------------- def __init__ ( self, **traits ): super( GenericTableFilterRule, self ).__init__( **traits ) if self.name == '': names = self.filter._trait_values.keys() if len( names ) > 0: names.sort() self.name = names[0] self.enabled = False #--------------------------------------------------------------------------- # Handles the value of the 'name' trait changing: #--------------------------------------------------------------------------- def _name_changed ( self, name ): """ Handles a change to the value of the **name** trait. """ filter = self.filter if (filter is not None) and (filter._object is not None): self.value = filter._trait_values.get( name ) self.value_editor = filter._object.base_trait( name ).get_editor() #--------------------------------------------------------------------------- # Event handlers: #--------------------------------------------------------------------------- def _anytrait_changed ( self, name, old, new ): if (name not in self.ignored_traits) and (self.filter is not None): self.filter.modified = True if name != 'enabled': self.enabled = True #--------------------------------------------------------------------------- # Clones a new object from this one, optionally copying only a specified # set of traits: #--------------------------------------------------------------------------- def clone_traits ( self, traits = None, memo = None, copy = None, **metadata ): """ Clones a new object from this one, optionally copying only a specified set of traits.""" return super( GenericTableFilterRule, self ).clone_traits( traits, memo, copy, **metadata ).set( enabled = self.enabled, name = self.name ) #--------------------------------------------------------------------------- # Returns a description of the filter: #--------------------------------------------------------------------------- def description ( self ): """ Returns a description of the filter. """ return '%s %s %s' % ( self.name, self.operation, self.value ) #--------------------------------------------------------------------------- # Returns whether the rule is true for a specified object: #--------------------------------------------------------------------------- def is_true ( self, object ): """ Returns whether the rule is true for a specified object. """ try: value1 = getattr( object, self.name ) type1 = type( value1 ) value2 = self.value if type1 is not type( value2 ): value2 = type1( value2 ) return getattr( self, self.operation_ )( value1, value2 ) except: return False #--------------------------------------------------------------------------- # Implemenations of the various rule operations: #--------------------------------------------------------------------------- def eq ( self, value1, value2 ): return (value1 == value2) def ne ( self, value1, value2 ): return (value1 != value2) def lt ( self, value1, value2 ): return (value1 < value2) def le ( self, value1, value2 ): return (value1 <= value2) def gt ( self, value1, value2 ): return (value1 > value2) def ge ( self, value1, value2 ): return (value1 >= value2) def contains ( self, value1, value2 ): return (value1.lower().find( value2.lower() ) >= 0) def starts_with ( self, value1, value2 ): return (value1[ : len( value2 ) ].lower() == value2.lower()) def ends_with ( self, value1, value2 ): return (value1[ -len( value2 ): ].lower() == value2.lower()) #------------------------------------------------------------------------------- # 'GenericTableFilterRuleEnabledColumn' class: #------------------------------------------------------------------------------- class GenericTableFilterRuleEnabledColumn ( ObjectColumn ): """ Table column that indicates whether a filter rule is enabled. """ #--------------------------------------------------------------------------- # Returns the value of the column for a specified object: #--------------------------------------------------------------------------- def get_value ( self, object ): """ Returns the traits editor of the column for a specified object. """ return [ '', '==>' ][ object.enabled ] #------------------------------------------------------------------------------- # 'GenericTableFilterRuleAndOrColumn' class: #------------------------------------------------------------------------------- class GenericTableFilterRuleAndOrColumn ( ObjectColumn ): """ Table column that displays whether a filter rule is conjoining ('and') or disjoining ('or'). """ #--------------------------------------------------------------------------- # Returns the value of the column for a specified object: #--------------------------------------------------------------------------- def get_value ( self, object ): """ Returns the traits editor of the column for a specified object. """ if object.and_or == 'or': return 'or' return '' #------------------------------------------------------------------------------- # 'GenericTableFilterRuleNameColumn' class: #------------------------------------------------------------------------------- class GenericTableFilterRuleNameColumn ( ObjectColumn ): """ Table column for the name of an object trait. """ #--------------------------------------------------------------------------- # Returns the traits editor of the column for a specified object: #--------------------------------------------------------------------------- def get_editor ( self, object ): """ Returns the traits editor of the column for a specified object. """ return object.name_editor #------------------------------------------------------------------------------- # 'GenericTableFilterRuleValueColumn' class: #------------------------------------------------------------------------------- class GenericTableFilterRuleValueColumn ( ObjectColumn ): """ Table column for the value of an object trait. """ #--------------------------------------------------------------------------- # Returns the traits editor of the column for a specified object: #--------------------------------------------------------------------------- def get_editor ( self, object ): """ Returns the traits editor of the column for a specified object. """ return object.value_editor #------------------------------------------------------------------------------- # Defines the columns to display in the generic filter rule table: #------------------------------------------------------------------------------- # Columns to display in the table for generic filter rules. generic_table_filter_rule_columns = [ GenericTableFilterRuleAndOrColumn( name = 'and_or', label = 'or' ), GenericTableFilterRuleNameColumn( name = 'name' ), ObjectColumn( name = 'operation' ), GenericTableFilterRuleValueColumn( name = 'value' ) ] #------------------------------------------------------------------------------- # 'RuleTableFilter' class: #------------------------------------------------------------------------------- class RuleTableFilter ( TableFilter ): """ A table filter based on rules. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Overrides the default **name** trait name = 'Default rule-based filter' # List of the filter rules to be applied rules = List( GenericTableFilterRule ) # Event fired when the contents of the filter have changed modified = Event # Persistence ID of the view view_id = Str( 'traitsui.table_filter.RuleTableFilter' ) # Sample object that the filter will apply to _object = Any # Map of trait names and default values _trait_values = Any #--------------------------------------------------------------------------- # Traits view definitions: #--------------------------------------------------------------------------- error_view = View( Item( label = 'A menu or rule based filter can only be created for ' 'tables with at least one entry' ), title = 'Error Creating Filter', kind = 'livemodal', close_result = False, buttons = [ 'Cancel' ] ) #--------------------------------------------------------------------------- # Returns whether a specified object meets the filter/search criteria: # (Should normally be overridden) #--------------------------------------------------------------------------- def filter ( self, object ): """ Returns whether a specified object meets the filter or search criteria. """ is_first = is_true = True for rule in self.rules: if rule.and_or == 'or': if is_true and (not is_first): return True is_true = True if is_true: is_true = rule.is_true( object ) is_first = False return is_true #--------------------------------------------------------------------------- # Returns a user readable description of what kind of object will # satisfy the filter: # (Should normally be overridden): #--------------------------------------------------------------------------- def description ( self ): """ Returns a user-readable description of the kind of object that satisfies the filter. """ ors = [] ands = [] if len( self.rules ) > 0: for rule in self.rules: if rule.and_or == 'or': if len( ands ) > 0: ors.append( ' and '.join( ands ) ) ands = [] ands.append( rule.description() ) if len( ands ) > 0: ors.append( ' and '.join( ands ) ) if len( ors ) == 1: return ors[0] if len( ors ) > 1: return ' or '.join( [ '(%s)' % t for t in ors ] ) return super( RuleTableFilter, self ).description() #--------------------------------------------------------------------------- # Edits the contents of the filter: #--------------------------------------------------------------------------- def edit_view ( self, object ): """ Return a view to use for editing the filter. The ''object'' parameter is a sample object for the table that the filter will be applied to. It is supplied in case the filter needs to extract data or metadata from the object. If the table is empty, the ''object'' argument is None. """ self._object = object if object is None: return self.edit_traits( view = 'error_view' ) names = object.editable_traits() self._trait_values = object.get( names ) return View( [ [ 'name{Filter name}', '_' ], [ Item( 'rules', id = 'rules_table', editor = self._get_table_editor( names ) ), '|<>' ] ], id = self.view_id, title = 'Edit Filter', kind = 'livemodal', resizable = True, buttons = [ 'OK', 'Cancel' ], width = 0.4, height = 0.3 ) #--------------------------------------------------------------------------- # Returns a table editor to use for editing the filter: #--------------------------------------------------------------------------- def _get_table_editor ( self, names ): """ Returns a table editor to use for editing the filter. """ from .api import TableEditor return TableEditor( columns = generic_table_filter_rule_columns, orientation = 'vertical', deletable = True, sortable = False, configurable = False, auto_size = False, auto_add = True, row_factory = GenericTableFilterRule, row_factory_kw = { 'filter': self, 'name_editor': EnumEditor( values = names ) } ) #--------------------------------------------------------------------------- # Returns the state to be pickled (override of object): #--------------------------------------------------------------------------- def __getstate__ ( self ): """ Returns the state to be pickled. This definition overrides **object**. """ dict = self.__dict__.copy() if '_object' in dict: del dict[ '_object' ] del dict[ '_trait_values' ] return dict #--------------------------------------------------------------------------- # Handles the 'rules' trait being changed: #--------------------------------------------------------------------------- def _rules_changed ( self, rules ): """ Handles a change to the **rules** trait. """ for rule in rules: rule.filter = self #------------------------------------------------------------------------------- # Defines the columns to display in the menu filter rule table: #------------------------------------------------------------------------------- # Columns to display in the table for menu filters. menu_table_filter_rule_columns = [ GenericTableFilterRuleEnabledColumn( name = 'enabled', label = '' ), GenericTableFilterRuleNameColumn( name = 'name' ), ObjectColumn( name = 'operation' ), GenericTableFilterRuleValueColumn( name = 'value' ) ] #------------------------------------------------------------------------------- # 'MenuTableFilter' class: #------------------------------------------------------------------------------- class MenuTableFilter ( RuleTableFilter ): """ A table filter based on a menu of rules. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Overrides the default **name** trait name = 'Default menu-based filter' # Overrides the persistence ID of the view view_id = Str( 'traitsui.table_filter.MenuTableFilter' ) #--------------------------------------------------------------------------- # Returns whether a specified object meets the filter/search criteria: # (Should normally be overridden) #--------------------------------------------------------------------------- def filter ( self, object ): """ Returns whether a specified object meets the filter or search criteria. """ for rule in self.rules: if rule.enabled and (not rule.is_true( object )): return False return True #--------------------------------------------------------------------------- # Returns a user readable description of what kind of object will # satisfy the filter: # (Should normally be overridden): #--------------------------------------------------------------------------- def description ( self ): """ Returns a user8readable description of what kind of object satisfies the filter. """ result = ' and '.join( [ rule.description() for rule in self.rules if rule.enabled ] ) if result != '': return result return 'All items' #--------------------------------------------------------------------------- # Returns a table editor to use for editing the filter: #--------------------------------------------------------------------------- def _get_table_editor ( self, names ): """ Returns a table editor to use for editing the filter. """ from .api import TableEditor names = self._object.editable_traits() name_editor = EnumEditor( values = names ) if len( self.rules ) == 0: self.rules = [ GenericTableFilterRule( filter = self, name_editor = name_editor ).set( name = name ) for name in names ] for rule in self.rules: rule.enabled = False return TableEditor( columns = menu_table_filter_rule_columns, orientation = 'vertical', deletable = True, sortable = False, configurable = False, auto_size = False, auto_add = True, row_factory = GenericTableFilterRule, row_factory_kw = { 'filter': self, 'name_editor': name_editor } ) #------------------------------------------------------------------------------- # Define some standard template filters: #------------------------------------------------------------------------------- EvalFilterTemplate = EvalTableFilter( name = 'Evaluation filter template', template = True ) RuleFilterTemplate = RuleTableFilter( name = 'Rule-based filter template', template = True ) MenuFilterTemplate = MenuTableFilter( name = 'Menu-based filter template', template = True ) traitsui-4.1.0/traitsui/toolkit_traits.py0000644000175100001440000000052711674463546021656 0ustar ischnellusers00000000000000 from __future__ import absolute_import from .toolkit import toolkit def ColorTrait ( *args, **traits ): return toolkit().color_trait( *args, **traits ) def RGBColorTrait ( *args, **traits ): return toolkit().rgb_color_trait( *args, **traits ) def FontTrait ( *args, **traits ): return toolkit().font_trait( *args, **traits ) traitsui-4.1.0/traitsui/editor_factory.py0000644000175100001440000002720411674463546021621 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/07/2004 # #------------------------------------------------------------------------------ """ Defines the abstract EditorFactory class, which represents a factory for creating the Editor objects used in a Traits-based user interface. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import import sys, os from traits.api import HasPrivateTraits, Callable, Str, Bool, Event, Any, Property from .helper import enum_values_changed from .toolkit import toolkit_object #------------------------------------------------------------------------------- # 'EditorFactory' abstract base class: #------------------------------------------------------------------------------- class EditorFactory ( HasPrivateTraits ): """ Represents a factory for creating the Editor objects in a Traits-based user interface. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Function to use for string formatting format_func = Callable # Format string to use for formatting (used if **format_func** is not set). format_str = Str # Is the editor being used to create table grid cells? is_grid_cell = Bool( False ) # Are created editors initially enabled? enabled = Bool( True ) # The extended trait name of the trait containing editor invalid state # status: invalid = Str # Text aligment to use in most readonly editors # Possible values: left, right, top, bottom, just, vcenter, hcenter, center # Example: left,vcenter text_alignment = Str # The editor class to use for 'simple' style views. simple_editor_class = Property # The editor class to use for 'custom' style views. custom_editor_class = Property # The editor class to use for 'text' style views. text_editor_class = Property # The editor class to use for 'readonly' style views. readonly_editor_class = Property #--------------------------------------------------------------------------- # Initializes the object: #--------------------------------------------------------------------------- def __init__ ( self, *args, **traits ): """ Initializes the factory object. """ HasPrivateTraits.__init__( self, **traits ) self.init( *args ) #--------------------------------------------------------------------------- # Performs any initialization needed after all constructor traits have # been set: #--------------------------------------------------------------------------- def init ( self ): """ Performs any initialization needed after all constructor traits have been set. """ pass #--------------------------------------------------------------------------- # Returns the value of a specified extended name of the form: name or # context_object_name.name[.name...]: #--------------------------------------------------------------------------- def named_value ( self, name, ui ): """ Returns the value of a specified extended name of the form: name or context_object_name.name[.name...]: """ names = name.split( '.' ) if len( names ) == 1: # fixme: This will produce incorrect values if the actual Item the # factory is being used with does not use the default object='name' # value, and the specified 'name' does not contain a '.'. The # solution will probably involve providing the Item as an argument, # but it is currently not available at the time this method needs to # be called... names.insert( 0, 'object' ) value = ui.context[ names[0] ] for name in names[1:]: value = getattr( value, name ) return value #--------------------------------------------------------------------------- # Methods that generate backend toolkit-specific editors. #--------------------------------------------------------------------------- def simple_editor ( self, ui, object, name, description, parent ): """ Generates an editor using the "simple" style. """ return self.simple_editor_class( parent, factory = self, ui = ui, object = object, name = name, description = description ) def custom_editor ( self, ui, object, name, description, parent ): """ Generates an editor using the "custom" style. """ return self.custom_editor_class( parent, factory = self, ui = ui, object = object, name = name, description = description ) def text_editor ( self, ui, object, name, description, parent ): """ Generates an editor using the "text" style. """ return self.text_editor_class( parent, factory = self, ui = ui, object = object, name = name, description = description ) def readonly_editor ( self, ui, object, name, description, parent ): """ Generates an "editor" that is read-only. """ return self.readonly_editor_class( parent, factory = self, ui = ui, object = object, name = name, description = description ) #--------------------------------------------------------------------------- # Private methods #--------------------------------------------------------------------------- @classmethod def _get_toolkit_editor(cls, class_name): """ Returns the editor by name class_name in the backend package. """ editor_factory_classes = [factory_class for factory_class in cls.mro() if issubclass(factory_class, EditorFactory)] for index in range(len( editor_factory_classes )): try: factory_class = editor_factory_classes[index] editor_file_name = os.path.basename( sys.modules[factory_class.__module__].__file__) return toolkit_object(':'.join([editor_file_name.split('.')[0], class_name]), True) except Exception, e: if index == len(editor_factory_classes)-1: raise e return None #--------------------------------------------------------------------------- # Property getters #--------------------------------------------------------------------------- def _get_simple_editor_class(self): """ Returns the editor class to use for "simple" style views. The default implementation tries to import the SimpleEditor class in the editor file in the backend package, and if such a class is not to found it returns the SimpleEditor class defined in editor_factory module in the backend package. """ try: SimpleEditor = self._get_toolkit_editor('SimpleEditor') except: SimpleEditor = toolkit_object('editor_factory:SimpleEditor') return SimpleEditor def _get_custom_editor_class(self): """ Returns the editor class to use for "custom" style views. The default implementation tries to import the CustomEditor class in the editor file in the backend package, and if such a class is not to found it returns simple_editor_class. """ try: CustomEditor = self._get_toolkit_editor('CustomEditor') except: CustomEditor = self.simple_editor_class return CustomEditor def _get_text_editor_class(self): """ Returns the editor class to use for "text" style views. The default implementation tries to import the TextEditor class in the editor file in the backend package, and if such a class is not found it returns the TextEditor class declared in the editor_factory module in the backend package. """ try: TextEditor = self._get_toolkit_editor('TextEditor') except: TextEditor = toolkit_object('editor_factory:TextEditor') return TextEditor def _get_readonly_editor_class(self): """ Returns the editor class to use for "readonly" style views. The default implementation tries to import the ReadonlyEditor class in the editor file in the backend package, and if such a class is not found it returns the ReadonlyEditor class declared in the editor_factory module in the backend package. """ try: ReadonlyEditor = self._get_toolkit_editor('ReadonlyEditor') except: ReadonlyEditor = toolkit_object('editor_factory:ReadonlyEditor') return ReadonlyEditor #------------------------------------------------------------------------------- # 'EditorWithListFactory' abstract base class: #------------------------------------------------------------------------------- class EditorWithListFactory ( EditorFactory ): """ Base class for factories of editors for objects that contain lists. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Values to enumerate (can be a list, tuple, dict, or a CTrait or # TraitHandler that is "mapped"): values = Any # Extended name of the trait on **object** containing the enumeration data: object = Str( 'object' ) # Name of the trait on 'object' containing the enumeration data name = Str # Fired when the **values** trait has been updated: values_modified = Event #--------------------------------------------------------------------------- # Recomputes the mappings whenever the 'values' trait is changed: #--------------------------------------------------------------------------- def _values_changed ( self ): """ Recomputes the mappings whenever the **values** trait is changed. """ self._names, self._mapping, self._inverse_mapping = \ enum_values_changed( self.values ) self.values_modified = True ## EOF ######################################################################## traitsui-4.1.0/traitsui/ui.py0000644000175100001440000010603611674463546017222 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/07/2004 # #------------------------------------------------------------------------------ """ Defines the UI class used to represent an active traits-based user interface. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import import shelve import os from traits.api import (Any, Bool, Callable, DictStrAny, Event, HasPrivateTraits, Instance, Int, List, Property, Str, TraitError, on_trait_change, property_depends_on) from traits.trait_base import traits_home, is_str from .editor import Editor from .view_elements import ViewElements from .handler import Handler, ViewHandler from .toolkit import toolkit from .ui_info import UIInfo from .item import Item from .group import Group, ShadowGroup #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- # List of **kind** types for views that must have a **parent** window specified kind_must_have_parent = ( 'panel', 'subpanel' ) #------------------------------------------------------------------------------- # 'UI' class: #------------------------------------------------------------------------------- class UI ( HasPrivateTraits ): """ Information about the user interface for a View. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # The ViewElements object from which this UI resolves Include items view_elements = Instance( ViewElements ) # Context objects that the UI is editing context = DictStrAny # Handler object used for event handling handler = Instance( Handler ) # View template used to construct the user interface view = Instance( 'traitsui.view.View' ) # Panel or dialog associated with the user interface control = Any # The parent UI (if any) of this UI parent = Instance( 'UI' ) # Toolkit-specific object that "owns" **control** owner = Any # UIInfo object containing context or editor objects info = Instance( UIInfo ) # Result from a modal or wizard dialog: result = Bool( False ) # Undo and Redo history history = Any # The KeyBindings object (if any) for this UI: key_bindings = Property # Instance( KeyBindings ) # The unique ID for this UI for persistence id = Str # Have any modifications been made to UI contents? modified = Bool( False ) # Event when the user interface has changed updated = Event( Bool ) # Title of the dialog, if any title = Str # The ImageResource of the icon, if any icon = Any # Should the created UI have scroll bars? scrollable = Bool( False ) # The number of currently pending editor error conditions errors = Int # The code used to rebuild an updated user interface rebuild = Callable #-- Private Traits --------------------------------------------------------- # Original context when used with a modal dialog _context = DictStrAny # Copy of original context used for reverting changes _revert = DictStrAny # List of methods to call once the user interface is created _defined = List # List of (visible_when,Editor) pairs _visible = List # List of (enabled_when,Editor) pairs _enabled = List # List of (checked_when,Editor) pairs _checked = List # Search stack used while building a user interface _search = List # List of dispatchable Handler methods _dispatchers = List # List of editors used to build the user interface _editors = List # List of names bound to the **info** object _names = List # Index of currently the active group in the user interface _active_group = Int # List of top-level groups used to build the user interface _groups = Property _groups_cache = Any # Count of levels of nesting for undoable actions _undoable = Int( -1 ) # Code used to rebuild an updated user interface _rebuild = Callable # The statusbar listeners that have been set up: _statusbar = List # Does the UI contain any scrollable widgets? # # The _scrollable trait is set correctly, but not used currently because # its value is arrived at too late to be of use in building the UI. _scrollable = Bool( False ) # List of traits that are reset when a user interface is recycled # (i.e. rebuilt). recyclable_traits = [ '_context', '_revert', '_defined', '_visible', '_enabled', '_checked', '_search', '_dispatchers', '_editors', '_names', '_active_group', '_undoable', '_rebuild', '_groups_cache' ] # List of additional traits that are discarded when a user interface is # disposed. disposable_traits = [ 'view_elements', 'info', 'handler', 'context', 'view', 'history', 'key_bindings', 'icon', 'rebuild', ] #--------------------------------------------------------------------------- # Initializes the traits object: #--------------------------------------------------------------------------- def traits_init ( self ): """ Initializes the traits object. """ self.info = UIInfo( ui = self ) self.handler.init_info( self.info ) #--------------------------------------------------------------------------- # Creates a user interface from the associated View template object: #--------------------------------------------------------------------------- def ui ( self, parent, kind ): """ Creates a user interface from the associated View template object. """ if (parent is None) and (kind in kind_must_have_parent): kind = 'live' self.view.on_trait_change( self._updated_changed, 'updated', dispatch = 'ui' ) self.rebuild = getattr( toolkit(), 'ui_' + kind ) self.rebuild( self, parent ) #--------------------------------------------------------------------------- # Disposes of the contents of a user interface: #--------------------------------------------------------------------------- def dispose ( self, result = None, abort = False ): """ Disposes of the contents of a user interface. """ if result is not None: self.result = result # Only continue if the view has not already been disposed of: if self.control is not None: # Save the user preference information for the user interface: if not abort: self.save_prefs() # Finish disposing of the user interface: self.finish() #--------------------------------------------------------------------------- # Recycles the user interface prior to rebuilding it: #--------------------------------------------------------------------------- def recycle ( self ): """ Recycles the user interface prior to rebuilding it. """ # Reset all user interface editors: self.reset( destroy = False ) # Discard any context object associated with the ui view control: self.control._object = None # Reset all recyclable traits: self.reset_traits( self.recyclable_traits ) #--------------------------------------------------------------------------- # Finishes a user interface: #--------------------------------------------------------------------------- def finish ( self ): """ Finishes disposing of a user interface. """ # Reset the contents of the user interface self.reset( destroy = True ) # Make sure that 'visible', 'enabled', and 'checked' handlers are not # called after the editor has been disposed: for object in self.context.values(): object.on_trait_change( self._evaluate_when, remove = True ) # Notify the handler that the view has been closed: self.handler.closed( self.info, self.result ) # Clear the back-link from the UIInfo object to us: self.info.ui = None # Destroy the view control: self.control._object = None toolkit().destroy_control( self.control ) self.control = None # Dispose of any KeyBindings object we reference: if self.key_bindings is not None: self.key_bindings.dispose() # Break the linkage to any objects in the context dictionary: self.context.clear() # Remove specified symbols from our dictionary to aid in clean-up: self.reset_traits( self.recyclable_traits ) self.reset_traits( self.disposable_traits ) #--------------------------------------------------------------------------- # Resets the contents of the user interface: #--------------------------------------------------------------------------- def reset ( self, destroy = True ): """ Resets the contents of a user interface. """ for editor in self._editors: if editor._ui is not None: # Propagate result to enclosed ui objects: editor._ui.result = self.result editor.dispose() # Zap the control. If there are pending events for the control in # the UI queue, the editor's '_update_editor' method will see that # the control is None and discard the update request: editor.control = None # Remove any statusbar listeners that have been set up: for object, handler, name in self._statusbar: object.on_trait_change( handler, name, remove = True ) del self._statusbar[:] if destroy: toolkit().destroy_children( self.control ) for dispatcher in self._dispatchers: dispatcher.remove() #--------------------------------------------------------------------------- # Find the definition of the specified Include object in the current user # interface building context: #--------------------------------------------------------------------------- def find ( self, include ): """ Finds the definition of the specified Include object in the current user interface building context. """ context = self.context result = None # Get the context 'object' (if available): if len( context ) == 1: object = context.values()[0] else: object = context.get( 'object' ) # Try to use our ViewElements objects: ve = self.view_elements # If none specified, try to get it from the UI context: if (ve is None) and (object is not None): # Use the context object's ViewElements (if available): ve = object.trait_view_elements() # Ask the ViewElements to find the requested item for us: if ve is not None: result = ve.find( include.id, self._search ) # If not found, then try to search the 'handler' and 'object' for a # method we can call that will define it: if result is None: handler = context.get( 'handler' ) if handler is not None: method = getattr( handler, include.id, None ) if callable( method ): result = method() if (result is None) and (object is not None): method = getattr( object, include.id, None ) if callable( method ): result = method() return result #--------------------------------------------------------------------------- # Returns the current search stack level: #--------------------------------------------------------------------------- def push_level ( self ): """ Returns the current search stack level. """ return len( self._search ) #--------------------------------------------------------------------------- # Restores a previously pushed search stack level: #--------------------------------------------------------------------------- def pop_level ( self, level ): """ Restores a previously pushed search stack level. """ del self._search[ : len( self._search ) - level ] #--------------------------------------------------------------------------- # Performs all post user interface creation processing: #--------------------------------------------------------------------------- def prepare_ui ( self ): """ Performs all processing that occurs after the user interface is created. """ # Invoke all of the editor 'name_defined' methods we've accumulated: info = self.info.set( initialized = False ) for method in self._defined: method( info ) # Then reset the list, since we don't need it anymore: del self._defined[:] # Synchronize all context traits with associated editor traits: self.sync_view() # Hook all keyboard events: toolkit().hook_events( self, self.control, 'keys', self.key_handler ) # Hook all events if the handler is an extended 'ViewHandler': handler = self.handler if isinstance( handler, ViewHandler ): toolkit().hook_events( self, self.control ) # Invoke the handler's 'init' method, and abort if it indicates failure: if handler.init( info ) == False: raise TraitError, 'User interface creation aborted' # For each Handler method whose name is of the form # 'object_name_changed', where 'object' is the name of an object in the # UI's 'context', create a trait notification handler that will call # the method whenever 'object's 'name' trait changes. Also invoke the # method immediately so initial user interface state can be correctly # set: context = self.context for name in self._each_trait_method( handler ): if name[-8:] == '_changed': prefix = name[:-8] col = prefix.find( '_', 1 ) if col >= 0: object = context.get( prefix[ : col ] ) if object is not None: method = getattr( handler, name ) trait_name = prefix[ col + 1: ] self._dispatchers.append( Dispatcher( method, info, object, trait_name ) ) if object.base_trait( trait_name ).type != 'event': method( info ) # If there are any Editor object's whose 'visible', 'enabled' or # 'checked' state is controlled by a 'visible_when', 'enabled_when' or # 'checked_when' expression, set up an 'anytrait' changed notification # handler on each object in the 'context' that will cause the 'visible', # 'enabled' or 'checked' state of each affected Editor to be set. Also # trigger the evaluation immediately, so the visible, enabled or checked # state of each Editor can be correctly initialized: if (len( self._visible ) + len( self._enabled ) + len( self._checked )) > 0: for object in context.values(): object.on_trait_change( self._evaluate_when, dispatch = 'ui' ) self._evaluate_when() # Indicate that the user interface has been initialized: info.initialized = True #--------------------------------------------------------------------------- # Synchronize context object traits with view editor traits: #--------------------------------------------------------------------------- def sync_view ( self ): """ Synchronize context object traits with view editor traits. """ for name, object in self.context.items(): self._sync_view( name, object, 'sync_to_view', 'from' ) self._sync_view( name, object, 'sync_from_view', 'to' ) self._sync_view( name, object, 'sync_with_view', 'both' ) def _sync_view ( self, name, object, metadata, direction ): info = self.info for trait_name, trait in object.traits( **{metadata: is_str} ).items(): for sync in getattr( trait, metadata ).split( ',' ): try: editor_id, editor_name = [ item.strip() for item in sync.split( '.' ) ] except: raise TraitError( "The '%s' metadata for the '%s' trait in " "the '%s' context object should be of the form: " "'id1.trait1[,...,idn.traitn]." % ( metadata, trait_name, name ) ) editor = getattr( info, editor_id, None ) if editor is not None: editor.sync_value( '%s.%s' % ( name, trait_name ), editor_name, direction ) else: raise TraitError( "No editor with id = '%s' was found for " "the '%s' metadata for the '%s' trait in the '%s' " "context object." % ( editor_id,metadata, trait_name, name ) ) #--------------------------------------------------------------------------- # Gets the current value of a specified extended trait name: #--------------------------------------------------------------------------- def get_extended_value ( self, name ): """ Gets the current value of a specified extended trait name. """ names = name.split( '.' ) if len( names ) > 1: value = self.context[ names[0] ] del names[0] else: value = self.context[ 'object' ] for name in names: value = getattr( value, name ) return value #--------------------------------------------------------------------------- # Restores any saved user preference information associated with the UI: #--------------------------------------------------------------------------- def restore_prefs ( self ): """ Retrieves and restores any saved user preference information associated with the UI. """ id = self.id if id != '': db = self.get_ui_db() if db is not None: try: ui_prefs = db.get( id ) db.close() return self.set_prefs( ui_prefs ) except: pass return None #--------------------------------------------------------------------------- # Restores user preference information for the UI: #--------------------------------------------------------------------------- def set_prefs ( self, prefs ): """ Sets the values of user preferences for the UI. """ if isinstance( prefs, dict ): info = self.info for name in self._names: editor = getattr( info, name, None ) if isinstance( editor, Editor ) and (editor.ui is self): editor_prefs = prefs.get( name ) if editor_prefs != None: editor.restore_prefs( editor_prefs ) if self.key_bindings is not None: key_bindings = prefs.get( '$' ) if key_bindings is not None: self.key_bindings.merge( key_bindings ) return prefs.get( '' ) return None #--------------------------------------------------------------------------- # Saves any user preference information associated with the UI: #--------------------------------------------------------------------------- def save_prefs ( self, prefs = None ): """ Saves any user preference information associated with the UI. """ if prefs is None: toolkit().save_window( self ) return id = self.id if id != '': db = self.get_ui_db( mode = 'c' ) if db is not None: db[ id ] = self.get_prefs( prefs ) db.close() #--------------------------------------------------------------------------- # Gets the preferences to be saved for the user interface: #--------------------------------------------------------------------------- def get_prefs ( self, prefs = None ): """ Gets the preferences to be saved for the user interface. """ ui_prefs = {} if prefs is not None: ui_prefs[''] = prefs if self.key_bindings is not None: ui_prefs['$'] = self.key_bindings info = self.info for name in self._names: editor = getattr( info, name, None ) if isinstance( editor, Editor ) and (editor.ui is self): prefs = editor.save_prefs() if prefs != None: ui_prefs[ name ] = prefs return ui_prefs #--------------------------------------------------------------------------- # Gets a reference to the traits UI preference database: #--------------------------------------------------------------------------- def get_ui_db ( self, mode = 'r' ): """ Returns a reference to the Traits UI preference database. """ try: return shelve.open( os.path.join( traits_home(), 'traits_ui' ), flag = mode, protocol = -1 ) except: return None #--------------------------------------------------------------------------- # Returns a list of editors for the given trait name. #--------------------------------------------------------------------------- def get_editors ( self, name ): """ Returns a list of editors for the given trait name. """ return [ editor for editor in self._editors if editor.name == name ] #--------------------------------------------------------------------------- # Returns the list of editor error controls contained by the user # interface: #--------------------------------------------------------------------------- def get_error_controls ( self ): """ Returns the list of editor error controls contained by the user interface. """ controls = [] for editor in self._editors: control = editor.get_error_control() if isinstance( control, list ): controls.extend( control ) else: controls.append( control ) return controls #--------------------------------------------------------------------------- # Adds a Handler method to the list of methods to be called once the user # interface has been constructed: #--------------------------------------------------------------------------- def add_defined ( self, method ): """ Adds a Handler method to the list of methods to be called once the user interface has been constructed. """ self._defined.append( method ) #--------------------------------------------------------------------------- # Add's a conditionally enabled Editor object to the list of monitored # 'visible_when' objects: #--------------------------------------------------------------------------- def add_visible ( self, visible_when, editor ): """ Adds a conditionally enabled Editor object to the list of monitored 'visible_when' objects. """ try: self._visible.append( ( compile( visible_when, '', 'eval' ), editor ) ) except: pass # fixme: Log an error here... #--------------------------------------------------------------------------- # Add's a conditionally enabled Editor object to the list of monitored # 'enabled_when' objects: #--------------------------------------------------------------------------- def add_enabled ( self, enabled_when, editor ): """ Adds a conditionally enabled Editor object to the list of monitored 'enabled_when' objects. """ try: self._enabled.append( ( compile( enabled_when, '', 'eval' ), editor ) ) except: pass # fixme: Log an error here... #--------------------------------------------------------------------------- # Add's a conditionally checked (menu/toolbar) Editor object to the list of # monitored 'checked_when' objects: #--------------------------------------------------------------------------- def add_checked ( self, checked_when, editor ): """ Adds a conditionally enabled (menu) Editor object to the list of monitored 'checked_when' objects. """ try: self._checked.append( ( compile( checked_when, '', 'eval' ), editor ) ) except: pass # fixme: Log an error here... #--------------------------------------------------------------------------- # Performs an 'undoable' action: #--------------------------------------------------------------------------- def do_undoable ( self, action, *args, **kw ): """ Performs an action that can be undone. """ undoable = self._undoable try: if (undoable == -1) and (self.history is not None): self._undoable = self.history.now action( *args, **kw ) finally: if undoable == -1: self._undoable = -1 #--------------------------------------------------------------------------- # Routes a 'hooked' event to the correct handler method: #--------------------------------------------------------------------------- def route_event ( self, event ): """ Routes a "hooked" event to the correct handler method. """ toolkit().route_event( self, event ) #--------------------------------------------------------------------------- # Handles key events when the view has a set of KeyBindings: #--------------------------------------------------------------------------- def key_handler ( self, event, skip = True ): """ Handles key events. """ key_bindings = self.key_bindings handled = ((key_bindings is not None) and key_bindings.do( event, [], self.info, recursive = (self.parent is None) )) if (not handled) and (self.parent is not None): handled = self.parent.key_handler( event, False ) if (not handled) and skip: toolkit().skip_event(event) return handled #--------------------------------------------------------------------------- # Evaluates a specified function in the UI's context: #--------------------------------------------------------------------------- def evaluate ( self, function, *args, **kw_args ): """ Evaluates a specified function in the UI's **context**. """ if function is None: return None if callable( function ): return function( *args, **kw_args ) context = self.context.copy() context[ 'ui' ] = self context[ 'handler' ] = self.handler return eval( function, globals(), context )( *args, **kw_args ) #--------------------------------------------------------------------------- # Evaluates an expression in the UI's 'context' and returns the result: #--------------------------------------------------------------------------- def eval_when ( self, when, result = True ): """ Evaluates an expression in the UI's **context** and returns the result. """ context = self._get_context( self.context ) try: result = eval( when, globals(), context ) except: # fixme: Should the exception be logged somewhere? pass del context[ 'ui' ] return result #--------------------------------------------------------------------------- # Gets the context to use for evaluating an expression: #--------------------------------------------------------------------------- def _get_context ( self, context ): """ Gets the context to use for evaluating an expression. """ name = 'object' n = len( context ) if (n == 2) and ('handler' in context): for name, value in context.items(): if name != 'handler': break elif n == 1: name = context.keys()[0] value = context.get( name ) if value is not None: context2 = value.trait_get() context2.update( context ) else: context2 = context.copy() context2['ui'] = self return context2 #--------------------------------------------------------------------------- # Sets the 'visible', 'enabled' and/or 'checked' state for all Editors # controlled by a 'visible_when', 'enabled_when' or 'checked_when' # expression: #--------------------------------------------------------------------------- def _evaluate_when ( self ): """ Sets the 'visible', 'enabled', and 'checked' states for all Editors controlled by a 'visible_when', 'enabled_when' or 'checked_when' expression. """ self._evaluate_condition( self._visible, 'visible' ) self._evaluate_condition( self._enabled, 'enabled' ) self._evaluate_condition( self._checked, 'checked' ) #--------------------------------------------------------------------------- # Evaluates a list of ( eval, editor ) pairs and sets a specified trait on # each editor to reflect the boolean truth of the expression evaluated: #--------------------------------------------------------------------------- def _evaluate_condition ( self, conditions, trait ): """ Evaluates a list of (eval,editor) pairs and sets a specified trait on each editor to reflect the Boolean value of the expression. """ context = self._get_context( self.context ) for when, editor in conditions: value = True try: if not eval( when, globals(), context ): value = False except: from traitsui.api import raise_to_debug raise_to_debug() setattr( editor, trait, value ) #--------------------------------------------------------------------------- # Implementation of the '_groups' property: # (Returns the top-level Groups for the view (after resolving Includes)) #--------------------------------------------------------------------------- def _get__groups ( self ): """ Returns the top-level Groups for the view (after resolving Includes. (Implements the **_groups** property.) """ if self._groups_cache is None: shadow_group = self.view.content.get_shadow( self ) self._groups_cache = shadow_group.get_content() for item in self._groups_cache: if isinstance( item, Item ): self._groups_cache = [ ShadowGroup( shadow = Group( *self._groups_cache ), content = self._groups_cache, groups = 1 ) ] break return self._groups_cache #-- Property Implementations ----------------------------------------------- @property_depends_on( 'view, context' ) def _get_key_bindings ( self ): view, context = self.view, self.context if (view is None) or (context is None): return None # Get the KeyBindings object to use: values = context.values() key_bindings = view.key_bindings if key_bindings is None: from .key_bindings import KeyBindings return KeyBindings( controllers = values) return key_bindings.clone( controllers = values ) #-- Traits Event Handlers -------------------------------------------------- def _updated_changed ( self ): if self.rebuild is not None: toolkit().rebuild_ui( self ) def _title_changed ( self ): if self.control is not None: toolkit().set_title( self ) def _icon_changed ( self ): if self.control is not None: toolkit().set_icon( self ) @on_trait_change( 'parent, view, context' ) def _pvc_changed ( self ): parent = self.parent if (parent is not None) and (self.key_bindings is not None): # If we don't have our own history, use our parent's: if self.history is None: self.history = parent.history # Link our KeyBindings object as a child of our parent's # KeyBindings object (if any): if parent.key_bindings is not None: parent.key_bindings.children.append( self.key_bindings ) #------------------------------------------------------------------------------- # 'Dispatcher' class: #------------------------------------------------------------------------------- class Dispatcher ( object ): #--------------------------------------------------------------------------- # Initializes the object: #--------------------------------------------------------------------------- def __init__ ( self, method, info, object, method_name ): """ Initializes the object. """ self.method = method self.info = info self.object = object self.method_name = method_name object.on_trait_change( self.dispatch, method_name, dispatch = 'ui' ) #--------------------------------------------------------------------------- # Dispatches the method: #--------------------------------------------------------------------------- def dispatch ( self ): """ Dispatches the method. """ self.method( self.info ) #--------------------------------------------------------------------------- # Remove the dispatcher: #--------------------------------------------------------------------------- def remove ( self ): """ Removes the dispatcher. """ self.object.on_trait_change( self.dispatch, self.method_name, remove = True ) traitsui-4.1.0/traitsui/menu.py0000644000175100001440000001564511674463546017556 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 12/19/2004 # #------------------------------------------------------------------------------ """ Defines the standard menu bar for use with Traits UI windows and panels, and standard actions and buttons. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import Str # Import and rename the needed PyFace elements: from pyface.action.api import ToolBarManager as ToolBar from pyface.action.api import MenuBarManager as MenuBar from pyface.action.api import MenuManager as Menu from pyface.action.api import Group as ActionGroup from pyface.action.api import Action as PyFaceAction #------------------------------------------------------------------------------- # 'Action' class (extends the core pyface Action class): #------------------------------------------------------------------------------- class Action ( PyFaceAction ): """ An action on a menu bar in a Traits UI window or panel. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Pre-condition for showing the action. If the expression evaluates to False, # the action is not visible (and disappears if it was previously visible). # If the value evaluates to True, the action becomes visible. All # **visible_when** conditions are checked each time that any trait value # is edited in the display. Therefore, you can use **visible_when** # conditions to hide or show actions in response to user input. visible_when = Str # Pre-condition for enabling the action. If the expression evaluates to # False, the action is disabled, that is, it cannot be selected. All # **enabled_when** conditions are checked each time that any trait value # is edited in the display. Therefore, you can use **enabled_when** # conditions to enable or disable actions in response to user input. enabled_when = Str # Boolean expression indicating when the action is displayed with a check # mark beside it. This attribute applies only to actions that are included # in menus. checked_when = Str # Pre-condition for including the action in the menu bar or toolbar. If the # expression evaluates to False, the action is not defined in the display. # Conditions for **defined_when** are evaluated only once, when the display # is first constructed. defined_when = Str # The method to call to perform the action, on the Handler for the window. # The method must accept a single parameter, which is a UIInfo object. # Because Actions are associated with Views rather than Handlers, you must # ensure that the Handler object for a particular window has a method with # the correct name, for each Action defined on the View for that window. action = Str #------------------------------------------------------------------------------- # Standard actions and menu bar definitions: #------------------------------------------------------------------------------- # Menu separator: Separator = ActionGroup # The standard "close window" action: CloseAction = Action( name = 'Close', action = '_on_close' ) # The standard "undo last change" action: UndoAction = Action( name = 'Undo', action = '_on_undo', defined_when = 'ui.history is not None', enabled_when = 'ui.history.can_undo' ) # The standard "redo last undo" action: RedoAction = Action( name = 'Redo', action = '_on_redo', defined_when = 'ui.history is not None', enabled_when = 'ui.history.can_redo' ) # The standard "revert all changes" action: RevertAction = Action( name = 'Revert', action = '_on_revert', defined_when = 'ui.history is not None', enabled_when = 'ui.history.can_undo' ) # The standard "show help" action: HelpAction = Action( name = 'Help', action = 'show_help' ) # The standard Traits UI menu bar: StandardMenuBar = MenuBar( Menu( CloseAction, name = 'File' ), Menu( UndoAction, RedoAction, RevertAction, name = 'Edit' ), Menu( HelpAction, name = 'Help' ) ) #------------------------------------------------------------------------------- # Standard buttons (i.e. actions): #------------------------------------------------------------------------------- NoButton = Action( name = '' ) # Appears as two buttons: **Undo** and **Redo**. When **Undo** is clicked, the # most recent change to the data is cancelled, restoring the previous value. # **Redo** cancels the most recent "undo" operation. UndoButton = Action( name = 'Undo' ) # When the user clicks the **Revert** button, all changes made in the window are # cancelled and the original values are restored. If the changes have been # applied to the model (because the user clicked **Apply** or because the window # is live), the model data is restored as well. The window remains open. RevertButton = Action( name = 'Revert' ) # When theuser clicks the **Apply** button, all changes made in the window are # applied to the model. This option is meaningful only for modal windows. ApplyButton = Action( name = 'Apply' ) # When the user clicks the **OK** button, all changes made in the window are # applied to the model, and the window is closed. OKButton = Action( name = 'OK' ) # When the user clicks the **Cancel** button, all changes made in the window # are discarded; if the window is live, the model is restored to the values it # held before the window was opened. The window is then closed. CancelButton = Action( name = 'Cancel' ) # When the user clicks the **Help** button, the current help handler is # invoked. If the default help handler is used, a pop-up window is displayed, # which contains the **help** text for the top-level Group (if any), and for # the items in the view. If the default help handler has been overridden, # the action is determined by the custom help handler. See # **traitsui.help**. HelpButton = Action( name = 'Help' ) OKCancelButtons = [ OKButton, CancelButton ] ModalButtons = [ ApplyButton, RevertButton, OKButton, CancelButton, HelpButton ] LiveButtons = [ UndoButton, RevertButton, OKButton, CancelButton, HelpButton ] # The window has no command buttons: NoButtons = [ NoButton ] traitsui-4.1.0/traitsui/editors/0000755000175100001440000000000011674463546017676 5ustar ischnellusers00000000000000traitsui-4.1.0/traitsui/editors/tuple_editor.py0000644000175100001440000002005411674463546022750 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2008, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # #------------------------------------------------------------------------------ """ Defines the tuple editor factory for all traits user interface toolkits. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.trait_base import SequenceTypes, enumerate from traits.api import Bool, HasTraits, List, Tuple, Unicode, Int, Any, TraitType # CIRCULAR IMPORT FIXME: Importing from the source rather than traits.ui.api # to avoid circular imports, as this EditorFactory will be part of # traits.ui.api as well. from ..view import View from ..group import Group from ..item import Item from ..editor_factory import EditorFactory from ..editor import Editor #------------------------------------------------------------------------------- # 'ToolkitEditorFactory' class: #------------------------------------------------------------------------------- class ToolkitEditorFactory ( EditorFactory ): """ Editor factory for tuple editors. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Trait definitions for each tuple field types = Any # Labels for each of the tuple fields labels = List( Unicode ) # Editors for each of the tuple fields: editors = List( EditorFactory ) # Number of tuple fields or rows cols = Int( 1 ) # Is user input set on every keystroke? This is applied to every field # of the tuple, provided the field does not already have an 'auto_set' # metadata or an editor defined. auto_set = Bool( True ) # Is user input set when the Enter key is pressed? This is applied to # every field of the tuple, provided the field does not already have an # 'enter_set' metadata or an editor defined. enter_set = Bool( False ) #------------------------------------------------------------------------------- # 'SimpleEditor' class: #------------------------------------------------------------------------------- class SimpleEditor ( Editor ): """ Simple style of editor for tuples. The editor displays an editor for each of the fields in the tuple, based on the type of each field. """ #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self._ts = ts = TupleStructure( self ) self._ui = ui = ts.view.ui( ts, parent, kind = 'subpanel' ).set( parent = self.ui ) self.control = ui.control self.set_tooltip() #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes external to the editor. """ ts = self._ts for i, value in enumerate( self.value ): setattr( ts, 'f%d' % i, value ) #--------------------------------------------------------------------------- # Returns the editor's control for indicating error status: #--------------------------------------------------------------------------- def get_error_control ( self ): """ Returns the editor's control for indicating error status. """ return self._ui.get_error_controls() #------------------------------------------------------------------------------- # 'TupleStructure' class: #------------------------------------------------------------------------------- class TupleStructure ( HasTraits ): """ Creates a view containing items for each field in a tuple. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Editor this structure is linked to editor = Any # The constructed View for the tuple view = Any # Number of tuple fields fields = Int #--------------------------------------------------------------------------- # Initializes the object: #--------------------------------------------------------------------------- def __init__ ( self, editor ): """ Initializes the object. """ factory = editor.factory types = factory.types labels = factory.labels editors = factory.editors cols = factory.cols # Save the reference to the editor: self.editor = editor # Get the tuple we are mirroring: object = editor.value # For each tuple field, add a trait with the appropriate trait # definition and default value: content = [] self.fields = len( object ) len_labels = len( labels ) len_editors = len( editors ) if types is None: type = editor.value_trait.handler if isinstance( type, Tuple ): types = type.types if not isinstance( types, SequenceTypes ): types = [ types ] len_types = len( types ) if len_types == 0: types = [ Any ] len_types = 1 for i, value in enumerate( object ): type = types[ i % len_types ] auto_set = enter_set = None if isinstance(type, TraitType): auto_set = type.auto_set enter_set = type.enter_set if auto_set is None: auto_set = editor.factory.auto_set if enter_set is None: enter_set = editor.factory.enter_set label = '' if i < len_labels: label = labels[i] field_editor = None if i < len_editors: field_editor = editors[i] name = 'f%d' % i self.add_trait( name, type( value, event = 'field', auto_set = auto_set, enter_set = enter_set ) ) item = Item( name = name, label = label, editor = field_editor ) if cols <= 1: content.append( item ) else: if (i % cols) == 0: group = Group( orientation = 'horizontal' ) content.append( group ) group.content.append( item ) self.view = View( Group( show_labels = (len_labels != 0), *content ) ) #--------------------------------------------------------------------------- # Updates the underlying tuple when any field changes value: #--------------------------------------------------------------------------- def _field_changed ( self ): """ Updates the underlying tuple when any field changes value. """ self.editor.value = tuple( [ getattr( self, 'f%d' % i ) for i in range( self.fields ) ] ) # Define the TupleEditor class. TupleEditor = ToolkitEditorFactory ### EOF ####################################################################### traitsui-4.1.0/traitsui/editors/array_editor.py0000644000175100001440000002362711674463546022746 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2008, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 01/10/2006 # #------------------------------------------------------------------------------ """ Defines the array editor factory for all traits toolkit backends. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import import numpy from traits.api import Bool, HasTraits, Int, Float, Instance, false, TraitError from ..editor import Editor from ..editor_factory import EditorFactory # CIRCULAR IMPORT FIXME: Importing from the source rather than traits.ui.api # to avoid circular imports, as this EditorFactory will be part of # traits.ui.api as well. from ..view import View from ..group import Group from ..item import Item #------------------------------------------------------------------------------- # 'ToolkitEditorFactory' class: #------------------------------------------------------------------------------- class ToolkitEditorFactory ( EditorFactory ): """ Editor factory for array editors. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Width of the individual fields width = Int( -80 ) # Is user input set on every keystroke? auto_set = Bool( True ) # Is user input set when the Enter key is pressed? enter_set = Bool( False ) #------------------------------------------------------------------------------- # 'ArrayStructure' class: #------------------------------------------------------------------------------- class ArrayStructure ( HasTraits ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Editor that this structure is linked to editor = Instance( Editor ) # The constructed View for the array view = Instance( View ) #--------------------------------------------------------------------------- # Initializes the object: #--------------------------------------------------------------------------- def __init__ ( self, editor ): """ Initializes the object. """ # Save the reference to the editor: self.editor = editor # Set up the field width for each item: width = editor.factory.width # Set up the correct style for each filed: style = 'simple' if editor.readonly: style = 'readonly' # Get the array we are mirroring: object = editor.value # Determine the correct trait type to use for each element: trait = Float if object.dtype.type == 'i': trait = Int if len( object.shape ) == 1: self.view = self._one_dim_view( object, style, width, trait ) elif len( object.shape ) == 2: self.view = self._two_dim_view( object, style, width, trait ) else: raise TraitError( 'Only 1D or 2D arrays supported' ) #--------------------------------------------------------------------------- # 1D view: #--------------------------------------------------------------------------- def _one_dim_view ( self, object, style, width, trait ): content = [] shape = object.shape items = [] format_func = self.editor.factory.format_func format_str = self.editor.factory.format_str for i in range( shape[0] ): name = 'f%d' % i self.add_trait( name, trait( object[i], event = 'field', auto_set = self.editor.factory.auto_set, enter_set = self.editor.factory.enter_set ) ) items.append( Item( name = name, style = style, width = width, format_func = format_func, format_str = format_str, padding = -3 ) ) group = Group( orientation = 'horizontal', show_labels = False, *items ) content.append( group ) return View( Group( show_labels = False, *content ) ) #--------------------------------------------------------------------------- # 2D view: #--------------------------------------------------------------------------- def _two_dim_view ( self, object, style, width, trait ): content = [] shape = object.shape format_func = self.editor.factory.format_func format_str = self.editor.factory.format_str for i in range( shape[0] ): items = [] for j in range( shape[1] ): name = 'f%d_%d' % ( i, j ) self.add_trait( name, trait( object[i, j], event = 'field', auto_set = self.editor.factory.auto_set, enter_set = self.editor.factory.enter_set ) ) items.append( Item( name = name, style = style, width = width, format_func = format_func, format_str = format_str, padding = -3 ) ) group = Group( orientation = 'horizontal', show_labels = False, *items ) content.append( group ) return View( Group( show_labels = False, *content ) ) #--------------------------------------------------------------------------- # Updates the underlying tuple when any field changes value: #--------------------------------------------------------------------------- def _field_changed ( self ): """ Updates the underlying array when any field changes value. """ if not self.editor._busy: # Get the array we are mirroring: object = self.editor.value shape = object.shape value = numpy.zeros( shape, object.dtype ) # 1D if len( shape ) == 1: for i in range( shape[0] ): value[i] = getattr( self, 'f%d' % i ) # 2D elif len( shape ) == 2: for i in range( shape[0] ): for j in range( shape[1] ): value[i,j] = getattr( self, 'f%d_%d' % ( i, j ) ) self.editor.update_array( value ) #------------------------------------------------------------------------------- # Toolkit-independent 'SimpleEditor' class: #------------------------------------------------------------------------------- class SimpleEditor ( Editor ): """ Simple style of editor for arrays. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Is the editor read-only? readonly = false #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self._as = _as = ArrayStructure( self ) ui = _as.view.ui( _as, parent, kind = 'subpanel' ) ui.parent = self.ui self.control = ui.control #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ if not self._busy: self._busy = True object = self.value shape = object.shape _as = self._as # 1D if len( shape ) == 1: for i in range( shape[0] ): setattr( _as, 'f%d' % i, object[i] ) # 2D elif len( shape ) == 2: for i in range( shape[0] ): for j in range( shape[1] ): setattr( _as, 'f%d_%d' % ( i, j ), object[i,j] ) self._busy=False #--------------------------------------------------------------------------- # Updates the array value associated with the editor: #--------------------------------------------------------------------------- def update_array ( self, value ): """ Updates the array value associated with the editor. """ self._busy = True self.value = value self._busy = False # Define the ArrayEditor class ArrayEditor = ToolkitEditorFactory ### EOF --------------------------------------------------------------------- traitsui-4.1.0/traitsui/editors/color_editor.py0000644000175100001440000000573511674463546022746 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2008, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/21/2004 # #------------------------------------------------------------------------------ """ Defines the color editor factory for the all traits toolkit backends. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import Bool from ..toolkit import toolkit_object # CIRCULAR IMPORT FIXME: Importing from the source rather than traits.ui.api # to avoid circular imports, as this EditorFactory will be part of # traits.ui.api as well. from ..view import View from ..editor_factory import EditorFactory #------------------------------------------------------------------------------- # 'ToolkitEditorFactory' class: #------------------------------------------------------------------------------- class ToolkitEditorFactory ( EditorFactory ): """ Editor factory for color editors. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Is the underlying color trait mapped? mapped = Bool( True ) #--------------------------------------------------------------------------- # Traits view definition: #--------------------------------------------------------------------------- traits_view = View( [ 'mapped{Is value mapped?}', '|[]>' ] ) # Define the ColorEditor class # The function will try to return the toolkit-specific editor factory (located # in traitsui..color_editor, and if none is found, the # ToolkitEditorFactory declared here is returned. def ColorEditor(*args, **traits): """ Returns an instance of the toolkit-specific editor factory declared in traitsui..color_editor. If such an editor factory cannot be located, an instance of the abstract ToolkitEditorFactory declared in traitsui.editors.color_editor is returned. Parameters ---------- \*args, \*\*traits arguments and keywords to be passed on to the editor factory's constructor. """ try: return toolkit_object('color_editor:ToolkitEditorFactory', True)(*args, **traits) except: return ToolkitEditorFactory(*args, **traits) ## EOF ####################################################################### traitsui-4.1.0/traitsui/editors/text_editor.py0000644000175100001440000001002411674463546022577 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2008, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/07/2004 # #------------------------------------------------------------------------------ """ Defines the text editor factory for all traits toolkit backends. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import Dict, Str, Any, Bool # CIRCULAR IMPORT FIXME: Importing from the source rather than traits.ui.api # to avoid circular imports, as this EditorFactory will be part of # traits.ui.api as well. from ..view import View from ..group import Group from ..ui_traits import AView from ..editor_factory import EditorFactory #------------------------------------------------------------------------------- # Define a simple identity mapping: #------------------------------------------------------------------------------- class _Identity ( object ): """ A simple identity mapping. """ def __call__ ( self, value ): return value #------------------------------------------------------------------------------- # Trait definitions: #------------------------------------------------------------------------------- # Mapping from user input text to other value mapping_trait = Dict( Str, Any ) # Function used to evaluate textual user input evaluate_trait = Any( _Identity() ) #------------------------------------------------------------------------------- # 'ToolkitEditorFactory' class: #------------------------------------------------------------------------------- class ToolkitEditorFactory ( EditorFactory ): """ Editor factory for text editors. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Dictionary that maps user input to other values mapping = mapping_trait # Is user input set on every keystroke? auto_set = Bool( True ) # Is user input set when the Enter key is pressed? enter_set = Bool( False ) # Is multi-line text allowed? multi_line = Bool( True ) # Is editor readonly (will use custom / default editor appearance with readonly flag set to true) # in contrasrt with readonly style for item when completely another edito is used read_only = Bool( False ) # Is user input unreadable? (e.g., for a password) password = Bool( False ) # Function to evaluate textual user input evaluate = evaluate_trait # The object trait containing the function used to evaluate user input evaluate_name = Str # The optional view to display when a read-only text editor is clicked: view = AView # In a read-only text editor, allow selection and copying of the text. readonly_allow_selection = Bool(False) #--------------------------------------------------------------------------- # Traits view definition: #--------------------------------------------------------------------------- traits_view = View( [ 'auto_set{Set value when text is typed}', 'enter_set{Set value when enter is pressed}', 'multi_line{Allow multiple lines of text}', '', '|options:[Options]>' ] ) extras = Group( 'password{Is this a password field?}' ) # Define the TextEditor class. TextEditor = ToolkitEditorFactory ### EOF ####################################################################### traitsui-4.1.0/traitsui/editors/file_editor.py0000644000175100001440000000762111674463546022543 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2008, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # #------------------------------------------------------------------------------ """ Defines the file editor factory for all traits toolkit backends. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import List, Str, Bool, Int, Unicode, File # CIRCULAR IMPORT FIXME: Importing from the source rather than traits.ui.api # to avoid circular imports, as this EditorFactory will be part of # traits.ui.api as well. from ..view import View from ..group import Group from .text_editor import ToolkitEditorFactory as EditorFactory #------------------------------------------------------------------------------- # Trait definitions: #------------------------------------------------------------------------------- # Wildcard filter: filter_trait = List(Unicode) #------------------------------------------------------------------------------- # 'ToolkitEditorFactory' class: #------------------------------------------------------------------------------- class ToolkitEditorFactory ( EditorFactory ): """ Editor factory for file editors. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Wildcard filter to apply to the file dialog: filter = filter_trait # Optional extended trait name of the trait containing the list of filters: filter_name = Str # Should file extension be truncated? truncate_ext = Bool( False ) # Can the user select directories as well as files? allow_dir = Bool( False ) # Is user input set on every keystroke? (Overrides the default) ('simple' # style only): auto_set = False # Is user input set when the Enter key is pressed? (Overrides the default) # ('simple' style only): enter_set = True # The number of history entries to maintain: # FIXME: add support entries = Int( 10 ) # The root path of the file tree view ('custom' style only, not supported # under wx). If not specified, the filesystem root is used. root_path = File # Optional extend trait name of the trait containing the root path. root_path_name = Str # Optional extended trait name used to notify the editor when the file # system view should be reloaded ('custom' style only): reload_name = Str # Optional extended trait name used to notify when the user double-clicks # an entry in the file tree view. The associated path is assigned it: dclick_name = Str # The style of file dialog to use when the 'Browse...' button is clicked # Should be one of 'open' or 'save' dialog_style = Str('open') #--------------------------------------------------------------------------- # Traits view definition: #--------------------------------------------------------------------------- traits_view = View( [ [ '', 'truncate_ext{Automatically truncate file extension?}', '|options:[Options]>' ], [ 'filter', '|[Wildcard filters]<>' ] ] ) extras = Group() # Define the FileEditor class. FileEditor = ToolkitEditorFactory ## EOF ######################################################################## traitsui-4.1.0/traitsui/editors/tests/0000755000175100001440000000000011674463546021040 5ustar ischnellusers00000000000000traitsui-4.1.0/traitsui/editors/tests/test_default_override.py0000644000175100001440000000511611674463546025777 0ustar ischnellusers00000000000000 from __future__ import absolute_import from nose.tools import assert_equals from ...api import DefaultOverride, EditorFactory from traits.api import HasTraits, Int class DummyEditor(EditorFactory): x = Int(10) y = Int(20) def simple_editor(self, ui, object, name, description, parent): return ('simple_editor', self, ui, object, name, description, parent) def custom_editor(self, ui, object, name, description, parent): return ('custom_editor', self, ui, object, name, description, parent) def text_editor(self, ui, object, name, description, parent): return ('text_editor', self, ui, object, name, description, parent) def readonly_editor(self, ui, object, name, description, parent): return ('readonly_editor', self, ui, object, name, description, parent) class NewInt(Int): def create_editor(self): return DummyEditor() class Dummy(HasTraits): x = NewInt() object = Dummy() do = DefaultOverride(x=15, y=25, format_str='%r') def test_simple_override(): editor_name, editor, ui, obj, name, description, parent = do.simple_editor('ui', object, 'x', 'description', 'parent') assert_equals(editor_name, 'simple_editor') assert_equals(editor.x, 15) assert_equals(editor.y, 25) assert_equals(obj, object) assert_equals(name, 'x') assert_equals(description, 'description') assert_equals(parent, 'parent') def test_text_override(): editor_name, editor, ui, obj, name, description, parent = do.text_editor('ui', object, 'x', 'description', 'parent') assert_equals(editor_name, 'text_editor') assert_equals(editor.x, 15) assert_equals(editor.y, 25) assert_equals(obj, object) assert_equals(name, 'x') assert_equals(description, 'description') assert_equals(parent, 'parent') def test_custom_override(): editor_name, editor, ui, obj, name, description, parent = do.custom_editor('ui', object, 'x', 'description', 'parent') assert_equals(editor_name, 'custom_editor') assert_equals(editor.x, 15) assert_equals(editor.y, 25) assert_equals(obj, object) assert_equals(name, 'x') assert_equals(description, 'description') assert_equals(parent, 'parent') def test_readonly_override(): editor_name, editor, ui, obj, name, description, parent = do.readonly_editor('ui', object, 'x', 'description', 'parent') assert_equals(editor_name, 'readonly_editor') assert_equals(editor.x, 15) assert_equals(editor.y, 25) assert_equals(obj, object) assert_equals(name, 'x') assert_equals(description, 'description') assert_equals(parent, 'parent') traitsui-4.1.0/traitsui/editors/tests/__init__.py0000644000175100001440000000000011674463546023137 0ustar ischnellusers00000000000000traitsui-4.1.0/traitsui/editors/shell_editor.py0000644000175100001440000002237511674463546022736 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 09/27/2005 # #------------------------------------------------------------------------------- """ Editor that displays an interactive Python shell. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import Bool, Str, Event, Property from ..editor import Editor from ..basic_editor_factory import BasicEditorFactory from ..toolkit import toolkit_object #------------------------------------------------------------------------------- # 'ShellEditor' class: #------------------------------------------------------------------------------- class _ShellEditor ( Editor ): """ Base class for an editor that displays an interactive Python shell. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # An event fired to execute a command in the shell. command_to_execute = Event() # An event fired whenver the user executes a command in the shell: command_executed = Event( Bool ) # Is the shell editor is scrollable? This value overrides the default. scrollable = True #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ # Moving the import here, since PythonShell is implemented in the # Pyface backend packages, and we want to delay loading this toolkit # specific class until this editor is actually used. from pyface.python_shell import PythonShell locals = None value = self.value if self.factory.share and isinstance( value, dict ): locals = value self._shell = shell = PythonShell( parent, locals = locals ) self.control = shell.control if locals is None: object = self.object shell.bind( 'self', object ) shell.on_trait_change( self.update_object, 'command_executed', dispatch = 'ui' ) if not isinstance( value, dict ): object.on_trait_change( self.update_any, dispatch = 'ui' ) else: self._base_locals = locals = {} for name in self._shell.interpreter().locals.keys(): locals[ name ] = None # Synchronize any editor events: self.sync_value( self.factory.command_to_execute, 'command_to_execute', 'from' ) self.sync_value( self.factory.command_executed, 'command_executed', 'to' ) self.set_tooltip() #--------------------------------------------------------------------------- # Handles the user entering input data in the edit control: #--------------------------------------------------------------------------- def update_object ( self, event ): """ Handles the user entering input data in the edit control. """ locals = self._shell.interpreter().locals base_locals = self._base_locals if base_locals is None: object = self.object for name in object.trait_names(): if name in locals: try: setattr( object, name, locals[ name ] ) except: pass else: dic = self.value for name in locals.keys(): if name not in base_locals: try: dic[ name ] = locals[ name ] except: pass self.command_executed = True #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ if self.factory.share: value = self.value if isinstance( value, dict ): self._shell.interpreter().locals = value else: locals = self._shell.interpreter().locals base_locals = self._base_locals if base_locals is None: object = self.object for name in object.trait_names(): locals[ name ] = getattr( object, name, None ) else: dic = self.value for name, value in dic.items(): locals[ name ] = value #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_any ( self, object, name, old, new ): """ Updates the editor when the object trait changes externally to the editor. """ locals = self._shell.interpreter().locals if self._base_locals is None: locals[ name ] = new else: self.value[ name ] = new #--------------------------------------------------------------------------- # Disposes of the contents of an editor: #--------------------------------------------------------------------------- def dispose ( self ): """ Disposes of the contents of an editor. """ self._shell.on_trait_change( self.update_object, 'command_executed', remove = True ) if self._base_locals is None: self.object.on_trait_change( self.update_any, remove = True ) super( _ShellEditor, self ).dispose() #--------------------------------------------------------------------------- # Restores any saved user preference information associated with the # editor: #--------------------------------------------------------------------------- def restore_prefs ( self, prefs ): """ Restores any saved user preference information associated with the editor. """ control = self._shell.control try: control.history = prefs.get( 'history', [] ) control.historyIndex = prefs.get( 'historyIndex', -1 ) except: pass #--------------------------------------------------------------------------- # Returns any user preference information associated with the editor: #--------------------------------------------------------------------------- def save_prefs ( self ): """ Returns any user preference information associated with the editor. """ control = self._shell.control return { 'history': control.history, 'historyIndex': control.historyIndex } #--------------------------------------------------------------------------- # Handles the 'command_to_execute' trait being fired: #--------------------------------------------------------------------------- def _command_to_execute_fired ( self, command ): """ Handles the 'command_to_execute' trait being fired. """ # Show the command. A 'hidden' command should be executed directly on # the namespace trait! self._shell.execute_command(command, hidden=False) #------------------------------------------------------------------------------- # Create the editor factory object: #------------------------------------------------------------------------------- # Editor factory for shell editors. class ToolkitEditorFactory ( BasicEditorFactory ): # The editor class to be instantiated. klass = Property # Should the shell interpreter use the object value's dictionary? share = Bool( False ) # Extended trait name of the object event trait which triggers a command # execution in the shell when fired. command_to_execute = Str # Extended trait name of the object event trait which is fired when a # command is executed. command_executed = Str def _get_klass(self): """ Returns the toolkit-specific editor class to be used in the UI. """ return toolkit_object('shell_editor:_ShellEditor') # Define the ShellEditor ShellEditor = ToolkitEditorFactory ### EOF ################################################################## traitsui-4.1.0/traitsui/editors/table_editor.py0000644000175100001440000005222211674463546022710 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2008, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/21/2004 # #------------------------------------------------------------------------------ """ Defines the table editor factory for all traits user interface toolkits. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import (Int, Float, List, Instance, Str, Color, Font, Any, Tuple, Dict, Enum, Trait, Bool, Callable, Range, on_trait_change) from ..editor_factory import EditorFactory from ..handler import Handler from ..helper import Orientation from ..item import Item from ..table_filter import TableFilter from ..ui_traits import AView from ..view import View from .enum_editor import EnumEditor #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- # The filter used to indicate that the user wants to customize the current # filter customize_filter = TableFilter( name = 'Customize...' ) #------------------------------------------------------------------------------- # Trait definitions: #------------------------------------------------------------------------------- # A trait whose value can be True, False, or a callable function BoolOrCallable = Trait( False, Bool, Callable ) #------------------------------------------------------------------------------- # 'ToolkitEditorFactory' class: #------------------------------------------------------------------------------- class ToolkitEditorFactory ( EditorFactory ): """ Editor factory for table editors. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # List of initial table column descriptors columns = List( Instance('traitsui.table_column.TableColumn') ) # List of other table column descriptors (not initially displayed) other_columns = List( Instance('traitsui.table_column.TableColumn') ) # The object trait containing the list of column descriptors columns_name = Str # The desired number of visible rows in the table rows = Int # The optional extended name of the trait used to specify an external filter # for the table data. The value of the trait must either be an instance of # TableEditor, a callable that accepts one argument (a table row) and # returns True or False to indicate whether the specified object passes the # filter or not, or **None** to indicate that no filter is to be applied: filter_name = Str # Initial filter that should be applied to the table filter = Instance( 'traitsui.table_filter.TableFilter' ) # List of available filters that can be applied to the table filters = List( Instance( 'traitsui.table_filter.TableFilter' ) ) # The optional extended trait name of the trait used to notify that the # filter has changed and the displayed objects should be updated. # It should be an Event. update_filter_name = Str # Filter object used to allow a user to search the table. # NOTE: If left as None, the table will not be searchable. search = Instance( 'traitsui.table_filter.TableFilter' ) # Default context menu to display when any cell is right-clicked menu = Instance( 'traitsui.menu.Menu' ) # Default trait name containg menu menu_name = Str # Are objects deletable from the table? deletable = BoolOrCallable( False ) # Is the table editable? editable = Bool( True ) # Should the editor become active after the first click edit_on_first_click = Bool( True ) # Can the user reorder the items in the table? reorderable = Bool( False ) # Can the user configure the table columns? configurable = Bool( True ) # Should the cells of the table automatically size to the optimal size? auto_size = Bool( True ) # Mirrors the Qt QSizePolicy.Policy attribute, for horizontal and vertical # dimensions. For these to be useful, set auto_size to False. If these # are None, then the table size policy will not be set in that dimension # (for backwards compatibility). h_size_policy = Enum( None, "preferred", "fixed", "minimum", "maximum", "expanding", "minimum_expanding", "ignored" ) v_size_policy = Enum( None, "preferred", "fixed", "minimum", "maximum", "expanding", "minimum_expanding", "ignored" ) # Should a new row automatically be added to the end of the table to allow # the user to create new entries? If True, **row_factory** must be set. auto_add = Bool( False ) # Should the table items be presented in reverse order? reverse = Bool( False ) # The DockWindow graphical theme: dock_theme = Any # View to use when editing table items. # NOTE: If not specified, the table items are not editable in a separate # pane of the editor. edit_view = AView( ' ' ) # The handler to apply to **edit_view** edit_view_handler = Instance( Handler ) # Width to use for the edit view edit_view_width = Float( -1.0 ) # Height to use for the edit view edit_view_height = Float( -1.0 ) # Layout orientation of the table and its associated editor pane. This # attribute applies only if **edit_view** is not ' '. orientation = Orientation # Is the table sortable by clicking on the column headers? sortable = Bool( True ) # Does sorting affect the model (vs. just the view)? sort_model = Bool( False ) # Should grid lines be shown on the table? show_lines = Bool( True ) # Should the toolbar be displayed? (Note that False will override settings # such as 'configurable', etc., and is a quick way to prevent the toolbar # from being displayed; but True will not cause a toolbar to appear if one # would not otherwise have been displayed) show_toolbar = Bool( False ) # The vertical scroll increment for the table: scroll_dy = Range( 1, 32 ) # Grid line color line_color = Color( 0xC4C0A9 ) # Show column labels? show_column_labels = Bool( True ) # Show row labels? show_row_labels = Bool( False ) # Font to use for text in cells cell_font = Font # Color to use for text in cells cell_color = Color( 'black' ) # Color to use for cell backgrounds # The default is the "WindowColor" constant declared in ui.api: # we shall set the value in a trait initializer method, in order to avoid # circular imports. cell_bg_color = Color # Color to use for read-only cell backgrounds cell_read_only_bg_color = Color( 0xF8F7F1 ) # Whether to even-odd alternate the background color. alternate_bg_color = Bool(False) # Font to use for text in labels label_font = Font # Color to use for text in labels label_color = Color( 'black' ) # Color to use for label backgrounds # The default is the "WindowColor" constant declared in ui.api: # we shall set the value in a trait initializer method, in order to avoid # circular imports. label_bg_color = Color # Background color of selected item selection_bg_color = Color( 'light blue', allow_none = True ) # Color of selected text selection_color = Color( 'black' ) # Height (in pixels) of column labels column_label_height = Int( 25 ) # Width (in pixels) of row labels row_label_width = Int( 82 ) # The initial height of each row (<= 0 means use default value): row_height = Int( 0 ) # The optional extended name of the trait that the indices of the items # currently passing the table filter are synced with: filtered_indices = Str # The selection mode of the table. The meaning of the various values are as # follows: # # row # Entire rows are selected. At most one row can be selected at once. # This is the default. # rows # Entire rows are selected. More than one row can be selected at once. # column # Entire columns are selected. At most one column can be selected at # once. # columns # Entire columns are selected. More than one column can be selected at # once. # cell # Single cells are selected. Only one cell can be selected at once. # cells # Single cells are selected. More than one cell can be selected at once. selection_mode = Enum( 'row', 'rows', 'column', 'columns', 'cell', 'cells' ) # The optional extended name of the trait that the current selection is # synced with: selected = Str # The optional extended trait name of the trait that the indices of the # current selection are synced with: selected_indices = Str # The optional extended trait name of the trait that should be assigned # an ( object, column ) tuple when a table cell is clicked on (Note: If you # want to receive repeated clicks on the same cell, make sure the trait is # defined as an Event): click = Str # The optional extended trait name of the trait that should be assigned # an ( object, column ) tuple when a table cell is double-clicked on # (Note: if you want to receive repeated double-clicks on the same cell, # make sure the trait is defined as an Event): dclick = Str # Called when a table item is selected on_select = Any # Called when a table item is double clicked on_dclick = Any # A factory to generate new rows. # NOTE: If None, then the user will not be able to add new rows to the # table. If not None, then it must be a callable that accepts # **row_factory_args** and **row_factory_kw** and returns a new object # that can be added to the table. row_factory = Any # Arguments to pass to the **row_factory** callable when a new row is # created row_factory_args = Tuple # Keyword arguments to pass to the **row_factory** callable when a new row # is created row_factory_kw = Dict # Hooks for replacing parts of the implementation. table_view_factory = Callable() source_model_factory = Callable() model_factory = Callable() #--------------------------------------------------------------------------- # Traits view definitions: #--------------------------------------------------------------------------- traits_view = View( [ '{Initial columns}@', Item( 'columns', resizable = True ), '{Other columns}@', Item( 'other_columns', resizable = True ), '|{Columns}<>' ], [ [ 'deletable{Are items deletable?}', '9', 'editable{Are items editable?}', '9', '-[Item Options]>' ], [ 'show_column_labels{Show column labels?}', '9', 'configurable{Are columns user configurable?}', '9', 'auto_size{Should columns auto size?}', '-[Column Options]>' ], [ 'sortable{Are columns sortable?}', Item( 'sort_model{Does sorting affect the model?}', enabled_when = 'sortable' ), '-[Sorting Options]>' ], [ [ 'show_lines{Show grid lines?}', '|>' ], [ '_', 'line_color{Grid line color}@', '|<>' ], '|[Grid Line Options]' ], '|{Options}' ], [ [ 'cell_color{Text color}@', 'cell_bg_color{Background color}@', 'cell_read_only_bg_color{Read only color}@', '|[Cell Colors]' ], [ 'cell_font', '|[Cell Font]<>' ], '|{Cell}' ], [ [ 'label_color{Text color}@', 'label_bg_color{Background color}@', '|[Label Colors]' ], [ 'label_font@', '|[Label Font]<>' ], '|{Label}' ], [ [ 'selection_color{Text color}@', 'selection_bg_color{Background color}@', '|[Selection Colors]' ], '|{Selection}' ], height = 0.5 ) #--------------------------------------------------------------------------- # 'Editor' factory methods: #--------------------------------------------------------------------------- def readonly_editor ( self, ui, object, name, description, parent ): """ Generates an "editor" that is read-only. Overridden to set the value of the editable trait to False before generating the editor. """ self.editable = False return super(ToolkitEditorFactory, self).readonly_editor( ui, object, name, description, parent) def _cell_bg_color_default(self): """ Returns the default value of the cell background color. """ # NOTE: We are initializing the 'cell_bg_color' trait in this method # instead of in the trait definition so as to delay importing from # ui.api until needed (will lead to circular imports otherwise). from ..api import WindowColor return WindowColor def _label_bg_color_default(self): """ Returns the default value of the cell background color. """ # NOTE: We are initializing the 'cell_bg_color' trait in this method # instead of in the trait definition so as to delay importing from # ui.api until needed (will lead to circular imports otherwise). from ..api import WindowColor return WindowColor #--------------------------------------------------------------------------- # Event handlers: #--------------------------------------------------------------------------- @on_trait_change('filters[]') def _update_filter_editor ( self, object, name, old, new ): """ Handles the set of filters associated with the editor's factory being changed. """ values = { None: '000:No filter' } i = 0 for filter in self.filters: if not filter.template: i += 1 values[ filter ] = '%03d:%s' % ( i, filter.name ) values[ customize_filter ] = '%03d:%s' % ( (i + 1), customize_filter.name ) if self._filter_editor is None: self._filter_editor = EnumEditor( values = values ) else: self._filter_editor.values = values # Define the TableEditor class TableEditor = ToolkitEditorFactory #------------------------------------------------------------------------------- # Base class for toolkit-specific editors #------------------------------------------------------------------------------- class BaseTableEditor(object): """ Base class for toolkit-specific editors. """ #--------------------------------------------------------------------------- # Interface for toolkit-specific editors: #--------------------------------------------------------------------------- def set_menu_context ( self, selection, object, column ): """Call before creating a context menu for a cell, then set self as the controller for the menu. """ self._menu_context = { 'selection': selection, 'object': object, 'column': column, 'editor': self, 'info': self.ui.info, 'handler': self.ui.handler } #--------------------------------------------------------------------------- # pyface.action 'controller' interface implementation: #--------------------------------------------------------------------------- def add_to_menu ( self, menu_item ): """ Adds a menu item to the menu bar being constructed. """ action = menu_item.item.action self.eval_when( action.enabled_when, menu_item, 'enabled' ) self.eval_when( action.checked_when, menu_item, 'checked' ) def add_to_toolbar ( self, toolbar_item ): """ Adds a toolbar item to the toolbar being constructed. """ self.add_to_menu( toolbar_item ) def can_add_to_menu ( self, action ): """ Returns whether the action should be defined in the user interface. """ if action.defined_when != '': if not eval( action.defined_when, globals(), self._menu_context ): return False if action.visible_when != '': if not eval( action.visible_when, globals(), self._menu_context ): return False return True def can_add_to_toolbar ( self, action ): """ Returns whether the toolbar action should be defined in the user interface. """ return self.can_add_to_menu( action ) def perform ( self, action, action_event = None ): """ Performs the action described by a specified Action object. """ self.ui.do_undoable( self._perform, action ) def _perform ( self, action ): method_name = action.action info = self.ui.info handler = self.ui.handler context = self._menu_context self._menu_context = None selection = context[ 'selection' ] if method_name.find( '.' ) >= 0: if method_name.find( '(' ) < 0: method_name += '()' try: eval( method_name, globals(), context ) except: # fixme: Should the exception be logged somewhere? pass return method = getattr( handler, method_name, None ) if method is not None: method( info, selection ) return if action.on_perform is not None: action.on_perform( selection ) return action.perform( selection ) #--------------------------------------------------------------------------- # Menu support methods: #--------------------------------------------------------------------------- def eval_when ( self, condition, object, trait ): """ Evaluates a condition within a defined context and sets a specified object trait based on the result, which is assumed to be a Boolean. """ if condition != '': value = bool( eval( condition, globals(), self._menu_context ) ) setattr( object, trait, value ) #------------------------------------------------------------------------------- # Helper class for toolkit-specific editors to implement 'reversed' option: #------------------------------------------------------------------------------- class ReversedList ( object ): """ A list whose order is the reverse of its input. """ def __init__ ( self, list ): self.list = list def insert ( self, index, value ): """ Inserts a value at a specified index in the list. """ return self.list.insert( self._index( index - 1 ), value ) def index ( self, value ): """ Returns the index of the first occurrence of the specified value in the list. """ list = self.list[:] list.reverse() return list.index( value ) def __len__ ( self ): """ Returns the length of the list. """ return len( self.list ) def __getitem__ ( self, index ): """ Returns the value at a specified index in the list. """ return self.list[ self._index( index ) ] def __setslice__ ( self, i, j, values ): """ Sets a slice of a list to the contents of a specified sequence. """ return self.list.__setslice__( self._index( i ), self._index( j ), values ) def __delitem__ ( self, index ): """ Deletes the item at a specified index. """ return self.list.__delitem__( self._index( index ) ) def _index ( self, index ): """ Returns the "reversed" value for a specified index. """ if index < 0: return (-1 - index) result = (len( self.list ) - index - 1) if result >= 0: return result return index traitsui-4.1.0/traitsui/editors/key_binding_editor.py0000644000175100001440000000340111674463546024076 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2008, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/21/2004 # #------------------------------------------------------------------------------ """ Defines the key binding editor for use with the KeyBinding class. This is a specialized editor used to associate a particular key with a control (i.e., the key binding editor). """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import # FIXME: Import from the api.py file when it has been added. from ..basic_editor_factory import BasicEditorFactory from ..toolkit import toolkit_object # Callable which returns the editor to use in the ui. def key_binding_editor(*args, **traits): return toolkit_object('key_binding_editor:KeyBindingEditor')(*args, **traits) #------------------------------------------------------------------------------- # Create the editor factory object: #------------------------------------------------------------------------------- KeyBindingEditor = ToolkitEditorFactory = BasicEditorFactory(klass = key_binding_editor) ### EOF ------------------------------------------------------------------------ traitsui-4.1.0/traitsui/editors/image_enum_editor.py0000644000175100001440000000741111674463546023727 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2008, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/21/2004 # #------------------------------------------------------------------------------ """ Defines the image enumeration editor factory for all traits user interface toolkits. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import import sys from os import getcwd from os.path import join, dirname, exists from traits.api import Module, Type, Unicode, on_trait_change from .enum_editor import ToolkitEditorFactory as EditorFactory #------------------------------------------------------------------------------- # 'ToolkitEditorFactory' class: #------------------------------------------------------------------------------- class ToolkitEditorFactory ( EditorFactory ): """ Editor factory for image enumeration editors. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Prefix to add to values to form image names: prefix = Unicode # Suffix to add to values to form image names: suffix = Unicode # Path to use to locate image files: path = Unicode # Class used to derive the path to the image files: klass = Type # Module used to derive the path to the image files: module = Module #--------------------------------------------------------------------------- # Performs any initialization needed after all constructor traits have # been set: #--------------------------------------------------------------------------- def init ( self ): """ Performs any initialization needed after all constructor traits have been set. """ super( ToolkitEditorFactory, self ).init() self._update_path() #--------------------------------------------------------------------------- # Handles one of the items defining the path being updated: #--------------------------------------------------------------------------- @on_trait_change( 'path, klass, module' ) def _update_path ( self ): """ Handles one of the items defining the path being updated. """ if self.path != '': self._image_path = self.path elif self.klass is not None: module = self.klass.__module__ if module == '___main___': module = '__main__' try: self._image_path = join( dirname( sys.modules[ module ].__file__ ), 'images' ) except: self._image_path = self.path dirs = [ join( dirname( sys.argv[0] ), 'images' ), join( getcwd(), 'images' ) ] for d in dirs: if exists( d ): self._image_path = d break elif self.module is not None: self._image_path = join( dirname( self.module.__file__ ), 'images' ) # Define the ImageEnumEditor class. ImageEnumEditor = ToolkitEditorFactory ## EOF ######################################################################## traitsui-4.1.0/traitsui/editors/drop_editor.py0000644000175100001440000000361411674463546022566 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2008, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # #------------------------------------------------------------------------------ """ Defines a drop editor factory for all traits toolkit backends. A drop target editor handles drag and drop operations as a drop target. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import Any, Bool from .text_editor import ToolkitEditorFactory as EditorFactory #------------------------------------------------------------------------------- # 'ToolkitEditorFactory' class: #------------------------------------------------------------------------------- class ToolkitEditorFactory ( EditorFactory ): """ Editor factory for drop editors. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Allowable drop objects must be of this class (optional) klass = Any # Must allowable drop objects be bindings? binding = Bool(False) # Can the user type into the editor, or is it read only? readonly = Bool(True) # Define the DropEditor class. DropEditor = ToolkitEditorFactory ### EOF ####################################################################### traitsui-4.1.0/traitsui/editors/check_list_editor.py0000644000175100001440000000320711674463546023730 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2008, Riverbank Computing Limited # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # #------------------------------------------------------------------------------ """ Defines the editor factory for multi-selection enumerations, for all traits toolkit backends. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import Range from ..editor_factory import EditorWithListFactory #------------------------------------------------------------------------------- # 'ToolkitEditorFactory' class: #------------------------------------------------------------------------------- class ToolkitEditorFactory ( EditorWithListFactory ): """ Editor factory for checklists. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Number of columns to use when the editor is displayed as a grid cols = Range( 1, 20 ) # Define the CheckListEditor class CheckListEditor = ToolkitEditorFactory traitsui-4.1.0/traitsui/editors/api.py0000644000175100001440000000337511674463546021031 0ustar ischnellusers00000000000000 from __future__ import absolute_import from ..toolkit import toolkit from .array_editor import ArrayEditor from .boolean_editor import BooleanEditor from .button_editor import ButtonEditor from .check_list_editor import CheckListEditor from .code_editor import CodeEditor from .color_editor import ColorEditor from .compound_editor import CompoundEditor from .csv_list_editor import CSVListEditor from .custom_editor import CustomEditor from .date_editor import DateEditor from .styled_date_editor import StyledDateEditor from .default_override import DefaultOverride from .directory_editor import DirectoryEditor from .dnd_editor import DNDEditor from .drop_editor import DropEditor from .enum_editor import EnumEditor from .file_editor import FileEditor from .font_editor import FontEditor from .key_binding_editor import KeyBindingEditor from .image_editor import ImageEditor from .image_enum_editor import ImageEnumEditor from .instance_editor import InstanceEditor from .list_editor import ListEditor from .list_str_editor import ListStrEditor from .null_editor import NullEditor from .range_editor import RangeEditor from .rgb_color_editor import RGBColorEditor from .set_editor import SetEditor from .text_editor import TextEditor from .table_editor import TableEditor from .time_editor import TimeEditor from .title_editor import TitleEditor from .tree_editor import TreeEditor from .tuple_editor import TupleEditor from .history_editor import HistoryEditor from .html_editor import HTMLEditor from .popup_editor import PopupEditor from .value_editor import ValueEditor from .shell_editor import ShellEditor from .scrubber_editor import ScrubberEditor from .tabular_editor import TabularEditor from .progress_editor import ProgressEditor from .search_editor import SearchEditor traitsui-4.1.0/traitsui/editors/default_override.py0000644000175100001440000000433311674463546023576 0ustar ischnellusers00000000000000""" Editor factory that overrides certain attributes of the default editor. For example, the default editor for Range(low=0, high=1500) has '1500' as the upper label. To change it to 'Max' instead, use my_range = Range(low=0, high=1500, editor=DefaultOverride(high_label='Max')) Alternatively, the override can also be specified in the view: View(Item('my_range', editor=DefaultOverride(high_label='Max')) """ from __future__ import absolute_import from traits.api import Dict from ..editor_factory import EditorFactory class DefaultOverride(EditorFactory): """Editor factory for selectively overriding certain parameters of the default editor. """ _overrides = Dict def __init__(self, *args, **overrides): EditorFactory.__init__(self, *args) self._overrides = overrides def _customise_default(self, editor_kind, ui, object, name, description, parent): """ Obtain the given trait's default editor and set the parameters specified in `overrides` above. """ trait = object.trait(name) editor_factory = trait.trait_type.create_editor() for option in self._overrides: setattr(editor_factory, option, self._overrides[option]) editor = getattr(editor_factory, editor_kind)(ui, object, name, description, parent) return editor def simple_editor(self, ui, object, name, description, parent): return self._customise_default('simple_editor', ui, object, name, description, parent) def custom_editor(self, ui, object, name, description, parent): return self._customise_default('custom_editor', ui, object, name, description, parent) def text_editor(self, ui, object, name, description, parent): return self._customise_default('text_editor', ui, object, name, description, parent) def readonly_editor(self, ui, object, name, description, parent): return self._customise_default('readonly_editor', ui, object, name, description, parent) traitsui-4.1.0/traitsui/editors/instance_editor.py0000644000175100001440000000750211674463546023426 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2008, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/21/2004 # #------------------------------------------------------------------------------ """ Defines the instance editor factory for all traits user interface toolkits. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import Str, List, Enum, Unicode, Type, Bool from ..view import View, AKind from ..ui_traits import AView from ..instance_choice import InstanceChoice, InstanceChoiceItem from ..editor_factory import EditorFactory #------------------------------------------------------------------------------- # 'ToolkitEditorFactory' class: #------------------------------------------------------------------------------- class ToolkitEditorFactory ( EditorFactory ): """ Editor factory for instance editors. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # List of items describing the types of selectable or editable instances values = List( InstanceChoiceItem ) # Extended name of the context object trait containing the list of types of # selectable or editable instances name = Str # Is the current value of the object trait editable (vs. merely selectable)? editable = Bool(True) # Should the object trait value be selectable from a list of objects (a # value of True forces a selection list to be displayed, while a value of # False displays a selection list only if at least one object in the list # of possible object values is selectable): selectable = Bool( False ) # Should the editor support drag and drop of objects to set the trait value # (a value of True forces the editor to allow drag and drop, while a value # of False only supports drag and drop if at least one item in the list of # possible objects supports drag and drop): droppable = Bool( False ) # Should factory-created objects be cached? cachable = Bool(True) # Optional label for button label = Unicode # Optional instance view to use view = AView # Extended name of the context object trait containing the view, or name of # the view, to use view_name = Str # The ID to use with the view id = Str # Kind of pop-up editor (live, modal, nonmodal, wizard) kind = AKind # The orientation of the instance editor relative to the instance selector orientation = Enum( 'default', 'horizontal', 'vertical' ) # The default adapter class used to create InstanceChoice compatible # adapters for instance objects: adapter = Type( InstanceChoice, allow_none = False ) #--------------------------------------------------------------------------- # Traits view definitions: #--------------------------------------------------------------------------- traits_view = View( [ [ 'label{Button label}', 'view{View name}', '|[]' ], [ 'kind@', '|[Pop-up editor style]<>' ] ] ) # Define the InstanceEditor class. InstanceEditor = ToolkitEditorFactory ### EOF ####################################################################### traitsui-4.1.0/traitsui/editors/range_editor.py0000644000175100001440000002444711674463546022725 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2008, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/21/2004 # #------------------------------------------------------------------------------ """ Defines the range editor factory for all traits user interface toolkits. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import (CTrait, Property, Range, Enum, Str, Int, Any, Unicode, Bool, Undefined) # CIRCULAR IMPORT FIXME: Importing from the source rather than traits.ui.api # to avoid circular imports, as this EditorFactory will be part of # traits.ui.api as well. from ..view import View from ..editor_factory import EditorFactory from ..toolkit import toolkit_object #------------------------------------------------------------------------------- # 'ToolkitEditorFactory' class: #------------------------------------------------------------------------------- class ToolkitEditorFactory ( EditorFactory ): """ Editor factory for range editors. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Number of columns when displayed as an enumeration cols = Range( 1, 20 ) # Is user input set on every keystroke? auto_set = Bool(True) # Is user input set when the Enter key is pressed? enter_set = Bool(False) # Label for the low end of the range low_label = Unicode # Label for the high end of the range high_label = Unicode # FIXME: This is supported only in the wx backend so far. # The width of the low and high labels label_width = Int # The name of an [object.]trait that defines the low value for the range low_name = Str # The name of an [object.]trait that defines the high value for the range high_name = Str # Formatting string used to format value and labels format = Unicode( '%s' ) # Is the range for floating pointer numbers (vs. integers)? is_float = Bool( Undefined ) # Function to evaluate floats/ints when they are assigned to an object trait evaluate = Any # The object trait containing the function used to evaluate floats/ints evaluate_name = Str # Low end of range low = Property # High end of range high = Property # Display mode to use mode = Enum( 'auto', 'slider', 'xslider', 'spinner', 'enum', 'text', 'logslider' ) #--------------------------------------------------------------------------- # Traits view definition: #--------------------------------------------------------------------------- traits_view = View( [ [ 'low', 'high', '|[Range]' ], [ 'low_label{Low}', 'high_label{High}', '|[Range Labels]' ], [ 'auto_set{Set automatically}', 'enter_set{Set on enter key pressed}', 'is_float{Is floating point range}', '-[Options]>' ], [ 'cols', '|[Number of columns for integer custom style]<>' ] ] ) #--------------------------------------------------------------------------- # Performs any initialization needed after all constructor traits have # been set: #--------------------------------------------------------------------------- def init ( self, handler = None ): """ Performs any initialization needed after all constructor traits have been set. """ if handler is not None: if isinstance( handler, CTrait ): handler = handler.handler if self.low_name == '': self.low = handler._low if self.high_name == '': self.high = handler._high else: if (self.low is None) and (self.low_name == ''): self.low = 0.0 if (self.high is None) and (self.high_name == ''): self.high = 1.0 #--------------------------------------------------------------------------- # Define the 'low' and 'high' traits: #--------------------------------------------------------------------------- def _get_low ( self ): return self._low def _set_low ( self, low ): old_low = self._low self._low = low = self._cast( low ) if self.is_float is Undefined: self.is_float = isinstance( low, float ) if (self.low_label == '') or (self.low_label == unicode(old_low)): self.low_label = unicode(low) def _get_high ( self ): return self._high def _set_high ( self, high ): old_high = self._high self._high = high = self._cast( high ) if self.is_float is Undefined: self.is_float = isinstance( high, float ) if (self.high_label == '') or (self.high_label == unicode(old_high)): self.high_label = unicode(high) def _cast ( self, value ): if not isinstance( value, basestring ): return value try: return int( value ) except ValueError: return float( value ) #-- Private Methods -------------------------------------------------------- def _get_low_high ( self, ui ): """ Returns the low and high values used to determine the initial range. """ low, high = self.low, self.high if (low is None) and (self.low_name != ''): low = self.named_value( self.low_name, ui ) if self.is_float is Undefined: self.is_float = isinstance( low, float ) if (high is None) and (self.high_name != ''): high = self.named_value( self.high_name, ui ) if self.is_float is Undefined: self.is_float = isinstance( high, float ) if self.is_float is Undefined: self.is_float = True return ( low, high, self.is_float ) #--------------------------------------------------------------------------- # Property getters. #--------------------------------------------------------------------------- def _get_simple_editor_class( self ): """ Returns the editor class to use for a simple style. The type of editor depends on the type and extent of the range being edited: * One end of range is unspecified: RangeTextEditor * **mode** is specified and not 'auto': editor corresponding to **mode** * Floating point range with extent > 100: LargeRangeSliderEditor * Integer range or floating point range with extent <= 100: SimpleSliderEditor * All other cases: SimpleSpinEditor """ low, high, is_float = self._low_value, self._high_value, self.is_float if (low is None) or (high is None): return toolkit_object('range_editor:RangeTextEditor') if (not is_float) and (abs(high - low) > 1000000000L): return toolkit_object('range_editor:RangeTextEditor') if self.mode != 'auto': return toolkit_object('range_editor:SimpleEditorMap')[ self.mode ] if is_float and (abs(high - low) > 100): return toolkit_object('range_editor:LargeRangeSliderEditor') if is_float or (abs(high - low) <= 100): return toolkit_object('range_editor:SimpleSliderEditor') return toolkit_object('range_editor:SimpleSpinEditor') def _get_custom_editor_class ( self ): """ Creates a custom style of range editor The type of editor depends on the type and extent of the range being edited: * One end of range is unspecified: RangeTextEditor * **mode** is specified and not 'auto': editor corresponding to **mode** * Floating point range: Same as "simple" style * Integer range with extent > 15: Same as "simple" style * Integer range with extent <= 15: CustomEnumEditor """ low, high, is_float = self._low_value, self._high_value, self.is_float if (low is None) or (high is None): return toolkit_object('range_editor:RangeTextEditor') if self.mode != 'auto': return toolkit_object('range_editor:CustomEditorMap')[ self.mode ] if is_float or (abs(high - low) > 15): return self.simple_editor_class return toolkit_object('range_editor:CustomEnumEditor') def _get_text_editor_class( self ): """Returns the editor class to use for a text style. """ return toolkit_object('range_editor:RangeTextEditor') #--------------------------------------------------------------------------- # 'Editor' factory methods: #--------------------------------------------------------------------------- def simple_editor ( self, ui, object, name, description, parent ): """ Generates an editor using the "simple" style. Overridden to set the values of the _low_value, _high_value and is_float traits. """ self._low_value, self._high_value, self.is_float = self._get_low_high(ui) return super(RangeEditor, self).simple_editor(ui, object, name, description, parent) def custom_editor ( self, ui, object, name, description, parent ): """ Generates an editor using the "custom" style. Overridden to set the values of the _low_value, _high_value and is_float traits. """ self._low_value, self._high_value, self.is_float = self._get_low_high(ui) return super(RangeEditor, self).custom_editor(ui, object, name, description, parent) # Define the RangeEditor class RangeEditor = ToolkitEditorFactory ### EOF --------------------------------------------------------------------- traitsui-4.1.0/traitsui/editors/boolean_editor.py0000644000175100001440000000666011674463546023245 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2008, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/21/2004 # #------------------------------------------------------------------------------ """ Defines the Boolean editor factory for all traits toolkit backends. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import Dict, Str, Any # CIRCULAR IMPORT FIXME: Importing from the source rather than traits.ui.api # to avoid circular imports, as this EditorFactory will be part of # traits.ui.api as well. from ..view import View from .text_editor import ToolkitEditorFactory as EditorFactory #------------------------------------------------------------------------------- # Trait definitions: #------------------------------------------------------------------------------- # Mapping from user input text to Boolean values mapping_trait = Dict( Str, Any, { 'True': True, 'true': True, 't': True, 'yes': True, 'y': True, 'False': False, 'false': False, 'f': False, 'no': False, 'n': False, } ) #------------------------------------------------------------------------------- # 'ToolkitEditorFactory' class: #------------------------------------------------------------------------------- class ToolkitEditorFactory ( EditorFactory ): """ Editor factory for Boolean editors. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Dictionary mapping user input to other values. # These definitions override definitions in the 'text_editor' version mapping = mapping_trait #--------------------------------------------------------------------------- # Traits view definition: #--------------------------------------------------------------------------- traits_view = View() #--------------------------------------------------------------------------- # EditorFactory methods #--------------------------------------------------------------------------- def _get_custom_editor_class(self): """ Returns the editor class to use for "custom" style views. Overridden to return the simple_editor_class (instead of the CustomEditor class for the text editor's factory, which this class inherits from). """ return self.simple_editor_class # Define the BooleanEditor class BooleanEditor = ToolkitEditorFactory #- EOF ----------------------------------------------------------------------- traitsui-4.1.0/traitsui/editors/title_editor.py0000644000175100001440000000362211674463546022742 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2008, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # #------------------------------------------------------------------------------ """ Defines the title editor factory for all traits toolkit backends. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import Bool from ..editor_factory import EditorFactory from ..toolkit import toolkit_object class ToolkitEditorFactory ( EditorFactory ): """ Editor factory for Title editors. """ allow_selection = Bool(False) def _get_simple_editor_class(self): """ Returns the editor class to use for "simple" style views. The default implementation tries to import the SimpleEditor class in the editor file in the backend package, and if such a class is not to found it returns the SimpleEditor class defined in editor_factory module in the backend package. """ SimpleEditor = toolkit_object('title_editor:SimpleEditor') return SimpleEditor #------------------------------------------------------------------------------- # Create the editor factory object: #------------------------------------------------------------------------------- TitleEditor = ToolkitEditorFactory ### EOF ####################################################################### traitsui-4.1.0/traitsui/editors/scrubber_editor.py0000644000175100001440000000455111674463546023432 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2007, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 07/14/2008 # #------------------------------------------------------------------------------- """ Editor factory for scrubber-based integer or float value editors. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import Float, Color, Property from ..ui_traits import Alignment from ..basic_editor_factory import BasicEditorFactory from ..toolkit import toolkit_object #------------------------------------------------------------------------------- # Create the editor factory object: #------------------------------------------------------------------------------- # Editor factory for scrubber-based integer or float value editors. class ScrubberEditor ( BasicEditorFactory ): # The editor class to be instantiated: klass = Property # The low end of the scrubber range: low = Float # The high end of the scrubber range: high = Float # The normal increment (default: auto-calculate): increment = Float # The alignment of the text within the scrubber: alignment = Alignment( 'center' ) # The background color for the scrubber: color = Color( None ) # The hover mode background color for the scrubber: hover_color = Color( None ) # The active mode background color for the scrubber: active_color = Color( None ) # The scrubber border color: border_color = Color( None ) # The color to use for the value text: text_color = Color( 'black' ) def _get_klass(self): """ Returns the toolkit-specific editor class to be instantiated. """ return toolkit_object('scrubber_editor:_ScrubberEditor') ### EOF ################################################################## traitsui-4.1.0/traitsui/editors/rgb_color_editor.py0000644000175100001440000000454411674463546023575 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 11/22/2004 # #------------------------------------------------------------------------------ """ Defines a subclass of the base color editor factory, for colors that are represented as tuples of the form ( *red*, *green*, *blue* ), where *red*, *green* and *blue* are floats in the range from 0.0 to 1.0. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from .color_editor import ToolkitEditorFactory as EditorFactory from ..toolkit import toolkit_object #------------------------------------------------------------------------------- # 'ToolkitEditorFactory' class: #------------------------------------------------------------------------------- class ToolkitEditorFactory ( EditorFactory ): """ Factory for editors for RGB colors. """ pass # Define the RGBColorEditor class # The function will try to return the toolkit-specific editor factory (located # in traitsui..rgb_color_editor, and if none is found, the # ToolkitEditorFactory declared here is returned. def RGBColorEditor(*args, **traits): """ Returns an instance of the toolkit-specific editor factory declared in traitsui..rgb_color_editor. If such an editor factory cannot be located, an instance of the abstract ToolkitEditorFactory declared in traitsui.editors.rgb_color_editor is returned. Parameters ---------- \*args, \*\*traits arguments and keywords to be passed on to the editor factory's constructor. """ try: return toolkit_object('rgb_color_editor:ToolkitEditorFactory', True)( *args, **traits) except: return ToolkitEditorFactory(*args, **traits) traitsui-4.1.0/traitsui/editors/custom_editor.py0000644000175100001440000000466511674463546023143 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2008, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 07/19/2005 # #------------------------------------------------------------------------------ """ Defines the editor factory used to wrap a non-Traits based custom control. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import Callable, Tuple, Property from ..basic_editor_factory import BasicEditorFactory from ..toolkit import toolkit_object #------------------------------------------------------------------------------- # 'ToolkitEditorFactory' class: #------------------------------------------------------------------------------- class ToolkitEditorFactory ( BasicEditorFactory ): """ Editor factory for custom editors. """ # Editor class to be instantiated. klass = Property # Factory function used to create the custom control factory = Callable # Arguments to be passed to the user's custom editor factory args = Tuple #--------------------------------------------------------------------------- # Initializes the object: #--------------------------------------------------------------------------- def __init__ ( self, *args, **traits ): if len( args ) >= 1: self.factory = args[0] self.args = args[1:] super( ToolkitEditorFactory, self ).__init__( **traits ) #--------------------------------------------------------------------------- # Property getters #--------------------------------------------------------------------------- def _get_klass(self): """ Returns the editor class to be created. """ return toolkit_object('custom_editor:CustomEditor') # Define the CustomEditor class. CustomEditor = ToolkitEditorFactory ### EOF ####################################################################### traitsui-4.1.0/traitsui/editors/tree_editor.py0000644000175100001440000001321311674463546022555 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2008, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # #------------------------------------------------------------------------------ """ Defines the tree editor factory for all traits user interface toolkits. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import Any, Dict, Bool, Tuple, Int, List, Instance, Str, Enum from ..tree_node import TreeNode from ..dock_window_theme import DockWindowTheme from ..editor_factory import EditorFactory from ..helper import Orientation #------------------------------------------------------------------------------- # Trait definitions: #------------------------------------------------------------------------------- # Size of each tree node icon IconSize = Tuple( ( 16, 16 ), Int, Int ) #------------------------------------------------------------------------------- # 'ToolkitEditorFactory' class: #------------------------------------------------------------------------------- class ToolkitEditorFactory ( EditorFactory ): """ Editor factory for tree editors. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Supported TreeNode objects nodes = List( TreeNode ) # Mapping from TreeNode tuples to MultiTreeNodes multi_nodes = Dict # The column header labels if any. column_headers = List(Str) # Are the individual nodes editable? editable = Bool(True) # Selection mode. selection_mode = Enum('single', 'extended') # Is the editor shared across trees? shared_editor = Bool(False) # Reference to a shared object editor editor = Instance( EditorFactory ) # The DockWindow graphical theme # FIXME: Implemented only in wx backend. dock_theme = Instance( DockWindowTheme ) # Show icons for tree nodes? show_icons = Bool(True) # Hide the tree root node? hide_root = Bool(False) # Layout orientation of the tree and the editor orientation = Orientation # Number of tree levels (down from the root) that should be automatically # opened auto_open = Int # Size of the tree node icons # FIXME: Document as unimplemented or wx specific. icon_size = IconSize # Called when a node is selected on_select = Any # Called when a node is clicked on_click = Any # Called when a node is double-clicked on_dclick = Any # Call when the mouse hovers over a node on_hover = Any # The optional extended trait name of the trait to synchronize with the # editor's current selection: selected = Str # The optional extended trait name of the trait that should be assigned # a node object when a tree node is activated, by double-clicking or # pressing the Enter key when a node has focus (Note: if you want to # receive repeated activated events on the same node, make sure the trait # is defined as an Event): activated = Str # The optional extended trait name of the trait that should be assigned # a node object when a tree node is clicked on (Note: If you want to # receive repeated clicks on the same node, make sure the trait is defined # as an Event): click = Str # The optional extended trait name of the trait that should be assigned # a node object when a tree node is double-clicked on (Note: if you want to # receive repeated double-clicks on the same node, make sure the trait is # defined as an Event): dclick = Str # The optional extended trait name of the trait event that is fired # whenever the application wishes to veto a tree action in progress (e.g. # double-clicking a non-leaf tree node normally opens or closes the node, # but if you are handling the double-click event in your program, you may # wish to veto the open or close operation). Be sure to fire the veto event # in the event handler triggered by the operation (e.g. the 'dclick' event # handler. veto = Str # The optional extended trait name of the trait event that is fired when the # application wishes the currently visible portion of the tree widget to # repaint itself. refresh = Str # Mode for lines connecting tree nodes # # * 'appearance': Show lines only when they look good. # * 'on': Always show lines. # * 'off': Don't show lines. lines_mode = Enum ( 'appearance', 'on', 'off' ) # FIXME: Document as unimplemented or wx specific. # Whether to alternate row colors or not. alternating_row_colors = Bool(False) # Any extra vertical padding to add. vertical_padding = Int(0) # Whether or not to expand on a double-click. expands_on_dclick = Bool(True) # Whether the labels should be wrapped around, if not an ellipsis is shown # This works only in the qt backend and if there is only one column in tree word_wrap = Bool(False) # Define the TreeEditor class. TreeEditor = ToolkitEditorFactory ### EOF ####################################################################### traitsui-4.1.0/traitsui/editors/code_editor.py0000644000175100001440000000715311674463546022536 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2008, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 01/27/2006 # #------------------------------------------------------------------------------ """ Defines the code editor factory for all traits toolkit backends, useful for tools such as debuggers. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import Instance, Str, Color, Enum, Bool from ..editor_factory import EditorFactory #------------------------------------------------------------------------------- # 'ToolkitEditorFactory' class: #------------------------------------------------------------------------------- class ToolkitEditorFactory ( EditorFactory ): """ Editor factory for code editors. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Object trait containing list of line numbers to mark (optional) mark_lines = Str # Background color for marking lines mark_color = Color( 0xECE9D8 ) # Object trait containing the currently selected line (optional) selected_line = Str # Object trait containing the currently selected text (optional) selected_text = Str # Object trait containing the currently selected text start position (optional) selected_start_pos = Str # Object trait containing the currently selected text end position (optional) selected_end_pos = Str # Background color for selected lines selected_color = Color( 0xA4FFFF ) # Where should the search toolbar be placed? search = Enum( 'top', 'bottom', 'none' ) # Background color for lines that match the current search search_color = Color( 0xFFFF94 ) # Current line line = Str # Current column column = Str # Should code folding be enabled? foldable = Bool( True ) # Should line numbers be displayed in the margin? show_line_numbers = Bool( True ) # Is user input set on every change? auto_set = Bool( True ) # Should the editor auto-scroll when a new **selected_line** value is set? auto_scroll = Bool( True ) # Optional key bindings associated with the editor key_bindings = Instance( 'traitsui.key_bindings.KeyBindings' ) # Calltip clicked event calltip_clicked = Str # The lexer to use. Default is 'python'; 'null' indicates no lexing. lexer = Str('python') # Object trait containing the list of line numbers to dim (optional) dim_lines = Str # Object trait to dim lines to. Can be of form #rrggbb or a color spec. If # not specified, dark grey is used. dim_color = Str # Object trait containing the list of line numbers to put squiggles under # (optional) squiggle_lines = Str # Object trait for the color of squiggles. If not specified, red is used. squiggle_color = Str # Define the Code Editor class. CodeEditor = ToolkitEditorFactory ### EOF ####################################################################### traitsui-4.1.0/traitsui/editors/history_editor.py0000644000175100001440000000352111674463546023320 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2008, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/21/2004 # #------------------------------------------------------------------------------- """ Defines a text editor which displays a text field and maintains a history of previously entered values. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import Int, Bool from ..basic_editor_factory import BasicEditorFactory from ..toolkit import toolkit_object # Define callable which returns the 'klass' value (i.e. the editor to use in # the EditorFactory. def history_editor(*args, **traits): return toolkit_object('history_editor:_HistoryEditor')(*args, **traits) #------------------------------------------------------------------------------- # Create the editor factory object: #------------------------------------------------------------------------------- class ToolkitEditorFactory( BasicEditorFactory ): # The number of entries in the history: entries = Int( 10 ) # Should each keystroke update the value (or only the enter key, tab, etc.)? auto_set = Bool( False ) HistoryEditor = ToolkitEditorFactory( klass = history_editor ) # EOF ######################################################################### traitsui-4.1.0/traitsui/editors/html_editor.py0000644000175100001440000001457311674463546022574 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/21/2004 # #------------------------------------------------------------------------------ """ Defines the HTML editor factory. HTML editors interpret and display HTML-formatted text, but do not modify it. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import Str, false from ..basic_editor_factory import BasicEditorFactory from ..toolkit import toolkit_object # Callable that returns the editor to use in the UI. def html_editor(*args, **traits): return toolkit_object('html_editor:SimpleEditor')(*args, **traits) #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- # Template used to create code blocks embedded in the module comment block_template = """
%s
""" # Template used to create lists embedded in the module comment list_template = """<%s> %s """ #------------------------------------------------------------------------------ # 'ToolkitEditorFactory' class: #------------------------------------------------------------------------------ class ToolkitEditorFactory ( BasicEditorFactory ): """ Editor factory for HTML editors. """ #-------------------------------------------------------------------------- # Trait definitions: #-------------------------------------------------------------------------- # Should implicit text formatting be converted to HTML? format_text = false # External objects referenced in the HTML are relative to this url base_url = Str # The object trait containing the base URL base_url_name = Str # Should links be opened in an external browser? open_externally = false #--------------------------------------------------------------------------- # Parses the contents of a formatted text string into the corresponding # HTML: #--------------------------------------------------------------------------- def parse_text ( self, text ): """ Parses the contents of a formatted text string into the corresponding HTML. """ text = text.replace( '\r\n', '\n' ) lines = [ ('.' + line).strip()[1:] for line in text.split( '\n' ) ] ind = min( *([ self.indent( line ) for line in lines if line != '' ] + [ 1000, 1000 ]) ) if ind >= 1000: ind = 0 lines = [ line[ ind: ] for line in lines ] new_lines = [] i = 0 n = len( lines ) while i < n: line = lines[i] m = self.indent( line ) if m > 0: if line[m] in '-*': i, line = self.parse_list( lines, i ) else: i, line = self.parse_block( lines, i ) new_lines.append( line ) else: new_lines.append( line ) i += 1 text = '\n'.join( new_lines ) paragraphs = [ p.strip() for p in text.split( '\n\n' ) ] for i, paragraph in enumerate( paragraphs ): if paragraph[:3].lower() != '

': paragraphs[i] = '

%s

' % paragraph return '\n'.join( paragraphs ) #--------------------------------------------------------------------------- # Parses a code block: #--------------------------------------------------------------------------- def parse_block ( self, lines, i ): """ Parses a code block. """ m = 1000 n = len( lines ) j = i while j < n: line = lines[j] if line != '': k = self.indent( line ) if k == 0: break m = min( m, k ) j += 1 j -= 1 while (j > i) and (lines[j] == ''): j -= 1 j += 1 temp = [ ((' ' * (self.indent( line ) - m)) + line.strip()) for line in lines[ i: j ] ] return ( j, block_template % '\n
'.join( temp ) ) #--------------------------------------------------------------------------- # Parses a list: #--------------------------------------------------------------------------- def parse_list ( self, lines, i ): """ Parses a list. """ line = lines[i] m = self.indent( line ) kind = line[m] result = [ '
  • ' + line[ m + 1: ].strip() ] n = len( lines ) j = i + 1 while j < n: line = lines[j] k = self.indent( line ) if k < m: break if k == m: if line[k] != kind: break result.append( '
  • ' + line[ k + 1: ].strip() ) j += 1 elif line[k] in '-*': j, line = self.parse_list( lines, j ) result.append( line ) else: result.append( line.strip() ) j += 1 style = [ 'ul', 'ol' ][ kind == '*' ] return ( j, list_template % ( style, '\n'.join( result ), style ) ) #--------------------------------------------------------------------------- # Calculates the amount of white space at the beginning of a line: #--------------------------------------------------------------------------- def indent ( self, line ): """ Calculates the amount of white space at the beginning of a line. """ return len( line ) - len( (line + '.').strip() ) + 1 HTMLEditor = ToolkitEditorFactory(klass = html_editor) #-EOF-------------------------------------------------------------------------- traitsui-4.1.0/traitsui/editors/null_editor.py0000644000175100001440000000273611674463546022600 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2008, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 07/26/2006 # #------------------------------------------------------------------------------- """ Defines a completely empty editor, intended to be used as a spacer. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from ..basic_editor_factory import BasicEditorFactory from ..toolkit import toolkit_object # Callable which returns the editor to use in the ui. def null_editor(*args, **traits): return toolkit_object('null_editor:NullEditor')(*args, **traits) #------------------------------------------------------------------------------- # Create the editor factory object: #------------------------------------------------------------------------------- NullEditor = BasicEditorFactory(klass = null_editor) ### EOF --------------------------------------------------------------------- traitsui-4.1.0/traitsui/editors/date_editor.py0000644000175100001440000000546211674463546022542 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2008, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: Judah De Paula # Date: 10/7/2008 # #------------------------------------------------------------------------------ """ A Traits UI editor that wraps a WX calendar panel. """ from __future__ import absolute_import from traits.trait_types import Bool, Int, Enum, Str from ..ui_traits import AView from ..editor_factory import EditorFactory class DateEditor(EditorFactory): """ Editor factory for date/time editors. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- #-- ReadonlyEditor traits -------------------------------------------------- # Message to show when Date is None. message = Str('Undefined') # The string representation of the date to show. Uses time.strftime format. strftime = Str('%B %d %Y (%a)') # An optional view to display when a read-only text editor is clicked: view = AView #-- CustomEditor traits ---------------------------------------------------- # Should users be able to pick future dates when using the CustomEditor? allow_future = Bool(True) # How many months to show at a time. months = Int(3) # True: Must be a List of Dates. False: Must be a Date instance. multi_select = Bool(False) # When a user multi-selects entries and some of those entries are already # selected and some are not, what should be the behavior for the seletion? # Options:: # # 'toggle' -- Toggle each day to the opposite of the current state. # 'on' -- Always turn them on. # 'off' -- Always turn them off. # 'max_change' -- Change all to same state, with most days changing. # For example 1 selected and 9 not, then they would # all get selected. # 'min_change' -- Change all to same state, with min days changing. # For example 1 selected and 9 not, then they would # all get unselected. on_mixed_select = Enum('toggle', 'on', 'off', 'max_change', 'min_change') # How much space to put between the individual months. padding = Int(5) # Does the user have to hold down Shift for the left-click multiselect? shift_to_select = Bool(False) traitsui-4.1.0/traitsui/editors/styled_date_editor.py0000644000175100001440000000336011674463546024121 0ustar ischnellusers00000000000000 from traits.api import Bool, List, Str from .date_editor import DateEditor class CellFormat(object): """ Encapsulates some common visual attributes to set on the cells of a calendar widget. All attributes default to None, which means that they will not override the existing values of the calendar widget. """ italics = None bold = None underline = None # The color attributes should be strings representing color names, # from the list: # red, green, blue, cyan, magenta, yellow, gray, white, # darkRed, darkGreen, darkBlue, darkCyan, darkmagenta, darkYellow, darkGray, # black, lightGray # # Alternatively, they can be a tuple of (R,G,B) values from 0-255. bgcolor = None fgcolor = None def __init__(self, **args): for key,val in args.items(): setattr(self, key, val) class ToolkitEditorFactory(DateEditor): """ A DateEditor that can show sets of dates in different styles. """ # The name of a dictionary on the object that maps names to groups # (list/tuples) of datetime.date objects. Each of these groups can be # styled using the **styles** dict. dates_trait = Str() # The name of a dictionary on the object that maps names of styles to # CellFormat objects. The names used must match the names used in the # **dates** dict. styles_trait = Str() # Allow selection of arbitrary dates in the past. allow_past = Bool(True) # Allow selection of arbitrary dates in the future. allow_future = Bool(True) # A list of strings that will be offered as an alternative to specifying # an absolute date, and instead specify a relative date. relative_dates = List() StyledDateEditor = ToolkitEditorFactory traitsui-4.1.0/traitsui/editors/font_editor.py0000644000175100001440000000440611674463546022570 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2008, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/21/2004 # #------------------------------------------------------------------------------ """ Defines the font editor factory for all traits user interface toolkits. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from ..editor_factory import EditorFactory from ..toolkit import toolkit_object #------------------------------------------------------------------------------- # 'ToolkitEditorFactory' class: #------------------------------------------------------------------------------- class ToolkitEditorFactory ( EditorFactory ): """ Editor factory for font editors. """ pass # Define the FontEditor class # The function will try to return the toolkit-specific editor factory (located # in traitsui..font_editor, and if none is found, the # ToolkitEditorFactory declared here is returned. def FontEditor(*args, **traits): """ Returns an instance of the toolkit-specific editor factory declared in traitsui..font_editor. If such an editor factory cannot be located, an instance of the abstract ToolkitEditorFactory declared in traitsui.editors.font_editor is returned. Parameters ---------- \*args, \*\*traits arguments and keywords to be passed on to the editor factory's constructor. """ try: return toolkit_object('font_editor:ToolkitEditorFactory', True)(*args, **traits) except Exception, e: return ToolkitEditorFactory(*args, **traits) ## EOF ######################################################################## traitsui-4.1.0/traitsui/editors/list_str_editor.py0000644000175100001440000000772311674463546023472 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2007, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 05/08/2007 # #------------------------------------------------------------------------------- """ Traits UI editor factory for editing lists of strings. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import Any, Str, Enum, List, Bool, Instance, Property from ..basic_editor_factory import BasicEditorFactory from ..toolkit import toolkit_object from pyface.image_resource import ImageResource #------------------------------------------------------------------------------- # 'ListStrEditor' editor factory class: #------------------------------------------------------------------------------- class ListStrEditor ( BasicEditorFactory ): """ Editor factory for list of string editors. """ #-- Trait Definitions ------------------------------------------------------ # The editor class to be created: klass = Property # The optional extended name of the trait to synchronize the selection # values with: selected = Str # The optional extended name of the trait to synchronize the selection # indices with: selected_index = Str # The optional extended name of the trait to synchronize the activated value # with: activated = Str # The optional extended name of the trait to synchronize the activated # value's index with: activated_index = Str # The optional extended name of the trait to synchronize the right clicked # value with: right_clicked = Str # The optional extended name of the trait to synchronize the right clicked # value's index with: right_clicked_index = Str # Can the user edit the values? editable = Bool( True ) # Are multiple selected items allowed? multi_select = Bool( False ) # Should horizontal lines be drawn between items? horizontal_lines = Bool( False ) # The title for the editor: title = Str # The optional extended name of the trait containing the editor title: title_name = Str # Should a new item automatically be added to the end of the list to allow # the user to create new entries? auto_add = Bool( False ) # The adapter from list items to editor values: adapter = Instance( 'traitsui.list_str_adapter.ListStrAdapter', () ) # The optional extended name of the trait containing the adapter: adapter_name = Str # What type of operations are allowed on the list: operations = List( Enum( 'delete', 'insert', 'append', 'edit', 'move' ), [ 'delete', 'insert', 'append', 'edit', 'move' ] ) # Are 'drag_move' operations allowed (i.e. True), or should they always be # treated as 'drag_copy' operations (i.e. False): drag_move = Bool( False ) # The set of images that can be used: images = List( ImageResource ) # Right-click context menu (Qt4 only). The value can be one of: # # - Instance( Menu ): Use this menu as the context menu # - string: Name of traits that will provide menu # - None: Use the default context menu # - False: Do not display a context menu menu = Any def _get_klass(self): """ Returns the editor class to be created. """ return toolkit_object('list_str_editor:_ListStrEditor') ##EOF ######################################################################### traitsui-4.1.0/traitsui/editors/directory_editor.py0000644000175100001440000000261211674463546023623 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2008, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # #------------------------------------------------------------------------------ """ Defines the directory editor factory for all traits toolkit backends. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from .file_editor import ToolkitEditorFactory as EditorFactory #------------------------------------------------------------------------------- # 'ToolkitEditorFactory' class: #------------------------------------------------------------------------------- class ToolkitEditorFactory ( EditorFactory ): """ Editor factory for directory editors. """ pass # Define the DirectoryEditor class DirectoryEditor = ToolkitEditorFactory ### EOF ####################################################################### traitsui-4.1.0/traitsui/editors/time_editor.py0000644000175100001440000000271611674463546022562 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2008, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: Judah De Paula # Date: 10/7/2008 # #------------------------------------------------------------------------------ """ A Traits UI editor that wraps a WX timer control. """ from __future__ import absolute_import from traits.api import Str from ..editor_factory import EditorFactory from ..ui_traits import AView class TimeEditor(EditorFactory): """ Editor factory for time editors. Generates _TimeEditor()s. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- #-- ReadonlyEditor traits -------------------------------------------------- # Message to show when Time is None. message = Str('Undefined') # The string representation of the time to show. Uses time.strftime format. strftime = Str('%I:%M:%S %p') # An optional view to display when a read-only text editor is clicked: view = AView traitsui-4.1.0/traitsui/editors/compound_editor.py0000644000175100001440000000401011674463546023435 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2008, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # #------------------------------------------------------------------------------ """ Defines the compound editor factory for all traits toolkit backends. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import List, true from ..editor_factory import EditorFactory #------------------------------------------------------------------------------- # Trait definitions: #------------------------------------------------------------------------------- # List of component editor factories used to build a compound editor editors_trait = List( EditorFactory ) #------------------------------------------------------------------------------- # 'ToolkitEditorFactory' class: #------------------------------------------------------------------------------- class ToolkitEditorFactory ( EditorFactory ): """ Editor factory for compound editors. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Component editor factories used to build the editor editors = editors_trait # Is user input set on every keystroke? auto_set = true # Define the CompoundEditor class CompoundEditor = ToolkitEditorFactory ## EOF ######################################################################## traitsui-4.1.0/traitsui/editors/button_editor.py0000644000175100001440000001005511674463546023132 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2008, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/21/2004 # #------------------------------------------------------------------------------ """ Defines the button editor factory for all traits toolkit backends. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import Str, Range, Enum, Property, Trait # CIRCULAR IMPORT FIXME: Importing from the source rather than traits.ui.api # to avoid circular imports, as this EditorFactory will be part of # traits.ui.api as well. from ..view import View from ..ui_traits import AView, Image from ..editor_factory import EditorFactory #------------------------------------------------------------------------------- # 'ToolkitEditorFactory' class: #------------------------------------------------------------------------------- class ToolkitEditorFactory ( EditorFactory ): """ Editor factory for buttons. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Value to set when the button is clicked value = Property # Optional label for the button label = Str # The name of the external object trait that the button label is synced to label_value = Str # The name of the trait on the object that contains the list of possible # values. If this is set, then the value, label, and label_value traits # are ignored; instead, they will be set from this list. When this button # is clicked, the value set will be the one selected from the drop-down. values_trait = Trait(None, None, Str) # (Optional) Image to display on the button image = Image # Extra padding to add to both the left and the right sides width_padding = Range( 0, 31, 7 ) # Extra padding to add to both the top and the bottom sides height_padding = Range( 0, 31, 5 ) # Presentation style style = Enum( 'button', 'radio', 'toolbar', 'checkbox' ) # Orientation of the text relative to the image orientation = Enum( 'vertical', 'horizontal' ) # The optional view to display when the button is clicked: view = AView #--------------------------------------------------------------------------- # Traits view definition: #--------------------------------------------------------------------------- traits_view = View( [ 'label', 'value', '|[]' ] ) #--------------------------------------------------------------------------- # Implementation of the 'value' property: #--------------------------------------------------------------------------- def _get_value ( self ): return self._value def _set_value ( self, value ): self._value = value if isinstance(value, basestring): try: self._value = int( value ) except: try: self._value = float( value ) except: pass #--------------------------------------------------------------------------- # Initializes the object: #--------------------------------------------------------------------------- def __init__ ( self, **traits ): self._value = 0 super( ToolkitEditorFactory, self ).__init__( **traits ) # Define the ButtonEditor class ButtonEditor = ToolkitEditorFactory ### EOF --------------------------------------------------------------------- traitsui-4.1.0/traitsui/editors/__init__.py0000644000175100001440000000256611674463546022020 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/07/2004 # #------------------------------------------------------------------------------ # Adding this statement for backwards compatibility (since editors.py was a # file prior to version 3.0.3). from __future__ import absolute_import from .api import (toolkit, ArrayEditor, BooleanEditor, ButtonEditor, CheckListEditor, CodeEditor, ColorEditor, CompoundEditor, CustomEditor, DateEditor, DefaultOverride, DirectoryEditor, DNDEditor, DropEditor, EnumEditor, FileEditor, FontEditor, KeyBindingEditor, ImageEditor, ImageEnumEditor, InstanceEditor, ListEditor, ListStrEditor, NullEditor, RangeEditor, RGBColorEditor, SetEditor, TextEditor, TableEditor, TimeEditor, TitleEditor, TreeEditor, TupleEditor, HistoryEditor, HTMLEditor, PopupEditor, ValueEditor, ShellEditor, ScrubberEditor, TabularEditor, ProgressEditor, SearchEditor) traitsui-4.1.0/traitsui/editors/search_editor.py0000644000175100001440000000345111674463546023066 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2009, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: Evan Patterson # Date: 06/25/09 # #------------------------------------------------------------------------------- """ A single line text widget that supports functionality common to native search widgets. """ from __future__ import absolute_import from traits.api import Bool, Property, Str from ..toolkit import toolkit_object from ..basic_editor_factory import BasicEditorFactory class SearchEditor(BasicEditorFactory): """ A single line text widget that supports functionality common to native search widgets. """ # The editor class to be created: klass = Property # The descriptive text for the widget text = Str("Search") # Is user input set on every keystroke? auto_set = Bool(True) # Is user input set when the Enter key is pressed? enter_set = Bool(False) # Whether to show a search button on the widget search_button = Bool(True) # Whether to show a cancel button on the widget cancel_button = Bool(False) # Fire this event on the object whenever a search should be triggered, # regardless of whether the search term changed search_event_trait = Str def _get_klass(self): """ Returns the toolkit-specific editor class to be instantiated. """ return toolkit_object('search_editor:SearchEditor') traitsui-4.1.0/traitsui/editors/enum_editor.py0000644000175100001440000000650411674463546022567 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2008, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # #------------------------------------------------------------------------------ """ Defines the editor factory for single-selection enumerations, for all traits user interface toolkits. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import import os, sys from ..editor_factory import EditorWithListFactory from traits.api import Any, Range, Enum, Bool from ..toolkit import toolkit_object #------------------------------------------------------------------------------- # Trait definitions: #------------------------------------------------------------------------------- # Supported display modes for a custom style editor Mode = Enum( 'radio', 'list' ) #------------------------------------------------------------------------------- # 'ToolkitEditorFactory' class: #------------------------------------------------------------------------------- class ToolkitEditorFactory ( EditorWithListFactory ): """ Editor factory for enumeration editors. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # (Optional) Function used to evaluate text input: evaluate = Any # Is user input set on every keystroke (when text input is allowed)? auto_set = Bool( True ) # Number of columns to use when displayed as a grid: cols = Range( 1, 20 ) # Display modes supported for a custom style editor: mode = Mode #--------------------------------------------------------------------------- # 'Editor' factory methods: #--------------------------------------------------------------------------- def _get_custom_editor_class ( self ): """ Returns the editor class to use for "custom" style views. Overridden to return the editor class for the specified mode. """ editor_file_name = \ os.path.basename(sys.modules[self.__class__.__module__]. __file__) try: if self.mode == 'radio': return toolkit_object(editor_file_name.split('.')[0] + ':RadioEditor', raise_exceptions = True) else: return toolkit_object(editor_file_name.split('.')[0] + ':ListEditor', raise_exceptions = True) except: return super(ToolkitEditorFactory, self)._get_custom_editor_class() # Define the EnumEditor class. EnumEditor = ToolkitEditorFactory ### EOF ####################################################################### traitsui-4.1.0/traitsui/editors/value_editor.py0000644000175100001440000001153211674463546022734 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2006, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 01/05/2006 # #------------------------------------------------------------------------------ """ Defines the tree-based Python value editor and the value editor factory. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import Instance, Int, false from .tree_editor import TreeEditor from ..view import View from ..item import Item from ..value_tree import RootNode, value_tree_nodes from ..editor_factory import EditorFactory from ..editor import Editor #------------------------------------------------------------------------------- # 'SimpleEditor' class: #------------------------------------------------------------------------------- class _ValueEditor ( Editor ): """ Simple style of editor for values, which displays a tree. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Is the editor read only? readonly = false # The root node of the value tree root = Instance( RootNode ) # Is the value editor scrollable? This values overrides the default. scrollable = True #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self.update_editor() editor = TreeEditor( auto_open = self.factory.auto_open, hide_root = True, editable = False, nodes = value_tree_nodes ) self._ui = self.edit_traits( parent = parent, view = View( Item( 'root', show_label = False, editor = editor ), kind = 'subpanel' ) ) self._ui.parent = self.ui self.control = self._ui.control #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes external to the editor. """ self.root = RootNode( name = '', value = self.value, readonly = self.readonly ) #--------------------------------------------------------------------------- # Disposes of the contents of an editor: #--------------------------------------------------------------------------- def dispose ( self ): """ Disposes of the contents of an editor. """ self._ui.dispose() super( _ValueEditor, self ).dispose() #--------------------------------------------------------------------------- # Returns the editor's control for indicating error status: #--------------------------------------------------------------------------- def get_error_control ( self ): """ Returns the editor's control for indicating error status. """ return self._ui.get_error_controls() #------------------------------------------------------------------------------- # 'ToolkitEditorFactory' class: #------------------------------------------------------------------------------- class ToolkitEditorFactory ( EditorFactory ): """ Editor factory for tree-based value editors. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Number of tree levels to automatically open auto_open = Int( 2 ) # Define the ValueEditor class. ValueEditor = ToolkitEditorFactory #--EOF------------------------------------------------------------------------- traitsui-4.1.0/traitsui/editors/dnd_editor.py0000644000175100001440000000364311674463546022371 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2008, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 06/25/2006 # #------------------------------------------------------------------------------ """ Defines the editor factory for a drag-and-drop editor. A drag-and-drop editor represents its value as a simple image which, depending upon the editor style, can be a drag source only, a drop target only, or both a drag source and a drop target. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from ..ui_traits import Image from ..editor_factory import EditorFactory #------------------------------------------------------------------------------- # 'ToolkitEditorFactory' class: #------------------------------------------------------------------------------- class ToolkitEditorFactory ( EditorFactory ): """ Editor factory for drag-and-drop editors. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # The image to use for the target: image = Image # The image to use when the target is disabled: disabled_image = Image # Define the DNDEditor class. DNDEditor = ToolkitEditorFactory # EOF ######################################################################### traitsui-4.1.0/traitsui/editors/image_editor.py0000644000175100001440000000335211674463546022703 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2007, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 06/05/2007 # #------------------------------------------------------------------------------- """ Traits UI 'display only' image editor. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import Property from ..ui_traits import Image from ..basic_editor_factory import BasicEditorFactory from ..toolkit import toolkit_object #------------------------------------------------------------------------------- # 'ImageEditor' editor factory class: #------------------------------------------------------------------------------- class ImageEditor ( BasicEditorFactory ): # The editor class to be created: klass = Property # The optional image resource to be displayed by the editor (if not # specified, the editor's object value is used as the ImageResource to # display): image = Image def _get_klass(self): """ Returns the editor class to be instantiated. """ return toolkit_object('image_editor:_ImageEditor') #-- EOF ----------------------------------------------------------------------- traitsui-4.1.0/traitsui/editors/list_editor.py0000644000175100001440000001607311674463546022600 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2008, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/21/2004 # #------------------------------------------------------------------------------ """ Defines the list editor factory for the traits user interface toolkits.. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import (HasTraits, BaseTraitHandler, Range, Str, Any, Int, Instance, Property, Bool, Callable, Enum, PrototypedFrom) # CIRCULAR IMPORT FIXME: Importing from the source rather than traits.ui.api # to avoid circular imports, as this EditorFactory will be part of # traits.ui.api as well. from ..view import View from ..item import Item from ..ui_traits import style_trait, AView from ..editor_factory import EditorFactory from ..toolkit import toolkit_object # Currently, this traits is used only for the wx backend. from ..helper import DockStyle #------------------------------------------------------------------------------- # Trait definitions: #------------------------------------------------------------------------------- # Trait whose value is a BaseTraitHandler object handler_trait = Instance( BaseTraitHandler ) # The visible number of rows displayed rows_trait = Range( 1, 50, 5, desc = 'the number of list rows to display' ) # The visible number of columns displayed columns_trait = Range( 1, 10, 1, desc = 'the number of list columns to display' ) editor_trait = Instance( EditorFactory ) #------------------------------------------------------------------------------- # 'ToolkitEditorFactory' class: #------------------------------------------------------------------------------- class ToolkitEditorFactory ( EditorFactory ): """ Editor factory for list editors. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # The editor to use for each list item: editor = editor_trait # Can the list be reorganized, or have items added and deleted. mutable = Bool(True) # The style of editor to use for each item: style = style_trait # The trait handler for each list item: trait_handler = handler_trait # The number of list rows to display: rows = rows_trait # The number of list columns to create: columns = columns_trait # Use a notebook for a custom view? use_notebook = Bool(False) # Show a right-click context menu for the notebook tabs? (Qt only) show_notebook_menu = Bool(False) #-- Notebook Specific Traits ----------------------------------------------- # Are notebook items deletable? deletable = Bool(False) # The extended name of the trait on each page object which should be used # to determine whether or not an individual page should be deletable. deletable_trait = Str() # FIXME: Currently, this trait is used only in the wx backend. # The DockWindow graphical theme dock_theme = Any # FIXME: Currently, this trait is used only in the wx backend. # Dock page style to use for each DockControl: dock_style = DockStyle # Export class for each item in a notebook: export = Str # Name of the view to use in notebook mode: view = AView # The type of UI to construct ('panel', 'subpanel', etc) ui_kind = Enum( 'subpanel', 'panel' ) # A factory function that can be used to define that actual object to be # edited (i.e. view_object = factory( object )): factory = Callable # Extended name to use for each notebook page. It can be either the actual # name or the name of an attribute on the object in the form: # '.name[.name...]' page_name = Str # Name of the [object.]trait[.trait...] to synchronize notebook page # selection with: selected = Str #--------------------------------------------------------------------------- # Traits view definition: #--------------------------------------------------------------------------- traits_view = View( [ [ 'use_notebook{Use a notebook in a custom view}', '|[Style]' ], [ Item( 'page_name', enabled_when = 'object.use_notebook' ), Item( 'view', enabled_when = 'object.use_notebook' ), '|[Notebook options]' ], [ Item( 'rows', enabled_when = 'not object.use_notebook' ), '|[Number of list rows to display]<>' ] ] ) #--------------------------------------------------------------------------- # 'Editor' factory methods: #--------------------------------------------------------------------------- def _get_custom_editor_class ( self ): if self.use_notebook: return toolkit_object('list_editor:NotebookEditor') return toolkit_object('list_editor:CustomEditor') #------------------------------------------------------------------------------- # 'ListItemProxy' class: # This class is used to update the list editors when the object changes # external to the editor. #------------------------------------------------------------------------------- class ListItemProxy ( HasTraits ): # The list proxy: list = Property # The item proxies index into the original list: index = Int # Delegate all other traits to the original object: _ = PrototypedFrom( '_zzz_object' ) # Define all of the private internal use values (the funny names are an # attempt to avoid name collisions with delegated trait names): _zzz_inited = Any _zzz_object = Any _zzz_name = Any def __init__ ( self, object, name, index, trait, value ): super( ListItemProxy, self ).__init__() self._zzz_inited = False self._zzz_object = object self._zzz_name = name self.index = index if trait is not None: self.add_trait( 'value', trait ) self.value = value self._zzz_inited = (self.index < len( self.list )) def _get_list ( self ): return getattr( self._zzz_object, self._zzz_name ) def _value_changed ( self, old_value, new_value ): if self._zzz_inited: self.list[ self.index ] = new_value # Define the ListEditor class ListEditor = ToolkitEditorFactory ### EOF --------------------------------------------------------------------- traitsui-4.1.0/traitsui/editors/set_editor.py0000644000175100001440000000362211674463546022414 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2008, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/21/2004 # #------------------------------------------------------------------------------ """ Defines the set editor factory for all traits user interface toolkits. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from ..editor_factory import EditorWithListFactory from traits.api import Bool, Str #------------------------------------------------------------------------------- # 'ToolkitEditorFactory' class: #------------------------------------------------------------------------------- class ToolkitEditorFactory ( EditorWithListFactory ): """ Editor factory for editors for sets. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Are the items in the set ordered (vs. unordered)? ordered = Bool( False ) # Can the user add and delete all items in the set at once? can_move_all = Bool( True ) # Title of left column: left_column_title = Str # Title of right column: right_column_title = Str # Define the SetEditor class SetEditor = ToolkitEditorFactory ### EOF --------------------------------------------------------------------- traitsui-4.1.0/traitsui/editors/progress_editor.py0000644000175100001440000000341511674463546023465 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2008, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # #------------------------------------------------------------------------------ """ Defines the progress editor factory for all traits toolkit backends, """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import Int, Bool, Str from ..editor_factory import EditorFactory class ToolkitEditorFactory ( EditorFactory ): """ Editor factory for code editors. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # The title title = Str # The message to be displayed along side the progress guage message = Str # The starting value min = Int # The ending value max = Int # If the cancel button should be shown can_cancel = Bool(False) # If the estimated time should be shown show_time = Bool(False) # if the percent complete should be shown show_percent = Bool(False) # Define the Code Editor class. ProgressEditor = ToolkitEditorFactory ### EOF ####################################################################### traitsui-4.1.0/traitsui/editors/popup_editor.py0000644000175100001440000000623611674463546022770 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import Float, Enum, Any, Property from ..view import View from ..item import Item from ..editor_factory import EditorFactory from ..basic_editor_factory import BasicEditorFactory from .text_editor import TextEditor from ..ui_traits import EditorStyle from ..ui_editor import UIEditor from ..toolkit import toolkit_object #------------------------------------------------------------------------------- # '_PopupEditor' class: #------------------------------------------------------------------------------- class _PopupEditor ( UIEditor ): #--------------------------------------------------------------------------- # Creates the traits UI for the editor: #--------------------------------------------------------------------------- def init_ui ( self, parent ): """ Creates the traits UI for the editor. """ return self.object.edit_traits( view = self.base_view(), parent = parent ) def base_view ( self ): """ Returns the View that allows the popup view to be displayed. """ return View( Item( self.name, show_label = False, style = 'readonly', editor = TextEditor( view = self.popup_view() ), padding = -4, ), kind = 'subpanel' ) def popup_view ( self ): """ Returns the popup View. """ factory = self.factory item = Item( self.name, show_label = False, padding = -4, style = factory.style, height = factory.height, width = factory.width ) editor = factory.editor if editor is not None: if not isinstance( editor, EditorFactory ): editor = editor() item.editor = editor return View( item, kind = factory.kind ) #------------------------------------------------------------------------------- # 'PopupEditor' class: #------------------------------------------------------------------------------- class PopupEditor ( BasicEditorFactory ): # The class used to construct editor objects: klass = Property # The kind of popup to use: kind = Enum( 'popover', 'popup', 'info' ) # The editor to use for the pop-up view (can be None (use default editor), # an EditorFactory instance, or a callable that returns an EditorFactory # instance): editor = Any # The style of editor to use for the popup editor (same as Item.style): style = EditorStyle # The height of the popup (same as Item.height): height = Float( -1.0 ) # The width of the popup (same as Item.width): width = Float( -1.0 ) def _get_klass( self ): """ The class used to construct editor objects. """ return toolkit_object('popup_editor:_PopupEditor') traitsui-4.1.0/traitsui/editors/csv_list_editor.py0000644000175100001440000003430011674463546023444 0ustar ischnellusers00000000000000"""This modules defines CSVListEditor. A CSVListEditor provides an editor for lists of simple data types. It allows the user to edit the list in a text field, using commas (or optionally some other character) to separate the elements. """ #------------------------------------------------------------------------------ # # Copyright (c) 2011, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Author: Warren Weckesser # Date: July 2011 # #------------------------------------------------------------------------------ from traits.api import Str, Int, Float, Enum, Range, Bool, Trait, TraitError from traits.trait_handlers import RangeTypes from .text_editor import TextEditor from ..editor_factory import EditorFactory from ..helper import enum_values_changed def _eval_list_str(s, sep=',', item_eval=None, ignore_trailing_sep=True): """Convert a string into a list. Parameters ---------- s : str The string to be converted. sep : str or None `sep` is the text separator of list items. If `sep` is None, each contiguous stretch of whitespace is a separator. item_eval : callable or None `item_eval` is used to evaluate the list elements. If `item_eval` is None, the list will be a list substrings of `s`. ignore_trailing_sep : bool If `ignore_trailing_sep` is False, it is an error to have a separator at the end of the list (i.e. 'foo, bar,' is invalid). If `ignore_trailing_sep` is True, a separator at the end of the string `s` is ignored. Returns ------- values : list List of converted values from the string. """ if item_eval is None: item_eval = lambda x: x s = s.strip() if sep is not None and ignore_trailing_sep and s.endswith(sep): s = s[:-len(sep)] s = s.rstrip() if s == '': values = [] else: values = [item_eval(x.strip()) for x in s.split(sep)] return values def _format_list_str(values, sep=',', item_format=str): """Convert a list to a string. Each item in the list `values` is converted to a string with the function `item_format`, and these are joined with `sep` plus a space. If `sep` is None, a single space is used to join the items. Parameters ---------- values : list The list of values to be represented as a string. sep : str String used to join the items. A space is also added after `sep`. item_format : callable Converts its single argument to a string. Returns ------- s : str The result of converting the list to a string. """ if sep is None: joiner = ' ' else: joiner = sep + ' ' s = joiner.join(item_format(x) for x in values) return s def _validate_range_value(range_object, object, name, value): """Validate a Range value. This function is used by the CSVListEditor to validate a value when editing a list of ranges where the Range is dynamic (that is, one or both of the 'low' and 'high' values are strings that refer to other traits in `object`. The function implements the same validation logic as in the method traits.trait_types.BaseRange._set(), but does not call the set_value() method; instead it simply returns the valid value. If the value is not valid, range_object.error(...) is called. Parameters ---------- range_object : instance of traits.trait_types.Range object : instance of HasTraits This is the HasTraits object that holds the traits to which the one or both of range_object.low and range_object.high refer. name : str The name of the List trait in `object`. value : object (e.g. int, float, str) The value to be validated. Returns ------- value : object The validated value. It might not be the same type as the input argument (e.g. if the range type is float and the input value is an int, the return value will be a float). """ low = eval(range_object._low) high = eval(range_object._high) if low is None and high is None: if isinstance(value, RangeTypes): return value else: new_value = range_object._typed_value(value, low, high) satisfies_low = (low is None or low < new_value or ((not range_object._exclude_low) and (low == new_value))) satisfies_high = (high is None or high > new_value or ((not range_object._exclude_high) and (high == new_value))) if satisfies_low and satisfies_high: return value # Note: this is the only explicit use of 'object' and 'name'. range_object.error(object, name, value) class CSVListEditor(EditorFactory): """A text editor for a List. This editor provides a single line of input text of comma separated values. (Actually, the default separator is a comma, but this can changed.) The editor can only be used with List traits whose inner trait is one of Int, Float, Str, Enum, or Range. The 'simple', 'text' and 'custom' styles are all the same. The 'readonly' style provides the same formatting in the text field as the other editors, but the user can not change the value. Like other Traits editors, the background of the text field will turn red if the user enters an incorrectly formatted list or if the values do not match the type of the inner trait. This validation only occurs while editing the text field. If, for example, the inner trait is Range(low='lower', high='upper'), a change in 'upper' will not trigger the validation code of the editor. The editor removes whitespace of entered items with strip(), so for Str types, the editor should not be used if whitespace at the beginning or end of the string must be preserved. Constructor Keyword Arguments ----------------------------- sep : str or None, optional The separator of the values in the list. If None, each contiguous sequence of whitespace is a separator. Default is ','. ignore_trailing_sep : bool, optional If this is False, a line containing a trailing separator is invalid. Default is True. auto_set : bool If True, then every keystroke sets the value of the trait. enter_set : bool If True, the user input sets the value when the Enter key is pressed. Example ------- The following will display a window containing a single input field. Entering, say, '0, .5, 1' in this field will result in the list x = [0.0, 0.5, 1.0]. >>> class Foo(HasTraits): .... x = List(Range(low=0.0, high=1.0)) .... traits_view = View(Item('x', editor=CSVListEditor())) .... def _x_changed(self): .... print self.x .... >>> f = Foo() >>> f.configure_traits() """ # The separator of the element in the list. sep = Trait(',', None, Str) # If False, it is an error to have a trailing separator. ignore_trailing_sep = Bool(True) # Include some of the TextEditor API: # Is user input set on every keystroke? auto_set = Bool(True) # Is user input set when the Enter key is pressed? enter_set = Bool(False) def _funcs(self, object, name): """Create the evalution and formatting functions for the editor. Parameters ---------- object : instance of HasTraits This is the object that has the List trait for which we are creating an editor. name : str Name of the List trait on `object`. Returns ------- evaluate, fmt_func : callable, callable The functions for converting a string to a list (`evaluate`) and a list to a string (`fmt_func`). These are the functions that are ultimately given as the keyword arguments 'evaluate' and 'format_func' of the TextEditor that will be generated by the CSVListEditor editor factory functions. """ t = getattr(object, name) # Get the list of inner traits. Only a single inner trait is allowed. it_list = t.trait.inner_traits() if len(it_list) > 1: raise TraitError("Only one inner trait may be specified when " "using a CSVListEditor.") # `it` is the single inner trait. This will be an instance of # traits.traits.CTrait. it = it_list[0] # The following 'if' statement figures out the appropriate evaluation # function (evaluate) and formatting function (fmt_func) for the # given inner trait. if it.is_trait_type(Int) or it.is_trait_type(Float) or \ it.is_trait_type(Str): evaluate = \ lambda s: _eval_list_str(s, sep=self.sep, item_eval=it.trait_type.evaluate, ignore_trailing_sep=self.ignore_trailing_sep) fmt_func = lambda vals: _format_list_str(vals, sep=self.sep) elif it.is_trait_type(Enum): values, mapping, inverse_mapping = enum_values_changed(it) evaluate = \ lambda s: _eval_list_str(s, sep=self.sep, item_eval=mapping.__getitem__, ignore_trailing_sep=self.ignore_trailing_sep) fmt_func = \ lambda vals: \ _format_list_str(vals, sep=self.sep, item_format=inverse_mapping.__getitem__) elif it.is_trait_type(Range): # Get the type of the values from the default value. # range_object will be an instance of traits.trait_types.Range. range_object = it.handler if range_object.default_value_type == 8: # range_object.default_value is callable. defval = range_object.default_value(object) else: # range_object.default_value *is* the default value. defval = range_object.default_value typ = type(defval) if range_object.validate is None: # This will be the case for dynamic ranges. item_eval = lambda s: _validate_range_value( range_object, object, name, typ(s)) else: # Static ranges have a validate method. item_eval = lambda s: range_object.validate( object, name, typ(s)) evaluate = \ lambda s: _eval_list_str(s, sep=self.sep, item_eval=item_eval, ignore_trailing_sep=self.ignore_trailing_sep) fmt_func = lambda vals: _format_list_str(vals, sep=self.sep) else: raise TraitError("To use a CSVListEditor, the inner trait of the " "List must be Int, Float, Range, Str or Enum.") return evaluate, fmt_func def _make_text_editor(self, ui, object, name, description, parent, readonly=False): """Create the actual text editor for this list. Parameters ---------- ui : instance of traitsui.ui.UI Passed on to factory functions of the TextEditor instance. object : instance of HasTraits The HasTraits instance with the trait `name`. name : str The name of the trait on `object`. description : str This is a description of the trait. If, for example, the Item holding the trait defines a tooltip, that string will end up in `description`. It is passed on to the factory functions of the TextEditor instance. parent : object The parent of the backend-dependent control that will be used to implement the editor. readonly : bool If True, create a read-only editor. Otherwise, the editor field will be editable by the user. Returns ------- ed : object An editor generated by either TextEditor.simple_editor(...) or TextEditor.readonly_editor(...), depending on the value of `readonly`. """ evaluate, fmt_func = self._funcs(object, name) # Create a TextEditor with the appropriate evaluation and formatting # functions. editor_factory = TextEditor(evaluate=evaluate, format_func=fmt_func, auto_set=self.auto_set, enter_set=self.enter_set) # Call the appropriate factory function to create the actual editor. if readonly: ed = editor_factory.readonly_editor(ui, object, name, description, parent) else: ed = editor_factory.simple_editor(ui, object, name, description, parent) # Hook up a listener on `object` so that the display is updated if # the list changes external to the editor. object.on_trait_change(ed.update_editor, name + '[]') return ed def simple_editor(self, ui, object, name, description, parent): e = self._make_text_editor(ui, object, name, description, parent) return e def custom_editor(self, ui, object, name, description, parent): return self.simple_editor(ui, object, name, description, parent) def text_editor(self, ui, object, name, description, parent): return self.simple_editor(ui, object, name, description, parent) def readonly_editor(self, ui, object, name, description, parent): e = self._make_text_editor(ui, object, name, description, parent, readonly=True) return e traitsui-4.1.0/traitsui/editors/tabular_editor.py0000644000175100001440000001270511674463546023255 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2007, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 05/20/2007 # #------------------------------------------------------------------------------- """ A traits UI editor for editing tabular data (arrays, list of tuples, lists of objects, etc). """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import Str, Bool, Property, List, Enum, Instance from ..ui_traits import Image from ..basic_editor_factory import BasicEditorFactory from ..toolkit import toolkit_object #------------------------------------------------------------------------------- # 'TabularEditor' editor factory class: #------------------------------------------------------------------------------- class TabularEditor ( BasicEditorFactory ): """ Editor factory for tabular editors. """ #-- Trait Definitions ------------------------------------------------------ # The editor class to be created: klass = Property # Should column headers (i.e. titles) be displayed? show_titles = Bool( True ) # The optional extended name of the trait used to indicate that a complete # table update is needed: update = Str # The optional extended name of the trait used to indicate that the table # just needs to be repainted. refresh = Str # Should the table update automatically when the table item's contents # change? Note that in order for this feature to work correctly, the editor # trait should be a list of objects derived from HasTraits. Also, # performance can be affected when very long lists are used, since enabling # this feature adds and removed Traits listeners to each item in the list. auto_update = Bool( False ) # The optional extended name of the trait to synchronize the selection # values with: selected = Str # The optional extended name of the trait to synchronize the selection rows # with: selected_row = Str # Whether or not to allow selection. selectable = Bool( True ) # The optional extended name of the trait to synchronize the activated value # with: activated = Str # The optional extended name of the trait to synchronize the activated # value's row with: activated_row = Str # The optional extended name of the trait to synchronize left click data # with. The data is a TabularEditorEvent: clicked = Str # The optional extended name of the trait to synchronize left double click # data with. The data is a TabularEditorEvent: dclicked = Str # The optional extended name of the trait to synchronize right click data # with. The data is a TabularEditorEvent: right_clicked = Str # The optional extended name of the trait to synchronize right double # clicked data with. The data is a TabularEditorEvent: right_dclicked = Str # The optional extended name of the trait to synchronize column # clicked data with. The data is a TabularEditorEvent: column_clicked = Str # The optional extended name of the trait to synchronize column # right clicked data with. The data is a TabularEditorEvent: column_right_clicked = Str # The optional extended name of the Event trait that should be used to # trigger a scroll-to command. The data is an integer giving the row. scroll_to_row = Str # Controls behavior of scroll to row scroll_to_row_hint = Enum("center", "top", "bottom", "visible") # Can the user edit the values? editable = Bool( True ) # Can the user edit the labels (i.e. the first column) editable_labels = Bool( False ) # Are multiple selected items allowed? multi_select = Bool( False ) # Should horizontal lines be drawn between items? horizontal_lines = Bool( True ) # Should vertical lines be drawn between items? vertical_lines = Bool( True ) # Should the columns automatically resize? Don't allow this when the amount # of data is large. auto_resize = Bool( False ) # Whether to stretch the last column to fit the available space. stretch_last_section = Bool( True ) # The adapter from trait values to editor values: adapter = Instance( 'traitsui.tabular_adapter.TabularAdapter', () ) # What type of operations are allowed on the list: operations = List( Enum( 'delete', 'insert', 'append', 'edit', 'move' ), [ 'delete', 'insert', 'append', 'edit', 'move' ] ) # Are 'drag_move' operations allowed (i.e. True), or should they always be # treated as 'drag_copy' operations (i.e. False): drag_move = Bool( False ) # The set of images that can be used: images = List( Image ) def _get_klass(self): """ Returns the toolkit-specific editor class to be instantiated. """ return toolkit_object('tabular_editor:TabularEditor') ### EOF ####################################################################### traitsui-4.1.0/traitsui/helper.py0000644000175100001440000001011411674463546020053 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/25/2004 # #------------------------------------------------------------------------------ """ Defines various helper functions that are useful for creating Traits-based user interfaces. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from string import uppercase, lowercase from traits.api import BaseTraitHandler, CTrait, Enum, TraitError from .ui_traits import SequenceTypes #------------------------------------------------------------------------------- # Trait definitions: #------------------------------------------------------------------------------- # Layout orientation for a control and its associated editor Orientation = Enum( 'horizontal', 'vertical' ) # Docking drag bar style: DockStyle = Enum( 'horizontal', 'vertical', 'tab', 'fixed' ) #---------------------------------------------------------------------------- # Return a 'user-friendly' name for a specified trait: #---------------------------------------------------------------------------- def user_name_for ( name ): """ Returns a "user-friendly" name for a specified trait. """ name = name.replace( '_', ' ' ) name = name[:1].upper() + name[1:] result = '' last_lower = 0 for c in name: if (c in uppercase) and last_lower: result += ' ' last_lower = (c in lowercase) result += c return result #------------------------------------------------------------------------------- # Format a number with embedded commas: #------------------------------------------------------------------------------- def commatize ( value ): """ Formats a specified value as an integer string with embedded commas. For example: commatize( 12345 ) returns "12,345". """ s = str( abs( value ) ) s = s.rjust( ((len( s ) + 2) / 3) * 3 ) result = ','.join( [ s[ i: i+3 ] for i in range( 0, len(s), 3 ) ] ).lstrip() if value >= 0: return result return '-' + result #------------------------------------------------------------------------------- # Recomputes the mappings for a new set of enumeration values: #------------------------------------------------------------------------------- def enum_values_changed ( values, strfunc=unicode ): """ Recomputes the mappings for a new set of enumeration values. """ if isinstance( values, dict ): data = [ ( strfunc( v ), n ) for n, v in values.items() ] if len( data ) > 0: data.sort( lambda x, y: cmp( x[0], y[0] ) ) col = data[0][0].find( ':' ) + 1 if col > 0: data = [ ( n[ col: ], v ) for n, v in data ] elif not isinstance( values, SequenceTypes ): handler = values if isinstance( handler, CTrait ): handler = handler.handler if not isinstance( handler, BaseTraitHandler ): raise TraitError, "Invalid value for 'values' specified" if handler.is_mapped: data = [ ( strfunc( n ), n ) for n in handler.map.keys() ] data.sort( lambda x, y: cmp( x[0], y[0] ) ) else: data = [ ( strfunc( v ), v ) for v in handler.values ] else: data = [ ( strfunc( v ), v ) for v in values ] names = [ x[0] for x in data ] mapping = {} inverse_mapping = {} for name, value in data: mapping[ name ] = value inverse_mapping[ value ] = name return ( names, mapping, inverse_mapping ) traitsui-4.1.0/traitsui/context_value.py0000644000175100001440000000422511674463546021462 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2008, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 08/18/2008 # #------------------------------------------------------------------------------ """ Defines some helper classes and traits used to define 'bindable' editor values. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import HasPrivateTraits, Instance, Str, Int, Float, Either #------------------------------------------------------------------------------- # 'ContextValue' class: #------------------------------------------------------------------------------- class ContextValue ( HasPrivateTraits ): """ Defines the name of a context value that can be bound to some editor value. """ # The extended trait name of the value that can be bound to the editor # (e.g. 'selection' or 'handler.selection'): name = Str #-- object Interface ------------------------------------------------------- def __init__ ( self, name ): """ Initializes the object. """ self.name = name # Define a shorthand name for a ContextValue: CV = ContextValue #------------------------------------------------------------------------------- # Trait definitions useful in defining bindable editor traits: #------------------------------------------------------------------------------- InstanceOfContextValue = Instance( ContextValue, allow_none = False ) def CVType( type ): return Either( type, InstanceOfContextValue, sync_value = 'to' ) CVInt = CVType( Int ) CVFloat = CVType( Float ) CVStr = CVType( Str ) traitsui-4.1.0/traitsui/dockable_view_element.py0000644000175100001440000001443411674463546023114 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 12/14/2005 # #------------------------------------------------------------------------------- """ Defines the DockableViewElement class, which allows Traits UIs and Traits UI elements to be docked in external PyFace DockWindow windows. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import HasPrivateTraits, Instance, Bool from .ui import UI from .group import Group from .view import View from .view_element import ViewSubElement from pyface.dock.idockable import IDockable #------------------------------------------------------------------------------- # 'DockableViewElement' class: #------------------------------------------------------------------------------- class DockableViewElement ( HasPrivateTraits, IDockable ): """ Allows Traits UIs and Traits UI elements to be docked in external PyFace DockWindow windows. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # The Traits UI that can be docked with an external DockWindow ui = Instance( UI ) # The (optional) element of the Traits UI that can be docked element = Instance( ViewSubElement ) # Should the DockControl be closed on redocking? should_close = Bool( False ) #-- IDockable interface -------------------------------------------------------- #--------------------------------------------------------------------------- # Should the current DockControl be closed before creating the new one: #--------------------------------------------------------------------------- def dockable_should_close ( self ): """ Should the current DockControl be closed before creating the new one? """ element = self.element if element is None: element = self.ui.view.content if not isinstance( element, Group ): element = Group().set( content = [ element ] ) group = Group().set( content = [ element ] ) self._view = View().set( **self.ui.view.get() ).set( content = group, title = '' ) # FIXME: The following private traits are being set here to facilitate # rebuilding the ui (which will require the context and the handler). # When a current dock control is closed (close_dock_control method), the # contents of self.ui have been disposed of and self.ui is now None. # Now if a new UI needs to be created by calling dockable_get_control # (e.g., when doing an 'undock' action on a dock window), we need to # pass on the context and handler to the UI. Therefore, we are setting # these private traits here so dockable_get_control can access them. # In future, we need to investigate if there is a better way to do this. self._context = self.ui.context.copy() # Make copy since context will be emptied when calling self.ui.dispose() self._handler = self.ui.handler return (self.should_close or (self.element is None)) #--------------------------------------------------------------------------- # Gets a control that can be docked into a DockWindow: #--------------------------------------------------------------------------- def dockable_get_control ( self, parent ): """ Gets a control that can be docked into a DockWindow. """ # Create the new UI: ui = self._view.ui( self._context, parent = parent, kind = 'subpanel', handler = self._handler ) # Discard the reference to the view created previously: self._view = None # If the old UI was closed, then switch to using the new one: if self.element is None: self.ui = ui else: self._ui = ui return ui.control #--------------------------------------------------------------------------- # Allows the object to override the default DockControl settings: #--------------------------------------------------------------------------- def dockable_init_dockcontrol ( self, dock_control ): """ Allows the object to override the default DockControl settings. """ dockable = self if self.element is not None: dockable = DockableViewElement( ui = self._ui, element = self.element, should_close = True ) self._ui = None dock_control.set( dockable = dockable, on_close = dockable.close_dock_control ) #--------------------------------------------------------------------------- # Handles the closing of a DockControl containing a Traits UI: #--------------------------------------------------------------------------- def close_dock_control ( self, dock_control, abort ): """ Handles the closing of a DockControl containing a Traits UI. """ ui = self.ui # Ask the traits UI handler if it is OK to close the window: if (not abort) and (not ui.handler.close( ui.info, True )): # If not, tell the DockWindow not to close it: return False # Otherwise, clean up and close the traits UI: ui.dispose( abort = abort ) # Break our linkage to the UI and ViewElement object: self.ui = self.element = None # And tell the DockWindow to remove the DockControl: return True traitsui-4.1.0/traitsui/default_dock_window_theme.py0000644000175100001440000000442111674463546023775 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2007, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 07/14/2007 # #------------------------------------------------------------------------------- """ Defines the default DockWindow theme. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from .dock_window_theme import DockWindowTheme from .theme import Theme #------------------------------------------------------------------------------- # Define the default theme: #------------------------------------------------------------------------------- # The original DockWindows UI redone as a theme: default_dock_window_theme = DockWindowTheme( use_theme_color = False, tab_active = Theme( '@std:tab_active', label = ( 0, -3 ), content = ( 7, 6, 0, 0 ) ), tab_inactive = Theme( '@std:tab_inactive', label = ( 0, -1 ), content = ( 5, 0 ) ), tab_hover = Theme( '@std:tab_hover', label = ( 0, -2 ), content = ( 5, 0 ) ), tab_background = Theme( '@std:tab_background' ), tab = Theme( '@std:tab', content = 0, label = ( -7, 0 ) ), vertical_splitter = Theme( '@std:vertical_splitter', content = 0, label = ( 0, -25 ) ), horizontal_splitter = Theme( '@std:horizontal_splitter', content = 0, label = ( -24, 0 ) ), vertical_drag = Theme( '@std:vertical_drag', content = ( 0, 10 ) ), horizontal_drag = Theme( '@std:horizontal_drag', content = ( 10, 0 ) ) ) traitsui-4.1.0/traitsui/image/0000755000175100001440000000000011674463546017307 5ustar ischnellusers00000000000000traitsui-4.1.0/traitsui/image/library/0000755000175100001440000000000011674463546020753 5ustar ischnellusers00000000000000traitsui-4.1.0/traitsui/image/library/std.zip0000644000175100001440000016556211674463546022310 0ustar ischnellusers00000000000000PK ݑ8נ alert16.pngUT {H{HUxdPNG  IHDRa pHYs  ~RIDATxKZaϟq(F9^hpv8d^sNֈ,jQEE$D!]xws*[l]|nߗ<-ܦE";|n͝E"(8P`,<RBp )Q2mz$ܶpxq|+4*>CDZa08a+NTQpYe=~ SL{j p8v :2J4jUQܝygSxC%f(;eƚAyXW~?^#hSmk~?}>z(\Xfk"c(YanKkQdWc @d,cxy'ҽ}}]#$)1M64Npw1AIܖE=G(Z9Q%@1kˉ}FŠ e 2D9]0#asy\Q+W((i"pvfUIsۼ$%&$Q Do_y69%IENDB`PKݑ8BE5.pngUT {H{HUxd sb``p i@$?5R B xnPOǐ9o.9վ3cӑ Nns4f-V,$сQnz^s6쐘~t 5[lnٛ>xd`>sov[nYiS {IzVɏ<ܞ:IVT)]wċU-3&~G>wkF绞YN3?plۮd]>S+W ,c=yѾ5Z6޿fy\W {ǥW^9'>?ʎ-fxÕ.~ejYW|~fR9r >*r^qa{3|Mn+o|)=g:'?A?S4!]e8$]V{V.2BzB}׎7^53fNٸ\v uvOZ>w<^ uKN-z5^ګW_ĝ99ͳRχ8o©Bx|^^yāW%]5 J`Z?'AY?Ѧw,u<]\9%4PKݑ8zqABG5.pngUT {H{HUxd sb``p i@$?5R B xnϞ.!s޽\.spm K <2t-^iɮ9u崊 ZV֔)xܙIcMC#>F`%~T[WyV)TʐwZ{ L _ija}if7W VtGg )C5c6|gx$Zj\~cUKg.0sVxye}+M``lmșR2[}zccݣ{x\OrWVKnF^>VTwqwQ~-Ne߹MF{V,%ӯ}Y8'Lw!k˲)2AvOx{%_4ʦ<*a?۲`*&"˭-.z%ܹs}_7s5Tk[~Դ;u[`ݧՏn93al?"v]jXU"=aJh/ |*άۻ6%%N7eSB͞ "n\&pnjg_1b&30vRm溭3C$P;r /7685gSqI Ek9Lޣ_8ww?X!&̠Lnřye=zWF?j9 rbZ *g.Zy-F7e2fqɿK,u}Y ,*7 ?[xF57ڜO}6enrX!iOxy˾W؎Y2XZ=Nj~OXe筞tϑG~&86r/T̜p~]w}Րv0)K)i%'V\! dsC X&2xsJhPKݑ8|BG6.pngUT {H{HUxd sb``p i@$?5R B xnV=Oǐ9o^N83s}L *ӌ ЪsR< bUq=8,s;ZX-MC\upxOV*=A!Ϟ ^O|mbENM dlģ)Ⱥ n{ekD|v,{KeI I?<DZk ۲|cיKN4l%σkߔe o{3־ ro2q­"{LgT7yɱCuU 5|֡y/=>s6dg{UJׇv|wqmfmF>ns?ݳ_u\үSj:_a%wkt0˵cS 4s4c;5H֏|]YnejJ.׿15r݌ݙ7b:1jowl7uTh4MiխE&}t+9}1_|\3@3nhzǎSz!!MwkCn2)\(4zog.>zs/q%ŋ2köUD<o`׺Ǿ/旬^.1zi%]{>"ټgg=/\(c^b̳U-٤MQ@ob1dE<o<}޵twkk_> /pQԶ1_ëЩ_ p[j"^2{!ڦ߂67ɩpj:=iTy͏^4\ŸĠ1!VN|kǬy6"R_1jpJ~<_U*F`B[q+?eNHh۳M_*v~\W  vSy<} %նX.tf9V^e]|9iB(0`&q?X2xsJhPKݑ8yBH5.pngUT {H{HUxdՕ7}gfM-:FKZ!zReJ$ByDd;,X!$d22=ihVR ej:U6E\͸a6WU sJn\lFKYTL׻;/v5"]b2#˭&h$Bq-klPS5F&<16Zjg;7X:L0`Wi5o>)h~p2y$C'bۄTNl~ F_UShAb5SGzxMA>yuN|=g2݇$ Ue ݊fLr "R21^}zx\ '|[A< T[\2pG( #G8/%.L"Ğ ۹љQgsx7ͦkBj񷅊֨#SKpsA%rY2&d׊x/ZŹZ[}bUO9<nEImLo3]95/y+%蕩tP` j8EY䟈'ipha N2Eg: 5o)Ipo.2Ro:2Vդa8ȁy|;tOQn(̩y㔢A m}k5z6،Zųpi|L֤dӛխs0 ڿ8[.GOdsW][{]E G$ʁ*AI kLuSӃ -[ I <`04 ĹOiU/H zE1313N۵|uFl0T J+F֎~Bt+pn$*o*dY2 =dJDx|N#"]ѵx 0@ RC:yԿ/}٠Ѩiѓg:cj 2UI\ 垇|2g'r9@(|*Փ&GE'c2/b&O>6\3I76èP3g\j[V|fEqTm]~?Nφ@^,6FFR@ 6{$M*#6o`HKs+&>o&o|r2ZijKFyyF}snHDu؃ 㗎#e|>^ͬ!Wr0Tz%Kv,:tIb"+ju}+u_i`G?q'hεr&v^۫%F#ELNXܯH,]"k}=Pz6=C$j+)\،:-O)*ˆUjh1ߒwm:0 !{Jj`#4ΩHiҔ`0A0g'NL͇se|=pggDA.7'mZ"]gG7[ nϙTXUL eI-*'kU |,cydHsfmUqJd.z}xg6Q}j&𛋣cyvUJP~,?_vʁNhiw=sr2_ʈ<"sEu1(.…֑2FjG %Pwꩅhz/ kǿUxnۻNd(-&SL&N[2J5qh.r׀_iXmSϳ[Sc߷[ κo]_/:_Djxq|*)W/間s11*KUc^zK{0<# 3k&tV2;nU b*put EJx-;(7\\4,Kcqq͍EnfC~ ]`B` 擢{ @ ӀHnj=py3.ٰMc7孺ڸ:};W'̒}3_E6tULŤmheG6 bAY`zQKS \J6wu33T$N|-q(y'h-uKt촰@-è b@ u>1$pnؾVB4&K +ҷP>3#Bd _+恐Akms=7xrфsNNtnMF ٣B>#z,j<.ymQ45'g gN8(3ddhج!ڞ?\F (Dag{*%,#ohOϗ l>CGt e g^rmkڳݍ̠gjꙤHv#F|і p5h{yScETqj 8 "cL\k0 =bz]8A-tMki,HCx54U XEW =QX܂[Kle)5ا+;;$SV3m&AMb<HO@~D/>0Da{ف5YJi#BR$h3ʘ?$ʃ4EN7;:_u`V|9P}m;ՂBܘ ~ U{Ĕ=$ywMu{\/U#dCi=9xVj+qbQ H2|D ޿P7䒏QbRȫFnPq%' yV}1mgD3 W|B[ߧm4!< D".Ml.v5gE}Bb'ɋjltP֢00ߧ6b, >$q yaZ|7*| #֤|FyEP<+GaMAUwm3UPggqJ9Zb02k"bl$F"i6$dr !53$ia! ~P9D|/Z_PqRbeLQ0]0eܧ `&'eMKۚ؉Oސ, Fwuß+-|(M.; Պ\ks:FL_iskHڋ%+D]Jw9*u%Pױ|U)83ryMе`D2;GžEs ݦ6uX4N<#w c_+/РCb}Jb1}[k:B73bjzohus*-eƘ_UGޫS6 T&$29ROEpR!dX ؒ`³4A[D\=7a%^!ʜB1E&3>0b@zPW "mO 7 d6a5a.Q\N]MܰkG@8C[_0|wɊp$wtyeZXVbu:: sـre#0|uELs"C{\x YlrUh~ϘعF%;Հ)B"Ut^X/?]dG=ȅJI8 AAB ߔUa{vc|q2dzDB_u݇geArc{ En>"m.qѳ':i|EK,}-c1u 1LDI2=R;6فIJJ?S1[*7*QlZ^"ޢ6~?$,|sЂX!S4jg|4{9B va`) |0K;MBB#%fOgow%\mSS:).\ZUfLr:(Pŝktn/eqo79[ƁQ (>+"$})J Y<+=v6GQ,-g+-vډDnSnw弥I]Tʲ;*v}%_1#ΰ!A),CFfBx2#gز?c۵n}{oy 17ӂww^$]-X3f($Jv TO%GOnoO"Dte`4˱doXO;t4+䡈0g8X4x[(ŵ?xn>{)+SeP}%2%Ճ𳴥@|7C"0mgFG|10q ҇a+-JNbZrh8g@onPX4E?_>L}l:B%t8bo (4̌~tLI1i ?U)R)lp?IASh} Mas 5\alá apnBлl#TH{rvǡ`fd Gt BelS坯;^sR<&3 >86[ҳ37ʿ}u:HPZQ i%Or9DVr^0ҫ/$˄)m{R  Mn]ю \( vNl~?wW(A1#^ s1'ϳź!Kv(IBj"&r,.b̤%.s?dąapSW!ڨ *Jn7 DnFd!,,s{/R9ni%ɀ*w5Ƀ!?+L{6`I>gaڽtςt t6un&&3o [-^x\=7"Iz&Yl, IJyVj!D:^D{oS>Ζ^?I *`}mɎJXkkaӛ%ڸǭݮMW)o^&UMBYj`2R w`d̂ųg8:bjbpZ NjIiO'oƍs(Q%=?MGs&x]e|1 P푮ƥ&#ДDR:ox92'sp備y\]_򡦕6>lD17m *IMnDXm8Pe#%~QJ)RэE? ceZj y[SN^% 1â4/,%LjoN{Be Z KY DkyNmz4-ZAUEƁޙx)$?FR|ZX1D%"Ѡ38,}Ѥ8Rdqs0tD:S\"/#VUB䀺JH>zF `RDl|)2eI<)~/`AW]L f"OiZ0v X 6E 46jA͍t BBc0u0Bc/ݐstզQS6y6@N6q~XYnl`x֓|JTfGm}x½akm@cX,>ʚeo'?y֧p*^~uL| 3~0W3+U>AvbS]_5n=АoQÖ*A`B]g<;4Bk!̥ fp3{~ʑgiړrfV+A{nb="o?gJa48 76V\C bEBDJeo/e۳,t bf%n08bcɬVU)k_kV5=}UzJ1&PQS12b̵^'MjdG2BѲLȖd9֮gBW5񯸹Jț%ژԕ~8L$V;zU+ }y%֪ґ @RԑxҡrT85ʱR|i@j~Ca\$)_>l2!l6  7ygdrw#c9<'3Gȕ-2!SrE1GutZ_ f4FGsi&l,A=6vdq|20Cl\_: dth5Ԋnxh#PTXQ"+xľ.VF"pP5ئxɦp nȽnOH_%*՚`+𜾸ŝ犺Qdsѽj x쫭ku# ZⓎ!67 1v^(wǻ(=rߵAŢ=~XHzq֋6R507pt )".>±bB.w{K5%G;quu~3Oրm[q}z`]8rB_5ŋ!tTW;xs^R${d0:G/*>o)Ų>9>ԓvOY| ?NK}ud`{/Hi `AF)Z%A'  i~fmjG~߳L%DLH1iR'\K'vxuf9f².Q!{ojC5-xjRI!SL|Օ'{2E>-IyU*g=ص~|nƆ{Z6.ᅵt{ xՂθHY\T:=:>5pE,Ljϱmk" EY ZfS8̍hxTpHX+D}ﰕw<"#Ÿr>15kOsP~Y Kbyq[]׭xqIJ%xU!+A{ټv9rVӜF5,;o6@`\ѰJuOsRUݗJȨCbS"vmh{ARF'5_27!ҖaVH0JUaaVH*bQ>99U~b9)nB3AoffVz,M7e7\ 0jޭ£-5CSHTzOB! 3ZZ%ɫAǦ_w?Fcet-m016wSSufz8z[ͅɊtnZPa;AFlu8`+귋>>mS3^D;fs n$j)Xcp]1nx<FiU/swy?5 \4c(P\t3L"𷢲%Çл58BB_=0ْ] 0y油$8C1O!j.Ĥt $y|Q9-մVx~`*(lJ@^%X+?Q6CGz*tlV\xe&f4aLoBBq=R-0.#ѴYŨ~?.3Hkš$OrRzW3SP8T%Qr`֊H(35T"W[BƗlE &~a+Y…i#uaO y("|L==C=2YEVoUp&FPKݑ8 ېH),BlackChromeT.pngUT {H{HUxdzSOvp BKNq@qwwB@ ťw((noλ̜w>fG5xTx๲&F_~1斑|0=eqZ u3w%O翎6Vb4Iᥠfkava^G!#acJbzQ i2ڐlԲrb`+,E9%?!p!-kmdeJY5[ xK_/p"BuXB6[#w#^_@Ύ>2H}uw!dzAUiR@Ģ#C{4䎨wdr=ƻC?%7ۼͥK֬#Z =z|dwy}"@lf{fNr*]vZX=vCyCa2Q ,2(7} "s'.j0;@pQIŸ<8߀|~Fݸ`oW^{:Ɩr9oוVt? rz.MV 'ʀʏfHځa05ceDUM 4шA}2 lmmȞjZ إR"Au^476x.[(c*1} ^ka9 V4K7OAyQ7SN;YT漋O\33@/[ڒKfMh$LDS}u# -什N K:oÄ*Q WϚaD=->^bϴAcuZ?,H m=37޾S Eb~J''qoi9b۪ƕޯᆨ.|/2 %)pћ'uq_\n̹*) \]_<&BFֻ„8h*`:,ec##{yhAGA'knyzU+/B=_if1޼.k= AM!aEpx}ըqY?rt8>W?qYIQ]zx툅mqz \\>zYQa|_d&.ᨇM$&W2(;;ܪo|KRHNYgabsۋo_>\zZ7 yI km4wTH6F` oQ4kʣziu_>(Ӥ@*|:挡Qx[0wKeǶeU5u!ߥEU  k);#4SB1kGr'ϞMX!cWCVVf];<w-8TƒԍԢb|$57[oQ~ K7pv:J'봳G]NjoTT κL|Lޔ\.1̟^|9M ^VоPKص~=ȆvrV>?2sSp-~K?dn,%$JgEz8%ʌj 3UtK>k.çрG_%BJcǵI[P.;ぽ,c=]HS(!Cf0jL+:JгjUi@]qȌWP )C< |[6?K O d`|W -ϤX,7s;p|_\%KI }v| "۸ɧdF/)l]E#I1oAϻ{T%a+&z2(G-.lW̵yO`)il/Gy9PO+.0BN4pcN_窠Xq-(rrh^`GG>'n,@_"GM̌ԥq҈4r_s',Vu;_3Hjj2Ə#R?HJ_+Ȓ5$fZqb1lM%hzk 9 ({!H.}u6o`aK ZY``Tqfgbuډs4//ӞaҰ~cN!;!DuԎv6TiߜX0 1o2f };eg5Ѱ['Jt%?B\B-ZO rGVjRF~) {U9ywLtTahAD3o5~8E,n徬BLNSA(ص&Omڟ\&omψo1\>[P8%1=#qG,a*ۮ Sƈ3㿓B3  $՞oYX:']W5n|F-ߘ5L 2"]̭R o:eTSk ɴԳou /I]$ZJ´1YckEެb,#q"fhFM4EE̋>Vc(Ն\ՍBҍs $ [@[zSB訪 K 1;gd,,*;eG TbWȐIA& V4RKR`ۻ>/\vF( zLA)ocp V=>Us55!)ąJv"TJ·Gd[=rqC&[vKE~<0ܽq}y5ཆVy#q>. ZY.YdzOT;T2*CJSpٙ{)C5&}'4͇+X'< `Z{E9r|V2 vܩu }w:y\(WC^l 1y)lv&Bj4ӾGNsg²Y\DŽCyw66>ɩCx6k+"\bYc#t0t9Yh^ DABl-Ī8FHK’0x5PBDΘ%^ׯ*Hdⶆi+kjiڦn* HD9 |7]Y (.]8Vr骱th6E ڴz%fT} Ztms&()Wk(g#ݝG(0 4tqWvj$ ZҤV6gvHW:/LVTH0wV97u"kHo$—7{sj'<ԛ4^m r!@vA~( @8IR%g 14EVͺ3zk[RʥYem|'3kћjG%Lh-p`d)fCJlgrٞMͮ_}S(-!<,3{8CVOiRm%0̈́-bjDW7i]#.4*fos;v=& '>6/)J+ath ?ge[=# ه P pîp1l>)MٍYjVP"he$Bmau.ZJJ gmL:υXVq!^[w2&2OȿzT OΗ'?gD< hv[ݕ;ً RG7M}qO+icO}i;,8G:a]!M^]~>v;}u+9*]Yfr]ozX-?[P+Ib~tsy+Y <}iV%u4q=d*#.K~])~KK~fznn1\#Aox_M RK3y7;$UpG Ug$Kf02,&\KUZֿR_GI}dwU~b.9gIf#փeLP\HXר Pcoѐ>0hې;ic9et*e! ;qė|j|yIiKqFhHIXPAO/^Ӑ \.}lSbaS=^xp\|j4'z|3~rS'4:T>噆1zs+7E"(c Z8ER-Uĥߤix "ݍ|CuXGa{8w}slH-);;Yi/co[5Y![3 öKA @e<q׾BOE}}J2X {#{29{ f-:Sk҉ 3~_BnKOl6=v,O BׂYUz[W,em]^6QM_-RvV;uA eYp\Ў$cj_3?)o@`.Yio.7XUׂ`^ZjxM`㕞 W"!)"3X7oʅ-7ˆ"XB I5A^r-N/e{tgn|mU:deC]U)97fRya2# 8ꪎR!Wn  \X[hQ=4tC!^kKS1ɷ.]=qՆ} ̿n&w!#XGAfh .e@ ڭ .7ϤZ9,"baoC5]GMZ g~.eJO|YYB ڍe<Mog*C?w,GCVBX%ӪZ>?\'lgxx3ɘ$~W{ǥ텻gwh&S3e+{."5$"qwp1{ި4gc]x)_V|Zz&yԓ ბ"!Sd&4Ѭlт#@fJӥ>7T^AI5g~d˶0LӘtd&œ}F6Ƹwm nt-y-J7l$LŕϳC0ပWU *WxNu vb> \(fȼ-$;em`Z +ws|^ףxȓm.*M# Ř>=r?aM@\AEl%H 눨4U e-\f5@j}ѩ|pIҼJVʻpy{c\YD8LXBy Śv'"~ϨQ]Zc=ɜ(TWfXnSZMCFsKkɥwPG-]`&1YȔ6GY7q=[Cߞ%%M9Hi<{=ۥw-TatYNެy @2>g~!V#=arv$dn`<A.&bW<ӫAyi2?ZF3zn g y D61-.$\< =H=E)/2לٶePC@,]fAJXM͢fҔ1a&g"6zMr6 ~o@wyԟ۰D5__mjqpFt)Ϛj7Md{-l#=ΝCB<˫. lŭU+QF*G`ckF̀LT 0/T~з>b^}kpu4mcc#nTQKp;~QxxFl;{oѿ;63 >Bկz]|ɑFw#d!]ccG(!Wθ8!0AM~aILhFvN:6N84N:4*uw*ZxyYĽBٍ&$i' ;5@eNLtNh"ŭXe>KsSo[ŮD A3~w(:x TΞ =僲B_r0cN5=~15NdQE"^~+>HN;J̬u:ژ8*IAHDHݮKVN}`,a*'3'Qo¸*Xmc>|f~!E0L2K6]y~j, tp;ǃ(_Pa!KaԖqc.rH'3ʥKV<[ DI|j o}(:~.6D4_l|[ewt :y)q s ܈wC:!E3;/x~וsl]Ps}%w\m  NB|CGj 7H#x E3ݎSqHm:?rl:*U/>@MhP{ b >KoMΐ9;OmyPJmACSO EDA8D㘯¼ ><>*253l.O)|10i%e\`2*hl RűxUT, Β?1C0:%&LԀ8q$=uh8N;|I.Ջ7oMAOߥ,%iF@:HK+p뱱X$4mcթ"{DtO}PZ M;*Jz`Oa尲"6|Q2Ϫ_>o"E)i?E%pbUD/P;0q ) ,zӝ+i/]`Q{ V [=8P[\> fMPe^aߵEJ]s`*)Nt Rm<YM~a7U߉G?據 s&BTZGIX 7P?+LShz9?9F M_:fVY Qҍ'O:)UDT+I0Z=cz /r Q+-K!+pK],Bmyg ϳ4jFVzT*rX׏ǎyЁkZC.Z IpP٫.Jc< 1@24&F)̢g}Ky=~Mqzvaa#cAeTOz _Ma G (O |~ڣ'w>mmcMu+P?wxTJA@ǦIe" 4a5]\X#FH608(}HDRXR;P 3pZY}q~uwbv =q ҧ!+,!MI16F޺.m5t4~l+2o+˻=#8imq~U_^Yc eÐg Jol̹~~w+6~~64Sr8 x)) o>rqXNh)2 (zk}(5?`  L h"B+@p¹{{{nw777vW12?L0(`QТ , .3P0#|ufp0",..z_N0k(s EP@fb0# J9<0Bs/_67Iֆ6t%j&P?lYLpҥ76x4 sm(1uT JWh!|, K@ɓ'8se-JmI&`UTf)PuC Dt>`6eWŋJ 2?Jt`$EDCj"j\DаP?ys^<P ,--%J0q\cN0Qnh"r;[99'9@baւ1 5,CZр,j){@A(_^>1`4S)h|Fp8G ȏ?1< -!M,5 )_<%:= {nx]l҂p6 r߾}vm`U,߿uwRك jՀh"&[n.S*Zt1M O ܹݻw[?xh y + |!# 7oK}{t"r@aFWH!͏7 >|^voF`!ch4c蚪P[HS[~^vi`"Jy b,+)a0``nnnfkk˵:33Q1 2cH3 WҬj6CȲ!~ݵvvkkSN}EQEiFӯ5+:>k-,CH`<2s>t:q"Ba~:c#2F# lCS]IENDB`PKݑ843 jGG3.pngUT {H{HUxd sb``p i $-?IR B xn.!s~\#qA}u=3B]Vy'w(t8:.=Z17J BE4vI7\v䰌{o3?j1k]7}2Zum X02lO)= { p޸ukUhH*Ѓ _z۷Wޖ)dNJ9<?P\lEoU5u={U"Ӿ{n GK9{EGK^N3ٳ={=ucĕUo|x3g1b%j~oعsΘrki){Ǐ<-~mƓOYX?8puĺ>/9-ꪪ< l o޼yrfdjPѤ.,.Qi #:խ1HRMs :Έ2}{|{߿M~uM ^Ύǎg%|' Zxg6H1_朗@W?޼z.q !Z/7{/ ^}`L@ ' %j\qR6iu7e`{^֕>>W{`nfVQYyZ쩑bO,DN֝2lؾ}:0n}]}^l;(I5K?\1{8AoꟜg.;k$ò 7^l?(=#}COAnnٳϤݹy-:3O=50 [۳}}}$l2>2=TmqQ3{v)ZSAi$x唰ԓ)q[ ̕==U0 ϑٿmٷ_ SRZL@r &LP{=s}>}0zgic j~ǣ@ַv-׫ ט3gV)(x8?kfaZ%a&yNI"&Xr.&\?&%/쪴A#JfIPƕ[3׍>Z\]DTAQqraW PS 6~/|YRv1nk/]J%)Xq2èAo]51y[SP e6Bgz!-Yz+fw݀k^bJʥ7-{p F1W@gVa 7 JZ^D9K~FW*h s\Vpg@)sv-87U},IΔhhM|ӑ@۞g LG&vךGWwoyđrY ]QNQPvN_׿ɮFЍobz uu)"─wѻ5/uב6Du-Q$?WXLLLW?NV56zxxdCaQ==}{h4k;ˆ =03J&"gOBz{'#V/A}Kˋãf:df+ccVyw8tE 7`Nu %WQ+܊ 8J+jxh nPА;SNN%ʤNQNH:ܼDz&tV+)BpÂ;?wLS3jbb+?az1as8!dDO6S&e⺫f <7!O\ж{>zc 3$g4cZhZ&Ȧ fitBsԵe淚 ]+A@F׌Sඒ,69+@|q-:Blm5$6$s ȍ 3fzwXFe ?MK n ,~m0pDF/ox'٢ |T(=-Z&"T%l6$SItAG&6w]̿ώJ:;k' | rz; d~KçufoU=6Jii rFO^Z1fg{P;;I@;'a&`|}[p#@S0Opwxii):ٳ܆7ZT T!@-:EL`~SC}-*88?Ւˡ&Sx1%VzA,(ۗ0W+7ߜ8rr!HW~] / .-} e:6S8|Y4~dcVd1C_!n**5ةb@KC1JAKX([PT)"288x t܋VQ+jh*qD:u=E6`lg%KA}3 "@Ju.bs- *ͯZw/H.ٞ;אHᢷ'=OX$(ꘃPYF iI?YՀ  R:Z '{bMK|||U$9̬309요LffnqNW;-CiER@ v& g e|Y˗Jt[lDZ/] dϻ8]]srV_7~ؑpMŨRXA EIc );uSabx_76x'kcu.pJ?neu?6VOuIV+\A IjcŸB[W-? &-WiۊnbĿ+.֛!帙UGYI-D \󇄗ّ}\pNGI,8RqCc#z?Q;3w=]g"ZB(-tdB:~՞ hsnx/HFmN+ƨ6eAe'nX7R{R:.tY 4=۹ %5HE8~cgt҄.:Ega+]w 18d&錋S]n Zg_e":/C(Lw^ =i+1II-3Dwv]dz+O8(w7WM"zp`M,\@tajPrwm V#քJ3UJS:{c ?Hf%WK __ΒϚd{M8jn?~adاrz2cD M:E яxT";pԅP;4{G^B)xч<8,/9&X)(!Y!`Hxr ;h[jh=XE˺AB BZ;9(AC}!L:{zƔѓ P\4s)DND /<`n#L[@1_a_`CbTdb6eQ-fu!oVC |Pem:86؃T|ئ)s:>R?2t,s9jŗEw&JƍV7^ @@\@K֐~(z,DyRY;Ty^Yyբh ?H4nL`r8/;'M;9G<(KP21~e}ʱG8%;T4Y~|fFٙ/v09$ +/o|&xv..xY'$$^#1;;;.KSRX֑URPa;ۥBhK}},IOVTܻRvppPΎ0ULJ )Qs .$֯R+bkJy@`nЦ%S4^|/v3K+l}}(DL"GU:0bvţ)Fx\0$h#-F-@0;SHpL8Dj/(lu Zai/8=Zr{R|%p7.tu?9ש(ze z**) >h?6M}~d9L'9VvIϨ5WTT?BNwHEA񶵕ۻfaM*zק˪TSl=#X&Ԫ_?QZգ+GڋSdNCɐl!I P}=>>+E;mKII'7tv3wƂT=+kk055b3Cg'7~"YL`Cr)v@ZH\-ä$s1 #VV;8PIxȣQ"ǔkvfȘ=#.cWr{A,;d; yyy0 %=UBM0?Ӝ?A۲'C]v"4|=t8+|ZqȾ~f^Ϸ(:Qb$6+"g.f;Gcqш"e˅K-+&$1-휐P'=Q"딈Ӣsf{V;}3mYΔxZOį9c.0q7@華gAҶ &j,l 7|:zehi00Zv111)9}{w^VOⅅfjt+^FO^'З5V{$w*v+_4J3]:?Q{?=5uO vc, ?J.:t &?S0re/'UW afS`vU%G\+j|2"\A(#_q/JH/\`'/lM_(MEf}}}ҊYj#T}V7q6gV]$xT?cv* ͓vx~7q)0e%@@5:&BvzB:M~3j4bJ'h(+zOCB(xm2%%%E0Z::,P*m/|Ol!ק9t祪fjFݍIRUok]!U (;;[~ $OlM!znYU+6xE<[L` e4ONw\xYίKOog&t\wFh~UEE.σBKJzx@Rʦ ,z+I"9֠3MR=hO_VĜŗ$%_7Z+?6B4 }]mg#0& >P j$fўz>+oV:OAڨΡҗsvjCRJ5PDڻa A;nege6y}AΌA3,Ny#TT"`^-4'8I}$%_d9?b(yN=Tr-V24o[O!ؗ/ o[ߤ88cZ ޗ}SZPQyqꙃ1=$ 1aNN聏 3$>"pKmqæn#.3V uI_R4ڄ_o~l6a״(X)=;,kP=w*6,ve#PbR~eqAG mX37BR~P&TRrG' I%_ʺ7gw`Kv["B~:Z.fLYʽ Jҏ{,m_Nbjjti\cxַ0g[h; 3A#=|}n4=ݩ$5v sU!WKm_?ziq!~r܋IpO5z=z 8%O@ Mesm&x QF>>y)h NZ+ٸ㱣%V}g(~~l&@*1kBb-.`{UNCA01tSb}G?%7ޡb1U*ޮ%n3 V'@Ћ&wԿa @}wԿay=KG"Vٿ_-ޢӔ7ma#M( jK|"OKoÞF\-k}Ɔ⧱KdSW>20N ^|)1^ǽ`KX?<뤙5AcDQրLHA&_6An 98]$ G 0ܕOj H'5^ ff/5 ,.\Ko5"]V͠ M!_lUMF}_lK场,AMR.Q/y;ѥwL,?x_k %vaC|Gܖ0My1#rp")Zf;}HGnZd!,l>N_ib9aYd1YE+#&J׉}Ibhw؉zDHԓZVh,G\TfAcGGץ%1h{w U^.,R( I9Dz=ubE*6Dn&]۵';0mY'']]as++oN$Y^pSv[ 7652,@ް:x.2e8]*M&EE訩k::䤽߂qT65<˕tHIK堍?~6~!#RDC[Sw#m #tBh{`UQ]) l=6u<CYb_G1}Yr(HlgK;d_q{?K&R4RQTst~KF,Gܓ\ڸtBZ\$36حy_:;WfeQF1eɬ^!)CD[[O}1YsQDT ϤC72h.}a[0@70SA8p4}q1@=njDg||ĻlCuׇ76඀FЖӟi[Osr^QY1 l+eh\:C/)gooF1F9s: kTw#ऐ]8o{=܀l)[埣aI;*Ӻ'LNYjh74ln]i7o}!b DG&wnFnLڶ;\oC4~4A{U[跉'>`iu-T Sȋm/.S >+]XJ>~c /5[7r˔" WvUX<9b]}h1]#.2~fv|YAyw([1Mţof= •8e>ʗ7wo_$%(;NU=S|v#&ޚ$/-)qjk:R €/ޢia}PH ~(ĥpIA{\T F[u/>ƒh9zOà^t<iE0:ڥYUL# /gǩU՛Ue[JP= h;8LiA{f\5D0o*7UvW^f%cC;hE>(zZ.PVmx e &ջ#8՛nWQ5p2;_}iy<^3^HBٹ% @ xj< OE/(x7 ^o=#6.:> R&fRƏ:+ + Bϲϰ(M\U@w=9ɓ1( x}Qʨ'l/ pCğYa.[UU-e0`f#;5I}‘wn^ƨDzNӞ@ EO;~T9bz֪& ^DF`NR' +]fȓU"Y msm=?SLC__E2A** u/S5.Yg̳K@Ip3gs_4:=F6V T第޻wT %N1HDZ!kPQX'5BYOACqΏ3WN - $q.4p-__VۏS111Ttӕm/ÇU2q='Ga" ta&o _ߧU#O1 (..~U0A@3 βljs!8a~iimDgEfnz p6nnbDPvi)F`LFgMH믖UεW*BZ~-FHUU,U)$s670#esnU ѷ.ёl3 bw9WyDM/=&bYkc=‡fJu|7NzC.+R/mLTqŒZAZUP@Pԇ@"a^[#\ʠیK+9vhE6 ~-<:YY[S71ai:ٳ]~5[8,#($B|ݻDy#oޜ{LA˴O+|\S!M^CU&<]̺XI(wyi6thf&_"D]شsm#???=T@DĪw Y{Y~~>:6QOdj75C*_<wXUvI^j`a[ZZ^$r P 9@/(,sm?b!9[;̽~L Y\Zr46iл&%9DEUY[iͳS}/#K1~1t,@F* t/ *XHd6̿}}]EK51-z4GZh;[QE*6!܏;l"Y-P$G±<{WՋY4w!B{|b.z_Q[SOܜ5syߊ:VB&;~ =f#ݢ>H3kNkB" EG4d;'b VWd9ggg(+sm7) 3Gh.6v'(hfxΒ1bXC4dءg*Fl:wS>?]%7bo, ZyYsq)%퓁t`ۻP@щ25}m- 3!r?9Pq)2(.K_v~mo۝xH* 8y!%-V^?~MC *+qqavl&Ls6ثcͽͩ״ ̑$،ﶒudѶ$auu_;:ҌCz~ ..% vvw{zJvCw~s46fDy<ǭt/R(!N]qCCD&|~#sҁR$tLfflPW pL9~j322T">(J3sVfeC񣩩y^:ηmmyہ WD).(X RA}Ѷ%|bno$&2Jj9JO՝4zp̛W QrҀAui @F!I ܯD<|DlD2+Wr]/ DY 䧤N ߨURR*36s=ci!ӧO 2agDi2 95C#е5:K_hYkQ$7o}ooe*,lVA>Z d+oTKJn99uu;B"$B/s-~|=C".3SmxVǜ{,3u?~ʕp57^Fá~i2&oD,22b66 ,EY@S ԲODOhtSUωe}3ҟ]cn 75q`25J3rrbR-Ugkja< |=vGW5#n̍?iA#om MMe]caa{3c@l{W9!--U??F]4g ku5F5͕ 'WT\C d,b3(١os.O|GFG \l0?G<עKΖ˘ 9B%?}Gg?3gBѧ''rga1F~l=yJ(pz5u9.bRЇaH{4?=~yFLwƾwob@M![JT A舩L!jth^% m d4Sg,V'~Y\).#B@s3,E y{uUR8-AmGTOIٳԻm]GEWW˷/U6qؠc8@_^D$+Jr00a6lZ;|'[\K>srk}kDt}e g֟$$%]ui)jhR_5mrLѮnKӓ^yF|M3h=7'o>{'Y KUVWW V 4Tww7h̜SSU 7SKJb˛R1(7222}\V'QmTu}2;skQ_c/kϬu8^Vf΁E$ܐ|X.T\\y@XڠiE(eh!2U6l366F"נ#_j+/.ٻjⓐTmzRI͛9wU4獌NO# * `w'_Px1)9&'')($ @Hgڇř:~'z C[|*y)XD[Dbw73x(,*zcE3Lu}T@QSaS hU+mҖ6߾AgKځ9geq;m4[[;oU+oOMԢljp]`?/KOw"/oQ= I2RR MMʅ'G@>jrX篭ҁx||vZA}ʌ~Ne3iꚛ;n[4 +u3b#K/2MI跗Pan/^êf;o:n(Kħ6 `9Oni0h?KT\^^^QZZ0uO8/F*~~466fغWm剕ޒW}|[d@V]Pmi3cx}S;G-SI}EC3$QP#+>cqkuA/٢fyuNp{]0|{6n?ev7^ N߾Zl MiLw:} uz*}E[ZBKѕkqҩ+?3&P(W܉/Zښھtd/kGuJNلdw #.w(Budl$H=J߮AJ>^; ߻04ºBpϟY-v8*fy^vG_+qCH^鋽/z>ÇLEz|ۃu뷻I©i05~q`0c3ښzAPK ݑ8"ś)GreyItemInset.pngUT {H{HUxdPNG  IHDRsBIT|d pHYs  ~tEXtSoftwareAdobe FireworksONtEXtCreation Time11/26/07uUYIDAThk+Uǿ3s_nڽ _EAJt֊ EݸBgQ7Pu&[Hm(5i3 sI}L2s29$fc Qu ! ȆXkq䛽/O 9Hqg`! CaS|cR/..^f̌4Hg pBb&ш`izCBHG/{mOnxi׽!O9cT*j|`WW>YIw-U9Z)~g D@mIz/@NQ~?hSZgjM~@֑ayyӄlkЯQkeIO Fq$ILz0ttvmWJeԤBbBOEMDR6gKKKE\.HRg^]{iVZfRf@)uc)S˳P[Պkm[kJV=\__:<<9IENDB`PK|88PAhorizontal_drag.pngUT GGUxd sb``p @$;8 <"bB xn`cHŜ6r:($~WG愨sb$_JϬ?N5Sq5v>֦53sZ2lWԔxv fw\f(i>0xsJhPK|88m˾horizontal_splitter.pngUT GGUxd sb``p 3 H6R@1!ftP01b+y8X?W1AwƍÑ ښRaou}Ye۟c⒠`5Y/N?fwN~py+rMgtsYPK>(5U^3 image_info.pyUT mNyNUxd]o0{~t"{RӔ2^T*dX$1rL+$wR7iȃs`4!“5L"hE$^֢]YO|[23f+}"(/@{m<"_})&<8q8cv1CA`7bY<<e;p_ 0/uyŷ|5\|W,9wKs:BQ>g=@됷6a( Ơj`Tkp8u4oTQ]u.< HqЖJ8] ,гmu.Xۗv/}A-NkӧTbϢR|:񋀰5y'+$anGtXq b8LU]0a 2R T-(bu季=x°6aa]>Oxfgp3 H o&G:[mo~t bx$8H`ށBFJƠR]O!OqC4uTNP)bzC ptń6{CR lTjB̸:eb P" ™ǐ9i'>6M OOhLa/?1^G" b(`\Nu};cKIKuiw&O6RkI%$tD7GzN\aYq5O卌)Ow:gxp) 8Djy5)]ܐ&"  [z)h,0pr528uL\zG7@!yʦpIPK> -'image_volume.pyUT tNNUxd]R@ +SXt/P2XXcfj&N6D3ҳ$ Qgx~uqv6q8nU*#xt~'X@Fo!8 }=W%0oB1]7h|`\\wWW F 9{1\_!9w2Z0dKT<[9rMWT('زnЪZUV𳵐> 1?a}OlB8< FF;Q5ek -&% WvĀu~?I+wfUbMAcvՙU^QpZt( a<Y|Nt:^PK ݑ8T~Iinset_grey.pngUT {H{HUxdPNG  IHDRľI pHYs  ~wIDATxKL[qJvegQJ݌4MΦ>R$H"T(JB"71mNlbm0 ZfffT9'{`cc2}yl6Z8\.FB\~fZZZB!]KK >x.)/hFqq1l6pzܸq`0((@("J$!N4%߿zJ:,qAΞ=fǃף BB읊5ňtvvH$H$tvv2662S`M8uV:^1Z{蠣CnzzzUU@>G4?btvUSho޼Iww7$IRTx=*^@cc#qjjjp\|-b1` BUJH 111}>}CaX\?3 ֭[d2޾} 8|0%%%TWWrr8x<. zzzH&;88l U_WBn8u!U0L1&''yJ[=ޢ"f3NsD"?ńӳ묛3oM cǨGKK 9H+>Y7M@bPUUjIb%uGGGY޽{w}aHٌ墩i!Wӹ8SSSܽ{Op鶴?,,,p B-Kf,ؾ5}|fggY[[SxojtDQ}l<:pƛ1Tܾ}\.<>4.2[.\'oHEG~ۖb:}q(nBЖ-"u6N !>!FFF̸zϞ=0)?Abtuum88<<,(P&!2>>w}}>4.aNlnnG$Km&B(duqj~~c-ZΪGr9}oVB@EcVWW;tGRz<`lll˦$SSSBLOO癙annϟ{9uFC_eccXZZbqqQGKKK,//fQϏ 2d#wI}.l3Boo2j`K IENDB`PKݑ83|{JJ07.pngUT {H{HUxd sb``p I $W/eR B xnOǐ9o/ 2(P~(*Ľ^@ROҡxxas}p`tsYPKݑ8KIJ08.pngUT {H{HUxd sb``p ) $ M R B xnoOǐ9o/*600ފ a9Yަ6-އ7n2SRNA!e7 CZCVQG]F``tsYPKݑ8fEoTJ0A.pngUT {H{HUxd sb``p ) $ M R B xnF6Oǐ9o/60=~c*K`?//n~[7ܶE x\v~1=Z"A0<]\9%4PK X8ԲOOLB.pngUT (~H(~HUxdPNG  IHDR pHYs  ~IDATx!@ H0p1 ]q$($B _bZ@mA?Ym?9At.DF7P3d-Yw g'Zk)616 $ѡAH#POGaQ@ B" AH}2p\ b"7SPATԴXq$}h1#A:CYځ"_] g|j92r.&IENDB`PK X85 OOLG.pngUT ~H~HUxdPNG  IHDR pHYs  ~IDATx!@ H0p?Ի IP0 $}MѝN*v[j–;|ØS8DGLa>8 k AdĘZ 0cRur2prBachS( B" AH[4p,! $ѵPAH# +GE &ɱ{>DE8h(LH" o'c8P|3% U}wC[x8IENDB`PKݑ8}< license.txtUT {H{HUxdE=n0 wZ.IA-&&*KHK$ǧ-ri ~]oMpᧆ ApG.b9ҹs43ta+Ծ-O b/h=:v$zbE %2-FA0 ᔃ6܂TZKw5:ۡ-1q1E|p ""ZȈ1""b#1l\k-E &Ѧ8D8:7G"iYD< B"=AHk7p/"V!V“ALS&}*1pЈ+.D4"OD "#p1?Hg(K;W%W߉XmuشűIENDB`PK 9Qר""notebook_close.pngUT &H&HUxdPNG  IHDR֕ pHYsodIDATxNQY.],]|,\`03Ms`, Qjimtcv,LM0q\_uo=gù///\G|jKP8 iB-gL>pL @7؞0 U!8)\;G%"5VvtlqlRt'-HٕUr]`#b]G88,)W,+o5_a N@oq9k.$tGĤjLve"Llf)HӍ*;U%nVO7Jyp grf̶c"G^JeQ*VF*pL)$X8.X G*/Hޚd̶c"rl)`zS$'c cH{C ȰW;_RՖ*SyF2@ڶ+ry?ț"L7XS?'N /9t<^]57~_  Ѡ䛷$}@ Yƒ)w) ǡzsz88Kƒ)TISu7 c SӟqTs#,??b]tEXtAuthorUlead Systems, Inc.>vIENDB`PK֕9T"notebook_open.pngUT 䕴H䕴HUxd sb``p s@ Hv8 8 <"0) z.!sI8^/gEg>KS2rMm{xy-˛,I ~Kgfh|~-)-X"5cFПoo7oϱ5o2P͚vph0gПv@Ӎ_xy^kKj7:y9;+*vEBijBQ>7vHs_L:?y:!?k28@w̓(f o}hݡvkj7%?MN#ݷMv$| 6~nMDN>kuӛ TRҗ Սo>Ldq2m3"NxʘVL>vFю?Ϸ%X;׳p8xHx|Bo۟ؕ{{Z[_p꧌SYSl~*S\}gE|Uzy+n=hHw-d!(/]YcQa2W&-,fi*vgҿ}?ꖽ&3V~UwbB|*-m L_eF=ח̦>XS{0{͕'%s?{[mi-"gY?o[~ș۟ڦ5U^l ־xq#Jkv{/}VE,'S_zI9B1uM̳o|^=3놄}k ֘m 2Sn 7y_jk ߭xC?S׈Ғ"Мbϼdve@U ~.PK|88qgLtab_active.pngUT GGUxd sb``p  @,$R B xn`cHŜ y829qAK9\nž5.jҳ03|ggX^%$7j>|ޝIg0)3T05K?;밡wQ/% ~.PK|885_tab_background.pngUT GGUxd sb``p m@,$R B xn`cHŜ 68z?Å&~Tv׿  1?ja?!,'nW0t ;ןy/FܥJ[].) PK|88`Pw tab_hover.pngUT GGUxd sb``p  @,$R B xn`cHŜ668?zqAPE_c ,wk$S~ c3\u֜ozmq`΁f\7; g^:p<[  G>2t;0ܮ*`rb(5U^3 image_info.pyUTmNUxPK> -' 0image_volume.pyUTtNUxPK ݑ8T~I %inset_grey.pngUT{HUxPKݑ83|{J +J07.pngUT{HUxPKݑ8KI J08.pngUT{HUxPKݑ8fEoT J0A.pngUT{HUxPK X8ԲOO _LB.pngUT(~HUxPK X85 OO LG.pngUT~HUxPKݑ8}< olicense.txtUT{HUxPK )X8ldRR LT.pngUTN~HUxPK 9Qר"" tnotebook_close.pngUT&HUxPK֕9T" notebook_open.pngUT䕴HUxPK|88qgL tab_active.pngUTGUxPK|885_ tab_background.pngUTGUxPK|88`Pw qtab_hover.pngUTGUxPK|88<) `tab_inactive.pngUTGUxPK|88} Rtab.pngUTGUxPK|88q@ Svertical_drag.pngUTGUxPK|88$\ $vertical_splitter.pngUTGUxPKݑ8{y XG0.pngUT{HUxPKݑ8=|y XG1.pngUT{HUxPK$$ ftraitsui-4.1.0/traitsui/image/library/icons.zip0000644000175100001440000005121311674463546022614 0ustar ischnellusers00000000000000PK|88w array_node.pngUT GGUxdkLOy4!Iі&ndKi X_ CFfPʠev:&`$B01K aNWPl?νwsk)H1pM*ShM0[>DڴllGb-ARI5$fH j6@fzH2+;ğĶ q#Ɖb A^ N_2@E(Z!_؁Om$.T[MCɓBthȽY4C\I'Vx7#2Ru<9z{Oʂ!'\VK`:ڗk5 Uauw,(S-\Jv>CJ(~/K|^+Ҳ;DHۭ ^i׳/DuA{;^l8!^)v'Ch۶8Oa,4ˡ}DQT)RpH'cx!9l6onq5 Mk~oV7{c A~ cPRHTO*Q k'|~8(qiFBۄI]nFd9)MʉnyL,X S7IQCܙ0lA 0c8qpM\3wiZB:G,7tDhNG0]tGYE\D|Lkz w{ tͺ$ܾZl`@^P"AFSI [zULw}L*yBR~Z8S2vvvwcEcKbu>eFab|%aY.X,6}ړSs_|1}FPoo7.F#ff975n=ӝ}[̙Rr=|7kJuPK @~e8z\;b8JeoOI3iaPwBW< AiqnqqJ<-ͺw|s:boG)`[QDXu5d RP4T{C((?OYJmt *+ۤAg/18#Ѐс/'.p*~8|z2ʬYhaԹs]J6ߕBt¡ PԔmm-[~?B\.WbBLIUTD&'K7 B5kx[UpwLyqՑ Nm᫤ٳsܦ)څLJJ8r8((躞ĵw/OR&M]C8 TSav G/,L8IdӉ|o^sSi#+'GSwg [`k)={xb4\$`4nɏw0 M@ k耝}@L i( p M/IENDB`PK|887* ! dict_node.pngUT GGUxd[Lƿ\${)-T0["s[ڔ[l @X,"Z(-e-r)V%hԸeb,J| YKl_OrsvN@a<mXl*n؅;.D-"ƱwD> uBY7d=wBy7RF聢2.웃|~A 'R{2a: 4 'BP@9 EiCHp JR6a(]AF9G*jPS Z2䑱ȔO&=5ZNe=t~"lҐ Yj/j[ R.SW=Y̷}[JZL*~E& <ͶR2rѐu4rodyv4)Ս1 z|j&TjTE'到͐S)I=h^c$1{nm?K/+˃[ߚ[~Tԁ e߄Nz9!Ҝ8k򻗖G]Ӂ,=}ۚ'1:odbr\[?*G PڳǏ5g%JGv"JNV&;̾=n s%V*/':G[s9zֲF|>@tL߿_*֏[7WnV]ZPK|88$float_node.pngUT GGUxd]H\"t߾?DRYAj$]SYeRQJX^!c:u9[kTBT">r[e4*jԧҥuI L)AeCUAt j+16#\FSP`F6b)͈Eň]"h%2dS[ŕiJ?c `H ^z j<8u1/q|MWԽa[45Lo=K ;Z&h6I>Z>M+H ŠNβPK @~e8jP{{folder-new.pngUT GGUxdPNG  IHDRabKGDC pHYs B(xtIME UO-IDAT8˥=hSaޖ{SI۴$ V\JEAM]AP['qpE.@%-A-Bh!?!!AŇ܍L&s5hkU_z>MP\g/[}C(˧=}$?  il ci1 l22v\ޛБl*gH֡(UmSk繼Pa3. rf_>cvMl/~p0Urs0~d4Ydi1S(e`6H<%A4jF')εbm;M  T -v[7H0t]|TtZ|}OT#[mm:%b@VXF"R AbH 0"duE\6%,V4_=EP ԅ0Z`={QmAP pkk/Ggs]H"/\7ᚩIENDB`PK |88~Ƿfunction_node.pngUT GGUxdPNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDATxb?% XJK; f100+rrR8e55i+;x~GbIŮ55dcc>~|]RA##T%a* rrꊞ*< L >ccc)w X~Ġ1p -FF`^GG6>>N70^ׯ&߿4$$$W mãG}:ADAZZAHt!!aǏoܸ| @A @3,[wihY\#'' 6`ݺ_ϟg & ر**2.]:=a߾ˁ1.!!Y ӇoY޽{k/_]AFFMCC_'$$AO߿c^F ,-YLÇ>b>u7o^~5+_JIIs XZZ)(H1/2,Z(@xx?VPPa`aaPY hjwA\\AJJ(W _5W qq `%++.Gϟ89ف)ܹ8q`ӧ˯_?,X0@\moQAQQ 8gP`FP͛gW^jy X@ĭ[WWp缼ڥrr߿bsP>0a2<{f2@0 ܹss %(qrr1̜9=z/F=ã  ,-mqssCX=;&cg+IENDB`PKk>/U(( image_info.pyUT NNUxdj0Bt!-.XRz'((֮1L6oH,= !_r0*<*xmBۙ;S_e}Pɳ+0)v&:Fi_V?UWT2v֪znt Zi>uj=g^)QеlmM J+=Iw)VٙU*0evCeu>~՗ !;R-y,ښS-PΆX?.lmn궍!BNuco, nhN{g\yf14hN+& ˅Z),X2+$$h:EPY!a'\6LgBY 7q/")ִTT@Aj$tXPQ:$ ^B%TcMpxӭvAE]3k B_v+cEȰpLǑ(tXPQƾY!}BR\66@xDh ?ڰn-7ni!<Kimage_volume.pyUT NNUxdQ1 +zSAdy":ٰӦue޶a˾BI#I [(;BӭzO9p]&'ױ TE2gs|ԫt(0E҆IN,  `#YCsh}9 ՏRC"U9%d.YiBh#lw(iTfr;bo l03*/us`^DWQOPK|88ސ~$ int_node.pngUT GGUxd]HߙK] EWx7Bm'7[Ӗ̥æo7&"Mu[$ml̍6sS6Hn 眗\ޱZP R6p7<}>[C_֪O$h$$Ib/IB2{In%=%+ɸc'AL1NR |;t#.R R!ᴓ3caaTn5\ C>Cu0Ah` Ag]`3~ Cw-1c0mq#0ѻs Dx mvFvx-L%1³R.H.,VChAiV+i/JVOF$q`硰vFw8Ox6whC^VYu2G|6koo৷ލ?^"][ 7y>.V7΍MN>(:-?1\/bDvM?󪤸4"U9˚5-WOG | hRn 7XUee?PK9MNZh license.txtUT )H)HUxdsI-N.,(ϳR|TBqAjrfZfjs~AeQfzF \C2LD!3/-(7COfrj^q*\GScAPIbRNgnbzj1HcNPK|88kF  list_node.pngUT GGUxdQmP =v&#izhK5LԎUbvK[>2 Wi U[T.]\è̘as~<_gN^+],્D^8ys+X`$}\|'"_²JX ; y dP(B(PA^ U1TPTAYePVBU@UR؎Byrh"UP@Վ?| B#@pB.Am Fm&,Gh:4Hs6Ql"]z)%.%MݤG{NY7(~J ;E9ZovʰӶa.NClrQ6 q Sl4'ܜ 'A|t?|I >_'I%g铜aʜ_p2gOqW\>'ɷ4Fo5 4W\=͖nxϝ3{>1Xl_]u%G :#Ί-1xNJp@asI}D5/|)/9'ZNfC|2eܯ'rsˬcf~MF$xj=l٬HlkioUӲҞx-{ڮ21 j@a n]z=}˗s!?sOeU>qxpc_NX8X0ɭ'CGC6fmD̵:Νbѡݎ_?n]:;ur*ܱVU Ŷm$IBvrzӶ=},c>c4o)xux79:.V'Z'}-WP; zu BwV?>B7@FUr,qsD* V֠GhNeD*ÏV:§$Mt>@`22=bT2n VKE64Ӵ{qH| ^3^};_Ϧi,z.KLAtdYffd ,!/n Sg>ə>=ʌM_ö-&~ ;1)$7`[]= ]+ Ĉj;FHf?yʲQĘ.^n@7B"_LszIENDB`PK|88- none_node.pngUT GGUxd sb``p  $5tW ] S ] [ W W W _ _ ̠P $JJ*Z" - j@Ƥǫy3gΜ={ܹsϟpŋ/]t+W\zڵkׯ_q͛7oݺu;wܽ{޽{G?~ɓO>˗_flap~ƒ `g7@$owVY #536uFK<}]ٯ1hL~~ P1Vr .OΏ?}*:ʒ[ukLYIeʺ(-l+*aΉ}&Mĥ`ѪeD'l1v5Kim\ьW/]q;b7Y!1Sg & GE:&PK (kA8object_node.pngUT rGrGUxdPNG  IHDRasBIT|d pHYs|4ktEXtSoftwarewww.inkscape.org<IDAT8;hQ{cg_l6*H0-T0tvTHlXhl,RР 1+dpvgv#Eb8wseYRz"HZ䍻FH$`{1q7m|X-a/ԭ235(L8`@l0'c({xy`uYeeGv$NI~3t1\sQ@)ku =Nem @?EoD a20CFzuP=lh:e0b @Nd#͌2, |vnb?hOܫ= ^f Mk~oV7{c A~ cPRHV[@m83,-3_DI8!1-7Fst5Z]Լ+z:l=3j1rQoRLck$$UTT!u*ݤRCbEL/1bHKAbIl.buGLA:.5^҆ZR8*83 <\`-<& FVlF&"#ڌGv#~ ь=HHād&ۑųy7z1sfE,an a,E \x3q,XI =IN!GzE|X<2+F*q*#볚mTّZ"ł$Y*7qE_eeGUR$+wvvwY]A~ XټO>sǺzE6~璒ڙRs/Vϐ,j+{H\{F䑌>ϳ_ ~߷oOeʩ>udlVnq3/PK 9ff red_ball.pngUT yHyHUxdPNG  IHDRa pHYs  ~IDATx=K$Zrt!}%!!j!B DP!JBB"(͗Aaj? L6a|0º"(:L`T(j:mފ0X6bQK%M4Eއ^ɤrh7`<{4`  ~0vX&gmh,\;8<7]7`j𗐖(䁢IENDB`PK (kA8 root_node.pngUT rGrGUxdPNG  IHDRasBIT|d pHYs|4ktEXtSoftwarewww.inkscape.org<IDAT8;hQ{cg_l6*H0-T0tvTHlXhl,RР 1+dpvgv#Eb8wseYRz"HZ䍻FH$`{1q7m|X-a/ԭ235(L8`@l0'c({xy`uYeeGv$NI~3t1\sQ@)ku =Nem @?EoD a20CFzuP=lh:e0b @Nd#͌2, |vnb?hOܫ= ^f Mk~oV7{c A~ cPRHMf] h kIENDB`PK|88{s$'string_node.pngUT GGUxd_LR&$nr?˭Q LD/a]e9 BZRsmrMy9cVe;w=*FID*ΤrH}'i-׬ I#=j!MCQSiČ'ftc~J=Al ĆH7KLػtR2aũU\F+8+:m財ێ}! .7=ncpQSxLbd ixB"20|S 9Y"'N@|h ,y#ã5=:@.x(Z,ofڿ,PQOrI1}HY_UPEmH*;}=ZTr5!:{kY_-luƫ 73 v}pUȿvj2iepRZP.+ow:ܧ+WiwsUG?PK e9{kktop_left_origin.pngUT 5H5HUxdPNG  IHDR<" pHYs  ~IDATx1kPCG2CԣxEf^=h0YT АE z};%-b7x  'aGJ)-?NNRJNy*yB)81NKj'I46VQVjz3fx<&",+^(n'^pm;c, ˲aX(Ppė[t:<|b|>_gZoYEu"|:?\__.Qm=\I@aH/1 jul&WR4Mɲ?[*4MDc&ٌ{F#D0, &`۶#/a^_2b8^v<}fi777K.mۈx8V+$y#Ѩ(<<',{{66! JP4t:H)YרE }wwoV )^v#jvPVk'm9y7 MӰ, ˲muqu|_Ajj>y1aya1IAj/xGDUUiJdYFUUuye53N8~)˒j[%J)aH)躎8EQрx΂M\MՅOK?R}+CcƧʤN76]nC'm>j4|hd(&cՁ z`Y5ofeuda  'kʞSIENDB`PK|88tuple_node.pngUT GGUxdQ]L#!۲ƨ Жu[ZNZ",B,Zhiv|:hgJ-QY> C>l=l>|Xbb|orwO M^\y:ʘV>+ÊBI!A cA@I!H}!l2d~L@> ydalIC|E( @Bi%s(ZDy/8$!( MA2$(eP\ri͠|&*QD]TjR'>SM `$DF#>LMrQj=>xM.9C\oz> 0Hn>fff]lS'd Mv$w》)yG<|z/t|~!rd'y"r2s_% k*z̼+5Ϗ l6c\{kLӫӫsVDĒ_neG:&rGeɵoܧ5}պ. ՘PhߝX4;FK>lwJb~qAZ^~N,LN]QtI0K߾t#kgQe{يxuZY*ճ<_ 2q~앁;˳M鈹"oث~ =]KJ~DuY>kMwA{K]Щ o?iPK|88w  array_node.pngUTGUxPK|88.J2B Lbool_node.pngUTGUxPK !f9 gg bottom_left_origin.pngUT5HUxPK f9m^^ nbottom_right_origin.pngUTP5HUxPK (kA8  class_node.pngUTrGUxPK|881! complex_node.pngUTGUxPK @~e8z/U(( !image_info.pyUTNUxPKu>K #image_volume.pyUTNUxPK|88ސ~$ %int_node.pngUTGUxPK9MNZh ]'license.txtUT)HUxPK|88kF  (list_node.pngUTGUxPK |88) ^a O+method_node.pngUTGUxPK|88- E/none_node.pngUTGUxPK (kA8 G1object_node.pngUTrGUxPK|88(Q' 4other_node.pngUTGUxPK 9ff c6red_ball.pngUTyHUxPK (kA8 8root_node.pngUTrGUxPK |88!$H :set_node.pngUTGUxPK|88{s$' <string_node.pngUTGUxPK e9{kk *?top_left_origin.pngUT5HUxPK e9kCSS Atop_right_origin.pngUT4HUxPK |88x^^ uDtraits_node.pngUTGUxPK|88 Gtuple_node.pngUTGUxPK^Jtraitsui-4.1.0/traitsui/image/library/image_LICENSE.txt0000644000175100001440000000112411674463546023736 0ustar ischnellusers00000000000000The icons are mostly derived work from other icons. As such they are licensed accordingly to the original license: Project License File ---------------------------------------------------------------------------- Enthought BSD 3-Clause LICENSE.txt Unless stated in this file, icons are the work of Enthought, and are released under a 3 clause BSD license. Files and orginal authors: ---------------------------------------------------------------------------- traitsui/image/library: std.zip | Enthought traitsui-4.1.0/traitsui/image/__init__.py0000644000175100001440000000010111674463546021410 0ustar ischnellusers00000000000000# Copyright (c) 2007 by Enthought, Inc. # All rights reserved. traitsui-4.1.0/traitsui/image/image.py0000644000175100001440000014007311674463546020750 0ustar ischnellusers00000000000000# Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 11/03/2007 """ Defines the ImageLibrary object used to manage Traits UI image libraries. """ import sys from os import (environ, listdir, remove, stat, makedirs, rename, access, R_OK, W_OK, X_OK) from os.path import (join, isdir, isfile, splitext, abspath, dirname, basename, exists) from stat import ST_MTIME from platform import system from zipfile import is_zipfile, ZipFile, ZIP_DEFLATED from time import time, sleep, localtime, strftime from thread import allocate_lock from threading import Thread from traits.api import (HasPrivateTraits, Property, Str, Int, List, Dict, File, Instance, Bool, Undefined, TraitError, Float, Any, cached_property) from traits.trait_base import get_resource_path, traits_home from traitsui.ui_traits import HasMargin, HasBorder, Alignment from traitsui.theme import Theme from traitsui.toolkit import toolkit from pyface.api import ImageResource from pyface.resource_manager import resource_manager from pyface.resource.resource_reference import (ImageReference, ResourceReference) #--------------------------------------------------------------------------- # Constants: #--------------------------------------------------------------------------- # Standard image file extensions: ImageFileExts = ( '.png', '.gif', '.jpg', 'jpeg' ) # The image_cache root directory: image_cache_path = join( traits_home(), 'image_cache' ) # Names of files that should not be copied when ceating a new library copy: dont_copy_list = ( 'image_volume.py', 'image_info.py', 'license.txt' ) #-- Code Generation Templates ---------------------------------------------- # Template for creating an ImageVolumeInfo object: ImageVolumeInfoCodeTemplate = \ """ ImageVolumeInfo( description = %(description)s, copyright = %(copyright)s, license = %(license)s, image_names = %(image_names)s )""" # Template for creating an ImageVolumeInfo license text: ImageVolumeInfoTextTemplate = \ """Description: %s Copyright: %s License: %s Applicable Images: %s""" # Template for creating an ImageVolume object: ImageVolumeTemplate = \ """from traitsui.image.image import ImageVolume, ImageVolumeInfo volume = ImageVolume( category = %(category)s, keywords = %(keywords)s, aliases = %(aliases)s, time_stamp = %(time_stamp)s, info = [ %(info)s ] )""" # Template for creating an ImageVolume 'images' list: ImageVolumeImagesTemplate = \ """from traitsui.image.image import ImageInfo from traitsui.ui_traits import Margin, Border images = [ %s ]""" # Template for creating an ImageInfo object: ImageInfoTemplate = \ """ ImageInfo( name = %(name)s, image_name = %(image_name)s, description = %(description)s, category = %(category)s, keywords = %(keywords)s, width = %(width)d, height = %(height)d, border = Border( %(bleft)d, %(bright)d, %(btop)d, %(bbottom)d ), content = Margin( %(cleft)d, %(cright)d, %(ctop)d, %(cbottom)d ), label = Margin( %(lleft)d, %(lright)d, %(ltop)d, %(lbottom)d ), alignment = %(alignment)s )""" #------------------------------------------------------------------------------- # Returns the contents of the specified file: #------------------------------------------------------------------------------- def read_file ( file_name ): """ Returns the contents of the specified *file_name*. """ fh = file( file_name, 'rb' ) try: return fh.read() finally: fh.close() #------------------------------------------------------------------------------- # Writes the specified data to the specified file: #------------------------------------------------------------------------------- def write_file ( file_name, data ): """ Writes the specified data to the specified file. """ fh = file( file_name, 'wb' ) try: fh.write( data ) finally: fh.close() #------------------------------------------------------------------------------- # Returns the value of a Python symbol loaded from a specified source code # string: #------------------------------------------------------------------------------- def get_python_value ( source, name ): """ Returns the value of a Python symbol loaded from a specified source code string. """ temp = {} source = source.replace('traitsui', 'traitsui') exec source.replace( '\r', '' ) in globals(), temp return temp[ name ] #------------------------------------------------------------------------------- # Returns a specified time as a text string: #------------------------------------------------------------------------------- def time_stamp_for ( time ): """ Returns a specified time as a text string. """ return strftime( '%Y%m%d%H%M%S', localtime( time ) ) #------------------------------------------------------------------------------- # Adds all traits from a specified object to a dictionary with a specified name # prefix: #------------------------------------------------------------------------------- def add_object_prefix ( dict, object, prefix ): """ Adds all traits from a specified object to a dictionary with a specified name prefix. """ for name, value in object.get().iteritems(): dict[ prefix + name ] = value #------------------------------------------------------------------------------- # Splits a specified **image_name** into its constituent volume and file names # and returns a tuple of the form: ( volume_name, file_name ). #------------------------------------------------------------------------------- def split_image_name ( image_name ): """ Splits a specified **image_name** into its constituent volume and file names and returns a tuple of the form: ( volume_name, file_name ). """ col = image_name.find( ':' ) volume_name = image_name[ 1: col ] file_name = image_name[ col + 1: ] if file_name.find( '.' ) < 0: file_name += '.png' return ( volume_name, file_name ) #------------------------------------------------------------------------------- # Joins a specified **volume_name** and **file_name** into an image name, and # return the resulting image name: #------------------------------------------------------------------------------- def join_image_name ( volume_name, file_name ): """ Joins a specified **volume_name** and **file_name** into an image name, and return the resulting image name. """ root, ext = splitext( file_name ) if (ext == '.png') and (root.find( '.' ) < 0): file_name = root return '@%s:%s' % ( volume_name, file_name ) #------------------------------------------------------------------------------- # 'FastZipFile' class: #------------------------------------------------------------------------------- class FastZipFile ( HasPrivateTraits ): """ Provides fast access to zip files by keeping the underlying zip file open across multiple uses. """ # The path to the zip file: path = File # The open zip file object (if None, the file is closed): zf = Property # The time stamp of when the zip file was most recently accessed: time_stamp = Float # The lock used to manage access to the 'zf' trait between the two threads: access = Any #-- Public Methods --------------------------------------------------------- def namelist ( self ): """ Returns the names of all files in the top-level zip file directory. """ self.access.acquire() try: return self.zf.namelist() finally: self.access.release() def read ( self, file_name ): """ Returns the contents of the specified **file_name** from the zip file. """ self.access.acquire() try: return self.zf.read( file_name ) finally: self.access.release() def close ( self ): """ Temporarily closes the zip file (usually while the zip file is being replaced by a different version). """ self.access.acquire() try: if self._zf is not None: self._zf.close() self._zf = None finally: self.access.release() #-- Default Value Implementations ------------------------------------------ def _access_default ( self ): return allocate_lock() #-- Property Implementations ----------------------------------------------- def _get_zf ( self ): # Restart the time-out: self.time_stamp = time() if self._zf is None: self._zf = ZipFile( self.path, 'r' ) if self._running is None: Thread( target = self._process ).start() self._running = True return self._zf #-- Private Methods -------------------------------------------------------- def _process ( self ): """ Waits until the zip file has not been accessed for a while, then closes the file and exits. """ while True: sleep( 1 ) self.access.acquire() if time() > (self.time_stamp + 2.0): if self._zf is not None: self._zf.close() self._zf = None self._running = None self.access.release() break self.access.release() #------------------------------------------------------------------------------- # 'ImageInfo' class: #------------------------------------------------------------------------------- class ImageInfo ( HasPrivateTraits ): """ Defines a class that contains information about a specific Traits UI image. """ # The volume this image belongs to: volume = Instance( 'ImageVolume' ) # The user friendly name of the image: name = Str # The full image name (e.g. '@standard:floppy'): image_name = Str # A description of the image: description = Str # The category that the image belongs to: category = Str( 'General' ) # A list of keywords used to describe/categorize the image: keywords = List( Str ) # The image width (in pixels): width = Int # The image height (in pixels): height = Int # The theme for this image: theme = Instance( Theme ) # The border inset: border = HasBorder # The margin to use around the content: content = HasMargin # The margin to use around the label: label = HasMargin # The alignment to use for the label: alignment = Alignment # The copyright that applies to this image: copyright = Property # The license that applies to this image: license = Property # A read-only string containing the Python code needed to construct this # ImageInfo object: image_info_code = Property #-- Default Value Implementations ------------------------------------------ def _name_default ( self ): return split_image_name( self.image_name )[1] def _width_default ( self ): if self.volume is None: return 0 image = self.volume.image_resource( self.image_name ) if image is None: self.height = 0 return 0 width, self.height = toolkit().image_size( image.create_image() ) return width def _height_default ( self ): if self.volume is None: return 0 image = self.volume.image_resource( self.image_name ) if image is None: self.width = 0 return 0 self.width, height = toolkit().image_size( image.create_image() ) return height def _theme_default ( self ): image = None if self.volume is not None: image = self.volume.image_resource( self.image_name ) return Theme( image, border = self.border, content = self.content, label = self.label, alignment = self.alignment ) #-- Property Implementations ----------------------------------------------- def _get_image_info_code ( self ): data = dict( [ ( name, repr( value ) ) for name, value in self.get( 'name', 'image_name', 'description', 'category', 'keywords' ).iteritems() ] ) data.update( self.get( 'width', 'height' ) ) theme = self.theme data[ 'alignment' ] = repr( theme.alignment ) add_object_prefix( data, theme.border, 'b' ) add_object_prefix( data, theme.content, 'c' ) add_object_prefix( data, theme.label, 'l' ) return (ImageInfoTemplate % data) def _get_copyright ( self ): return self._volume_info( 'copyright' ) def _get_license ( self ): return self._volume_info( 'license' ) #-- Private Methods -------------------------------------------------------- def _volume_info ( self, name ): """ Returns the VolumeInfo object that applies to this image. """ info = self.volume.volume_info( self.image_name ) if info is not None: return getattr( info, name, 'Unknown' ) return 'Unknown' #------------------------------------------------------------------------------- # 'ImageVolumeInfo' class: #------------------------------------------------------------------------------- class ImageVolumeInfo ( HasPrivateTraits ): # A general description of the images: description = Str( 'No volume description specified.' ) # The copyright that applies to the images: copyright = Str( 'No copyright information specified.' ) # The license that applies to the images: license = Str( 'No license information specified.' ) # The list of image names within the volume the information applies to. # Note that an empty list means that the information applies to all images # in the volume: image_names = List( Str ) # A read-only string containing the Python code needed to construct this # ImageVolumeInfo object: image_volume_info_code = Property # A read-only string containing the text describing the volume info: image_volume_info_text = Property #-- Property Implementations ----------------------------------------------- @cached_property def _get_image_volume_info_code ( self ): data = dict( [ ( name, repr( value ) ) for name, value in self.get( 'description', 'copyright', 'license', 'image_names' ).iteritems() ] ) return (ImageVolumeInfoCodeTemplate % data) @cached_property def _get_image_volume_info_text ( self ): description = self.description.replace( '\n', '\n ' ) license = self.license.replace( '\n', '\n ' ).strip() image_names = self.image_names image_names.sort() if len( image_names ) == 0: image_names = [ 'All' ] images = '\n'.join( [ ' - ' + image_name for image_name in image_names ] ) return (ImageVolumeInfoTextTemplate % ( description, self.copyright, license, images )) #-- Public Methods --------------------------------------------------------- def clone ( self ): """ Returns a copy of the ImageVolumeInfo object. """ return self.__class__( **self.get( 'description', 'copyright', 'license' ) ) #------------------------------------------------------------------------------- # 'ImageVolume' class: #------------------------------------------------------------------------------- class ImageVolume ( HasPrivateTraits ): # The canonical name of this volume: name = Str # The list of volume descriptors that apply to this volume: info = List( ImageVolumeInfo ) # The category that the volume belongs to: category = Str( 'General' ) # A list of keywords used to describe the volume: keywords = List( Str ) # The list of aliases for this volume: aliases = List( Str ) # The path of the file that defined this volume: path = File # Is the path a zip file? is_zip_file = Bool( True ) # The FastZipFile object used to access the underlying zip file: zip_file = Instance( FastZipFile ) # The list of images available in the volume: images = List( ImageInfo ) # A dictionary mapping image names to ImageInfo objects: catalog = Property( depends_on = 'images' ) # The time stamp of when the image library was last modified: time_stamp = Str # A read-only string containing the Python code needed to construct this # ImageVolume object: image_volume_code = Property # A read-only string containing the Python code needed to construct the # 'images' list for this ImageVolume object: images_code = Property # A read-only string containing the text describing the contents of the # volume (description, copyright, license information, and the images they # apply to): license_text = Property #-- Public Methods --------------------------------------------------------- def update ( self ): """ Updates the contents of the image volume from the underlying image store, and saves the results. """ # Unlink all our current images: for image in self.images: image.volume = None # Make sure the images are up to date by deleting any current value: del self.images # Save the new image volume information: self.save() def save ( self ): """ Saves the contents of the image volume using the current contents of the **ImageVolume**. """ path = self.path if not self.is_zip_file: # Make sure the directory is writable: if not access( path, R_OK | W_OK | X_OK ): return False # Make sure the directory and zip file are writable: elif ((not access( dirname( path ), R_OK | W_OK | X_OK )) or (exists( path ) and (not access( path, W_OK )))): return False # Pre-compute the images code, because it can require a long time # to load all of the images so that we can determine their size, and we # don't want that time to interfere with the time stamp of the image # volume: images_code = self.images_code if not self.is_zip_file: # We need to time stamp when this volume info was generated, but # it needs to be the same or newer then the time stamp of the file # it is in. So we use the current time plus a 'fudge factor' to # allow for some slop in when the OS actually time stamps the file: self.time_stamp = time_stamp_for( time() + 5.0 ) # Write the volume manifest source code to a file: write_file( join( path, 'image_volume.py' ), self.image_volume_code ) # Write the image info source code to a file: write_file( join( path, 'image_info.py' ), images_code ) # Write a separate license file for human consumption: write_file( join( path, 'license.txt' ), self.license_text ) return True # Create a temporary name for the new .zip file: file_name = path + '.###' # Create the new zip file: new_zf = ZipFile( file_name, 'w', ZIP_DEFLATED ) try: # Get the current zip file: cur_zf = self.zip_file # Copy all of the image files from the current zip file to the new # zip file: for name in cur_zf.namelist(): if name not in dont_copy_list: new_zf.writestr( name, cur_zf.read( name ) ) # Temporarily close the current zip file while we replace it with # the new version: cur_zf.close() # We need to time stamp when this volume info was generated, but # it needs to be the same or newer then the time stamp of the file # it is in. So we use the current time plus a 'fudge factor' to # allow for some slop in when the OS actually time stamps the file: self.time_stamp = time_stamp_for( time() + 10.0 ) # Write the volume manifest source code to the zip file: new_zf.writestr( 'image_volume.py', self.image_volume_code ) # Write the image info source code to the zip file: new_zf.writestr( 'image_info.py', images_code ) # Write a separate license file for human consumption: new_zf.writestr( 'license.txt', self.license_text ) # Done creating the new zip file: new_zf.close() new_zf = None # Rename the original file to a temporary name, so we can give the # new file the original name. Note that unlocking the original zip # file after the previous close sometimes seems to take a while, # which is why we repeatedly try the rename until it either succeeds # or takes so long that it must have failed for another reason: temp_name = path + '.$$$' for i in range( 50 ): try: rename( path, temp_name ) break except: sleep( 0.1 ) try: rename( file_name, path ) file_name = temp_name except: rename( temp_name, path ) raise finally: if new_zf is not None: new_zf.close() remove( file_name ) return True def image_resource ( self, image_name ): """ Returns the ImageResource object for the specified **image_name**. """ # Get the name of the image file: volume_name, file_name = split_image_name( image_name ) if self.is_zip_file: # See if we already have the image file cached in the file system: cache_file = self._check_cache( file_name ) if cache_file is None: # If not cached, then create a zip file reference: ref = ZipFileReference( resource_factory = resource_manager.resource_factory, zip_file = self.zip_file, path = self.path, volume_name = self.name, file_name = file_name ) else: # Otherwise, create a cache file reference: ref = ImageReference( resource_manager.resource_factory, filename = cache_file ) else: # Otherwise, create a normal file reference: ref = ImageReference( resource_manager.resource_factory, filename = join( self.path, file_name ) ) # Create the ImageResource object using the reference (note that the # ImageResource class will not allow us to specify the reference in the # constructor): resource = ImageResource( file_name ) resource._ref = ref # Return the ImageResource: return resource def image_data ( self, image_name ): """ Returns the image data (i.e. file contents) for the specified image name. """ volume_name, file_name = split_image_name( image_name ) if self.is_zip_file: return self.zip_file.read( file_name ) else: return read_file( join( self.path, file_name ) ) def volume_info ( self, image_name ): """ Returns the ImageVolumeInfo object that corresponds to the image specified by **image_name**. """ for info in self.info: if ((len( info.image_names ) == 0) or (image_name in info.image_names)): return info # Should never occur: return None #-- Default Value Implementations ------------------------------------------ def _info_default ( self ): return [ ImageVolumeInfo() ] def _images_default ( self ): return self._load_image_info() #-- Property Implementations ----------------------------------------------- @cached_property def _get_catalog ( self ): return dict( [ ( image.image_name, image ) for image in self.images ] ) def _get_image_volume_code ( self ): data = dict( [ ( name, repr( value ) ) for name, value in self.get( 'description', 'category', 'keywords', 'aliases', 'time_stamp' ).iteritems() ] ) data['info'] = ',\n'.join( [ info.image_volume_info_code for info in self.info ] ) return (ImageVolumeTemplate % data) def _get_images_code ( self ): images = ',\n'.join( [ info.image_info_code for info in self.images ] ) return (ImageVolumeImagesTemplate % images) def _get_license_text ( self ): return (('\n\n%s\n' % ('-' * 79)).join( [ info.image_volume_info_text for info in self.info ] )) #-- Private Methods -------------------------------------------------------- def _load_image_info ( self ): """ Returns the list of ImageInfo objects for the images in the volume. """ # If there is no current path, then return a default list of images: if self.path == '': return [] time_stamp = time_stamp_for( stat( self.path )[ ST_MTIME ] ) volume_name = self.name old_images = [] cur_images = [] if self.is_zip_file: zf = self.zip_file # Get the names of all top-level entries in the zip file: names = zf.namelist() # Check to see if there is an image info manifest file: if 'image_info.py' in names: # Load the manifest code and extract the images list: old_images = get_python_value( zf.read( 'image_info.py' ), 'images' ) # Check to see if our time stamp is up to data with the file: if self.time_stamp < time_stamp: # If not, create an ImageInfo object for all image files # contained in the .zip file: for name in names: root, ext = splitext( name ) if ext in ImageFileExts: cur_images.append( ImageInfo( name = root, image_name = join_image_name( volume_name, name ) ) ) else: image_info_path = join( self.path, 'image_info.py' ) if exists( image_info_path ): # Load the manifest code and extract the images list: old_images = get_python_value( read_file( image_info_path ), 'images' ) # Check to see if our time stamp is up to data with the file: if self.time_stamp < time_stamp: # If not, create an ImageInfo object for each image file # contained in the path: for name in listdir( self.path ): root, ext = splitext( name ) if ext in ImageFileExts: cur_images.append( ImageInfo( name = root, image_name = join_image_name( volume_name, name ) ) ) # Merge the old and current images into a single up to date list: if len( cur_images ) == 0: images = old_images else: cur_image_set = dict( [ ( image.image_name, image ) for image in cur_images ] ) for old_image in old_images: cur_image = cur_image_set.get( old_image.image_name ) if cur_image is not None: cur_image_set[ old_image.image_name ] = old_image cur_image.volume = self old_image.width = cur_image.width old_image.height = cur_image.height cur_image.volume = None images = cur_image_set.values() # Set the new time stamp of the volume: self.time_stamp = time_stamp # Return the resulting sorted list as the default value: images.sort( key = lambda item: item.image_name ) # Make sure all images reference this volume: for image in images: image.volume = self return images def _check_cache ( self, file_name ): """ Checks to see if the specified zip file name has been saved in the image cache. If it has, it returns the fully-qualified cache file name to use; otherwise it returns None. """ cache_file = join( image_cache_path, self.name, file_name ) if (exists( cache_file ) and (time_stamp_for( stat( cache_file )[ ST_MTIME ] ) > self.time_stamp)): return cache_file return None #------------------------------------------------------------------------------- # 'ZipFileReference' class: #------------------------------------------------------------------------------- class ZipFileReference ( ResourceReference ): # The zip file to read; zip_file = Instance( FastZipFile ) # The volume name: volume_name = Str # The file within the zip file: file_name = Str # The name of the cached image file: cache_file = File #-- The 'ResourceReference' API -------------------------------------------- # The file name of the image (in this case, the cache file name): filename = Property #-- ResourceReference Interface Implementation ----------------------------- def load ( self ): """ Loads the resource. """ # Check if the cache file has already been created: cache_file = self.cache_file if cache_file == '': # Extract the data from the zip file: data = self.zip_file.read( self.file_name ) # Try to create an image from the data, without writing it to a # file first: image = self.resource_factory.image_from_data( data, Undefined ) if image is not None: return image # Make sure the correct image cache directory exists: cache_dir = join( image_cache_path, self.volume_name ) if not exists( cache_dir ): makedirs( cache_dir ) # Write the image data to the cache file: cache_file = join( cache_dir, self.file_name ) fh = file( cache_file, 'wb' ) try: fh.write( data ) finally: fh.close() # Save the cache file name in case we are called again: self.cache_file = cache_file # Release our reference to the zip file object: self.zip_file = None # Return the image data from the image cache file: return self.resource_factory.image_from_file( cache_file ) #-- Property Implementations ----------------------------------------------- def _get_filename ( self ): if self.cache_file == '': self.load() return self.cache_file #------------------------------------------------------------------------------- # 'ImageLibrary' class: #------------------------------------------------------------------------------- class ImageLibrary ( HasPrivateTraits ): """ Manages Traits UI image libraries. """ # The list of available image volumes in the library: volumes = List( ImageVolume ) # The volume dictionary (the keys are volume names, and the values are the # corresponding ImageVolume objects): catalog = Dict( Str, ImageVolume ) # The list of available images in the library: images = Property( List, depends_on = 'volumes.images' ) #-- Private Traits --------------------------------------------------------- # Mapping from a 'virtual' library name to a 'real' library name: aliases = Dict #-- Public methods --------------------------------------------------------- def image_info ( self, image_name ): """ Returns the ImageInfo object corresponding to a specified **image_name**. """ volume = self.find_volume( image_name ) if volume is not None: return volume.catalog.get( image_name ) return None def image_resource ( self, image_name ): """ Returns an ImageResource object for the specified image name. """ # If no volume was specified, use the standard volume: if image_name.find( ':' ) < 0: image_name = '@images:%s' % image_name[1:] # Find the correct volume, possible resolving any aliases used: volume = self.find_volume( image_name ) # Find the image within the volume and return its ImageResource object: if volume is not None: return volume.image_resource( image_name ) # Otherwise, the volume was not found: return None def find_volume ( self, image_name ): """ Returns the ImageVolume object corresponding to the specified **image_name** or None if the volume cannot be found. """ # Extract the volume name from the image name: volume_name, file_name = split_image_name( image_name ) # Find the correct volume, possibly resolving any aliases used: catalog = self.catalog aliases = self.aliases while volume_name not in catalog: volume_name = aliases.get( volume_name ) if volume_name is None: return None return catalog[ volume_name ] def add_volume ( self, file_name = None ): """ If **file_name** is a file, it adds an image volume specified by **file_name** to the image library. If **file_name** is a directory, it adds all image libraries contained in the directory to the image library. If **file_name** is omitted, all image libraries located in the *images* directory contained in the same directory as the caller are added. """ # If no file name was specified, derive a path from the caller's # source code location: if file_name is None: file_name = join( get_resource_path( 2 ), 'images' ) if isfile( file_name ): # Load an image volume from the specified file: volume = self._add_volume( file_name ) if volume is None: raise TraitError( "'%s' is not a valid image volume." % file_name ) if volume.name in self.catalog: self._duplicate_volume( volume.name ) self.catalog[ volume.name ] = volume self.volumes.append( volume ) elif isdir( file_name ): # Load all image volumes from the specified path: catalog = self.catalog volumes = self._add_path( file_name ) for volume in volumes: if volume.name in catalog: self._duplicate_volume( volume.name ) catalog[ volume.name ] = volume self.volumes.extend( volumes ) else: # Handle an unrecognized argument: raise TraitError( "The add method argument must be None or a file " "or directory path, but '%s' was specified." % file_name ) def add_path ( self, volume_name, path = None ): """ Adds the directory specified by **path** as a *virtual* volume called **volume_name**. All image files contained within path define the contents of the volume. If **path** is None, the *images* contained in the 'images' subdirectory of the same directory as the caller are is used as the path for the *virtual* volume.. """ # Make sure we don't already have a volume with that name: if volume_name in self.catalog: raise TraitError( ("The volume name '%s' is already in the image " "library.") % volume_name ) # If no path specified, derive one from the caller's source code # location: if path is None: path = join( get_resource_path( 2 ), 'images' ) # Make sure that the specified path is a directory: if not isdir( path ): raise TraitError( "The image volume path '%s' does not exist." % path ) # Create the ImageVolume to describe the path's contents: image_volume_path = join( path, 'image_volume.py' ) if exists( image_volume_path ): volume = get_python_value( read_file( image_volume_path ), 'volume' ) else: volume = ImageVolume() # Set up the rest of the volume information: volume.set( name = volume_name, path = path, is_zip_file = False ) # Try to bring the volume information up to date if necessary: if volume.time_stamp < time_stamp_for( stat( path )[ ST_MTIME ] ): # Note that the save could fail if the volume is read-only, but # that's OK, because we're only trying to do the save in case # a developer had added or deleted some image files, which would # require write access to the volume: volume.save() # Add the new volume to the library: self.catalog[ volume_name ] = volume self.volumes.append( volume ) def extract ( self, file_name, image_names ): """ Builds a new image volume called **file_name** from the list of image names specified by **image_names**. Each image name should be of the form: '@volume:name'. """ # Get the volume name and file extension: volume_name, ext = splitext( basename( file_name ) ) # If no extension specified, add the '.zip' file extension: if ext == '': file_name += '.zip' # Create the ImageVolume object to describe the new volume: volume = ImageVolume( name = volume_name ) # Make sure the zip file does not already exists: if exists( file_name ): raise TraitError( "The '%s' file already exists." % file_name ) # Create the zip file: zf = ZipFile( file_name, 'w', ZIP_DEFLATED ) # Add each of the specified images to it and the ImageVolume: error = True aliases = set() keywords = set() images = [] info = {} try: for image_name in set( image_names ): # Verify the image name is legal: if (image_name[:1] != '@') or (image_name.find( ':' ) < 0): raise TraitError( ("The image name specified by '%s' is " "not of the form: @volume:name.") % image_name ) # Get the reference volume and image file names: image_volume_name, image_file_name = \ split_image_name( image_name ) # Get the volume for the image name: image_volume = self.find_volume( image_name ) if image_volume is None: raise TraitError( ("Could not find the image volume " "specified by '%s'.") % image_name ) # Get the image info: image_info = image_volume.catalog.get( image_name ) if image_info is None: raise TraitError( ("Could not find the image specified by " "'%s'.") % image_name ) # Add the image info to the list of images: images.append( image_info ) # Add the image file to the zip file: zf.writestr( image_file_name, image_volume.image_data( image_name ) ) # Add the volume alias needed by the image (if any): if image_volume_name != volume_name: if image_volume_name not in aliases: aliases.add( image_volume_name ) # Add the volume keywords as well: for keyword in image_volume.keywords: keywords.add( keyword ) # Add the volume info for the image: volume_info = image_volume.volume_info( image_name ) vinfo = info.get( image_volume_name ) if vinfo is None: info[ image_volume_name ] = vinfo = volume_info.clone() vinfo.image_names.append( image_name ) # Create the list of images for the volume: images.sort( key = lambda item: item.image_name ) volume.images = images # Create the list of aliases for the volume: volume.aliases = list( aliases ) # Create the list of keywords for the volume: volume.keywords = list( keywords ) # Create the final volume info list for the volume: volume.info = info.values() # Write the volume manifest source code to the zip file: zf.writestr( 'image_volume.py', volume.image_volume_code ) # Write the image info source code to the zip file: zf.writestr( 'image_info.py', volume.images_code ) # Write a separate licenses file for human consumption: zf.writestr( 'license.txt', volume.license_text ) # Indicate no errors occurred: error = False finally: zf.close() if error: remove( file_name ) #-- Default Value Implementations ------------------------------------------ def _volumes_default ( self ): result = [] # Check for and add the 'application' image library: app_library = join( dirname( abspath( sys.argv[0] ) ), 'library' ) if isdir( app_library ): result.extend( self._add_path( app_library ) ) # Get all volumes in the standard Traits UI image library directory: result.extend( self._add_path( join( get_resource_path( 1 ), 'library' ) ) ) # Check to see if there is an environment variable specifying a list # of paths containing image libraries: paths = environ.get( 'TRAITS_IMAGES' ) if paths is not None: # Determine the correct OS path separator to use: separator = ';' if system() != 'Windows': separator = ':' # Add all image volumes found in each path in the environment # variable: for path in paths.split( separator ): result.extend( self._add_path( path ) ) # Return the list of default volumes found: return result def _catalog_default ( self ): return dict( [ ( volume.name, volume ) for volume in self.volumes ] ) #-- Property Implementations ----------------------------------------------- @cached_property def _get_images ( self ): return self._get_images_list() #-- Private Methods -------------------------------------------------------- def _get_images_list ( self ): """ Returns the list of all library images. """ # Merge the list of images from each volume: images = [] for volume in self.volumes: images.extend( volume.images ) # Sort the result: images.sort( key = lambda image: image.image_name ) # Return the images list: return images def _add_path ( self, path ): """ Returns a list of ImageVolume objects, one for each image library located in the specified **path**. """ result = [] # Make sure the path is a directory: if isdir( path ): # Find each zip file in the directory: for base in listdir( path ): if splitext( base )[1] == '.zip': # Try to create a volume from the zip file and add it to # the result: volume = self._add_volume( join( path, base ) ) if volume is not None: result.append( volume ) # Return the list of volumes found: return result def _add_volume ( self, path ): """ Returns an ImageVolume object for the image library specified by **path**. If **path** does not specify a valid ImageVolume, None is returned. """ path = abspath( path ) # Make sure the path is a valid zip file: if is_zipfile( path ): # Create a fast zip file for reading: zf = FastZipFile( path = path ) # Extract the volume name from the path: volume_name = splitext( basename( path ) )[0] # Get the names of all top-level entries in the zip file: names = zf.namelist() # Check to see if there is a manifest file: if 'image_volume.py' in names: # Load the manifest code and extract the volume object: volume = get_python_value( zf.read( 'image_volume.py' ), 'volume' ) # Set the volume name: volume.name = volume_name # Try to add all of the external volume references as # aliases for this volume: self._add_aliases( volume ) # Set the path to this volume: volume.path = path # Save the reference to the zip file object we are using: volume.zip_file = zf else: # Create a new volume from the zip file: volume = ImageVolume( name = volume_name, path = path, zip_file = zf ) # If this volume is not up to date, update it: if volume.time_stamp < time_stamp_for( stat( path )[ ST_MTIME ] ): # Note that the save could fail if the volume is read-only, but # that's OK, because we're only trying to do the save in case # a developer had added or deleted some image files, which would # require write access to the volume: volume.save() # Return the volume: return volume # Indicate no volume was found: return None def _add_aliases ( self, volume ): """ Try to add all of the external volume references as aliases for this volume. """ aliases = self.aliases volume_name = volume.name for vname in volume.aliases: if ((vname in aliases) and (volume_name != aliases[ vname ])): raise TraitError( ("Image library error: " "Attempt to alias '%s' to '%s' when it is " "already aliased to '%s'") % ( vname, volume_name, aliases[ volume_name ] ) ) aliases[ vname ] = volume_name def _duplicate_volume ( self, volume_name ): """ Raises a duplicate volume name error. """ raise TraitError( ("Attempted to add an image volume called '%s' when " "a volume with that name is already defined.") % volume_name ) # Create the singleton image object: ImageLibrary = ImageLibrary() traitsui-4.1.0/traitsui/ui_traits.py0000644000175100001440000003646111674463546020614 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/14/2004 # #------------------------------------------------------------------------------ """ Defines common traits used within the traits.ui package. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import (Any, Delegate, Enum, Expression, Float, HasStrictTraits, Instance, List, Range, Str, Trait, TraitError, TraitPrefixList, TraitType) from traits.trait_base import get_resource_path #------------------------------------------------------------------------------- # Trait definitions: #------------------------------------------------------------------------------- # Orientation trait: Orientation = Trait( 'vertical', TraitPrefixList( 'vertical', 'horizontal' ) ) # Styles for user interface elements: EditorStyle = style_trait = Trait( 'simple', TraitPrefixList( 'simple', 'custom', 'text', 'readonly' ), cols = 4 ) # Group layout trait: Layout = Trait( 'normal', TraitPrefixList( 'normal', 'split', 'tabbed', 'flow', 'fold' ) ) # Trait for the default object being edited: AnObject = Expression( 'object' ) # The default dock style to use: DockStyle = dock_style_trait = Enum( 'fixed', 'horizontal', 'vertical', 'tab', desc = "the default docking style to use" ) # The category of elements dragged out of the view: ExportType = Str( desc = 'the category of elements dragged out of the view' ) # Delegate a trait value to the object's **container** trait: ContainerDelegate = container_delegate = Delegate( 'container', listenable = False ) # An identifier for the external help context: HelpId = help_id_trait = Str( desc = "the external help context identifier" ) # A button to add to a view: AButton = Any #AButton = Trait( '', Str, Instance( 'traitsui.menu.Action' ) ) # The set of buttons to add to the view: Buttons = List( AButton, desc = 'the action buttons to add to the bottom of the view' ) # View trait specified by name or instance: AView = Any #AView = Trait( '', Str, Instance( 'traitsui.view.View' ) ) # FIXME: on AButton and AView: TraitCompound handlers with deferred-import # Instance traits are just broken. The Instance trait tries to update the # top-level CTrait's fast_validate table when the import is resolved. However, # sometimes the CTrait gets copied for unknown reasons and the copy's # fast_validate table is not updated although the TraitCompound's slow_validates # table is modified. #------------------------------------------------------------------------------- # 'StatusItem' class: #------------------------------------------------------------------------------- class StatusItem ( HasStrictTraits ): # The name of the trait the status information will be synched with: name = Str( 'status' ) # The width of the status field. The possible values are: # # - abs( width ) > 1.0: Width of the field in pixels = abs( width ) # - abs( width ) <= 1.0: Relative width of the field when compared to # the other relative width fields. width = Float( 0.5 ) def __init__ ( self, value = None, **traits ): """ Initializes the item object. """ super( StatusItem, self ).__init__( **traits ) if value is not None: self.name = value #------------------------------------------------------------------------------- # 'ViewStatus' trait: #------------------------------------------------------------------------------- class ViewStatus ( TraitType ): """ Defines a trait whose value must be a single StatusItem instance or a list of StatusItem instances. """ # Define the default value for the trait: default_value = None # A description of the type of value this trait accepts: info_text = ('None, a string, a single StatusItem instance, or a list or ' 'tuple of strings and/or StatusItem instances') def validate ( self, object, name, value ): """ Validates that a specified value is valid for this trait. """ if isinstance( value, basestring ): return [ StatusItem( name = value ) ] if isinstance( value, StatusItem ): return [ value ] if value is None: return value result = [] if isinstance( value, SequenceTypes ): for item in value: if isinstance( item, basestring ): result.append( StatusItem( name = item ) ) elif isinstance( item, StatusItem ): result.append( item ) else: break else: return result self.error( object, name, value ) #------------------------------------------------------------------------------- # 'Image' trait: #------------------------------------------------------------------------------- image_resource_cache = {} image_bitmap_cache = {} def convert_image ( value, level = 3 ): """ Converts a specified value to an ImageResource if possible. """ global image_resource_cache if not isinstance( value, basestring ): return value key = value is_traits_image = (value[:1] == '@') if not is_traits_image: search_path = get_resource_path( level ) key = '%s[%s]' % ( value, search_path ) result = image_resource_cache.get( key ) if result is None: if is_traits_image: try: from .image.image import ImageLibrary result = ImageLibrary.image_resource( value ) except: result = None else: from pyface.image_resource import ImageResource result = ImageResource( value, search_path = [ search_path ] ) image_resource_cache[ key ] = result return result def convert_bitmap ( image_resource ): """ Converts an ImageResource to a bitmap using a cache. """ global image_bitmap_cache bitmap = image_bitmap_cache.get( image_resource ) if (bitmap is None) and (image_resource is not None): #try: image_bitmap_cache[ image_resource ] = bitmap = \ image_resource.create_bitmap() #except: # pass return bitmap class Image ( TraitType ): """ Defines a trait whose value must be a PyFace ImageResource or a string that can be converted to one. """ # Define the default value for the trait: default_value = None # A description of the type of value this trait accepts: info_text = 'an ImageResource or string that can be used to define one' def __init__ ( self, value = None, **metadata ): """ Creates an Image trait. Parameters ---------- value : string or ImageResource The default value for the Image, either an ImageResource object, or a string from which an ImageResource object can be derived. """ super( Image, self ).__init__( convert_image( value ), **metadata ) def validate ( self, object, name, value ): """ Validates that a specified value is valid for this trait. """ from pyface.image_resource import ImageResource if value is None: return None new_value = convert_image( value, 4 ) if isinstance( new_value, ImageResource ): return new_value self.error( object, name, value ) def create_editor ( self ): """ Returns the default UI editor for the trait. """ from .editors.api import ImageEditor return ImageEditor() #------------------------------------------------------------------------------- # 'ATheme' trait: #------------------------------------------------------------------------------- def convert_theme ( value, level = 3 ): """ Converts a specified value to a Theme if possible. """ if not isinstance( value, basestring ): return value if (value[:1] == '@') and (value.find( ':' ) >= 2): try: from .image.image import ImageLibrary info = ImageLibrary.image_info( value ) except: info = None if info is not None: return info.theme from .theme import Theme return Theme( image = convert_image( value, level + 1 ) ) class ATheme ( TraitType ): """ Defines a trait whose value must be a traits UI Theme or a string that can be converted to one. """ # Define the default value for the trait: default_value = None # A description of the type of value this trait accepts: info_text = 'a Theme or string that can be used to define one' def __init__ ( self, value = None, **metadata ): """ Creates an ATheme trait. Parameters ---------- value : string or Theme The default value for the ATheme, either a Theme object, or a string from which a Theme object can be derived. """ super( ATheme, self ).__init__( convert_theme( value ), **metadata ) def validate ( self, object, name, value ): """ Validates that a specified value is valid for this trait. """ from .theme import Theme if value is None: return None new_value = convert_theme( value, 4 ) if isinstance( new_value, Theme ): return new_value self.error( object, name, value ) #------------------------------------------------------------------------------- # 'BasePMB' class: #------------------------------------------------------------------------------- class BaseMB ( HasStrictTraits ): def __init__ ( self, *args, **traits ): """ Initializes the object. """ n = len( args ) if n > 0: if n == 1: left = right = top = bottom = args[0] elif n == 2: left = right = args[0] top = bottom = args[1] elif n == 4: left, right, top, bottom = args else: raise TraitError( '0, 1, 2 or 4 arguments expected, but %d ' 'specified' % n ) self.set( left = left, right = right, top = top, bottom = bottom ) super( BaseMB, self ).__init__( **traits ) #------------------------------------------------------------------------------- # 'Margin' class: #------------------------------------------------------------------------------- class Margin ( BaseMB ): # The amount of padding/margin at the top: top = Range( -32, 32, 0 ) # The amount of padding/margin at the bottom: bottom = Range( -32, 32, 0 ) # The amount of padding/margin on the left: left = Range( -32, 32, 0 ) # The amount of padding/margin on the right: right = Range( -32, 32, 0 ) #------------------------------------------------------------------------------- # 'Border' class: #------------------------------------------------------------------------------- class Border ( BaseMB ): # The amount of border at the top: top = Range( 0, 32, 0 ) # The amount of border at the bottom: bottom = Range( 0, 32, 0 ) # The amount of border on the left: left = Range( 0, 32, 0 ) # The amount of border on the right: right = Range( 0, 32, 0 ) #------------------------------------------------------------------------------- # 'HasMargin' trait: #------------------------------------------------------------------------------- class HasMargin ( TraitType ): """ Defines a trait whose value must be a Margin object or an integer or tuple value that can be converted to one. """ # The desired value class: klass = Margin # Define the default value for the trait: default_value = Margin( 0 ) # A description of the type of value this trait accepts: info_text = ('a Margin instance, or an integer in the range from -32 to 32 ' 'or a tuple with 1, 2 or 4 integers in that range that can be ' 'used to define one') def validate ( self, object, name, value ): """ Validates that a specified value is valid for this trait. """ if isinstance( value, int ): try: value = self.klass( value ) except: self.error( object, name, value ) elif isinstance( value, tuple ): try: value = self.klass( *value ) except: self.error( object, name, value ) if isinstance( value, self.klass ): return value self.error( object, name, value ) def get_default_value ( self ): """ Returns a tuple of the form: ( default_value_type, default_value ) which describes the default value for this trait. """ dv = self.default_value dvt = self.default_value_type if dvt < 0: if isinstance( dv, int ): dv = self.klass( dv ) elif isinstance( dv, tuple ): dv = self.klass( *dv ) if not isinstance( dv, self.klass ): return super( HasMargin, self ).get_default_value() self.default_value_type = dvt = 7 dv = ( self.klass, (), dv.get() ) return ( dvt, dv ) #------------------------------------------------------------------------------- # 'HasBorder' trait: #------------------------------------------------------------------------------- class HasBorder ( HasMargin ): """ Defines a trait whose value must be a Border object or an integer or tuple value that can be converted to one. """ # The desired value class: klass = Border # Define the default value for the trait: default_value = Border( 0 ) # A description of the type of value this trait accepts: info_text = ('a Border instance, or an integer in the range from 0 to 32 ' 'or a tuple with 1, 2 or 4 integers in that range that can be ' 'used to define one') #------------------------------------------------------------------------------- # Other trait definitions: #------------------------------------------------------------------------------- # The position of an image relative to its associated text: Position = Enum( 'left', 'right', 'above', 'below' ) # The alignment of text within a control: Alignment = Enum( 'default', 'left', 'center', 'right' ) # The spacing between two items: Spacing = Range( -32, 32, 3 ) #------------------------------------------------------------------------------- # Other definitions: #------------------------------------------------------------------------------- # Types that represent sequences: SequenceTypes = ( tuple, list ) traitsui-4.1.0/traitsui/extras/0000755000175100001440000000000011674463546017533 5ustar ischnellusers00000000000000traitsui-4.1.0/traitsui/extras/api.py0000644000175100001440000000176211674463546020664 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2006, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Written by: Jason Sugg # Date: 03/28/2006 # #------------------------------------------------------------------------------ """ Defines 'pseudo' package that imports all of the traits extras symbols. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from .checkbox_column import CheckboxColumn from .saving import CanSaveMixin, SaveHandler traitsui-4.1.0/traitsui/extras/edit_column.py0000644000175100001440000000403611674463546022412 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2006, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: Bryce Hendrix # Date: 09/13/2007 # #------------------------------------------------------------------------------ """ Defines the table column descriptor used for editing the object represented by the row """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.etsconfig.api import ETSConfig from ..table_column import ObjectColumn if ETSConfig.toolkit == 'wx': from pyface.ui.wx.grid.edit_renderer import EditRenderer else: raise NotImplementedError, "No EditColumn implementation for backend" #------------------------------------------------------------------------------- # 'EditColumn' class: #------------------------------------------------------------------------------- class EditColumn ( ObjectColumn ): def __init__ ( self, **traits ): """ Initializes the object. """ super( EditColumn, self ).__init__( **traits ) # force the renderer to be a edit renderer self.renderer = EditRenderer() self.label = '' def get_cell_color ( self, object ): """ Returns the cell background color for the column for a specified object. """ # Override the parent class to ALWAYS provide the standard color: return self.cell_color_ def is_editable ( self, object ): """ Returns whether the column is editable for a specified object. """ return False traitsui-4.1.0/traitsui/extras/saving.py0000644000175100001440000002201011674463546021367 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2009, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: Evan Patterson # Date: 06/18/2009 # #------------------------------------------------------------------------------ """ Provides a lightweight framework that removes some of the drudge work involved with implementing user-friendly saving behavior in a Traits UI application. """ from __future__ import absolute_import # ETS imports from pyface.api import FileDialog, confirm, error, YES, CANCEL from pyface.timer.api import Timer from traits.api import HasTraits, Str, Bool, Any, Int, Instance, on_trait_change from ..api import Handler class CanSaveMixin(HasTraits): """ A mixin-class for objects that wish to support GUI saving via a SaveHandler. It is the responsiblity of the child class to manage its dirty flag, which describes whether its information has changed since its last save. """ filepath = Str dirty = Bool(False) #----------------------------------------------------------------- # object interface #----------------------------------------------------------------- def __getstate__(self): """ We don't want to pickle the filepath because this can change, obviously, if the user moves around the pickled file. """ state = super(CanSaveMixin, self).__getstate__() del state['filepath'] del state['dirty'] return state #----------------------------------------------------------------- # CanSaveMixin interface #----------------------------------------------------------------- def validate(self): """ Returns whether the information in the object is valid to be saved in tuple form. The first item is the validation state (boolean) and the second item is the message to display if the object did not validate. By default, an object always validates. """ return (True, '') def save(self): """ Saves the object to the path specified by its 'filepath' trait. This method should also reset the dirty flag on this object. """ raise NotImplementedError class SaveHandler(Handler): """ A Handler that facilates adding saving to a Traits UI application. """ # The object which is to be saved (subclass of CanSaveMixin). It is assigned # to info.object in the 'init' method, which in many cases is what you want. # If not, override that method to set it to something else. saveObject = Any # The type of files to show in the save dialogs wildcard = Str('All files (*.*)|*.*') # The option extension which should appear at the end of all filenames. If # the user does not explicitly specifiy it, it is appended to the filename. extension = Str # This message to display when the Handler requests a save savePromptMessage = Str('Would you like to save?') # Whether to prompt for a save on exit if the save object is dirty promptOnExit = Bool(True) # Whether to allow the user to override a validation failure through a # confirmation dialog. By default, validation errors cannot be overriden. allowValidationBypass = Bool(False) # Whether to automatically save after a certain amount of time has passed # since the last save autosave = Bool(False) # Number of seconds between each autosave. Default is 5 minutes. autosaveInterval = Int(300) # If it is possible to override validation failures, this specifies whether # autosave will do so. If False and a validation errors occurs, no save # will occur. autosaveValidationBypass = Bool(True) # Protected traits _timer = Instance(Timer) #----------------------------------------------------------------- # Handler interface #----------------------------------------------------------------- def init(self, info): """ Set the default save object (the object being handled). Also, perform a questionable hack by which we remove the handled object from the keybinding's controllers. This means that a keybinding to 'save' only calls this object, not the object being edited as well. (For reasons unclear, the KeyBinding handler API is radically different from the Action API, which is the reason that this problem exists. Keybindings are a UI concept--they should *not* call the model by default.) """ keybindings = info.ui.key_bindings if keybindings is not None: keybindings.controllers.remove(info.object) self.saveObject = info.object return True def close(self, info, is_ok): """ Called when the user requests to close the interface. Returns a boolean indicating whether the window should be allowed to close. """ if self.promptOnExit: return self.promptForSave(info) else: return True def closed(self, info, is_ok): """ Called after the window is destroyed. Makes sure that the autosave timer is stopped. """ if self._timer: self._timer.Stop() #----------------------------------------------------------------- # SaveHandler interface #----------------------------------------------------------------- def exit(self, info): """ Closes the UI unless a save prompt is cancelled. Provided for convenience to be used with a Menu action. """ if self.close(info, True): info.ui.dispose() def save(self, info): """ Saves the object to its current filepath. If this is not specified, opens a dialog to select this path. Returns whether the save actually occurred. """ if self.saveObject.filepath == '': return self.saveAs(info) else: return self._validateAndSave() def saveAs(self, info): """ Saves the object to a new path, and sets this as the 'filepath' on the object. Returns whether the save actually occurred. """ fileDialog = FileDialog(action='save as', title='Save As', wildcard=self.wildcard, parent=info.ui.control) fileDialog.open() if fileDialog.path == '' or fileDialog.return_code == CANCEL: return False else: extLen = len(self.extension) if extLen and fileDialog.path[-extLen-1:] != '.' + self.extension: fileDialog.path += '.' + self.extension self.saveObject.filepath = fileDialog.path return self._validateAndSave() def promptForSave(self, info, cancel=True): """ Prompts the user to save the object, if appropriate. Returns whether the user canceled the action that invoked this prompt. """ if self.saveObject.dirty: code = confirm(info.ui.control, self.savePromptMessage, title="Save now?", cancel=cancel) if code == CANCEL: return False elif code == YES: if not self.save(info): return self.promptForSave(info, cancel) return True def _autosave(self): """ Called by the timer when an autosave should take place. """ if self.saveObject.dirty and self.saveObject.filepath != '': success, message = self.saveObject.validate() if success or (self.allowValidationBypass and self.autosaveValidationBypass): self.saveObject.save() @on_trait_change('autosave, autosaveInterval, saveObject') def _configure_timer(self): """ Creates, replaces, or destroys the autosave timer. """ if self._timer: self._timer.Stop() if self.autosave and self.saveObject: self._timer = Timer(self.autosaveInterval * 1000, self._autosave) else: self._timer = None def _validateAndSave(self): """ Try to save to the current filepath. Returns whether whether the validation was successful/overridden (and the object saved). """ success, message = self.saveObject.validate() if success: self.saveObject.save() else: title = "Validation error" if (self.allowValidationBypass and confirm(None, message, title=title) == YES): self.saveObject.save() success = True else: error(None, message, title=title) return success traitsui-4.1.0/traitsui/extras/__init__.py0000644000175100001440000000000011674463546021632 0ustar ischnellusers00000000000000traitsui-4.1.0/traitsui/extras/checkbox_column.py0000644000175100001440000000566511674463546023264 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2006, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: Jason Sugg # Date: 03/28/2006 # #------------------------------------------------------------------------------ """ Defines the table column descriptor used for toggleable columns. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.etsconfig.api import ETSConfig from ..table_column import ObjectColumn if ETSConfig.toolkit == 'wx': from pyface.ui.wx.grid.checkbox_renderer import CheckboxRenderer elif ETSConfig.toolkit == 'qt4': from ..qt4.extra.checkbox_renderer import CheckboxRenderer else: raise NotImplementedError, "No checkbox renderer for backend" #------------------------------------------------------------------------------- # 'CheckboxColumn' class: #------------------------------------------------------------------------------- class CheckboxColumn ( ObjectColumn ): #--------------------------------------------------------------------------- # Initializes the object: #--------------------------------------------------------------------------- def __init__ ( self, **traits ): """ Initializes the object. """ super( CheckboxColumn, self ).__init__( **traits ) # force the renderer to be a checkbox renderer self.renderer = CheckboxRenderer() #--------------------------------------------------------------------------- # Returns the cell background color for the column for a specified object: #--------------------------------------------------------------------------- def get_cell_color ( self, object ): """ Returns the cell background color for the column for a specified object. """ # Override the parent class to ALWAYS provide the standard color: return self.cell_color_ #--------------------------------------------------------------------------- # Returns whether the column is editable for a specified object: #--------------------------------------------------------------------------- def is_editable ( self, object ): """ Returns whether the column is editable for a specified object. """ # Although a checkbox column is always editable, we return this # to keep a standard editor from appearing. The editing is handled # in the renderer's handlers. return False traitsui-4.1.0/traitsui/extras/demo.py0000644000175100001440000007273511674463546021047 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 09/15/2005 # #------------------------------------------------------------------------------- """ A Traits UI demo that borrows heavily from the design of the wxPython demo. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import import sys import glob from configobj import ConfigObj from traits.api import (HasTraits, HasPrivateTraits, Str, Instance, Property, Any, Code, HTML, true, false, Dict) from traitsui.api import (TreeEditor, ObjectTreeNode, TreeNodeObject, View, Item, VSplit, Tabbed, VGroup, HGroup, Heading, Handler, UIInfo, InstanceEditor, HTMLEditor, Include, spring) from os import listdir from os.path import (join, isdir, split, splitext, dirname, basename, abspath, exists, isabs) #------------------------------------------------------------------------------- # Global data: #------------------------------------------------------------------------------- # Define the code used to populate the 'execfile' dictionary: exec_str = """from traits.api import * """ #---------------------------------------------------------------------------- # Return a 'user-friendly' name for a specified string: #---------------------------------------------------------------------------- def user_name_for ( name ): name = name.replace( '_', ' ' ) return name[:1].upper() + name[1:] #------------------------------------------------------------------------------- # Parses the contents of a specified source file into module comment and # source text: #------------------------------------------------------------------------------- def parse_source ( file_name ): try: fh = open( file_name, 'rb' ) source = fh.read().strip() fh.close() # Extract out the module comment as the description: # FIXME: This isn't ideal: it will retrieve the first docstring found # which might not be for the module as a whole. This needs to be # improved later. For now, we want to make sure we catch docstrings # even if there are comments etc. prior to them. comment = '' quotes_styles = ["'''", '"""'] for quotes in quotes_styles: start_index = source.find(quotes) if start_index >= 0: col = source.find( quotes, start_index + 3 ) if col >= 0: comment = source[ start_index + 3: col ] source = source[: start_index].strip() + source[ col + 3: ].strip() break return ( comment, source ) except: return ( '', '' ) #------------------------------------------------------------------------------- # 'DemoFileHandler' class: #------------------------------------------------------------------------------- class DemoFileHandler ( Handler ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # The current 'info' object (for use by the 'write' method): info = Instance( UIInfo ) #--------------------------------------------------------------------------- # Initializes the view: #--------------------------------------------------------------------------- def init ( self, info ): # Save the reference to the current 'info' object: self.info = info # Set up the 'print' logger: df = info.object df.log = '' sys.stdout = sys.stderr = self # Read in the demo source file: df.description, df.source = parse_source( df.path ) # Try to run the demo source file: # Append the path for the demo source file to sys.path, so as to # resolve any local (relative) imports in the demo source file. sys.path.append(dirname(df.path)) locals = df.parent.init_dic locals[ '__name__' ] = '___main___' locals['__file__'] = df.path sys.modules[ '__main__' ].__file__ = df.path try: execfile( df.path, locals, locals ) demo = self._get_object( 'modal_popup', locals ) if demo is not None: demo = ModalDemoButton( demo = demo ) else: demo = self._get_object( 'popup', locals ) if demo is not None: demo = DemoButton( demo = demo ) else: demo = self._get_object( 'demo', locals ) # FIXME: If a 'demo' object could not be found, then try to execute # the file setting __name__ to __main__. A lot of test scripts have # the actual test running when __name__==__main__ and so we can at # least run all test examples this way. Use a do_later loop so as to # finish building the current UI before running the test. if demo is None: locals['__name__'] = '__main__' #do_later(self.execute_test, df, locals) except Exception, excp: demo = DemoError( msg = str( excp ) ) # Clean up sys.path sys.path.remove(dirname(df.path)) df.demo = demo def execute_test(self, df, locals): """ Executes the file in df.path in the namespace of locals.""" execfile(df.path, locals, locals) #--------------------------------------------------------------------------- # Closes the view: #--------------------------------------------------------------------------- def closed ( self, info, is_ok ): """ Closes the view. """ info.object.demo = None #--------------------------------------------------------------------------- # Get a specified object from the execution dictionary: #--------------------------------------------------------------------------- def _get_object ( self, name, dic ): object = dic.get( name ) or dic.get( name.capitalize() ) if object is not None: if isinstance( type( object ), type ): try: object = object() except: pass if isinstance( object, HasTraits ): return object return None #--------------------------------------------------------------------------- # Handles 'print' output: #--------------------------------------------------------------------------- def write ( self, text ): self.info.object.log += text def flush ( self ): pass # Create a singleton instance: demo_file_handler = DemoFileHandler() #------------------------------------------------------------------------------- # 'DemoError' class: #------------------------------------------------------------------------------- class DemoError ( HasPrivateTraits ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # The error message text: msg = Code #--------------------------------------------------------------------------- # Traits view definitions: #--------------------------------------------------------------------------- traits_view = View( VGroup( Heading( 'Error in source file' ), Item( 'msg', style = 'custom', show_label = False ), ) ) #------------------------------------------------------------------------------- # 'DemoButton' class: #------------------------------------------------------------------------------- class DemoButton ( HasPrivateTraits ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # The demo to be launched via a button: demo = Instance( HasTraits ) # The demo view item to use: demo_item = Item( 'demo', show_label = False, editor = InstanceEditor( label = 'Run demo...', kind = 'live' ) ) #--------------------------------------------------------------------------- # Traits view definitions: #--------------------------------------------------------------------------- traits_view = View( VGroup( VGroup( Heading( 'Click the button to run the demo:' ), '20' ), HGroup( spring, Include( 'demo_item' ), spring ) ), resizable = True ) #------------------------------------------------------------------------------- # 'ModalDemoButton' class: #------------------------------------------------------------------------------- class ModalDemoButton ( DemoButton ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # The demo view item to use: demo_item = Item( 'demo', show_label = False, editor = InstanceEditor( label = 'Run demo...', kind = 'modal' ) ) #------------------------------------------------------------------------------- # 'DemoTreeNodeObject' class: #------------------------------------------------------------------------------- class DemoTreeNodeObject ( TreeNodeObject ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Cached result of 'tno_has_children': _has_children = Any # Cached result of 'tno_get_children': _get_children = Any #--------------------------------------------------------------------------- # Returns whether chidren of this object are allowed or not: #--------------------------------------------------------------------------- def tno_allows_children ( self, node ): """ Returns whether chidren of this object are allowed or not. """ return self.allows_children #--------------------------------------------------------------------------- # Returns whether or not the object has children: #--------------------------------------------------------------------------- def tno_has_children ( self, node = None ): """ Returns whether or not the object has children. """ if self._has_children is None: self._has_children = self.has_children() return self._has_children #--------------------------------------------------------------------------- # Gets the object's children: #--------------------------------------------------------------------------- def tno_get_children ( self, node ): """ Gets the object's children. """ if self._get_children is None: self._get_children = self.get_children() return self._get_children #--------------------------------------------------------------------------- # Returns whether or not the object has children: #--------------------------------------------------------------------------- def has_children ( self, node ): """ Returns whether or not the object has children. """ raise NotImplementedError #--------------------------------------------------------------------------- # Gets the object's children: #--------------------------------------------------------------------------- def get_children ( self, node ): """ Gets the object's children. """ raise NotImplementedError #------------------------------------------------------------------------------- # 'DemoFile' class: #------------------------------------------------------------------------------- class DemoFile ( DemoTreeNodeObject ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Parent of this file: parent = Any # Name of file system path to this file: path = Property # Name of the file: name = Str # UI form of the 'name': nice_name = Property # Files don't allow children: allows_children = false # Description of what the demo does: description = HTML # Source code for the demo: source = Code # Demo object whose traits UI is to be displayed: demo = Instance( HasTraits ) # Log of all print messages displayed: log = Code _nice_name = Str #--------------------------------------------------------------------------- # Implementation of the 'path' property: #--------------------------------------------------------------------------- def _get_path ( self ): return join( self.parent.path, self.name + '.py' ) #--------------------------------------------------------------------------- # Implementation of the 'nice_name' property: #--------------------------------------------------------------------------- def _get_nice_name ( self ): if not self._nice_name: self._nice_name = user_name_for( self.name ) return self._nice_name def _set_nice_name(self, value): old = self.nice_name self._nice_name = value self.trait_property_changed('nice_name', old, value) #--------------------------------------------------------------------------- # Returns whether or not the object has children: #--------------------------------------------------------------------------- def has_children ( self ): """ Returns whether or not the object has children. """ return False #------------------------------------------------------------------------------- # 'DemoPath' class: #------------------------------------------------------------------------------- class DemoPath ( DemoTreeNodeObject ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Parent of this package: parent = Any # Name of file system path to this package: path = Property # Name of the directory: name = Str # UI form of the 'name': nice_name = Property # Description of the contents of the directory: description = Property( HTML ) # Source code contained in the '__init__.py' file: source = Property( Code ) # Dictionary containing symbols defined by the path's '__init__.py' file: init_dic = Property # Should .py files be included? use_files = true # Paths do allow children: allows_children = true # Configuration dictionary for this node # This trait is set when a config file exists for the parent of this path. config_dict = Dict # Configuration file for this node. config_filename = Str # Cached value of the nice_name property. _nice_name = Str #--------------------------------------------------------------------------- # Implementation of the 'path' property: #--------------------------------------------------------------------------- def _get_path ( self ): return join( self.parent.path, self.name ) #--------------------------------------------------------------------------- # Implementation of the 'nice_name' property: #--------------------------------------------------------------------------- def _get_nice_name ( self ): if not self._nice_name: self._nice_name = user_name_for( self.name ) return self._nice_name #--------------------------------------------------------------------------- # Setter for the 'nice_name' property: #--------------------------------------------------------------------------- def _set_nice_name(self, value): old = self.nice_name self._nice_name = value self.trait_property_changed('nice_name', old, value) #--------------------------------------------------------------------------- # Implementation of the 'description' property: #--------------------------------------------------------------------------- def _get_description ( self ): if self._description is None: self._get_init() return self._description #--------------------------------------------------------------------------- # Implementation of the 'source' property: #--------------------------------------------------------------------------- def _get_source ( self ): if self._source is None: self._get_init() return self._source #--------------------------------------------------------------------------- # Implementation of the 'init_dic' property: #--------------------------------------------------------------------------- def _get_init_dic ( self ): init_dic = {} description, source = parse_source( join( self.path, '__init__.py' ) ) exec (exec_str + source) in init_dic return init_dic # fixme: The following code should work, but doesn't, so we use the # preceding code instead. Changing any trait in the object in # this method causes the tree to behave as if the DemoPath object # had been selected instead of a DemoFile object. May be due to # an 'anytrait' listener in the TreeEditor? #if self._init_dic is None: # self._init_dic = {} # #exec self.source in self._init_dic #return self._init_dic.copy() #--------------------------------------------------------------------------- # Initializes the description and source from the path's '__init__.py' # file: #--------------------------------------------------------------------------- def _get_init ( self ): if self.use_files: # Read in the '__init__.py' source file (if any): self._description, source = parse_source( join( self.path, '__init__.py' ) ) else: self._description = ('') source = '' self._source = exec_str + source #--------------------------------------------------------------------------- # Returns whether or not the object has children: #--------------------------------------------------------------------------- def has_children ( self ): """ Returns whether or not the object has children. """ path = self.path for name in listdir( path ): cur_path = join( path, name ) if isdir( cur_path ): return True if self.use_files: name, ext = splitext( name ) if (ext == '.py') and (name != '__init__'): return True return False #--------------------------------------------------------------------------- # Gets the object's children: #--------------------------------------------------------------------------- def get_children ( self ): """ Gets the object's children. """ if self.config_dict or self.config_filename: children = self.get_children_from_config() else: children = self.get_children_from_datastructure() return children #--------------------------------------------------------------------------- # Gets the object's children based on the filesystem structure. #--------------------------------------------------------------------------- def get_children_from_datastructure( self ): """ Gets the object's children based on the filesystem structure. """ dirs = [] files = [] path = self.path for name in listdir( path ): cur_path = join( path, name ) if isdir( cur_path ): if self.has_py_files( cur_path ): dirs.append( DemoPath( parent = self, name = name ) ) elif self.use_files: name, ext = splitext( name ) if (ext == '.py') and (name != '__init__'): files.append( DemoFile( parent = self, name = name ) ) dirs.sort( lambda l, r: cmp( l.name, r.name ) ) files.sort( lambda l, r: cmp( l.name, r.name ) ) return (dirs + files) #--------------------------------------------------------------------------- # Gets the object's children as specified in its configuration file or # dictionary. #--------------------------------------------------------------------------- def get_children_from_config( self ): """ Gets the object's children as specified in its configuration file or dictionary. """ if not self.config_dict: if exists(self.config_filename): try: self.config_dict = ConfigObj(self.config_filename) except: pass if not self.config_dict: return self.get_children_from_datastructure() dirs = [] files = [] for keyword, value in self.config_dict.items(): if not value.get('no_demo'): sourcedir = value.pop('sourcedir', None) if sourcedir is not None: # This is a demo directory. demoobj = DemoPath( parent = self, name = sourcedir ) demoobj.nice_name = keyword demoobj.config_dict = value dirs.append(demoobj) else: names = [] filenames = value.pop('files', []) if not isinstance(filenames, list): filenames = [filenames] for filename in filenames: filename = join(self.path, filename) for name in glob.iglob(filename): pathname, ext = splitext(name) if (ext == '.py') and \ (basename(pathname) != '__init__'): names.append(pathname) if len(names) > 1: config_dict = {} for name in names: config_dict[basename(name)] = {'files': name + '.py'} demoobj = DemoPath( parent = self, name = '') demoobj.nice_name = keyword demoobj.config_dict = config_dict dirs.append(demoobj) elif len(names) == 1: file = DemoFile(parent=self, name=names[0]) file.nice_name = keyword files.append(file) dirs.sort( lambda l, r: cmp( l.nice_name, r.nice_name ) ) files.sort( lambda l, r: cmp( l.nice_name, r.nice_name ) ) return (dirs + files) #--------------------------------------------------------------------------- # Returns whether the specified path contains any .py files: #--------------------------------------------------------------------------- def has_py_files ( self, path ): for name in listdir( path ): cur_path = join( path, name ) if isdir( cur_path ): if self.has_py_files( cur_path ): return True else: name, ext = splitext( name ) if ext == '.py': return True return False #------------------------------------------------------------------------------- # Defines the demo tree editor: #------------------------------------------------------------------------------- path_view = View( Tabbed( Item( 'description', label = 'Description', show_label = False, style = 'readonly', editor=HTMLEditor(format_text=True) ), Item( 'source', label = 'Source', show_label = False, style = 'custom' ), export = 'DockWindowShell', id = 'tabbed' ), id = 'traitsui.demos.demo.path_view', #dock = 'horizontal' ) demo_view = View( #VSplit( Tabbed( Item( 'description', label = 'Description', show_label = False, style = 'readonly', editor=HTMLEditor(format_text=True) ), Item( 'source', label = 'Source', show_label = False, style = 'custom' ), Item( 'demo', label = 'Demo', show_label = False, style = 'custom', resizable = True, # FIXME: # visible_when doesn't work correctly yet (for wx atleast) # for tabbed items. Needs more investigation. visible_when = 'demo', ), Item( 'log', show_label = False, style = 'readonly' ), export = 'DockWindowShell', id = 'tabbed', ), # JDM moving log panel provisionally to its own tab, distracting here. #VGroup( #Item( 'log', #show_label = False, #style = 'readonly' #), #label = 'Log' #), #export = 'DockWindowShell', #id = 'vsplit' #), id = 'traitsui.demos.demo.file_view', #dock = 'horizontal', handler = demo_file_handler ) demo_tree_editor = TreeEditor( nodes = [ ObjectTreeNode( node_for = [ DemoPath ], label = 'nice_name', view = path_view ), ObjectTreeNode( node_for = [ DemoFile ], label = 'nice_name', view = demo_view ) ] ) #------------------------------------------------------------------------------- # 'Demo' class: #------------------------------------------------------------------------------- class Demo ( HasPrivateTraits ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Path to the root demo directory: path = Str # Root path object for locating demo files: root = Instance( DemoPath ) # Title for the demo title = Str #--------------------------------------------------------------------------- # Traits view definitions: #--------------------------------------------------------------------------- def default_traits_view(self): """ Constructs the default traits view.""" traits_view = View( Item( name = 'root', id = 'root', show_label = False, editor = demo_tree_editor ), title = self.title, id = 'traitsui.demos.demo.Demo', #dock = 'horizontal', resizable = True, # JDM: Seems that QT interface does not deal well with these size # limits. # With them, we get repeated: # Object::disconnect: Parentheses expected, signal AdvancedCodeWidget::lostFocus # But without them, it throws an exception on exit: # Internal C++ object (_StickyDialog) already deleted. # No, actually sometimes we get the latter even with them. width = 950, height = 900 ) return traits_view #--------------------------------------------------------------------------- # Handles the 'root' trait being changed: #--------------------------------------------------------------------------- def _root_changed ( self, root ): """ Handles the 'root' trait being changed. """ root.parent = self #------------------------------------------------------------------------------- # Function to run the demo: #------------------------------------------------------------------------------- def demo ( use_files=False, dir_name = None, config_filename = '', title = 'Traits UI Demos' ): if dir_name is None: dir_name = dirname(abspath( sys.argv[0] )) path, name = split( dir_name ) if len(config_filename) > 0 and not isabs(config_filename): config_filename = join(path, name, config_filename) Demo( path = path, title = title, root = DemoPath( name = name, use_files = use_files, config_filename = config_filename ) ).configure_traits() traitsui-4.1.0/traitsui/theme.py0000644000175100001440000000405111674463546017701 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2007, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 07/13/2007 # #------------------------------------------------------------------------------- """ Defines 'theme' related classes. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import HasPrivateTraits from .ui_traits import Image, HasBorder, HasMargin, Alignment #------------------------------------------------------------------------------- # 'Theme' class: #------------------------------------------------------------------------------- class Theme ( HasPrivateTraits ): #-- Public Traits ---------------------------------------------------------- # The background image to use for the theme: image = Image # The border inset: border = HasBorder # The margin to use around the content: content = HasMargin # The margin to use around the label: label = HasMargin # The alignment to use for positioning the label: alignment = Alignment( cols = 4 ) # Note: The 'content_color' and 'label_color' traits should be added by a # toolkit-specific category... #-- Constructor ------------------------------------------------------------ def __init__ ( self, image = None, **traits ): """ Initializes the object. """ if image is not None: self.image = image super( Theme, self ).__init__( **traits ) # Create a default theme: default_theme = Theme() traitsui-4.1.0/traitsui/handler.py0000644000175100001440000005623611674463546020230 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/07/2004 # #------------------------------------------------------------------------------ """ Defines the Handler class used to manage and control the editing process in a Traits-based user interface. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from .toolkit import toolkit from .help import on_help_call from .view_element import ViewElement from .helper import user_name_for from .ui_info import UIInfo from traits.api import HasPrivateTraits, HasTraits, Instance #------------------------------------------------------------------------------- # Closes a DockControl (if allowed by the associated traits UI Handler): #------------------------------------------------------------------------------- def close_dock_control ( dock_control ): """ Closes a DockControl (if allowed by the associated Traits UI Handler). """ # Retrieve the traits UI object set when we created the DockControl: ui = dock_control.data # Ask the traits UI handler if it is OK to close the window: if not ui.handler.close( ui.info, True ): # If not, tell the DockWindow not to close it: return False # Otherwise, clean up and close the traits UI: ui.dispose() # And tell the DockWindow to remove the DockControl: return True #------------------------------------------------------------------------------- # 'Handler' class: #------------------------------------------------------------------------------- class Handler ( HasPrivateTraits ): """ Provides access to and control over the run-time workings of a Traits-based user interface. """ #--------------------------------------------------------------------------- # Informs the handler what the UIInfo object for a View will be: #--------------------------------------------------------------------------- def init_info ( self, info ): """ Informs the handler what the UIInfo object for a View will be. This method is called before the UI for the View has been constructed. It is provided so that the handler can save the reference to the UIInfo object in case it exposes viewable traits whose values are properties that depend upon items in the context being edited. """ pass #--------------------------------------------------------------------------- # Initializes the controls of a user interface: #--------------------------------------------------------------------------- def init ( self, info ): """ Initializes the controls of a user interface. Parameters ---------- info : UIInfo object The UIInfo object associated with the view Returns ------- A Boolean, indicating whether the user interface was successfully initialized. A True value indicates that the UI can be displayed; a False value indicates that the display operation should be cancelled. The default implementation returns True without taking any other action. Description ----------- This method is called after all user interface elements have been created, but before the user interface is displayed. Override this method to customize the user interface before it is displayed. """ return True #--------------------------------------------------------------------------- # Positions a dialog-based user interface on the display: #--------------------------------------------------------------------------- def position ( self, info ): """ Positions a dialog-based user interface on the display. Parameters ---------- info : UIInfo object The UIInfo object associated with the window Returns ------- Nothing. Description ----------- This method is called after the user interface is initialized (by calling init()), but before the user interface is displayed. Override this method to position the window on the display device. The default implementation calls the position() method of the current toolkit. Usually, you do not need to override this method, because you can control the window's placement using the **x** and **y** attributes of the View object. """ toolkit().position( info.ui ) #--------------------------------------------------------------------------- # Handles a request to close a dialog-based user interface by the user: #--------------------------------------------------------------------------- def close ( self, info, is_ok ): """ Handles the user attempting to close a dialog-based user interface. Parameters ---------- info : UIInfo object The UIInfo object associated with the view is_ok : Boolean Indicates whether the user confirmed the changes (such as by clicking **OK**.) Returns ------- A Boolean, indicating whether the window should be allowed to close. Description ----------- This method is called when the user attempts to close a window, by clicking an **OK** or **Cancel** button, or clicking a Close control on the window). It is called before the window is actually destroyed. Override this method to perform any checks before closing a window. While Traits UI handles "OK" and "Cancel" events automatically, you can use the value of the *is_ok* parameter to implement additional behavior. """ return True #--------------------------------------------------------------------------- # Handles a dialog-based user interface being closed by the user: #--------------------------------------------------------------------------- def closed ( self, info, is_ok ): """ Handles a dialog-based user interface being closed by the user. Parameters ---------- info : UIInfo object The UIInfo object associated with the view is_ok : Boolean Indicates whether the user confirmed the changes (such as by clicking **OK**.) Description ----------- This method is called *after* the window is destroyed. Override this method to perform any clean-up tasks needed by the application. """ return #--------------------------------------------------------------------------- # Handles the 'Revert' button being clicked: #--------------------------------------------------------------------------- def revert ( self, info ): """ Handles the **Revert** button being clicked. """ return #--------------------------------------------------------------------------- # Handles the 'Apply' button being clicked: #--------------------------------------------------------------------------- def apply ( self, info ): """ Handles the **Apply** button being clicked. """ return #--------------------------------------------------------------------------- # Shows the help associated with the view: #--------------------------------------------------------------------------- def show_help ( self, info, control = None ): """ Shows the help associated with the view. Parameters ---------- info : UIInfo object The UIInfo object associated with the view control : UI control The control that invokes the help dialog box Description ----------- This method is called when the user clicks a **Help** button in a Traits user interface. The method calls the global help handler, which might be the default help handler, or might be a custom help handler. See **traitsui.help** for details about the setting the global help handler. """ if control is None: control = info.ui.control on_help_call()( info, control ) #--------------------------------------------------------------------------- # Handles setting a specified object trait's value: #--------------------------------------------------------------------------- def setattr ( self, info, object, name, value ): """ Handles the user setting a specified object trait's value. Parameters ---------- object : object The object whose attribute is being set name : string The name of the attribute being set value The value to which the attribute is being set Description ----------- This method is called when an editor attempts to set a new value for a specified object trait attribute. Use this method to control what happens when a trait editor tries to set an attribute value. For example, you can use this method to record a history of changes, in order to implement an "undo" mechanism. No result is returned. The default implementation simply calls the built-in setattr() function. If you override this method, make sure that it actually sets the attribute, either by calling the parent method or by setting the attribute directly """ setattr( object, name, value ) #--------------------------------------------------------------------------- # Gets a specified View object: #--------------------------------------------------------------------------- def trait_view_for ( self, info, view, object, object_name, trait_name ): """ Gets a specified View object. """ # If a view element was passed instead of a name or None, return it: if isinstance( view, ViewElement ): return view # Generate a series of possible view or method names of the form: # - 'view' # trait_view_for_'view'( object ) # - 'class_view' # trait_view_for_'class_view'( object ) # - 'object_name_view' # trait_view_for_'object_name_view'( object ) # - 'object_name_class_view' # trait_view_for_'object_name_class_view'( object ) # where 'class' is the class name of 'object', 'object' is the object # name, and 'name' is the trait name. It returns the first view # or method result which is defined on the handler: klass = object.__class__.__name__ cname = '%s_%s' % ( object_name, trait_name ) aview = '' if view: aview = '_' + view names = [ '%s_%s%s' % ( cname, klass, aview ), '%s%s' % ( cname, aview ), '%s%s' % ( klass, aview ) ] if view: names.append( view ) for name in names: result = self.trait_view( name ) if result is not None: return result method = getattr( self, 'trait_view_for_%s' % name, None ) if callable( method ): result = method( info, object ) if result is not None: return result # If nothing is defined on the handler, return either the requested # view on the object itself, or the object's default view: return object.trait_view( view ) or object.trait_view() #-- 'DockWindowHandler' interface implementation ------------------------------- #--------------------------------------------------------------------------- # Returns whether or not a specified object can be inserted into the view: #--------------------------------------------------------------------------- def can_drop ( self, info, object ): """ Can the specified object be inserted into the view? """ from pyface.dock.api import DockControl if isinstance( object, DockControl ): return self.can_import( info, object.export ) drop_class = info.ui.view.drop_class return ((drop_class is not None) and isinstance( object, drop_class )) #--------------------------------------------------------------------------- # Returns whether or not a specified external view category can be # imported: #--------------------------------------------------------------------------- def can_import ( self, info, category ): return (category in info.ui.view.imports) #--------------------------------------------------------------------------- # Returns the DockControl object for a specified object: #--------------------------------------------------------------------------- def dock_control_for ( self, info, parent, object ): """ Returns the DockControl object for a specified object. """ from pyface.dock.api import IDockable, DockControl from .dockable_view_element import DockableViewElement try: name = object.name except: try: name = object.label except: name = '' if len( name ) == 0: name = user_name_for( object.__class__.__name__ ) image = None export = '' if isinstance( object, DockControl ): dock_control = object image = dock_control.image export = dock_control.export dockable = dock_control.dockable close = dockable.dockable_should_close() if close: dock_control.close( force = True ) control = dockable.dockable_get_control( parent ) # If DockControl was closed, then reset it to point to the new # control: if close: dock_control.set( control = control, style = parent.owner.style ) dockable.dockable_init_dockcontrol( dock_control ) return dock_control elif isinstance( object, IDockable ): dockable = object control = dockable.dockable_get_control( parent ) else: ui = object.get_dockable_ui( parent ) dockable = DockableViewElement( ui = ui ) export = ui.view.export control = ui.control dc = DockControl( control = control, name = name, export = export, style = parent.owner.style, image = image, closeable = True ) dockable.dockable_init_dockcontrol( dc ) return dc #--------------------------------------------------------------------------- # Creates a new view of a specified control: #--------------------------------------------------------------------------- def open_view_for ( self, control, use_mouse = True ): """ Creates a new view of a specified control. """ from pyface.dock.api import DockWindowShell DockWindowShell( control, use_mouse = use_mouse ) #--------------------------------------------------------------------------- # Handles a DockWindow becoming empty: #--------------------------------------------------------------------------- def dock_window_empty ( self, dock_window ): """ Handles a DockWindow becoming empty. """ if dock_window.auto_close: dock_window.control.GetParent.Destroy() #-- HasTraits overrides: ------------------------------------------------------- #--------------------------------------------------------------------------- # Edits the object's traits: (Overrides HasTraits) #--------------------------------------------------------------------------- def edit_traits ( self, view = None, parent = None, kind = None, context = None, handler = None, id = '', scrollable = None, **args ): """ Edits the object's traits. """ if context is None: context = self if handler is None: handler = self return self.trait_view( view ).ui( context, parent, kind, self.trait_view_elements(), handler, id, scrollable, args ) #--------------------------------------------------------------------------- # Configure the object's traits (Overrides HasTraits): #--------------------------------------------------------------------------- def configure_traits ( self, filename = None, view = None, kind = None, edit = True, context = None, handler = None, id = '', scrollable = None, **args ): """ Configures the object's traits. """ super( HasPrivateTraits, self ).configure_traits( filename, view, kind, edit, context, handler or self, id, scrollable, **args ) #-- Private Methods: ----------------------------------------------------------- #--------------------------------------------------------------------------- # Handles an 'Undo' change request: #--------------------------------------------------------------------------- def _on_undo ( self, info ): """ Handles an "Undo" change request. """ if info.ui.history is not None: info.ui.history.undo() #--------------------------------------------------------------------------- # Handles a 'Redo' change request: #--------------------------------------------------------------------------- def _on_redo ( self, info ): """ Handles a "Redo" change request. """ if info.ui.history is not None: info.ui.history.redo() #--------------------------------------------------------------------------- # Handles a 'Revert' all changes request: #--------------------------------------------------------------------------- def _on_revert ( self, info ): """ Handles a "Revert all changes" request. """ if info.ui.history is not None: info.ui.history.revert() self.revert( info ) #--------------------------------------------------------------------------- # Handles a 'Close' request: #--------------------------------------------------------------------------- def _on_close ( self, info ): """ Handles a "Close" request. """ if (info.ui.owner is not None) and self.close( info, True ): info.ui.owner.close() #------------------------------------------------------------------------------- # Default handler: #------------------------------------------------------------------------------- _default_handler = Handler() def default_handler ( handler = None ): """ Returns the global default handler. If *handler* is an instance of Handler, this function sets it as the global default handler. """ global _default_handler if isinstance( handler, Handler ): _default_handler = handler return _default_handler #------------------------------------------------------------------------------- # 'Controller' class: #------------------------------------------------------------------------------- class Controller ( Handler ): """ Defines a handler class which provides a view and controller for a specified model. This class is used when implementing a standard MVC-based design. The **model** trait contains most, if not all, of the data being viewed, and can be referenced in a Controller instance's View definition using unadorned trait names. (e.g., ``Item('name')``). """ #-- Trait Definitions ------------------------------------------------------ # The model this handler defines a view and controller for model = Instance( HasTraits ) # The Info object associated with the controller info = Instance( UIInfo ) #-- HasTraits Method Overrides --------------------------------------------- def __init__ ( self, model = None, **metadata ): """ Initializes the object and sets the model (if supplied). """ super( Controller, self ).__init__( **metadata ) self.model = model def trait_context ( self ): """ Returns the default context to use for editing or configuring traits. """ return { 'object': self.model, 'controller': self, 'handler': self } #-- Handler Method Overrides ----------------------------------------------- #--------------------------------------------------------------------------- # Informs the handler what the UIInfo object for a View will be: #--------------------------------------------------------------------------- def init_info ( self, info ): """ Informs the handler what the UIInfo object for a View will be. """ self.info = info #------------------------------------------------------------------------------- # 'ModelView' class: #------------------------------------------------------------------------------- class ModelView ( Controller ): """ Defines a handler class which provides a view and controller for a specified model. This class is useful when creating a variant of the standard MVC-based design. A subclass of ModelView reformulates a number of traits on its **model** object as properties on the ModelView subclass itself, usually in order to convert them into a more user-friendly format. In this design, the ModelView subclass supplies not only the view and the controller, but also, in effect, the model (as a set of properties wrapped around the original model). Because of this, the ModelView context dictionary specifies the ModelView instance itself as the special *object* value, and assigns the original model object as the *model* value. Thus, the traits of the ModelView object can be referenced in its View definition using unadorned trait names. """ #-- HasTraits Method Overrides --------------------------------------------- def trait_context ( self ): """ Returns the default context to use for editing or configuring traits. """ return { 'object': self, 'handler': self, 'model': self.model } #------------------------------------------------------------------------------- # 'ViewHandler' class: #------------------------------------------------------------------------------- class ViewHandler ( Handler ): pass traitsui-4.1.0/traitsui/__init__.py0000644000175100001440000000134511674463546020341 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005-2011, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/07/2004 # #------------------------------------------------------------------------------ from __future__ import absolute_import __version__ = '4.1.0' __requires__ = [ 'traits', 'pyface', ] traitsui-4.1.0/traitsui/message.py0000644000175100001440000001177611674463546020237 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 09/01/2005 # #------------------------------------------------------------------------------ """ Displays a message to the user as a modal window. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import HasPrivateTraits, Str, Float from .view import View from .group import HGroup from .item import Item, spring from pyface.timer.api import do_after #------------------------------------------------------------------------------- # 'Message' class: #------------------------------------------------------------------------------- class Message ( HasPrivateTraits ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # The message to be displayed message = Str #------------------------------------------------------------------------------- # Displays a user specified message: #------------------------------------------------------------------------------- def message ( message = '', title = 'Message', buttons = [ 'OK' ], parent = None ): """ Displays a message to the user as a model window with the specified title and buttons. If *buttons* is not specified, a single **OK** button is used, which is appropriate for notifications, where no further action or decision on the user's part is required. """ msg = Message( message = message ) ui = msg.edit_traits( parent = parent, view = View( [ 'message~', '|<>' ], title = title, buttons = buttons, kind = 'modal' ) ) return ui.result #------------------------------------------------------------------------------- # Displays a user specified error message: #------------------------------------------------------------------------------- def error ( message = '', title = 'Message', buttons = [ 'OK', 'Cancel' ], parent = None ): """ Displays a message to the user as a modal window with the specified title and buttons. If *buttons* is not specified, **OK** and **Cancel** buttons are used, which is appropriate for confirmations, where the user must decide whether to proceed. Be sure to word the message so that it is clear that clicking **OK** continues the operation. """ msg = Message( message = message ) ui = msg.edit_traits( parent = parent, view = View( [ 'message~', '|<>' ], title = title, buttons = buttons, kind = 'modal' ) ) return ui.result #------------------------------------------------------------------------------- # 'AutoCloseMessage' class: #------------------------------------------------------------------------------- class AutoCloseMessage ( HasPrivateTraits ): # The message to be shown: message = Str( 'Please wait' ) # The time (in seconds) to show the message: time = Float( 2.0 ) def show ( self, parent = None, title = '' ): """ Display the wait message for a limited duration. """ view = View( HGroup( spring, Item( 'message', show_label = False, style = 'readonly' ), spring ), title = title ) do_after( int( 1000.0 * self.time ), self.edit_traits( parent = parent, view = view ).dispose ) #------------------------------------------------------------------------------- # Displays a user specified message that closes automatically after a specified # time interval: #------------------------------------------------------------------------------- def auto_close_message ( message = 'Please wait', time = 2.0, title = 'Please wait', parent = None ): """ Displays a message to the user as a modal window with no buttons. The window closes automatically after a specified time interval (specified in seconds). """ msg = AutoCloseMessage( message = message, time = time ) msg.show( parent = parent, title = title ) traitsui-4.1.0/traitsui/ui_info.py0000644000175100001440000000532111674463546020230 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/13/2004 # #------------------------------------------------------------------------------ """ Defines the UIInfo class used to represent the object and editor content of an active Traits-based user interface. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import from traits.api import HasPrivateTraits, Instance, Constant, Bool #------------------------------------------------------------------------------- # 'UIInfo' class: #------------------------------------------------------------------------------- class UIInfo ( HasPrivateTraits ): """ Represents the object and editor content of an active Traits-based user interface """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Bound to a UI object at UIInfo construction time ui = Instance( 'traitsui.ui.UI', allow_none = True ) # Indicates whether the UI has finished initialization initialized = Bool( False ) #--------------------------------------------------------------------------- # Bind's all of the associated context objects as traits of the object: #--------------------------------------------------------------------------- def bind_context ( self ): """ Binds all of the associated context objects as traits of the object. """ for name, value in self.ui.context.items(): self.bind( name, value ) #--------------------------------------------------------------------------- # Binds a name to a value if it is not already bound: #--------------------------------------------------------------------------- def bind ( self, name, value, id = None ): """ Binds a name to a value if it is not already bound. """ if id is None: id = name if not hasattr( self, name ): self.add_trait( name, Constant( value ) ) if id != '': self.ui._names.append( id ) traitsui-4.1.0/traitsui/item.py0000644000175100001440000005071111674463546017541 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 10/07/2004 # #------------------------------------------------------------------------------ """ Defines the Item class, which is used to represent a single item within a Traits-based user interface. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from __future__ import absolute_import import re from string import find, rfind from traits.api import (Bool, Callable, Constant, Delegate, Float, Instance, Range, Str, Undefined, Dict,) from traits.trait_base import user_name_for from .view_element import ViewSubElement from .ui_traits import convert_theme, ContainerDelegate, EditorStyle from .editor_factory import EditorFactory #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- # Pattern of all digits: all_digits = re.compile( r'\d+' ) # Pattern for finding size infomation embedded in an item description: size_pat = re.compile( r"^(.*)<(.*)>(.*)$", re.MULTILINE | re.DOTALL ) # Pattern for finding tooltip infomation embedded in an item description: tooltip_pat = re.compile( r"^(.*)`(.*)`(.*)$", re.MULTILINE | re.DOTALL ) #------------------------------------------------------------------------------- # Trait definitions: #------------------------------------------------------------------------------- # Reference to an EditorFactory: ItemEditor = Instance( EditorFactory, allow_none = True ) # Amount of padding to add around an item: Padding = Range( -15, 15, 0, desc = 'amount of padding to add around item' ) #------------------------------------------------------------------------------- # 'Item' class: #------------------------------------------------------------------------------- class Item ( ViewSubElement ): """ An element in a Traits-based user interface. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # A unique identifier for the item. If not set, it defaults to the value # of **name**. id = Str # User interface label for the item in the GUI. If this attribute is not # set, the label is the value of **name** with slight modifications: # underscores are replaced by spaces, and the first letter is capitalized. # If an item's **name** is not specified, its label is displayed as # static text, without any editor widget. label = Str # Name of the trait the item is editing: name = Str # Style-sheet to apply to item / group (Qt only) style_sheet = Str # Help text describing the purpose of the item. The built-in help handler # displays this text in a pop-up window if the user clicks the widget's # label. View-level help displays the help text for all items in a view. # If this attribute is not set, the built-in help handler generates a # description based on the trait definition. help = Str # The HasTraits object whose trait attribute the item is editing: object = ContainerDelegate # Presentation style for the item: style = ContainerDelegate # Docking style for the item: dock = ContainerDelegate # Image to display on notebook tabs: image = ContainerDelegate # The theme to use for the item itself: item_theme = ContainerDelegate # The theme to use for the item's label: label_theme = ContainerDelegate # Category of elements dragged from view: export = ContainerDelegate # Should a label be displayed for the item? show_label = Delegate( 'container', 'show_labels' ) # Editor to use for the item: editor = ItemEditor # Additional editor traits to be set if default traits editor to be used: editor_args = Dict # Should the item use extra space along its Group's layout axis? If set to # True, the widget expands to fill any extra space that is available in the # display. If set to True for more than one item in the same View, any extra # space is divided between them. If set to False, the widget uses only # whatever space it is explicitly (or implicitly) assigned. The default # value of Undefined means that the use (or non-use) of extra space will be # determined by the editor associated with the item. resizable = Bool( Undefined ) # Should the item use extra space along its Group's layout axis? For # example, it a vertical group, should an item expand vertically to use # any extra space available in the group? springy = Bool( False ) # Should the item use any extra space along its Group's non-layout # orientation? For example, in a vertical group, should an item expand # horizontally to the full width of the group? If left to the default value # of Undefined, the decision will be left up to the associated item editor. full_size = Bool( Undefined ) # Should the item's label use emphasized text? If the label is not shown, # this attribute is ignored. emphasized = Bool( False ) # Should the item receive focus initially? has_focus = Bool( False ) # Pre-condition for including the item in the display. If the expression # evaluates to False, the item is not defined in the display. Conditions # for **defined_when** are evaluated only once, when the display is first # constructed. Use this attribute for conditions based on attributes that # vary from object to object, but that do not change over time. For example, # displaying a 'maiden_name' item only for female employees in a company # database. defined_when = Str # Pre-condition for showing the item. If the expression evaluates to False, # the widget is not visible (and disappears if it was previously visible). # If the value evaluates to True, the widget becomes visible. All # **visible_when** conditions are checked each time that any trait value # is edited in the display. Therefore, you can use **visible_when** # conditions to hide or show widgets in response to user input. visible_when = Str # Pre-condition for enabling the item. If the expression evaluates to False, # the widget is disabled, that is, it does not accept input. All # **enabled_when** conditions are checked each time that any trait value # is edited in the display. Therefore, you can use **enabled_when** # conditions to enable or disable widgets in response to user input. enabled_when = Str # Amount of extra space, in pixels, to add around the item. Values must be # integers between -15 and 15. Use negative values to subtract from the # default spacing. padding = Padding # Tooltip to display over the item, when the mouse pointer is left idle # over the widget. Make this text as concise as possible; use the **help** # attribute to provide more detailed information. tooltip = Str # A Callable to use for formatting the contents of the item. This function # or method is called to create the string representation of the trait value # to be edited. If the widget does not use a string representation, this # attribute is ignored. format_func = Callable # Python format string to use for formatting the contents of the item. # The format string is applied to the string representation of the trait # value before it is displayed in the widget. This attribute is ignored if # the widget does not use a string representation, or if the # **format_func** is set. format_str = Str # Requested width of the editor (in pixels or fraction of available width). # For pixel values (i.e. values not in the range from 0.0 to 1.0), the # actual displayed width is at least the maximum of **width** and the # optimal width of the widget as calculated by the GUI toolkit. Specify a # negative value to ignore the toolkit's optimal width. For example, use # -50 to force a width of 50 pixels. The default value of -1 ensures that # the toolkit's optimal width is used. # # A value in the range from 0.0 to 1.0 specifies the fraction of the # available width to assign to the editor. Note that the value is not an # absolute value, but is relative to other item's whose **width** is also # in the 0.0 to 1.0 range. For example, if you have two item's with a width # of 0.1, and one item with a width of 0.2, the first two items will each # receive 25% of the available width, while the third item will receive # 50% of the available width. The available width is the total width of the # view minus the width of any item's with fixed pixel sizes (i.e. width # values not in the 0.0 to 1.0 range). width = Float( -1.0 ) # Requested height of the editor (in pixels or fraction of available # height). For pixel values (i.e. values not in the range from 0.0 to 1.0), # the actual displayed height is at least the maximum of **height** and the # optimal height of the widget as calculated by the GUI toolkit. Specify a # negative value to ignore the toolkit's optimal height. For example, use # -50 to force a height of 50 pixels. The default value of -1 ensures that # the toolkit's optimal height is used. # # A value in the range from 0.0 to 1.0 specifies the fraction of the # available height to assign to the editor. Note that the value is not an # absolute value, but is relative to other item's whose **height** is also # in the 0.0 to 1.0 range. For example, if you have two item's with a height # of 0.1, and one item with a height of 0.2, the first two items will each # receive 25% of the available height, while the third item will receive # 50% of the available height. The available height is the total height of # the view minus the height of any item's with fixed pixel sizes (i.e. # height values not in the 0.0 to 1.0 range). height = Float( -1.0 ) # The extended trait name of the trait containing the item's invalid state # status (passed through to the item's editor): invalid = Str #--------------------------------------------------------------------------- # Initialize the object: #--------------------------------------------------------------------------- def __init__ ( self, value = None, **traits ): """ Initializes the item object. """ super( Item, self ).__init__( **traits ) if value is None: return if not isinstance( value, basestring ): raise TypeError, ("The argument to Item must be a string of the " "form: [id:][object.[object.]*][name]['['label']']`tooltip`" "[][#^][$|@|*|~|;style]") value, empty = self._parse_label( value ) if empty: self.show_label = False value = self._parse_style( value ) value = self._parse_size( value ) value = self._parse_tooltip( value ) value = self._option( value, '#', 'resizable', True ) value = self._option( value, '^', 'emphasized', True ) value = self._split( 'id', value, ':', find, 0, 1 ) value = self._split( 'object', value, '.', rfind, 0, 1 ) if value != '': self.name = value #--------------------------------------------------------------------------- # Returns whether or not the object is replacable by an Include object: #--------------------------------------------------------------------------- def is_includable ( self ): """ Returns a Boolean indicating whether the object is replaceable by an Include object. """ return (self.id != '') #--------------------------------------------------------------------------- # Returns whether or not the Item represents a spacer or separator: #--------------------------------------------------------------------------- def is_spacer ( self ): """ Returns True if the item represents a spacer or separator. """ name = self.name.strip() return ((name == '') or (name == '_') or (all_digits.match( name ) is not None)) #--------------------------------------------------------------------------- # Gets the help text associated with the Item in a specified UI: #--------------------------------------------------------------------------- def get_help ( self, ui ): """ Gets the help text associated with the Item in a specified UI. """ # Return 'None' if the Item is a separator or spacer: if self.is_spacer(): return None # Otherwise, it must be a trait Item: if self.help != '': return self.help object = eval( self.object_, globals(), ui.context ) return object.base_trait( self.name ).get_help() #--------------------------------------------------------------------------- # Gets the label to use for a specified Item in a specified UI: #--------------------------------------------------------------------------- def get_label ( self, ui ): """ Gets the label to use for a specified Item. """ # Return 'None' if the Item is a separator or spacer: if self.is_spacer(): return None label = self.label if label != '': return label name = self.name object = eval( self.object_, globals(), ui.context ) trait = object.base_trait( name ) label = user_name_for( name ) tlabel = trait.label if tlabel is None: return label if isinstance( tlabel, basestring ): if tlabel[0:3] == '...': return label + tlabel[3:] if tlabel[-3:] == '...': return tlabel[:-3] + label if self.label != '': return self.label return tlabel return tlabel( object, name, label ) #--------------------------------------------------------------------------- # Returns an id used to identify the item: #--------------------------------------------------------------------------- def get_id ( self ): """ Returns an ID used to identify the item. """ if self.id != '': return self.id return self.name #--------------------------------------------------------------------------- # Parses a '' value from the string definition: #--------------------------------------------------------------------------- def _parse_size ( self, value ): """ Parses a '' value from the string definition. """ match = size_pat.match( value ) if match is not None: data = match.group( 2 ) value = match.group( 1 ) + match.group( 3 ) col = data.find( ',' ) if col < 0: self._set_float( 'width', data ) else: self._set_float( 'width', data[ : col ] ) self._set_float( 'height', data[ col + 1: ] ) return value #--------------------------------------------------------------------------- # Parses a '`tooltip`' value from the string definition: #--------------------------------------------------------------------------- def _parse_tooltip ( self, value ): """ Parses a *tooltip* value from the string definition. """ match = tooltip_pat.match( value ) if match is not None: self.tooltip = match.group( 2 ) value = match.group( 1 ) + match.group( 3 ) return value #--------------------------------------------------------------------------- # Sets a specified trait to a specified string converted to a float: #--------------------------------------------------------------------------- def _set_float ( self, name, value ): """ Sets a specified trait to a specified string converted to a float. """ value = value.strip() if value != '': setattr( self, name, float( value ) ) #--------------------------------------------------------------------------- # Returns a 'pretty print' version of the Item: #--------------------------------------------------------------------------- def __repr__ ( self ): """ Returns a "pretty print" version of the Item. """ options = self._repr_options( 'id', 'object', 'label', 'style', 'show_label', 'width', 'height' ) if options is None: return "Item( '%s' )" % self.name return "Item( '%s'\n%s\n)" % ( self.name, self._indent( options, ' ' ) ) #------------------------------------------------------------------------------- # 'UItem' class: #------------------------------------------------------------------------------- class UItem ( Item ): """ An Item that has no label. """ show_label = Bool( False ) #------------------------------------------------------------------------------- # 'Custom' class: #------------------------------------------------------------------------------- class Custom ( Item ): """ An Item using a 'custom' style. """ style = EditorStyle( 'custom' ) #------------------------------------------------------------------------------- # 'UCustom' class: #------------------------------------------------------------------------------- class UCustom ( Custom ): """ An Item using a 'custom' style with no label. """ show_label = Bool( False ) #------------------------------------------------------------------------------- # 'Readonly' class: #------------------------------------------------------------------------------- class Readonly ( Item ): """ An Item using a 'readonly' style. """ style = EditorStyle( 'readonly' ) #------------------------------------------------------------------------------- # 'UReadonly' class: #------------------------------------------------------------------------------- class UReadonly ( Readonly ): """ An Item using a 'readonly' style with no label. """ show_label = Bool( False ) #------------------------------------------------------------------------------- # 'Label' class: #------------------------------------------------------------------------------- class Label ( Item ): """ An item that is a label. """ #--------------------------------------------------------------------------- # Initializes the object: #--------------------------------------------------------------------------- def __init__ ( self, label, item_theme = None, **traits ): super( Label, self ).__init__( label = label, item_theme = convert_theme( item_theme ), **traits ) #------------------------------------------------------------------------------- # 'Heading' class: #------------------------------------------------------------------------------- class Heading ( Label ): """ An item that is a fancy label. """ # Override the 'style' trait to default to the fancy 'custom' style: style = Constant( 'custom' ) #------------------------------------------------------------------------------- # 'Spring' class: #------------------------------------------------------------------------------- class Spring ( Item ): """ An item that is a layout "spring". """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Name of the trait the item is editing name = 'spring' # Should a label be displayed? show_label = Bool( False ) # Editor to use for the item editor = Instance( 'traitsui.api.NullEditor', () ) # Should the item use extra space along its Group's layout orientation? springy = True # A pre-defined spring for convenience spring = Spring() traitsui-4.1.0/traitsui/editors_gen.py0000644000175100001440000000447711674463546021115 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------ # Copyright (c) 2008, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in /LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # # Author: Vibha Srinivasan #------------------------------------------------------------------------------ """ Generates a file containing definitions for editors defined in the various backends. """ from __future__ import absolute_import import glob def gen_editor_definitions(target_filename = 'editors.py'): """ Generates a file containing definitions for editors defined in the various backends. The idea is that if a new editor has been declared in any of the backends, the author needs to create a file called '_definition' in the Traits package (in traitsui). This function will be run each time the user runs the setup.py file, and the new editor's definition will be appended to the editors.py file. The structure of the _definition file should be as follows:: myeditor_definition = ': 0|ްh+=bb lll>h //0 !@13m)eh ̊ ׀tw~?yP XX ؁)P#/P\ L:& 8#@_vvNϟ1rq10h$334$ӗ/ l@?_@,~8WT&# JkA}(ÇׯYG LFnn_@3`6H $4/AW1 Xǵ{ @li uNl +P13PXmk +d?/~>0= ^;.|Eh; !3>۷X7@ Q#K\PЈ$ׯ>|@FVF@CANRIENDB`traitsui-4.1.0/examples/demo/Applications/images/GG5.png0000644000175100001440000000240511674463545024106 0ustar ischnellusers00000000000000PNG  IHDRfg7 pHYs  ~IDATxK"m.:ZB:1ATL%ftl*%T_@CJ((: :#˾ϳyv|O?\̑_|&"i~bDtBDDz&M6 M zݮ4D^=:MCD nooqzzJ#UU!SX,86~ dZ-ejl²,uijLӄaPUIƞnFvvV˲PVa&J4dbBa #N#qLړh4tnJ0pxx]ױ' G.C.HRəzNDhZIyxx@T?*"ɤ c! "`RJ_. cuu6θfpvv68+LJH$l愈PVa#_gHQA0'N'"1&*GϐiBp6̣D=X4gfØutQUz]. affffbF`$0M`&0L i4a0M`&0L i4a0M`&0L i4a0M`&0L i4a0M`&0L i4a0M`&0L i4a0M`&0L i4a0M`&0L i4a0M`&0L i4a0]"?PE`FrޝG"B:FVCX, m'' AuB/3*|>m'`& Àar#_ghgg^d҆tŒN4 @Ӹa&0}pppt: ]EQx<b1n{8aH$HRPULfi(^/~nkLlnnnH$xx^\.looFIvx"BӁ(|XZZfff!"VVVN3x|=)?LQq"wa@D }b@k=0Ɔn lIENDB`traitsui-4.1.0/examples/demo/Applications/images/blue_ball.png0000644000175100001440000000167511674463545025455 0ustar ischnellusers00000000000000PNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<OIDATxb?% X@Aa ~q^8=n#A>67ot7/^ n##2Ӌ2=Ý$X =t]߉]׿: h 6b{A{1j9w7_~/ C8H?@1Agf5;HI\[@~?_TPd f`ar7@A?CnX|b`ec` ,@+ h{@q77v? gк`+i@ wV MΉ1@T7 'Ö@@Ԁ>mF gd&o@`ydDy /+< P@0ـbOف+@`Xajbvـg9L@ @Y8()<@ iQ^ @ d?` 33$ʀbsgosΕ㬭UGbDXZzN]_@NG4WqҊ8[ >oձ|ɱ&Y{ GY)?Ps-͕S \:̀p@@l : sh; H:%7H_Vt_'& _ m32' ;(+\ 842mzC_jEljEn rsȐ?paߔJ|g0NzFJ a#Js'ia4ԟQVJ# )ݵF (ldGId]L X0y;2яȧGߥW5P=&_6ҷ 2.?ِ>:AJ ´Ab6Nu0>'w\ҹs )]/w{Td3~fM;̫0 Na0BS)Fh #4Ma0BS)Fh #4Ma0BS)Fh #4Ma0BS)Fh #4Ma0BS)Fh #4Ma0BS)Fh #4Ma0BS)Fh #4Ma0BS)Fh #4Ma0BS)Fh #4Ma0B{} 0 SB?/\9ìlCF\Id]|{ 3 F-e;LqVV` xfLI1?SLcćz9{"f&?7:r;Io]ƻO{'sٳEN3>o=f} _HbsёK~l#I)|uw\y8;L 0>IdP+#pf6Rv$ )/ߤ6Q<l; eX[[وt2D[ d;_:۩Y&x7ӹ& d,7ơ\2b.% v| Xӹv\ bκ}Ԝ+/BYƋ`{/7e +َǿlG~~a~#Ғ|V'Uc:-RiL0ԢB'TS5R45~ d<# ٜƖsk:Pި B'rYAVb)Ӣ_isP $ia5-]%{mA++zHL?XDYz1r~>#i}VЧ6P}1m"'~ l6S\@ln(ɳ-}v}/HmkBF)3v/mkTSx}Kl$Iz^jw׮:xa֒3=g=f%HV3|V. %Pe|ڀlÆo>d6 { 6to_,@#"3"2232IvNM32#vqE5hq]?]SuVuhg}xev*5Z7[#UϮ35c#7Eo'j􍂱qsc5TggP6Qǵ]T۝q Zu܆Zk ~vsQulCz ~՛p#7[ 76nBv =r^õõ2ƾl;p6XC4g to Y!=-8{ ѱf?:QZ0F)FkSD }zJzb`7O%D|*)"B e&! q%V }uэ}ҌVknaq+o/$>sliU)v^@ g]= :b#O\ԸpLy?3łiQmoZlL$䰣-vEKb,x. tAn0%Œ3vFeYV~tS J5^bH-PNXbfT|A*M zfȥ*MרΆޤ=D\NYb1pV{5[)=19nb)^S"&)r/=K%Yb]mۙ](Q!@bS(sQ*$2ˉ M }Fd8bZʍ% F%K35o4HN;w@=\-M& fш,V 2ǞM#ag UxPnŇ[KYf c:lWM[VU"h(t(cJ[1JTU"h(EbJю3iJU$e弒&ÁtLFX*kqfKflS``@Mۓ̞ OA*+K2Q@eɞNm$#4<89SiHc՞qFMI1 4&$Имd!:}D]o%Ny! M`z0z]G`LSQu<܄65 f:EWإƩ+ud9@ B2n LOi)h+;5B7M%㦐#FE݈xgC$rLJ([O%8j1z`HT!T-?Dd >XG7)XxʀBtc ےN x4# -PڀCKK#E+d#5Jd+1Gbۈ2)dL:TڳZƈNa"%V(lBQ`{y4A# 05tLlg+Su ~яws A&(*#Foׅ9Tb3MjVgICԬX߶`\4%7 8kH@;YS|GC1o92S47Hk(nWPJ28e=qGr*. Q&դ@[CJf#} e#y\8O97KZ8#+*d*u<2L.f3Lt ["]NB Shr_ض`?i\?ើj}R!@vN]O~( $4jbLɍ.DӒJ$9` bKs3&&c7idWT|J@SD9lX=tTsF Q4!8h3ܜ4fQ[  M^!ezόcI_btb ,lUZK0,vR@XRҩ!SYƅ´)Ձ+_}ÑIኣZiں50V]7yHX^C25`Яt$ zaFh׌Ҍc5`ZQLzRѵ*]Q-H Ky-9s): b0 e<{zY}[UXh|dO|N}Jej˄C[dhNx"Zhui|Iʙ]d4VZD q&eE1G9@P~8sߠ :Fme}4:CGtqD(Bza3o[Nhܜ) #s=*eh۾I ^uҟ*N)@&vзG#4zprփQ'ԉn$i6ɳ-ry/:?#>T%AlUI_Q}z|Dr97s]M_ 6{Q~oF4,urĊ G{D_3sr:VF/=#֤YoNoi=oMLMHG4ihh'4=z˗D<}~\3 سgz%==EIsdQ@#Dղ.MӥoՁ3F! uG{+Ko5qH it?ʤyoe: `?**yowiom3e~㝓wiR$֗Uҗռ/[/k0zON}f^OiiaY!yDOYY?,V!Zp ~何e|be!鹡P> ]|;cAlh_7,-r_𫍩 Mߧlڄ%`eN[sUaCHQ gwۂ'/]HKTYZkWSN'>,YQP1'Yׯbw|6xNH$VP1?-@TKH11g"EAbjd3Xun͡OjvjD=UL@gQ 1w* J =:u+3`gs'ɲ/+(o+pV, %9hbP.*猅y- (I`ad6M"CV)Gyb9K168Ւk@,u=O3ɏ'\UmedIWzNOK={`  ^?ܕ¢m&χ{G'ɨm:3խn[wzL^ za–\#-]/)nQNeGzm$K>rHa_{_4#4l#F>#ЙFwqqY56,jj^2l^lFjc}Fʛ6mP6"zDX c.;B]8flؠy~ݸ2dXc Y/t ek,h20aoҹ].5[tJ􊟧lxRMD ʃ 3uzNy1 wp34J/ԸAo 77d\~ T# >reGS\lx:|-o sr߃/iKA?7c %,`Oa}d #`Q՟-lv>B&}$9D"4; i9O 8<3>dSiHs9eSB+T:]7QGwgLj'ğ{f;@PZ;-p:Tt܄5\Orkkg/ιvεv^ (\s =k ]5ts BCmz@s =s -\C:* aA^\gZg۹uv5t-IOs=k::ѹNtts =s :й5_˕wV@;+r|ӵsίʻ\;/vW9:[ykeʻ\C:~}Vz4t.йʻ\g/W:;::u\yeʻ\G::MYykeʻ\C:(?߉~, V5\#zhx.y#o Yivq%rLK:Axs=OW[WDkk%iuzVIk1G;767EvƯ3v$EDv,W_GOԒd;D@" ͡=nFвk\C:LWCSz"/9m]xTAb]FgA pT@a܇udOy % vHf'ā\5'{/.iE86yhx;N]A1QLj;_ZCe 2=Feu¶%}~Io@ @ #7PE.zkF@Oh \rK9lSA  I+IٺL-t aj96ҥ}a8d}v{k_xA Bl]%~GTLi:Vޒ(A3"u9g{Ok2q 5d!ШB-X8{J}~G+9gS0xLucэq1S7boz!:,].~)+9[DZo}tIQ/En=O_lbFˢsW"S;r䨂A^٦cPC1~*Ј/=%%˰B;@[khi6Z:ҹεi-x=4p9x0QVeK7iاO!θKmN N~v8~lHu,q#u@8n,+rN1AѾz_{H.y.23Ӥy;SӒS(~6Ņh_K \+tAOIknq!B݃u:T6Ua=-ʁoD+bo>}s¸/}_%&`V *v/@h(g^c59 uX]<0Ks zXfYr!^~gcS!r}'2Oеc V8O<9T^ ߕ ҇YtaMJStu^Bh\s( );m̙?0|/`d>yi>mqngor:2|0|ᯩ6jQ~ ͏Er&qX*'#<l4ރVzStB#Yi^? bhkrdVI#PdNz\{\Cߢ+NaMvM'VVI{]Hje;`i<3< mG_e=I޿PP;.½QRf[3]%4vų~ pL¸>ų YEǥV@^*FMX0b+?ZFŒ oNCqiGgnD|o9uIlj9h9e ~0'3ÑX!X85:E왑6*zgE.HydkV;am.7WՐ7_N׫Zz! 88#! Isc{e_6pi펮l=Be67 IIm#|.Ho '9_\=l4sE֗lV7FWaB>BGno}*؁4=rI47B5vȥ6Bd(`ѕ-s\86|i:I~1Z5v=h{;| zkg\ojb"[m6@qa| WXp7~T*>څ@ėGk@0{3*2$\L邮u7 R{^ہp\QpweۀۻWc{\_v,4Z +2UCu` NEa!"w}8hBPywAZ;H1l;;Ѐ]2MLrs|s5I43iyo2-,eŗo.Z78y8ubenWtK%DZvݒM8jKbTjjb=Zd"HR,ge#<8[V4KV2O$RAuPT*Œ84J< vդ;EĚ^I&R扔U+UBTti@Rቔ&2%lG"J‰ @^*Df:2wy"b-WJ%F*Wʞx"Y,쪿AX**VbKceWCX*eTrա2)>;R [2,)VѬXS QsD26^vRȸ"+6"d"IzLI$U2ͭ)LY$SBi*r)H"2LUƴRD*)#rMJU!2L薱I6HZ,Dzi48ғJ%qSDFP8V쥳l@㙎]-P*N:߳D!Ŏ:t8ҖNOXL[Wxښ58B֣'ıRD%!ڵ-I >mkG}`xBBXށTMem'PZ_\\}j]21ݻHlp u`K#8`A|6Udc`󤟠 `E (L- |0wK{맪Utݧ:}Q`]2{p|隃Tg&5m@& a}=U >d}Fy'=σ7< DFOr)Muat5rEXJ+H6IhX@g2Z !}y}7m%o9<{)[K ; Va<  gQצ2{76I? QO%JO[{#蜸;(ixdXڟcx2t#9$H pB:lmWޗ1y,+j< E ?w๨ {75AGN3mOm{:&uDh7$HB;dm  Xxl. veOZwI$F B\yJFQOnxD8X G9KʾgwL I,}TϞHVs*.)?t }5 jKg릟@i=At MϹ_ܻb&;uj^@k9D!'q4 W׆^!?ΟQpݥ˥w>;*e:OSryrB4~Am1d 'KecD~$pg/왉5>}ĶB'tLrz|6NY-#N}_y`zUt$ÇM/U_ 8ZIոvRaڂ3O2BWPn=O?@ M33KWxrdzaDJ֥zPgu^߁W63ޟ_[+|l>tKC/'w^uJ3Õ_d6=kq%qm\BO#b'o9h$aVy,6وDy><^N&q"=߀O`~m<U;¯vk# _OZn &0:՝鴂/YiT1D?WE/GzR̳qil8]1,= vᎿ<}CGf/,`Mlw. a4DN湃Z~ ZcQ&VZkH@ tn3;i|bشT\ ciQ}kn [՗0 tXo.BWb;bHq_6%>HNVג}#jV͟B0XRB>J%[\ )z\+W%wI˿PƸn=n[rաWWȗ}AdR3O$fDM:c`ܿ^FҝGtas6%"B "-t*Aʄ?RQg-dDɎE.Q1mzL)G@I!qN L(9ɝJOwTE1G(-$o7Tg{Ex<蝬% ZiiOJݚ)u{ԝSrS4 7)unmu:]c(ɺ3I2K]}q;H⍲_+X1^ы;:mRbP6?u죨V1&02a!6$b=lQ\1sX}BwlGM)lhQ&7:t@={ }i'#32ckZd&y tZ(MIFOjKx;dUApV ;RVCga|GhGZ׻|?.VH&>P48͚ja~u,ןdҕ;C\ɽ]k;itntuttmt4Zz6ӕI쁵`X^^09bV&,UG f1Nria{Z8z槅u<σw\gӪ]_?nx$_xK'I.,j9fSg&:SZ|QiE^f!W7&,k&';Ӟ'|6w>knkVhl\#epxyy&y6ތO# =n߀5ʖ=ʶ3ʎ6ΓۦIҍݧ|dLO"%],Ɏ(ɞzI3eT{6M$~M93 Y?; F/#w G˕xzET99gB2NGOhm=2Pipy?e2xM; -PhS4ȩZӁ5!IS%n,#.5JhJľBLƾBYbX%z%e.uJ,Gہ^!v>P}zNӧH*IUR:*V$ KARra ۧa4le/h8 'ޑ|!eqJ Ex,`t?6?j6=e+znv)]<f*O`wm]G8sojcjɅtr%\)c'wG=A)W='ZmSG\Tte<^Rk#2ǫQR.,':2%%ÙċGa"B+GGd޿lӝާ^[ülʟ/L&@HV]/a}Ӷ$x[ّ-$i$DmMlmkyޟ&OY[i9*Zg2<P&y <&ydiuf+;JHM9gcV\eo/O3Tts1詮f&UWegG,cyE{xM2:c̑,|N'^bgIZd$M,B/^&/ICQ/^<^ͺscz3^r=U5͊'T=ae+C߂SSed֑yrٟ)ɽZ[)[y:DԼc\ڒM <1g1I_틙,1)E}1yc6]g9-^3q׈,'TK3Tts1.z52y?3qc?9?HM/z_2ܳ9:a$_i#ZUq7!;|'^b.ggND|͟߇#!;z{rGqj;w[5tأdnjX٭s*g[F1}<ո}CV,Z LzyuJ̒'m5mkjEYI[8I;d'go|2zgihlOF2'-}zgu:։б[wYcֈ,d}M(~M̢=#y{.zn:{vo7Ccy4Dz ӵNB|Ie' mLՊdF]&ںN^q,c@[iuii4!.x`_CFdrЖjI<'#"MwA% 8 d 1QW `9} ļwvFG+|A}dP:F%=.(jDĭQ+W.\^rMjD'b$ywۤUol[IJVq5Pv8"5=~#ةlʵ"˵gZY3rr_Zxz%\)ۖpGeKqΥ { {~+SD{9V}x'@wʨ> "O?˰fP%aϠ [*ÙAW+ǥcRk%')~si(e0-HzS$_bNCQP}n6G,@7cf=H` jQf|DK1TďS_J#v֣w}|>] =VF^ץXq]`UڙoIy +`i.440_N{(=T %wtC)aH6rCȷLKU2@YE)VY0{d\INk^x]3Xg52Zp `^DhcTGzc$Mde}?DDy#+ioԣdw7y,'!YXMdzԓ[lZm1ud_7Tv4|5w1IWSPלJlPTs  Cq wf, wU}c3RNs"w/k e/<[],mUQ*+S_G3b rBHMl#iK[ͶF]m4Nc4e{GxbLǤ3:֏h*Ɖ`}ŭzL}ǡϧ+FIJ}饔s#m)k3l(-/ $Tt{Z3~2L>;=b>a Eue)oqeu(s]*se)mS^cK ;VS|f,bmQ?ӓrglQq 7B]Za*D:$|cG8M>xj4WV4]ƻ52ņe8%A3=[E.;~Dc!ntxh]\7Wvh׫O{>!z+ kn7з_Wyrmt/[]R*+жŪgyNR8G]=A2c0B9;oqtj M*z%àx(@Jb~qzܸz3C/ĞZ亾3Kʱ&`s1>~m]\_V Z×qccl/#Tz]?]SuVu 7I 677[ëjil`qcg@3#{mt;UqscPAe\FvQnwƵ&$jqj-U!ᲾG lw iOބjqM vK9طpu6mLfc߁Kݴ&_ؼ¦ 49)?)BGqO c'1 d\KrǭƗW[-E7I3Z}w(mC riU)v^@ g]= :x"GຟBqI]/yf<ӢRW]oZlL$䰣-vEKb,x. tAn0%Œ3vFeYV~l>r=ՕxkH!2 F8Al[968S0oU@i$͐K=U>Q I1zJtING_ ǧըߪ;>^OOMt1PGS,DLR^zrKڶ3PmCĦ&= PxQ*$2ˉ M }Fd8bZʍ% F%K35o4HN;w@=\-M& fш,V 2ǞM#ag UxPnŇZ4L!cCG R`Pc*JePelc[)p|V)1 AJPCќEHXL !818z& TiJWWr$w80ә)H!FR{V%36ݩ?00 &oiIf 槠pD[Q%WYU(}Di{]Zd 6L>89Si 0}>p܌4jLI1 4&Ԅ=% ٘#zs/q#y!o"׋0P<G`:U0xy5 f:]m`bi\L6A~jS;ԝ*'s сx#!lG@ЛȒqSȑU #nD3Sbí_b49SI$ZG`!43> =U$U)|KpO;9%9ƑM >2tJwɺ8f`r% P0th`ii3](Xv}`6`R|\|pb"r>-FvWo#:835Pm jϖk}#";aXZV GU:d_'/,h1iBpN,H7RG?v5"VR%# W@D8I_[>SQt6[X:'i Qb}ۂrt2ଡ#dMu .ӿWLް#p]A*GqȡDVfm *p`W.Aߢ3G~)|Q+Yad~E F?wDO$J.f3/|Jp-.f'}`!ob9/l[牟URf -VI'UdY 9W K|H!S҄^FZ珫8x1%7>LMK*̃6U/}lĚHLޤ]Q) Ma6gy_O`QdG~: ʇ{㰣psEmdTΏ6y$ӗMa?3%}Ia&2* -%D ;) ,)PԐ,^ BQaڔ Ho>h$IpQ LRm]L}m), qPɞ~ޯ>`X 2HA0EZ3Pi$.Q2 Lʊ0b r:Cp斿AAt :ht4"VQ"fvE "6: N89/SG 2+zJc TК+d})="/a+esgSJ(9I-:o]$>mH;͠!`=97Qzӌt"%V2hdA؁}t^IO!~V°l4Tɝ2ky3JJGɄՊ85TZ V*P\ԋ؄]Q1˥t?r~CpYb̚ނ8;]Qnqq; L&!+ RC &3౲ DX|¦_ԙM$w)&wi/|3^=XzFe#INV*]Vj%o Bma]uhȡut]Bo 9B0z*3ew6.ICF"!tiCGD>Q'ԉn&Ro6ɳ-ry/:?#>T%AlUI_-6ѧxMG|qR_!=f/@>NX11b+!~fNNH=WCb~ߚ0+OC-MGM|{}Js&[vHvMӣ|Isؗ5Cn=;y\snsYdQ|KEu4iWʻ4MU 4D]./,0ȻמJ?ʤyoe: `?**yowiomyKɻT)Sd*jޗi-ڗ5L=XwSS/4 U!S`LPx[pKiIUS5Rk {#>u}0^Z{ȎT(AWE;><`|q+b *lw䇥qȘʘ F[E1Sx2,:7'^]5;^5q垪c&(;KijE:γI_܃8:IFm酼dɭnluC׋`Rg3(&iRWQLq2w*;z8 n$64^(dCg,$G ڣ%xa14:79aQ3V5NabN8oWMno?Hy޴KB%H=wc [42ywᘱmcu(Ӓai*Cwlx RAI߆S_ =B+Aq-3- SHyK&Oio RKDyʆ'DT<~ԧd?Ni6O &ޢv6xFQ7MX!p&U˯!ޑZjs R¢sz`|*˒rOOOse rX{% c)&q) LpD,s-}h*'Ws Mr/%H; sImsD x%ꉮ;Di7Pmv5spy$g|vҔ+\sr- WuNio2ώO>?Exvw8[t.yj/ADe<5tg\C:VXCvs=s::ѹNhN܃ε쵳k\;9EPa5tgK5t54n!/Vuu\g:;W\CzZֵ5묡Zr9_yk目D;~+r :_yk\Chq]AG+r41c]A;+rk41g]AC+r kh ur|]sƫ~}Vz4t.й4JOws 櫭;HU }^e*:eH-!w:k>-9X1.Q=Lt|X_SԒYBVWSDqlН& (-.^Q/`{ eqQ\6^)` {*n{ Ԍ"80FdN<E8:yh;Nu>J?ImkP[k!ԀhǨSz؛z~2_+P}H| v617x %'J(p^zk |aavPHE?}{չETE r# cjOn7.yJ~17Q]>,].~)+9[DZo}tIQ/En=O_lbEQ9U{OBR+)p9QH RN1OUwhėn HeXwQ~ =l킿G*v94ݝ Q::D]'עxEh#> VF:V汎(q$~z#2£wx9Dg0]r69 }ڏ0g+];X^WOG |-,PW݀=3F g F:~E!{瑻8DGIv`yJfǦJuQCc rpp .kp{v{]">}lYQ#Hf%>Qǿ}o62mUb\̢%-]WyfI#.2joȣyT"J?*dxq6XQ5D9g*:/:{,=[2-h -'kfDRȄC M <6_Tx˟y$mgCC?cF\+7J uKhڻ?0zf' ~ͦ㋛/,]/$/S3} ~]fy_+mZT])-߃~c{C=VK]B  B|؂U.ZWCϦ[>^/6 q-='||7B"/|'2Oеc s"z6n_xGJa Pc6a k uA aNɆ,ѭ=|Ґʜ=]'u kOkGx-,[} Eyv_nVzc]mW^v>nD^;N*d~5 xX^}0v}_3^1Zt@E%X_c-1ΑDpAcZQg[$=7=r;W?GNǨ7ܒr$ ǣt%;tl;:oEUbvj`,a92ar-kᛧ+Zx#ZxXk_\wFWC߸N~u;]jk _O@1Hox~= 8҈%fVZ@u4J&g'467W渶7Kkt *vwQkMHԪPu[[ppYߣ6نD4jq]mB"z䲽E9pƾ5l;p[u\|L߆H`;E AŧNX'܀$&yE.e~Tb='W(Mok%g/ۨUywm?OxQ⪾[߁J7v%5#HM>XkK 7zmm~m P YG+_[>4pm|tulcrjNÕ{vZA.;-.ζ;l_;-Fjb,/ ǏPGPvȡhXp0{3*2$\L邮u7 2d{^ j7BḢʰp`at( C 6w'5z $,AءS. 0!쀧tq]6L6Wa{Jv;C>9h㸃]d:p6MLnsxso}xj\K=C&BpˆŘorSz-|bٚto %߄4jV$/8.i0 "Y닋ZW=c~>F{ cAwi;զ lgLxt]Z!SsAnɑTT]:!,=xON|S!]sV8 ľW evdd!н`/ϠoƽM]һ6GP:H#p~iq{x*lgA8A3`9'{E93^uM)ѼzQҦ.H^M4↤~t= 8Ѐ퓀Ph?8ܾ4ASe6:ٮiSNC[1\k0O9)W'K>gVP ڴݬy?يqN3!=zㅾڞAmɡ'}zS_Q=DZOHegxs1Ul=:5RQ5p^ǺkCF/LՊpϨ 8 ҵ_ѻbO2De'pl)ՊG|J9<9m!zge|Ϡ_cC21"h?C3Pgl5>ltĶB'tLrz|6NY-#N}_y`zUt$ÇM/U_ 8ZIոvRaڂeZzxow o͟<]r#.# sx'RbU=.~wj>߭C-X2߇Gͷ̟J^c[ i>iP2͟ "&2DnmDs}k-Hޟ7ug'zVd- ?_#h)zBd;G؜ڼʞ/~{2l0 3t6?O1_dj⏾??xï?C=${B([O{GD5yoBcZ8~"!F=#qY,(;Fh|v/cL>y <F# CcFm$yT,WgP^q4 x3LdVGk4ƨ~[TOj}rd0ѩ,O|ɺNSp`5&GDW.z9փ0͗JeK_ve؏a w x :2{axylbsIe!r{_"V2^4Fb0wCh@A1LæZ@d#N{玢s_7tfتQ3xK&piJϼ#@Rߵp?(1?DrȫQX=ldjQŒr!W*Y5 RXHNR\(?.;H\-2EvP=զW^]!_I7%GߤԹ!tң$$ɔ v,uя 57~cnjzF/jHķI嗋iNCiԱ@[\?[xCkȓqKGt8@uDqa==NBuE7=zG,!P:%rP):mJVԎ}5̑RL4:hP?K1Ԗ8vȪ .pwdi㥬>ϐ8к8.w\7L|*ɡ>ip5պN2 'ReY.?'_7ɤ+Iwz-{ɻTywrكڃڪ؃i5ӵl+Sk 6a=s4a>r".MX.f!W7*,c&!9Rkak)pϓ竅(O x7/ﺹ&ΤU~|]52GIr&N2͋,]=Yr̦N.,M=t|46a6ӎ6!+BnMX֨M>NwK=O:Dmr|iz"BIF=*Ll"G=AvF{ݾek -%e{ m%eg m'].YMOO\$7}?wEJbYQ==g؉mVIvA.=rf@~LwZ_>Gz+r r+.e^zzeD镡~IpevZ[.Ц`/hSsjBJKJY"G\jhєr}$%ә}\MU;İqK"K \r?X,Q5"#BZ|^ہs>=mOO-]ő!T~->tT4H"[AOi^Rp$N #8DC$$CA=X~lKծmܧ#zy>8kTl)ʻppȓ (ѝKSN`7X{1R+{Nõڦx= dT%! >O SBWWSPNљJǡHL3.S׹U/g#\CBmLctF`X(9[UEnU1♇iqYu6 WV6bxs}x9>yt}эNG.eDW$]nYNtd,JJ+?3Iw~>ȧ%D"WLɼW٦;OyyU?/>_.3lMb&+VE_mI&&#[* oIHښDG?kMĿdsBU&aey'$+桊'LP&yLJ1<ͺ3 :V8ws^ϘǬ2$^Sg䩪&cS]MlNۗ ]Ydyeju#YPO/ߓxIX^$MF/^^$y$uw0t#% Tg{j>Nz o]VW%:*Ȭ#5?3R{Eӵ*$Suye%6y8cb3YcRzblrZ{ 3 9gY/Of䩪&c7S]jeTeggmfesfsOo'摒s_egsBu}I0vFo&׫nBv2NN߽R']!ߝR`u=8 ?GBw0-,9$vj2G'ɒe&B[M=:Ufc.xq ;?f-.Xꮕ%O*jkծpB!o'-vNdMn]LVٞH3edNZifx(tcgy糒ǬY^9QE{Fz3 \&Yptn iekӝʦO6v3|{=:; «܍&y7Mu4}Xu)ǀ(.> QiQViwC7U]p>%!:-Ԓx4O΁GyEJX4pn c5\_?s~y֍W&t*OJz\P5Ո[oͣW.\^r{嚠~jOjII)ضHÓykSpDjz!FSٔkEkϴ\;\g:-J̧3(S-R8&3KaW(&/ѷsd©ۭO*WՕQ=}NGD~a͠ K*ÞAT32 VKG)ܥ2rKNR4P`d[rBI9K߿4 R Ĝ,5z mXto \-)0}K{9~;%"mԢ0Iub/Hmq˧FG}z2?}?KF1&Lqx%Hy${ZOW-tBd# q%]R}t"<3$o=ό2N|)F׆bN}駾R{>P!+1 tO P2AA5J~֓_!jAM,B X:Qc!G m$u t~V$Z'J%\S(RV~8JC6\lW;YykAdcg<3<ǁQ:Vi6Wz:bt-w)3՛s9y*>RemIU6U1vwVr\q=dl@mu$vkr^VK8Q$'p[Ʀ7Md\axUɱ[:3֨[J]hH=tt|>yHS?fVGo|E߯!tpQS wia!w ރ;Լ3Ƴ^}&OܼV@sw=UIO'-j.jF  @3]x6lq5]u *u>XxD!aXiZTg4=nCQ^u+3`zNC , CA!\7E6 t-vE/ܶi^(~:G%0N321@6h}:KA{ i B9Gt&ٿW3mkBSx]N0Æ WM- 2*5X|DZ=fLc(F? hҶ BLrGpodgd/e>f 9]WA\\Lf[xilϣTs1H QlHاEt(SAZ_Y X mkBTWx흍8 FSHI!)$FRHnw HYx3ꇤsaaaaxIǏ'U{o_ھgW9 o'GW {>~Jlo߾)*/N\ϱov[iZ_ձaJΝ/:6O- 92b?Tlk%?_21B sY5>:>c=1Ow y^- ڶ,XzusM#גU]>H_yYv!ۉ_mi Rus]Xm_g)YY)m]y,m z1aaaxEߓGקo/Y\k6xjgH|yu.\aæM&wk#ϐ$?]Mo\Ⱦ,/ڥQ@~6s?)}, l gX #vQg Bٙ^uのuhm?}{].~}v_J;xogJY]޳@.)oqC?}>@Xߘ'-(W? źvƔOʙRv[K?[A}?-wmՑ}g\=c}M ggg DŽ-B^k_g?F? v0||؎=ǧHPgs/hؑI t~{n^}ZyD5XWvO)"c0vY Z|~_%/,p\ɹyΰZ/;/xs_9?Pܯ5ݻ\[y|č8gʱL{? 0 0 _k3>z_\S |<)b|7aaaxn.ta?l^Cvkؽ#~e)3<3^kdlc&jK+o"e<.ʞ`^(3zu l+6v<ï k7]/lc[`On}򚄫 G뎱zt^v2)?;Wmr5ocIz?Ozx{&!ez."ѯ 1Gg{+ҏlw<=}GݽFƨ^)zIpG K֜{{e G12ۭqiumf>.}~a? 0 0 [u+7Svq֭y΅ ?ނ}XwŶv?ߩDZۓ-q/?߳=<~#>Fk"qzrQo 9r,nY[;o:)@-`ק-7({߯S@µK9֠ɸ>:n3 _[_*mtcmC>qSL=<6;ǫsaaa{xˌ\ފpx?0׋#5zяc]x^l򼠕(f:~٣^lin59W~\;?vn6erUbS~v^U O7O(|;+SG4|?f*?rW~2oNٟS9~daևmH6mX[J~s.ym4ٶO|Bd/b5ɿyU? 0 0 0 0 0 0 0.P~*1@G\⟿KrKXs2(ߥ纎J8'>X@▼QQbqwx b)_K|v 1M6kee-2Ǜ59?K^E~9ϱQﱮYF8N?~;:=J<-tĒyNAgC \NXKs)'^Kg\~2}6}Գ)n]Or^j~"{p29w6/.z-v:+M{WJYZ굢`% Ҥl9ힶկ#OUz+U?;sd~vND7*.Y+v:ye;8}~|+ÑޅN9}{Bƞ#txխsXɿkSV/uJ=o G<ջL'L:D]6jfgLz/+ؽ[{rCMYq~[{yy czA;w9zszWHVax3 %mkBTx흍) q ĉ8D^>׻gI@XjjgiЃ`0 `0 ?ϟ|:seQ3|ӧO|:2|.};7eGFO6_Qv]T]^ˮg{>pjzkuo{yye?{-x/ D:3D&򈼹e^Hyi#/OGzϪ߯_~ :sMe#M3Y#=2 QЙ[\s=E8}E>GȩT ڲTg-}VfoSVwzV}./>~!?U1<#}=F[ ~QڋBN..+푹^edLo+[\-k dW(}6q$#?z6Bөi?L7!3O_Q}Пuo[=tkȋM!'}/Ƈdr2_Cﲨ: `0 :8o=+8-4}۞cĥXdq{bUq©ήm!ƶg*ΪU\z[GA=^+ru{LV U?)V>ғ)x|Yҁgi\yi^cUo*= !TY?rfgWsʽVn*VX#=Fϫ+[F~yH\L~[O҇h5ݵTow|Sfӟ+);F;:x )/OS yUo2e)Ve3'wgGg=J^`0  ľu kU,Ksؑ5nY,bXw{ w&3QהNQev ]ƷgcH˞i{A3I8hwduwUIWq8I>+@pQşGcZ\ƪUߝ]/:3d;ɫ:gB9R|GW~w2;fzt|+i5nΟgZY|<1NyŬ|E7k?z/k><=Α}N΅>uWydʬdz `0 *\?W8GY:Dgcg< 2+'W6qn؟{ru"wU쏘~c#T?+y{Q,,^qF/Xv8.֩g3}ȸOP ~n%hUG4(_sn|W}Tg&x^c,Fѭ+ <#+}/Uw8BRh_|33!mr\7U9m({ѝpvew[xG]߱?g;,nҽow8]וb?OV=Z_#ve?vN_WrYLo;1g9pV^G~>[_vNOS3 `0Q[ veO\k^8֔v<Zbz\Opbn$~}oz3ј mK vU]^iNWA#x딫jt q :E= z%օq)CcYEqyRG-+u (K\hP'*^ء^q=m=y|Kvūe\rȊ4={W1;=ݷxp;o@>ȘT\Ԏ+C=*ɫ|GJOCW]x1.ﵠ9_Eб Vq)v(ʑ}[GwǺ{-oSdו_˞׃2;iT&w*w:g׭SOsj%Z[~_˯d֮+w]7 `0]kIu+eL]ւoA^;=GR?v쯱;<y o$N1紈=:ߥPVu< <&3KyC/4r)i=*/|Ύ^]QNН1qGw>ù{ ?Kv:A}E:_n+{u=rq͓̳]>>d}+|L01`0 leg:׺񶊝`W,3O?]\9P~[kOWiGc~)-<w.3q}'vuw$Vnv(r52S;Wk_Kϔ8B/hEՠ'9w?K;x:x<|@cϽVyc@ۖSw8Bq]=2lBe6V}eR( VeZT4ade2ޒ+nYBTqSߔ<[&=f[|szP)G}{Zׅ3n7jpWwftEw[ǽ;`l? `0 `0 `{~i`oLy>uoi\qK|}7Svu9G쯿c¾#>,jow{ՆݲL=mW2u_8دjo?kD߱mw>#}E:OۡO;y`$jwymkBT6x횉m0]HI!)$FR?6c>>~sm+vuՑνYu8uN?WP>1JsWiV_uKEϸ/rˆ_gKW]ױEYcl,[TYHT}xL#}A GV7^}>iҞ-i;}LJX&TP3T#ߨgJl e'=?͘ona|7>?ǐU%;/mN/IfQփz{G}?v✽3X~j{zTAO^ʰ>?sy|G)PU{ ..T}6ڳ-F`p]k߅~b  О$wݓٱ|sCoA+q3lOx@(0a+? T,_7s\Ϙ^Bl1)C+k(FyN"8dPC_9>O0&l4Im+nwGrŰ)/tihf ѸX>E)<,6s45zb?J\<OM%O#(76:= ӋYAƒH Ls6MXBcX&ǘJte. 3.je(??Lj=%wZizFTx$kP8Em jAOހ>~؆B9 ֤8UKCvjbL Cy ;mj P. DkwUE€3ܨ8xUJs\ɟ+;}sFQ(KIXݛƨ 1 +KdX];Jģcx$D׷X`i @l̏rnm$^9΄zBGϞQ=nfkDe; <a>,⢞jk0B[p($Ǡp4 nq`XƓ vϵ.xHnorJ5Hu뇗 f a[Z:>36[g RL؍?( &w.7C#~B{] UW 71jk~ecGrD.=K@WDZM0倐0\xvqNZ ># BE )&yA}t?B Ym(WIpɱ |2+\2 )l8tl@Z.Be񅋍RSƃm>dIl'N adĢG3%#)?$s _5=YBR#-k"qGP-e"f%֩-ϓ378M9ϊ,_*n;HEBƱcl~ ˝[/sagIE2,z1t:kLș壋G){7ond{@rP>kwk׽ #kXfyEAB9uM4P=_lgW؇N#_nGpp ,ZUu6ȓVӰ0EK7*|]{75F\ԶzQz! uH>upT٣o3P)[^6` -d&*=%fY<^ط`_6|h3ء>2 Pq7ώ ,NsjF=B` 큳CiU)R鐏@LҮǧmb<2FHRqùFXi䎲OmGA}:*u f:@ʫRH.66jcGOpO- 6HKJU:Jǃv,3DZEƮqq7p?ȌK%ȧ$;?Qr6pP7`a^=R_)m>D3#£ _' Iɭu͋C-Rne㯄ssL<ȭ/R)|Lt_1Lk=rr 4/gEr~PnB[\g[{gYvRW' {Fem1{ wL;7&$xc0 n&u@5sCCձm8Heft x{q(aтa?Q%l4ςxmWI׆GC1kQ3iJh,KRO`ʲ4)%b6B8\pe;u)ko)#WSncRx{[sXv195_0Kՙ7>Tp5ٴl3S"؝LX睫[5m Q="u}pϘ*xbՉ#iM+@Z! Ϯ~jYݬ$?5mtu] %@݅:4h8ۃtu3; ΑO1A/r R*5i&j#Y2:$Z(ad@>'z L뇶6Z8|`6"X1_z' F-я?X^ A:?1;h/KVB' vOnFS ƤQ{=kh7MwXQp\v͓O/. N3HKRlK"q^Wh1wt h@3e6N|I;y?8t[[! $,ήLe"z%IކAkRl!3u8ځy?_W)AbCO!rza5Sn֗#<43y6"R߃CQ&>[# BHǽ{vekOTlq(UH͵h ݔ8,@tՂL{p/*L"d_y k,4 G̖bD>,.ok"D;|7[.DCA#ilϟI֬Dq]+eE _-- ڰc^Lq1~CCC9gNH8BkhJ#Z-`VoMa 9r$պZ-hkh ?C$ ^tď9d(8P݅]ڶw[wl;dn׆oKd Hބ(DInI M_(5)6H/Y1 QRk,nXHʉ?>df&6^EJmt{CCc`0ʅv5x<\9Yc}106"״!֏9dl:' 1H"z'7QqɌ#KR./CVgQȬ\ `?d1yuM6Ƶ8ZX]8^pwQE &1frRKi$GݜЕh3'{;;~FK37ku<pdʎ+C RMzƏ7)nҀ lEGyl:̑IoBS%|ЕsTulebA}Aʹ10A{KʘӺtjdLI=r PRg_LbR Şl?␔)![Fo wi&k^CV(t@pW2{hxHGRn͉eCbxԉ6GQd27\ثdS=\Ff*0ۣOP5(rZߙxQZ>~GAeN-jY7Ҿn;n?ӹ"Px}/NW:݊&׾:x" ꭥу;R펔 c䛅љElmG§a= h¨BG_uYnZ쫭FYs U"zM&:Gnu.DX5Xn;}ԫ%XO?~2&Frjj8 yA*W I9/ub)Zl: s 85J>~iI3Yԕ;:#hELם[ROd^GA˩f~Y!En0~/A Km>^WYq"<цF*c:xw|͞w%ehRgd9̕v3v Dgh>>?3hYDkgC(ʹƒԕSԜ| 2Q94(?OGQ34 fccPopTYaW(>@tX4`LGٞpɄaŰl\[9c26U M6f,'C4i?W~psϠ?kAKrŵk@I|>^xs?\`,D̒5W^w DMXf_8<%|8_왉pP1Wlm߃f?4:́_Ԕv M;k:p_sj؎qw]$F}y ,b'N=o0, ~M YR46+!}@~ujctCP.Y(x׎z?70WXFܣo3z0c8RGg0 TU򄽻w"/4֏CQ`[{Ocn]+{{ N!33+5]qpj' r9FDȬ)~: 9Gmx2-?sraG"yvUpa;Ră A\& ?#n 0eed~oq嶭!!DzP^H)>oȑ.ļԶ=Hy7S-M ?8ycߧq|#5"2Б lm#UeΤVbM͘jAc7Z ]> 4gb s 2WRsKg6 's8qzTT[R[w)I95xWj #!nN+zPڔ KgTE,?{^RDݥ=Ru^zîc&D'i74SJߔ&HUG[crͦ<׿~4}څh;lpAZ%XZ;tQ?yk1+Ƴu6[ Dc4Ɯ*dB#!}e>samhG3c^8u9󼵕⸈߂UyB;f "Yi=D =4&|C3g]~WgjhSIXU"1A5Fr4{AljwTt6</N \Rta| i>T.Wo>>xϯY{緷m,J{gg}v~)]s!?wXGFl!7U|Cnfﳅ:.@mq%臔Ru?.:aBֺE#Gg'yXDuSWNJD)21ѵVagWPqȒ s?¶@g")s\T{f3go^w:^"{d#!φt},nyWFKv„X4|VB~,˘_&fjp/WԍwaO H 3I`u1ͤ+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_Wݚw)2iTXtXML:com.adobe.xmp Adobe Fireworks CS3 2007-10-06T22:15:44Z 2007-10-06T22:29:43Z image/png IDATxOl&v! vtibۢJՖV*J 7=T=QjU@J(ZuѪ]BB 'NDZ=37c;dm1-}ӌ'{Ͽ20WR VJb01Ub \ne$9z߬gVF~W] y3^{>l*`GLY$x+ JuݧdÇq1+q\qR_kkх~:`[xAmW$ ۩oL&Ϸe +G[UL&$Rk1F &{BACcuֵo=zoܸ1dwψDڟi`q|L_ϟ0Ưea^Mﰢcvuu}1 h*$3/T,>`qD" |(͛w;vl'x ;0C\ZhȌ?԰ 0?}d'Fp'rС@ H̐wb;Z/;=myjkk[uwfl]-A SI cF1Bktww8娫R$n*ZhQ>q c|| @GG;v.ب[D]7O:u~+RWW߿Kخr+nPh gN%M=ʈ['Zj[KA0bQxV2EoۿٹԩS߾}0kE^fA>'s3444q̙ON Adobe Fireworks CS3 2007-10-06T21:59:47Z 2007-10-06T22:14:15Z image/png n?prVWxZnI8Ѭ)1@#. f&# шK)&B= ȯ K< ++S^}q<V]\sٟv OOOi9'dOʶ/)dz ?AxKoc[C3S? hå 96)v[hg)v9F'2oe[snR 6kr}}E-W7$2P_ASmW` WaWgkkG֮,s1EV(Waku{ 'Llv]i= z=_5JAk8R"/а+[$˟oIÇ5]9Ub{NBbepp_i!܈K=';9g]*4um}|ҏ5\@+p/D$2#<-m0?!ܛd:ew^G_HEG2"~ApV^.Ͽl癣/m~+L:vF=h9>ا3u?0(.B?pMq:bPy?Y#m+q!j7S+&=([?S川Y"ty}|gMЏ 7gmau=??_[?6|V3v胏kKG6Eh<f#XfwbvVJ.p\@g.j+y3%,N*:/vF#H&|?mzP(QY#P̤B- ,3P{t(dphGHs+8 8mWƏ-`` &㙵+P&/V&>.b ̉f) Ǥ~5} +.wEJAmZ-"ycԀq4+ 3`aW݌F# _@9;/'Ln-j T!J;b+@?YM XkkG֣t(cb6) .I>a9CW>E쿙dV U;,iG!y/Q R%cz5dӒ< A!T9pFy[D:sȨ,l ;HF߂ڿz]%Lc[q3+acktA䊲E R-Baf}pcQYׅDBgy 7JR4>ū<7XY`|6wZ+1 &ooELp6­aA>JYj֣`zQqwc0 i_|f3JFɟ~: D4#O(@i @w>)AV?BTnKݡJ4 oPU"c,2]@;B?b5|5 (LDJ p%%[+txu bg QD.+yɊܙL󒜍l/sDj6V0'&zL 8d  .ܓ,.$*p,._jF0@GGH/7kDhõK'0B !#1\5[~Ȝ$2TW쟳^.L`a֡Y/wW7(B so,YG%-3~EZTq ڠ6AF3HNYgdd iGK7uQk>g 2o9[HQeWh7pgۭ%s~jF:#6*\g$.in:W_.Aԕߩ.XA >RfX?ˈ-k s.˹,CU ^cKb=TNDuub5R/>jzȥ7U&\rDE+<) {:z\CPdv툏}lA`ƛ{Sb?)r:CGhH_=9?"zΘu Rژ ӦT8w R^-_/C`;u> ~.;V[&vo,}/.޶W]jسҹgC9 X1/'V^)}9cxX T}J(ٱGk8 7UR.6d|2Jw(4A1K1IcRilNغT[4]*{4쫊!g{uAל|:%Fa8/YGwO"E n9;aIoߙ]]W7g)~]g)mrRk>Z."M8t#w&6K66a ek@zjT}lL1E}l`dž9)>}lSOy! HmkBF)3 mkTSx}KIz^jwg8|KkH/Jr|c~;fmUsȞ@ԓ,MM{Ze|ڀlÆo>d6 { 6to_,@㏈̈Ȭj2Y3UD|Gl5{gzudld0{>9g{rkcrw79ig޽)$X$&o~yց?7wOZ5·?ڹO.ıVz)gݍBR 5.p?[mb^nemo}F`]ЛΔjm>ܥw{;l$!gwI..!qKnpq#2CZn# ڷ41sYffYTl|8(ac`3lRl<77:OSx&Iiz/c]@- 3`g#0R#nfMT8_t"^g>ѫ; 5ǩ5d ^Qjt&~r m?&atat mӧv 6by?͜S<{$0XJ@t#o$ Z6BcShl M)4M`k̢. | POvD9=#"R|O透t4# ȃ!7{&{A~Hje0HŠtig\`-30c`cQn8V0zabxκc6)ѳ,nKў3ʍ]@7F"7.ɭ 3(@?9T@~@r oM1 *alB(TgFj@y+ԢڅЧlr᳷Fii(,xiiU=s|0AԵҿ:C~6ܴvt?_qZg)J 3oB#G({6HArX ğ02m HIǑQn-_/_! 6#s<1LHf0FK 1L5qJgJeEF2'HptSp X*"i1$$0Ù9DyJf]Z_b#4lL te- =5d"]IW;:0a<;$$wJ)5Ivӱnc?F@;ߎvӖĝZkG&hMbgo%3:JjVn %d 3QE6gx^r }v9ri2m]͚4%>!EE[_Bx5WM 7Y䡫x#Ro=Æ&IFC఩Zd˿t/܅tv wu]qI)&yyBfqBv!ꖘ'nFb&z5YDL_ :L /ÿS`aod@&tG3ҧHzC$^="܊F0)ۥheJ%NI16 65+ѷ=\ n.Ι$f#m6ie&BodhWfR@y_'NUl4`pޥLhg2Yxx*"u _u30ENg P mhΆqh<ҽ+0MVVcl6tJD;=; {\n܉f1:au"I$`ᑞE]gpβGٟgO ! t:O1s@X򡭃\(w+:_s.XtcVjXmx -x# _aC<ӭlxSvgjK۞egq+?@ p'>Uԇw6V%' 1;:_n:'e>E_(>~s;zO",T2] yقߔ(0g0Yi!dShhMM6ut) X_#fI9dNj-3Y'T!q 2cTErE8xgzg6܎e0tq)_Ȳ~Bc~EBBhp3 >Gi*wZ`ep`/R0le[q@ߔ$CsxMk-jؕUC 9Fhfb؍+4P?[ Cplgy/iv]LSnqRg!+`(7V-G?;Q8 00B64pM_a=i"}蘵7^ {^'m Hb2T{Akw70IKݦ2k8Z!ᗌؔ*O%>)V%V .}P`H8O0!$vh} lˏhYķ9MXLxGl<$mq9„˚bl_.C/Jb~~o~2Ch--V?/~ hwUo:Ca/ { VV"FDF!W&f[yz][l_sos.]{)ee<}yNSpWA(ub44)O?] wDV;ݱS6d< xWMΪ;>`ݱq. G1Y20棄L Z g؟A$1yHFg|/92"B bjG $cc$-8}%Y{oBlr.=IYF]r iܢ )#xy5d&g N8ҷf˓M3nZܴM[){C[,V0̈́w -kujӺǶ\kFMtM׀'6~Lـ:^x_HyeqLu%m#t>X ֯9rXH("䷅gM,oN0>*HaEtr+9{mj`^\Gj{#z_AO ߡR%~aL#a9CC?{fw>DVeA:Ut5\*\ikΕvvjXJCWz^iJCW:m۽Е^Vum+ ]ihŸfqE_>[Jg/Zgήtv t%@xSJG/ZGttsD>]iJC/\C{4tC 7rSi%ʻJ;92ˠwvv~VUz4tЕΣߜw^ ]4tM4tˡwήt~WU:zttѕxsVUz4tЕ4"/gx9љTZkӹX2$Zg-4FWt6)-HN8?H"fU8^+sZ37o=6;H\kS8&UUq֞hpϴt}C=dz!~d MɬȥUT޼`֏#ir>֧^/?{9I9u{OBVk0)F5Gd`w kPΧ߻4K{OEvI$$2Η ̬zkn _: JKWZҕ^>-u_D{F$v5)t#\}ӛIicW > r Qn6mۼ6]{eBۉ?9:/Ol(,Kb4ɬQ4DzT,Yq<1!F֡İ8++NJl8%_yysDzC{_pQ&nh;o}|,rEF9\bCOɈfsT\g;ѷ4$.,wM3 E2x35D֟F|+}."<_c}n՗i,0~WyZϭsD )]OxǹmANZy S= /b=y|\wϿɖۉ ׾/Yoҟ|t1?'P&:Ԯvhf| r= xMLяy ℴ/>u"'k,Z ļk/8z)/C/W;zK[/HI-_;K\ [=xYsKlwu= ܯX_X䤩'%HYa#ZF+\Do%Zc \4On~ijq/kiQׇ(IdGVݗ5TԶQ"ߝK9t{R؈Y W)Ղ e}ۨz#PIWd=cKXeMwڠ7vŏ/C=xy>4.F=NE WyrZHʜ>(smc {-8גz?3gב~~9c.U'ݍ{]f/;~NOYI]6< 'xShg/Ow MӞf@φ/[ЊݭIc2'}.lAI.6V-Dw.%e gvM/=7 Rn t~8= ȵGޥE.?4}nҟzkv!&{e^{;$z4fgG~m;]6Pq kU|pEr\lD@_I} 8b+Iz``P;{sIEpggKmA:[Bn9N%Udӛ>U ]EHC%)6*`tڦ7@>Enbo3Y(}s66NYG2[6MBr3rs5}&b٬ Q9P#eӲnu;[]dIٽO+}5L[{;YvPi"H4c{dф/{:mOyдk^~Fͯ;?l*7mq[~UAoP7N R%Npfk~I0 |` J/#nf-קtoCn;V4JwhZӆJY=ֲ=Q(S=b"# :q !A*9l|?gz Z(w!tPM"'u4X'Jt cVRhX!M5lC]1$#AmyWk4<;gSSɸ o~qkA f6W!x69{NTS4 )-uvlӪM69P4[Swf R2%2ZipѨyzx:LC$Xk6kכl2M 밎rZj)d o-?$c-τL_"む7|?MPd @ZlDƯ5Z nde#JPkm?(ʶbIf,rAB2 [fHdb+=?ZX :fԁf+_'i|(_R \}d F[8e4-7#+ 0/|JUw-7:]jrg/|T@GVM˧ہPթ7Y # ?4V=2c Ya3Q: 'O0t[݆E:\ьįhsīPZRqL)zBE&zBf-7A}iתv)&d1Zi nI%P/Ȕ/]KxnyDei-6/y(R7iub0tiVf?i4Gl{Po(zB1@ǯݮ '2i> ij %6 @Ff!\ ١4nU ٽ59PUkvyh 7f ub,/Axh"P<`4V^,᫱. d] U{ edojh@yHaSi1SjC A+dpr4*/]THTk6ؽdyMKgmZ"뽐E+JSf J,n( Ъt bG/x))/YEŬ!H_q| U '7SHķ&:\WIE"oqN+ 耝u ata:0-mdkxD]#1zÓWucƒ~>ڽ FbYGezlEXW2Iw-~'Y BRꇜDNU|Ƹ\7U:uYŤfGƙuE8;֛0eV. JEML}ݘ{[X CM} N3js垱+\ ˽{-7Q'Ismraۼ8u`=dh?&IG&R;Tm  ""xDl. v.tof_'?A@*GU?>A~Xr"Qڏs"}"o*O'C-uwA=R]tFLнO/$X[z̈]74x*֧@7329 ˾i*Ҁk:9>6R?ÓEhm:kOgrآ/]>~s~Y~1|}"3ΡOC[ȵޡ!b_!kĚ`~3L{u֏4 %ՙ<ŝWɵ54$z{YdiCVOoB[oMepu2vpO`ڳ!z,}+KR)SVe=S \gzk or#OE$\Q!r!e*G"r9*8%VJw?P<l2bwg ۓu/?};z+߶ݲbWfnl/ra)GX:kZk/fXyp??1Chx]kE+?_hi}o?'2?Q( ڼk/~k>l 3 t46?O 1N_dg⏾?Z+O_G?C3$;X+o?=CKjɅ&iQ3DZg-ފx4pKHItD/Z3v%黂b[4ݰx:oDzF"'b1/z< eD!o`G8DgudRh.UWOS#D'b-7QjjLZ!l2&u1ˑtdGh~ZٴeGZ61qQ^<'څ2S6@ƸG69f2T]rZ~ZQ&^UVkHa tn(!U˶>\V*6F wj> 5 4jFW8 H:C.AĻ)́+SP wQćWyZ>a%c ;X+*R5m!C!ʼn fp,9iPo}mGK.zK0ȜLk(NygLC( /a( itO#J8˹.ͥ2Br$ :PқBIAI)( @ɕPrs䦢t dTN)?y @ʓrH%J^!~/g5\-HJCw/M8rv qtCg{$ZyG̲ocIӺq%?VzzFRdusm{,_>i {F: AjUa_gɣ)Z{TB N=\e,PM]X,ѧ>߼ԅU1lu֣T v]-lF~ ijW珛ϫ&^(I;INgdI.T"j9fS˳ j*ܩ/MXMq7&TcEf5jSȝi ߄M/X֪w_,"k #<Ϟ&ϼ;ʹ=< 7(;%Pv(Z^ = 8ϻ::^i723w)ٓHo2iËweYP[zIW2z=vr*I.j1G ֏΂WGdOH*gˢl"\H啑+Ck5"Z}M^(nMՌ6Kx;g4qlPR%4Mg64rUnbq)K$~4)XnDFO#$ozZ|Bi;#vΈCZ &򋧔C&[!W}h84 GE4ܐp)4dGAiu,S{DD2,]ۤOyڿعM۱Gv=~|t֚=uw=4)+'Q %d7G=Q)'{N#b|=lt%>OStbW5WsPtKY?c:eFte:7¶b;r]sAy.XBm&A%JD떥u[]6=|ab\VÕU#ղx.^ή^.O\btd/ej˭ʉ%I:wEux&)⮳oPTb1)it5i8/jZ^e擭y,;2$證klML4YhKV6Su11pCTO'^I:xIXY$O,^Y$UuOa'KS=lQ;H+MeX\_T*#Ԝ/9+*ת%џUy5"g{yz9詞jeT?3qc?9?Hs?}s/Lh|K՚_ʻ <;=|2Kgw9?ˇ~J%],h> tֽnf)W5&sUkv=:Nⶨ6ZjyVжv=kۺ;J'vA;-OY/y~)*siy=}_oz"c=tV~hDiz`yFg&=#\Ypt^eAx 'kӽ˦7zfuq2_W+ҹwnd:{iFK\M,zgn|} }T<.8@j+ =ZDz\^r{ެuQ"^g%楬{cY_dJ>юGʳ 7X/\'\w庉z -K(P WlQe>^@m/X6ٞGB ҽp8M÷#V#|N'HUwʤ>b *O, G)]@R2< ^F7\c2r͒KNSG,Xhd= sBl(5sRҌso|{cEѲb [ja)ht*b&Fik O|QjGHMX12b=z-Wؓ)W14T\ ;i}_Ft9*1t2eI*![tR, 2'eqJ9?9=<%eY!nz[ѽ#K$//K6u .l`l&ɦ{x%[|zB<= {LrYJH/2z9-nEK\)X|>zggd˘wF71ԎQ2s8y(V}:5^Y8z^G !^%U }DD*+;F |'#߭`}\<8uNc+ͻ"b ֏Q~{q~Rb]刧>S ?ul>mx +'1V`OP(QVOq }(n5$ kPS$}ϏVCԷC\0+JṡYK[tu[_A =~%av'Yk[Fu#&]zİ;B΢+ }JWSMt >Z'zZ~g i=a%C'R"ѳ4ڍ~##՟''tJQ箞Qe691bї$Z(US;!N3M6]&ľVIIC]ci/_Ƙ[WW}q".#BWOW#xjpzؔ{Xg?}J\^z Nh~~ILVinDͻ2niL]k%:sK7Gsq޴>UGu~%o\K:Ry,G9^U^.zG))p5?)%8GN8v$u8k]%9K1pɷ~r߰w Do>Iu4N^dF Wª]1$K/v3mmo+yüפ8Zc}PFmxH%EnОךeQ\ Q Ih -z*rj+{iG@Yְ?´CcwMKPXrJpc%\H<~SܓRkRq>sjӮ57$Zmy5L\Hf˓˓ t-ן푟7[ݛk;'/Xlw~GVS/->rm [-6,Nݨg75FSS` YNX|eK\Tz0 dfSj6Q9语Juvo<^܄Bַ'o֦FQk0un]rz^5ڟmAp! w竈˔f0וXYw.͝)^zoܜmlM kw@&&Y6^ֶgxYa6kś;f3=igkkxwRBPzu@Cje6:ӓ&\\Bf㮇6tҋG.k/O(roYp 1 cnn d×-ݭIc2'6r$R.iK.}o2} /6i}tz&6uuu6Q:A~|a|g6\/w7xyB|M[rzg+Z|ԾlrSTӻ;(xNR2!lc&u.?턢|}}`$5j.{_@{ =q܋ai۴UmR9~a;]n>M/|a? b:c1ӈ阆cI4E%Aeѵku|~SOk6S:Zm=7C8?qg:Dk ǵ Fnp6tz>l<؁+WԊX;&ct&k {|&hZh-1F@Dc8xA`i9X/=?^]ai9o@4$j/[a9ٞ:|eh* ]*LszSjЧN˦TxENͷkeSe*[pӱ $x^A4k_Zl"u_0ךdu4d"Щ˚ly&D"]j q|iD9Fhzl"}He؍jBgDZ5;}!aPHñkA'{n˄GԹV9M X`6# lM"Hh2 Q&JϏVKNwZd C^3@FV~WwoZ~рF]\x4d2S[x4e2Įʥ LK&&cL_%B;GELubk 34j[e:H%Z͆ϊJܖϦJYw|7u[%"^O#t1t̅ @YX_}> {i|9WLlF߶Y;ڴ6X]I77ɟp,"[Cs\<dlcsH- ^@au~7g֪Uun:}\5za/4L).,Yd+:<X_etoեܗl4 v 7i}){R yK~'HiMrYO/60Zq ٞwBR8NMKtG*gSQjB:S&BwJ6WH 9 t2ƤK{OKszjAJ'w7w;)lچZ]\I_@6d~ ;놪5bosUG3ɾl]y1ljE߷=MWfevyÑUe 2ћV¢';'>)NuoQ;+jH`lrt t?|gg筏Zоg=U]'ڻp> :PQz1GmAOzsV,&Js!k`I1i~FHEyq7`poL9ŏI!zFp(c-~IUbE?4DS[=V fv.GlgT4ϓ߫LU?tȫף[T0<뻨 zN)LнHzXC-=oĮajk|_֧@7gle=-[^o x-BRځzQP='֧u!53~Bm5amkOgrJl yjLY?L+r1$:kCC2C׈5=c8B<i ZKܽKu|ݕ7.5\<.dҟW ZgC*XMEC痪R,z\\0.gzkG3o[佤}oo"Ns|"~x͑^ܱv.LÆ <@G?oTϰD %JA/;?AK~~?4CBן[+ӣ?ο1t&\hl2kݟJx5sp_h!O4> hc^>}w?o}N<){#y*"=BqBLiIRW_w޴SaD&rkEP%rP*]5-'s CTαBۀ2Ev!鰫ˮNNaН(N軲iT-y=NH{WŹ_gwQL_-#,!R߬}<1VNoS%'%q .%R %7k rH[RT(yP | %?%9+]bF4UBYDZm>d_+ YɸfL/q/㣏rBc[}ݼ/Q7nZR; .W:p=@S?7uaD|RV?Ǩ%]wYxxZKQjoTZ9&g"(^ؑIl/Q秞(UKOp߂s5|۝yd=uAB(u5#7=@zG,R+RW`o"S|ӑJړkzkRt2L(N>Z=vBl: C"߂J&J|9Ժ8.wɺ4Z(F ΋q~M*矓ϛҕ;CZΒ{çɻN;otnA:\{P*הk N׳)WF /{ݥ#GE,sc*TEf1NSriawZOOW Q:=-ln~i_iBU󪉗9JRN4qY~q Z²ڄC'wKc/jSv\M XarلeTrty7!jSy6De.ȣ7ϳ3γ2z3m?Ey${M}#N -eʮWeOC1󮎎lڦy`|Jd"䛹L%]e&^'界nܦJt3c`9Qk8Y+ٲ94H>aq:2uye$ipu?e2DMx_jS4ʩ[A5#R%Y"G谔j#$eә#\Xb\%%e.MJl$ہ^;oP#vΈ3b箉)P*VU2::N" GCr 74\m/hx /ّ$F}euKԢ%x(t??n6);e+vnv]<fkO`vw]]O:sojjJɅtzgp<rS kO:6ruTʉSH#$G'5]*gh=d{S@U )zzNx΍f9؎azkc+KG1+ֵPePRc>&Ѻe_]VM+y'G`pe:oH,K9燗뻗'׷4jm9r,#f$%rrb"cIR]Q]1IJA>-,!,rLdJk6]}5˫ڶWirٟdk 4dU^*7]%ۚώo4|%#!zk[M.5y.ڒ甪:j]L)OH>.0_CO/1/x̣HG1.(XzT^G|<ŕIvu=UwAnv*q=Bkږjܾ\V|F>B9X]WwUV9^)Ӊ%{2^'a/1h/ju/)fSc 5Tg{z>[ oS+V׫%:Ȣ#5egʵ*goIlU1y+SsWbіl>TO'yxgwپbR4S<c}eYF5$xy>cj}Anv*:zgy<2|yϢl"c*R:z_2܋9:a$_i#o׫nB~2NO!߃R]߽R`uu< Z9B"XL)QHkHrB~Ops1W!_-4>&|d|_9O %=G.(JBQ+WWz\^7r]jקzjIy)v״)YB,C`!֋)I,]hnbB*+[xPj[ Mg<ő±t5)N @xU< R*_2oe8 (QpP- O(Q 1ט\Ӕ|K82ٮ(zO$[+J <4{E(x}CvsvJ*56ڦ%ݻaS)_RS?VL}y^ Ut5t GU ;WNEZW,]t| EY҆mȖ2jḔ9K-eB%eY.eN?ONOon)ssIY*"en*e+ĭEtɩ˒MjølK-)X|e*!IA0^+G6OO_z \$K^N˨[>o~ 1e&(2Q:p%| uԯ 3>g41UgfgWQBȺuIGlB! Q9Iw+rxe39NXA*JXë¼c_s_ԩ/XWb9⩏Bꏴ2r[Ak b "BԮ硿ayGabc>?Guٺ rEX%JN}oGI#qRRPXפ1fUb}_%rKPmUUH8Ezx1b6>zOxz:}/qZN7Gp*d0Ga܀{7-p_77+?u$9W1rGRT*_aUşޑjJe5\ h'Oyʨ%X %2ߩ)ǚjӤ9syX.G[G(Ur=)qX+.Gm~O֜cQb90cgh AΖ=BV-)&z qi+NS"Т1C=yj\dzӔ>xyrǶ''NmĆǦkI5ȿYg{ZHC!\cԃSks\'O 9ѱ"u7A7޸9["\UngkMLkmm͵lwwv/;f3%Zۥw)-G/[7I-wH]gz҄Kl҆.\\zef/A*S6?:M̜91se-o<B8b3Nb3J) ͍Sx>IiRx^ (e0صsP p}1C:}Y1&F4VNFoiih*/W:Bбq{5G"0HP1@gp$DlRǼLtbLr~^M 6Om^91l䟒-#t%&aGТ6 s[:Niqb)?Fg8)`.yk^Z;/P Sԧ0=MSPs+p^w1ĉwtNc > Z6BcShl M)4M` Y5E#]*S)@<FszF.Eȥ!"ViGC>n޵9tmyZLi1(AY20n F:7+R&g&g;_n" 9I=˒6l9إ tcDk)r ;ͭp *;3ȊCSP(ţ6h&-y SdPP hP@*..f'Zt )^Ghdqau-/x=Ʊ;aSMl/ʓ ?_qZg)J 3oB#G({6HArX ğ02m HIǑQn-_/_! 6#s<1LHf0FK 1L5qJgJeNp"u ⫦_},U<aCv^פ R!CpT-2_fBvt|Ӌ;亮$t՘5Q˳"7c=⶛ QER$V4I.E;/p=|>%NI16 65+ѷ=\ n.Ι$f#m6ie&BodhWfR@y_'NUl4`pޥLhg2srhxx*"u _u30ENg P mhΆqh<ҽ+0MVVcl6tJD;=; {\n܉f1:au"I$`ᑞE]gpβGٟgӭܖydMu:O1s@X򡭃\(w+:_s.XtcVjXmx -x# _in{| V"VkMIy04NjB{<1Z }]Y1ԫ@nf6[)(B0 ǖ =Ny_tS<$g/>*B=WU[Qn qZ !~vlq$xa`0*4lhVp'ü{D:'81kooM/eGqBl/)UK|RJ.\n5P`H8O0!#Uo}S[VҦGo&'e/( YF]r iܢ )#xy5d&g N8ҷf䍒g8ķx(+nP9g3!e)"/Vr7ɏB6 K@(sYmsDy+艁;TY޷=i5#rQ"g|7CTZM=@K{a1w}]z0g(pOl ݇J,hA碊.Q+pTڹΕv6C#2WiJC/ZC+ ]iJC=vW Ъ4t+ п,=.Cg+]Elٕήtξt({_@@z*]Ehѕttȇ+ ]ikhЕ4t5Fs*ڹZyWi];GYv~3VUysΕv6oʻJC/VUy4ˠw4VU:{9tvٕ6oʻJG/VU:y"oʻJC/VUБހT 8::stu[3zRu: Gd밤+D-72c # otZ\x?;]i@Q~!T\;x}u?=2u>ԗIŋ)Hodt lϊ _Bam]W7$dhr>D!B$W2-1- #at:^mF𿍜t tcH K#>< u@yRr㯇L?ߏAy3s}TJ##Òқr _cqbt$Q.'R֋G/gҘ8 5~iP*}-&]ЈFt ,.a}Tt{WFzii.钄Z2<QoͭPCK\iJKWZ˧?nhH_#1X9#Q8unk~Ocz1)8M`0 Ǵa\N<ٍrmrtܦk]h;g [VgɃu=zE wɗY&5*HJ2גR=+݁O9=B1B=u:6qeXu /qNHqh/k. DӍ-bǺ-O^n#yY:(gkRl ;Lp* qClG9Ţ.6 y=b(9}YpqQo8ch1=osߴOEgpϭ2V2OKt(85> 87 Y =/D~x*|A}!PE'/7!r};1ڷ%+ 㙜@.D=VM،8ANp\{AV\o)1aQs‡ѸNuEKჿ7yE'|`݂\/p8od M}=鱱P>xo}wUs^QwULqg]==]S.XA2 ;V,X؀@,@aY2[6vH,EȌ̬̌)MgUf9'N_OvϽ~ՙ:{z|0}ϱߨEe΢?KVOs]{5>0NS'9hYaVg+l>^v6[ vatgǞ~t !zݟSok0Q۠IxgYU/UNB\Yn&g|.dܛ:ha5dt/'>| Oȓ?Kq\+( w}PRۋ?/!e<8*I?[${v W0_W -o 9&=<[dۦQ.$6cx,<jC뭟W|AIEz l@˳+P;DP䕆T#i!l WgaM]AFĪ f|'Yk_s[?wl^[yVAvY>4,Ff8sw 1ίC &[`Q82#+mj ~" m.^cV¦3XnWVz.7 Nm"D{~zk6 OJ;a]>=4K&g;4 N.9Fmhe{.hy.+[ps\Vw( ׂB+7wf7WF+"[Md##TcSevް.6eݴ&_FO? ݡ 4nVm`l ڱEȳ䲏/!3·LݥVD_6խ͵ް]Ȃ74Zo7[- -i,G4Z.4qW\1*+5z$?wɥė!- 0vin{[F.[M6č9h_[MutEL}/ F@6p&쯁o#hg=?ae.XbJtx# 7eРV DŽ;`5@0aWBnhsX"\kT2d*c vZ]l߶ӷwGOS[ + ^oAKImmB?naM\V[ o ST:s%W(^4^A6VPo6p4Fc[ oUAk G]Vs X.mpθoIʉx VKeHY q3p'Wo.gݐ@CW2h.{ 򒁷{F7x:m~` 1XǴ4eyʞPW &bip8>D`k',;zO>M6;.hx0\7Mon/!˄:tsÏUX$Py Q`"H_0ꕀJkOT O:`ѥRiYihL0E̬JK]Zj0̗J^2W6w`e܏O`  M#[td k ~g@u !2=ecY&oR!i@ }`MæX1[X}[ۆn {՗0 '6C{ncPy莘 %nK~|FwYC+0FUJ緍Xm6P5+5 ˕`\͕HoT.i\qEvզW^]oDI&y%1#./p0p+;(;=<ʅ_η@H-99d!K Jud%+KHA]lKvJ.ٱ\ZD:*M){,yr #pIqN .9cqK \ri&y5y܈?r9D! І yLdsęcz};,;E% X=9b3>߻z]O xPp~;Bf5ʈ̻K)ut47qcnjz/jHhۤ22ԉEuށ98<69 .ȯ ȓl K*OVU;з8 !y0f{ҴҵD,@:Yq i'#32((T: ,N:XMT$`M-U ;Z>P$yAhu-}_ &҉w$=ԇ1ڬ\i;EEuɲ/ɳf;v%tGeJovxk*Ys|}U> ϸ&_o0&_)K̋^{ja|P^]50yÛ.+lO cIJdYa哐]wnDzyQ7gOgOsd;I&3zy i ߩLOMy' EU ӚYYyt^4ǵ1Y:PR28Duu<ˣ7Sȫ'~O7lRBsl+!;9@vj90f6e}חn ˇa+{IÑ`810ƻHI-A=P0?j6eݷ H|;{-][yvI "w.$8;@#R:&Hue}fsM{*I A3+#^x0D+qIq)D;wN.#9gF'S׹Uf3Z̡Pxi5\?ƃ[2}k& %|tuҿ̭*G_W0M]>/xO"e\sfG=HWɣn%6=YҒte=ѱ(-][~$%Q- ![(1qxttJEeRGzm 򒲭។Oɦ[Y![#+pcVsyw񍂎NeA4*Ɯ(J*U쑪]P\cHuil⢲eGOgQ*d{UdhFFsb.;2{0%ˬYŽK/p NB~Iӳ o-NCAx"yw~Wiksi:Ɖ j,'Ql^.AkkAiaaD`l|R5|k_b؈CRB-9H`$L˝S ;K$[[u8&棳>͏gbA,}f+m!LAE@|kksϕ+z+V{허0=7/J۲BVvW`VI-v8#gvV$^Pv$^PNޗQ8S-aO8&3V+as ~!#vUtcuqx3: UKaÖp8p8 KG,RY4sII^x*lK@x*`"Y (I5Y)ꍂk A=ҝx bCvs|:%2mE[aRj^PJ8/=FG}}z29~ZcS͍7ddN*7Jh1y(jZ[ Z-2k.DˬTZ$)Zf3drt2kJ˒,8Zfc̖bTb j_nfuӞjt'ɗn.Mٵ|t(K$ӥ(tb=3fϙjL3t%Qs  C} I)@13t>!g@Ŝ|Ԭ3Oe+[!x :k83GP%{ :B4+Ao}`@WRf=x }+~@'ksKu܂wЧJK]9Ρ`{P;~ 0NTsoP:9!|#\ya*Ns sz@Cyxݴ/:+}A[3^ inX8A2o$3B(@H qR>+T -OGm({D&@4ih#0. @&:VklomZ--TG}OXo4F=Xgwٝ vgYA44V*tus Fcs~|}\\zV>@V>X[||SY\tat1j{Ml_ԗ-i (Yk4Jb@F2u}?U6j3*ӨM#?bܹCAh cc,yv\elLrB6ec!S ٘lc,x#At6y&+V}BgRS-WjűLE{^ZYRp]0d\ׇZ8֑"iNU5 תAj]S/;K,u٩9uצhpGC|pv 9O1HӘk-M*@`:2^Ut^ 9T]wT+éU,N̊)㨧.@p1t(MYX<&¡ 0E vrٲ * "*SJ\cZqZ%QmdP٫#Cgl4Dfq,OTT۳5ϩM38Z 10YIlB܀M~xcUxsxŎ'M~ G[p3QG_fu@Ba}@':ԧ=5rt<r7-&XF QbjXkةkQ5FM[{0؀dk>ÿi74#)8yTOT[HZ}伵i23 /]lfljǜ Nz+AvWw?OA;(``\ sC\c 2@< :~~$^7}z゚f${1w)Ow'@#PA`ʘ3X[6 ;A%dC`1i6I'R VO=IJ8qPO`J]j#Ȋ633رxsF9Tb; dS(wz+:,pE?h<-"awS>^ufMv)eG#l_# cYܐޏ3Ѐ k]Ov{ La9VfƍOz32**c2%sg(1lx$<{wzlΩ=U}eɖ߆8K$ j@-فC~iR{@) 7yά'K9c;5~ ls<=@ CDѓjN9>5xz w~H}i|Vg2'K=+zZE#>C1?#j_K31}}E½o'zEuxY=:j&N4 LV`h ?Va@ )6DG"}C&תW+ =_S uȯڮ}J&$~h}At縈G^KXUJtC?Eiz=g}ȼ5Y ^fOͻW2|h>lKQ㭽_?W>q*BD8=t`g;^˞_;?{}􍏿}=%yuw~?O|W?3-z"L絯;o׻?f6`Xf"(t_1xsq!>h;(}ҷQKw8?%gw>?OMD~:7֩7O~5Hs]Xh)bv/yqKꮠ 1zyT.}P^q68;}xJO'˫/Tg.Dx~W=O0BJ|:1: a;ʙ5ZiC^t$^,lIѸq^OiM}^a"lb3:T9Wb:8 J*n_@O.p6Ŋ؂0*36tfl]hy!b=q7oXTb;bw[6_1s-*IG-/ޟlUXS!>ఒYr\ yط0(AdmSy`w3ZOw1_m7Ыj7 =ɒ}י2KTvQv W˅_η@Lb\-r*C!ǡcX^KX\bďD.p6䳁pɎ"QlzNcɓSC>XW\r3<p&b9ѼRPqmnKJEq9bm@N3 \q㘞gQ+n{O|.wJꓺC[nA68B7z4WVB;C#ss$ ..Fdޕg<^`Աe?g,(ǵbNO3eP#o*.˄ϨaN|.U9LpG~SptoqBtaik_C2Y4t&8:_{EᓑJډkkU*u'&!6VvV)䎬m30I^Zw]Kz>A>ka ϸ&_o0&_)D /x8Au QBzuռ4i#o=VؚJ+<')͓z&gu"OBvݹ%E<=iUKa6yE^0+WW'Lkf>NwSg~O:dmyƼfX2BIz{9Pɺ,ތ[O# =jdK Q@~笳Øu۔]_TN%$nS~LlUvLv{NS۔&zM3 > Fm/#W G땸{EMqE pD[pDp,=+WEXmMZРjN&-)c#G 40ZФd8YQU>\#1,ыֹ~XĨ@j`{a_mCwvp }xyq$<i_ GÊa)`XJ)0,a0,% G+OB0"]&;( C{[ǗU۸O{tyҿt&m ŧ_<f*w`wm]Gͳ'5,ܹBv༇ Pw{ >"8cTXk[{N8ڤ= d0d=C >w CBR@sQ?s:yft8y~[j1îE1Vc<%cѷf"QrG'[7-ܪru= l$Rj>gvd9ރTp<^Rkhѓ(-IW[7`ORݢp ""GGd_Ti!uְ,/)ۚItleѬyT4^E_$Yl~$[$Mt,9/E[$-ړ-g̻z<_r2N-l9>ɗcKs.3_&/I˗/Ij<_2ww'0t#%Tg3_2ZΊ쑪'սp{pzydfTe):S3)9.3yTW|Oek{Zt]֋=YrNN&ጝp.!u޺l9sxwye^G o+sfc\,gT+Ej59^liT?{(Sd=Qx8ϔ\e˜8rNx= ׮Vv*&d;dwKĚeu9ˇ|w"Ʒ]`/h~> {]{)) ]ؾK podbfY2/?V⅊M%rǏ[c)kr/@vϡl3Y$_\"e?[|[g^o-OO!?Y|%IfWp,SW3Yq3YnN6(Ҟ6QX'7EE"@WEFfd?'##7 \z5]a"01}P|>!_$T>=ۛ4$[g+w7we9&ڻf=crb4m&Nφ'YG9`%!<-%ԒCh@ʴ9հ#O@k5xj]^ 9=_lb>:Sh~(2ЇhƻҮx<8)\Dͷ6?Wn~\r׹r{`~3?}r$9-+dՉmiu{8 fLO}n3Ry`>kE kGu D}[%q8el?c%θ:װ 8og[Kw9[7*Wgʨ> O_qX$v8l StzJ"ՑEC`>ǧS ,6ZԽ&)O-4ciztܧK'5&?ܸqC-N洺y#Q,y*G%ߐea-ZBJeIeV?O&O'٩,BeO;Vl)V{M .ɠ%jaX7Mw0|(ݴ/^0]G72t8;N2]H'3:)=jFKX־gWz-}nM¯:A~D;憅c!FL2# $pK/2Me"x!xHa D| OK31-O`VZ@*3P $łwt쁢l e,.aHeBUBu^T/U2 R*XaΪ`y~wL*.x. K{TGF0+;] 7VhBo¸, 9W\]TK7rk~0넶|..~8%C'ϏY 2D'q#%n7 < [~aiGabc~زUeĚEXԘx%[j~%:`˨8)*3Fb5joU^D{ɗA$_Gr.!zoq8p1b֕p=Rz8{%<DzNKq>=Z<KcXKgXE5Cn'.JәϗY8*zu #:2B5_sR12J֩<7T<^B3?oe`9D@Z:q%ܑ%[=ˢ K/|=y[팍4h>6*۵Ѷiu&pLrYTyfgKi^^GUm pZqTFh<6ZUt2:W{:!H+;35j/x#Yoj!0o6:vTp,.yACW^c jg4Y5U5JA+cY"!%Sf~e`ɿ77·ʽ;-|skgAf<@[0\C0&^µխ-$=|}k|7v>\SAr]Eh C5֐pYdwGH.Bqg}hh.1;imkBSx]N0Æ WM- 2*5X|DZ=fLc(F? hҶ BLrGpodgd/e>f 9]WA\\Lf[xilϣTs1H QlHاEt(SAZ_Y X mkBTWx흍8 FSHI!)$FRHnw HYx3ꇤsaaaaxIǏ'U{o_ھgW9 o'GW {>~Jlo߾)*/N\ϱov[iZ_ձaJΝ/:6O- 92b?Tlk%?_21B sY5>:>c=1Ow y^- ڶ,XzusM#גU]>H_yYv!ۉ_mi Rus]Xm_g)YY)m]y,m z1aaaxEߓGקo/Y\k6xjgH|yu.\aæM&wk#ϐ$?]Mo\Ⱦ,/ڥQ@~6s?)}, l gX #vQg Bٙ^uのuhm?}{].~}v_J;xogJY]޳@.)oqC?}>@Xߘ'-(W? źvƔOʙRv[K?[A}?-wmՑ}g\=c}M ggg DŽ-B^k_g?F? v0||؎=ǧHPgs/hؑI t~{n^}ZyD5XWvO)"c0vY Z|~_%/,p\ɹyΰZ/;/xs_9?Pܯ5ݻ\[y|č8gʱL{? 0 0 _k3>z_\S |<)b|7aaaxn.ta?l^Cvkؽ#~e)3<3^kdlc&jK+o"e<.ʞ`^(3zu l+6v<ï k7]/lc[`On}򚄫 G뎱zt^v2)?;Wmr5ocIz?Ozx{&!ez."ѯ 1Gg{+ҏlw<=}GݽFƨ^)zIpG K֜{{e G12ۭqiumf>.}~a? 0 0 [u+7Svq֭y΅ ?ނ}XwŶv?ߩDZۓ-q/?߳=<~#>Fk"qzrQo 9r,nY[;o:)@-`ק-7({߯S@µK9֠ɸ>:n3 _[_*mtcmC>qSL=<6;ǫsaaa{xˌ\ފpx?0׋#5zяc]x^l򼠕(f:~٣^lin59W~\;?vn6erUbS~v^U O7O(|;+SG4|?f*?rW~2oNٟS9~daևmH6mX[J~s.ym4ٶO|Bd/b5ɿyU? 0 0 0 0 0 0 0.P~*1@G\⟿KrKXs2(ߥ纎J8'>X@▼QQbqwx b)_K|v 1M6kee-2Ǜ59?K^E~9ϱQﱮYF8N?~;:=J<-tĒyNAgC \NXKs)'^Kg\~2}6}Գ)n]Or^j~"{p29w6/.z-v:+M{WJYZ굢`% Ҥl9ힶկ#OUz+U?;sd~vND7*.Y+v:ye;8}~|+ÑޅN9}{Bƞ#txխsXɿkSV/uJ=o G<ջL'L:D]6jfgLz/+ؽ[{rCMYq~[{yy czA;w9zszWHVax3 %mkBTx흍) q ĉ8D^>׻gI@XjjgiЃ`0 `0 ?ϟ|:seQ3|ӧO|:2|.};7eGFO6_Qv]T]^ˮg{>pjzkuo{yye?{-x/ D:3D&򈼹e^Hyi#/OGzϪ߯_~ :sMe#M3Y#=2 QЙ[\s=E8}E>GȩT ڲTg-}VfoSVwzV}./>~!?U1<#}=F[ ~QڋBN..+푹^edLo+[\-k dW(}6q$#?z6Bөi?L7!3O_Q}Пuo[=tkȋM!'}/Ƈdr2_Cﲨ: `0 :8o=+8-4}۞cĥXdq{bUq©ήm!ƶg*ΪU\z[GA=^+ru{LV U?)V>ғ)x|Yҁgi\yi^cUo*= !TY?rfgWsʽVn*VX#=Fϫ+[F~yH\L~[O҇h5ݵTow|Sfӟ+);F;:x )/OS yUo2e)Ve3'wgGg=J^`0  ľu kU,Ksؑ5nY,bXw{ w&3QהNQev ]ƷgcH˞i{A3I8hwduwUIWq8I>+@pQşGcZ\ƪUߝ]/:3d;ɫ:gB9R|GW~w2;fzt|+i5nΟgZY|<1NyŬ|E7k?z/k><=Α}N΅>uWydʬdz `0 *\?W8GY:Dgcg< 2+'W6qn؟{ru"wU쏘~c#T?+y{Q,,^qF/Xv8.֩g3}ȸOP ~n%hUG4(_sn|W}Tg&x^c,Fѭ+ <#+}/Uw8BRh_|33!mr\7U9m({ѝpvew[xG]߱?g;,nҽow8]וb?OV=Z_#ve?vN_WrYLo;1g9pV^G~>[_vNOS3 `0Q[ veO\k^8֔v<Zbz\Opbn$~}oz3ј mK vU]^iNWA#x딫jt q :E= z%օq)CcYEqyRG-+u (K\hP'*^ء^q=m=y|Kvūe\rȊ4={W1;=ݷxp;o@>ȘT\Ԏ+C=*ɫ|GJOCW]x1.ﵠ9_Eб Vq)v(ʑ}[GwǺ{-oSdו_˞׃2;iT&w*w:g׭SOsj%Z[~_˯d֮+w]7 `0]kIu+eL]ւoA^;=GR?v쯱;<y o$N1紈=:ߥPVu< <&3KyC/4r)i=*/|Ύ^]QNН1qGw>ù{ ?Kv:A}E:_n+{u=rq͓̳]>>d}+|L01`0 leg:׺񶊝`W,3O?]\9P~[kOWiGc~)-<w.3q}'vuw$Vnv(r52S;Wk_Kϔ8B/hEՠ'9w?K;x:x<|@cϽVyc@ۖSw8Bq]=2lBe6V}eR( VeZT4ade2ޒ+nYBTqSߔ<[&=f[|szP)G}{Zׅ3n7jpWwftEw[ǽ;`l? `0 `0 `{~i`oLy>uoi\qK|}7Svu9G쯿c¾#>,jow{ՆݲL=mW2u_8دjo?kD߱mw>#}E:OۡO;y`$jwymkBT6x횉m0]HI!)$FR?6c>>~sm+vuՑνYu8uN?WP>1JsWiV_uKEϸ/rˆ_gKW]ױEYcl,[TYHT}xL#}A GV7^}>iҞ-i;}LJX&TP3T#ߨgJl e'=?͘ona|7>?ǐU%;/mN/IfQփz{G}?v✽3X~j{zTAO^ʰ>?sy|G)PU{ ..T}6ڳ-F`p]k߅~b  О$wݓٱ|sCoA+q3lOx@(0a+? T,_7s\Ϙ^Bl1)C+k(FyN"8dPC_9>O0&l4Im+nwGrŰ)/tihf ѸX>E)<,6s45zb?J\<OM%O#(76:= ӋYAƒH Ls6MXBcX&ǘJte. 3.je(??Lj=%wZizFTx$kP8Em jAOހ>~؆B9 ֤8UKCvjbL Cy ;mj P. DkwUE€3ܨ8xUJs\ɟ+;}sFQ(KIXݛƨ 1 +KdX];Jģcx$D׷X`i @l̏rnm$^9΄zBGϞQ=nfkDe; <a>,⢞jk0B[p($Ǡp4 nq`XƓ vϵ.xHnorJ5Hu뇗 f a[Z:>36[g RL؍?( &w.7C#~B{] UW 71jk~ecGrD.=K@WDZM0倐0\xvqNZ ># BE )&yA}t?B Ym(WIpɱ |2+\2 )l8tl@Z.Be񅋍RSƃm>dIl'N adĢG3%#)?$s _5=YBR#-k"qGP-e"f%֩-ϓ378M9ϊ,_*n;HEBƱcl~ ˝[/sagIE2,z1t:kLș壋G){7ond{@rP>kwk׽ #kXfyEAB9uM4P=_lgW؇N#_nGpp ,ZUu6ȓVӰ0EK7*|]{75F\ԶzQz! uH>upT٣o3P)[^6` -d&*=%fY<^ط`_6|h3ء>2 Pq7ώ ,NsjF=B` 큳CiU)R鐏@LҮǧmb<2FHRqùFXi䎲OmGA}:*u f:@ʫRH.66jcGOpO- 6HKJU:Jǃv,3DZEƮqq7p?ȌK%ȧ$;?Qr6pP7`a^=R_)m>D3#£ _' Iɭu͋C-Rne㯄ssL<ȭ/R)|Lt_1Lk=rr 4/gEr~PnB[\g[{gYvRW' {Fem1{ wL;7&$xc0 n&u@5sCCձm8Heft x{q(aтa?Q%l4ςxmWI׆GC1kQ3iJh,KRO`ʲ4)%b6B8\pe;u)ko)#WSncRx{[sXv195_0Kՙ7>Tp5ٴl3S"؝LX睫[5m Q="u}pϘ*xbՉ#iM+@Z! Ϯ~jYݬ$?5mtu] %@݅:4h8ۃtu3; ΑO1A/r R*5i&j#Y2:$Z(ad@>'z L뇶6Z8|`6"X1_z' F-я?X^ A:?1;h/KVB' vOnFS ƤQ{=kh7MwXQp\v͓O/. N3HKRlK"q^Wh1wt h@3e6N|I;y?8t[[! $,ήLe"z%IކAkRl!3u8ځy?_W)AbCO!rza5Sn֗#<43y6"R߃CQ&>[# BHǽ{vekOTlq(UH͵h ݔ8,@tՂL{p/*L"d_y k,4 G̖bD>,.ok"D;|7[.DCA#ilϟI֬Dq]+eE _-- ڰc^Lq1~CCC9gNH8BkhJ#Z-`VoMa 9r$պZ-hkh ?C$ ^tď9d(8P݅]ڶw[wl;dn׆oKd Hބ(DInI M_(5)6H/Y1 QRk,nXHʉ?>df&6^EJmt{CCc`0ʅv5x<\9Yc}106"״!֏9dl:' 1H"z'7QqɌ#KR./CVgQȬ\ `?d1yuM6Ƶ8ZX]8^pwQE &1frRKi$GݜЕh3'{;;~FK37ku<pdʎ+C RMzƏ7)nҀ lEGyl:̑IoBS%|ЕsTulebA}Aʹ10A{KʘӺtjdLI=r PRg_LbR Şl?␔)![Fo wi&k^CV(t@pW2{hxHGRn͉eCbxԉ6GQd27\ثdS=\Ff*0ۣOP5(rZߙxQZ>~GAeN-jY7Ҿn;n?ӹ"Px}/NW:݊&׾:x" ꭥу;R펔 c䛅љElmG§a= h¨BG_uYnZ쫭FYs U"zM&:Gnu.DX5Xn;}ԫ%XO?~2&Frjj8 yA*W I9/ub)Zl: s 85J>~iI3Yԕ;:#hELם[ROd^GA˩f~Y!En0~/A Km>^WYq"<цF*c:xw|͞w%ehRgd9̕v3v Dgh>>?3hYDkgC(ʹƒԕSԜ| 2Q94(?OGQ34 fccPopTYaW(>@tX4`LGٞpɄaŰl\[9c26U M6f,'C4i?W~psϠ?kAKrŵk@I|>^xs?\`,D̒5W^w DMXf_8<%|8_왉pP1Wlm߃f?4:́_Ԕv M;k:p_sj؎qw]$F}y ,b'N=o0, ~M YR46+!}@~ujctCP.Y(x׎z?70WXFܣo3z0c8RGg0 TU򄽻w"/4֏CQ`[{Ocn]+{{ N!33+5]qpj' r9FDȬ)~: 9Gmx2-?sraG"yvUpa;Ră A\& ?#n 0eed~oq嶭!!DzP^H)>oȑ.ļԶ=Hy7S-M ?8ycߧq|#5"2Б lm#UeΤVbM͘jAc7Z ]> 4gb s 2WRsKg6 's8qzTT[R[w)I95xWj #!nN+zPڔ KgTE,?{^RDݥ=Ru^zîc&D'i74SJߔ&HUG[crͦ<׿~4}څh;lpAZ%XZ;tQ?yk1+Ƴu6[ Dc4Ɯ*dB#!}e>samhG3c^8u9󼵕⸈߂UyB;f "Yi=D =4&|C3g]~WgjhSIXU"1A5Fr4{AljwTt6</N \Rta| i>T.Wo>>xϯY{緷m,J{gg}v~)]s!?wXGFl!7U|Cnfﳅ:.@mq%臔Ru?.:aBֺE#Gg'yXDuSWNJD)21ѵVagWPqȒ s?¶@g")s\T{f3go^w:^"{d#!φt},nyWFKv„X4|VB~,˘_&fjp/WԍwaO H 3I`u1ͤ+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_Wݚw)2iTXtXML:com.adobe.xmp Adobe Fireworks CS3 2007-10-06T21:59:47Z 2007-10-07T00:32:43Z image/png XIDATxo}<%RR,˲:"rT#@ZISN!0z@ ZI*=4&;N8-aQݙyz%M_H[0 w3Zgfn9g>ى/ ;%b$w .Ƙy~??׿|%[`d[V* |<ϳ,....?~_}SROR*)S?bsi>B A((Iyi^:=s~wAҺ6cˑƆX5bĘŨ%$,,˺W^}'|W_]ԖԑU9X8\esITeYTMZ1@̲,}WԩS%iEҪ`bvzOzLPi-jo^F(,몵 괖 Br?IԐTsv\U b괗kR}|FxGvJ*iYҚc/I\k cݺ4]/cǎ=ZA"TTDIQ]1j.D!o|㋒fTbBRME,*|*hf޺||ks=㏪8f1"um:vHrFU-t:)$ tw >{FӡS;nkiڔ$=ztNE$+*b1Y$.\8b!IꮯMH;^/^jwg$(Tv>֜B][miƊ& MLLhvnNz jl6'nܸPq̢q,i6ki/|銲}zv~~PU1JsW~(ΟO?YwըszXS!o>ڵ ysyVG}D9(φxιO W[_y=j5=vz`b$v[޹-ZSfI>|" c1;lՅw.PT3N{I(ꥶ_qdolT$U(Vg/^SQөGkn{vzM+T%!qVUT$P2v;^KBбOh `,/]Vk)$)<,*Jrt1UHnȔއ_,ht'&nk]w$BJ-WyT*0ȓ}7rmmM!:<7^k.m)`4,$)0:,;oH{ ] mNzo6C>Ƹ`$F).vƸ/V}|_䣱W~{noJ֛U5F,}ݺ!Igi޶(7鮫RI4=ݔsLNaGohb$Acc<vWl6UU7`~_P aWfSNnٯrpgMN+\i|2;;y$Ewo8S㪌U$5Ə11 o }+΀tkuwOzڕr>-\"9ij~hJ{/lR6tⓧthD1)ԻCv)ԜZZ&ɩVj^VkuI.vZm9yHSs:|rngJ{; ic!I㍪BUՒ|<|rreL,s{ g(ϕTySohnU+UQtS yy%[sK)\1%lzg8%IKeiq`TNur*$Nqo1U!6p)oI=~z`B, & `lHTup{^eij4]vاfN_nbX0!LbX0!LbX0!LO V4!w&Lbӊ s: `B, & `B,lm~X0!LbX0!LbX0!LbX0!LbX0!LbX0!LbX0!LbX0!LbX0!LbX0!LbX0!LbX0!LbK%a`cdX0^# & `B, & `B, & `B, & `B, & `B, & `B, & `B, & `B, & `B, & `B, & `B, & `B, & `B, & `B, & `B, & `B, & `B, & `B, & `B, & `B, & `B, & `B, & `B, & `B, & `B, & `B, & `B, & `B, & `B,Hbˇ ^F<ˢT"jE7wݛBN'K%k 2oZqdy/#d3PlOpEwa,\H䣏}yk|,x% #!_YYe9p.CESQ1xܹk"Uq/z INIRۋ .T~Pv~{{KEz"y~A*IM̞@TϽK~ӟ^WR G?O?2MbRs5f4>1'soQ~@娢=+*.-<9E9s?/\YsNƴxsNIRc:8'tЧTMʹ"n7˳g^0-Ik*l\H?uԑ澘$IEt+\QQq&$_|?~|k_;,iI/WϭIJc ꒚_җN<z49H'# ࣧ,IVwsg}Ch↤k.K iUR'ƘIR btѐ4%io~_>$ Z91Ƙyxٳg3ϼvڵ]UI*pYňb\[R7kSI $KtHҬC'O<O Adobe Fireworks CS3 2007-10-06T22:15:44Z 2007-10-06T22:30:22Z image/png mprVWxX]hWٽww'; aUA߬D(UĢ>tBJyԧ%/jEhXK_%%jsfvl|np~33ιߜ3?{"QV]T9syÅ._eXr,XYU &Cu|_u|_ %"1 ħ|wrN<8`fwqll&# {0>?%K&+6ōυl9>((&l85C]Fp|Iw x+-5QF㷷JAuJrpy>֨+3fo8\FLpC\OIvs3)IXBB3ؒ6/lF] cA8$)B_iؕ:k Z>%o'*g;#sYoJ)>Gi}nsh$Qc2"WuJAr 䞟qZ\"ꀈ[ss߲XR] qb.UQ|S&P<__ DLIq*k¬u5y7ճB ?- ʄWz\4!߭ցsZBߦAu|_#Fqs/^3&_pȰ :}g3ٙGo9tHaðwal^Hf@""3"2232+AvNM32#}"2r/Ze}Ekgti5ҵ۵9> [K۩79nmʸ~4BW Co>\m?k+{ƒ5zi cmdvwЕ1bxJ[.P^A-vnjx ބ6\kF~Pc~5Zp%'GI%;9lVV貆6&ЁC&Z dg2v]3kB̬iavb8A0kg `3Tb ؘ1jNx:FxjvKTKwnc!BR׌H#h!K`"€š@S84%I䫝a\%WCtqd(S@!ŒB^sDUbi |eNZ6h?qFW)@ l`~ 'gO9n4,ȺF~[̤:@6D (ơd/rG%Jk] iQqs=%N:h:NICFѥF=`&{džʹ/,li UɱbäNZevIHll% Y7>۠hnW j$ &bx@K_cK#J ptHITJ+8q,nVDVy::K))3tJ'hYmZhp+n:ppЏ$@;Y<iI+=fTz-7E@Î4Btλ*gpʶ֣EGqj-hEJ;.17`4([ Q<3NS |eԆr鬟w ɳ/Pki>zOL(Gٸa#O`uƝl6jam:ӄCj[mvr&EV!HbV>,+}ynI>6xb?L\aEİŠRM$}eBqMVv;sGT=`oXuěɥ6/%>KafQHaBɤ/M`Jh#´WS:{ib^!;8mg[ 8˻IhXDJeNQHD RI)|o>୫YW2HA@7INx"zhG-\j'řJGeY\*OF'{:G;,. {]éM(Q fx: HeΎ̗ 9#hO! TNc~ybR-Ml.ү~JM,:#u2st73vM/$ASn8!}qxĔ_o=)J6=Ƿ*d~H V, J5/gOZG~EI]nfx,݇~tKf,R NHa#J]~ΟIz,Ed/H㛜ԗɠ/qv5q~cj6]~:٠a%v#:XHTI'0|e6_tM'84 (%g;<*OB=אU+A(5V- >nrn#v8y +ԫ*V8 I{E2Dž01nl_6'p6$F#JC.lpyyAiQljlh:iȵMrLJqő~MjQlMIߢQ{z}:9S8UG2_!eU4|]#ķMKlbc.W|͜kt]r/2Z(W!|s {o-LMJ{瑪#28!Mћ&:0zkbeK8ˢg^;axI.HDղ ai[u`w`G糱# neV,GqJU-[ @q>j[[i.}.7>8yGUQbl^ ^ UL=XSa'gG+OK ~GWyp%ggYcX9yٸ5 2n*~ӏkbeܐpn(4/Fk+eb#_p=[#-uCn +T"7`*& (iZ*ٵ5TN h3\6 9m"RiU2/x(m4)jMݩ#{kUNV '^fOYW[rcQ(/b lw䋕qʘZ@6RXs`q>oSQ>eUgCTdd͎W\bt(82-6 Zu 9h$]E:։]/;cw (Jg`9Ud3M&["WT +10|k5VKn^;W^+9W՚zխX8t'93jg#aY9&̋Pvl:eXGnQLڦ ([zF 5p!ΠgZQB&l-хn-ѵ@;<ÇPQ$:BTcn#7!79d$Iq8!W.:SiUGw~~5dg=Nټc7 snCxh"׍J׾@ޢx{Kw622=a\UZ1,1 XF{ Mt5tdk,Ժ3.pDkJJ>GaΌg7prb{'ݳa3lʢ#G]xSx }pm؋Yr >ftsa8}!c巐+H=_B9t;(󌾎c+˒"O2z o Trz߃g_,2ւ~%t}c(a :nCEP[ O;Km )AK{X" ˯'-ZӐEXA"%C0$-y)K^% \@Nr!.stlP]"gqK:` :y+sa a|:WXBOBW ]XBmD>^XBOB˶Ѕ.,B;liyXh6Ӷva ]l }/ADu8]XBOB;.,ta} 7rUXʻ:_wHgXyWXEʻ:Y:y+ XyWXBoʻB/.V:XyWŰʻf6[f+ 6XyWF|9+ XyWXBzX`'BZouE>WZK,i~S;i5_lXW |($l#7cTd%uEԫqVPZjYш}=*mߑw.~#ILt,*n$*cޑh*FE$moYh ,t 0DcBE _ n`O~~_b Erȍn O/[Q<mt}\TYk}crS>qٓe <قp|,>C#QƟ&KQר#N_]Lpn;.]CQ L;߂B gz:}+oɯކ_FGoR0' sl ,,A٭NWٺL/tgaj%6}a8d}vGk̯A i! _#*&4Gnc頙 Q;c_{OsW2|_cAw">x{., 8F&H,dA"`Ɛ̺fFl]t}(By s倪by Zr'?AHmyFuV WVi.W^%tcp-"#q}tMQE=O_jrFT= I5DB[z䌎A%ncB>UU_{J,k) !a-uL[[h˷Y>V҅.YMx=4ǹ`p=x p_3(3&Zs#L?v8~^N%^pT dq݉2>BH\߉1/ ,㉒FK\;VA)tq`=X{W\h%:aZK‡`\KƢ._7zE$|`<@w.WϽ: g{/T*KŷQE*sK~/KŚ~^`}[xA ,)$oE<5l]}g8%N-qٯbfm-B>P$.{7$ѣ:ʚ?|Dejx_"z&z>x{|7痍=ܾmhtsz\wɹ!ܣxMm镕56"3@% Ϛ?]z&?Cq:n{gUv =hosGNmZ{߶Ɲ=h_ml# +8’~k9t'>쯯>"`wwKgtYaH9<o d7vqoek>qCŝ]t:6[O:} Be0  Ѱ :$d  Stj6Ἵrģp|ct{ö iC5 mc$>7q][_Bq>w#i u.+A D76yؕ3BgYm5h{]Thvxr`^k`>5肍;nn_Wj_*bV j{To6e^Vmtr*MH먀YfݩWDW \]d2gUʦ[s[7ѡ^V!T{k1^n:f-m[gyN@ kesՇ@!VTz٭T;DĶ]bS"rZA%SE*nRe-=Zd"HVkW*NT*eqܪK8g =J 5FiNr "HvݬP"VIWqTy*x:%bxx"F9DlGuHj!"W:D:<ԃj6e:ut*VVZj4'Ab=ڡJRuQ TٸzF1i@VfY:TE*lX.) M*2N٬Yש9"sQK0"dsRqD22˩A@ڵ2QJ>AO>!{eS*6!')'EX!5!e5~6au5>{`K ^JV/^{KgU#() ed>/tc hifu@ c|=h۾*S>ob-M `k&a ֞h9A4>Cxy sK<(КpN͑F_ڰ7)^ kGӉD@6}N&dftJ܃+H)XCm>ZwP+AߧꙏPУ3Dl$<}a«9ʍ]̓ENІSVK1c]m.Z@EtXי5yHm=FF~P#yQ> i!~t; 8ЀPl?8޾4B Sk)e>*٣ޝskOkK߇sZ{ %;Zq/M~ ϡm=Ft(Mϙ_ bG։v ӕA{ȎQE?խ!fEHkkO8ge_ѳ"ϔ|z|Y=VňϨ+/dVTO)kczDs_:.}GH\_Bn#x#DfgO^o!'[tL:$Cc#h?~"xg=*P)Ex!k~kB-#Ve5#Tac3U۵Stx׉xw MX&)H)Gebݡ- =i)@a~091LæVlCf#FsGQoiY3U_(kFb '&pm*Ϣ3@Rp? ?Fyxy6¨bM9 Klr%,x[.J\<.3HO7uM J6=: ea%̓,IgLՀ Ѓw}XًRcȁT.,]lv~t%"B#+t"Aʄ?RQ-dDɎE.QlzLL)G@IqN L(9ɝJ(Owa7@xTw>7%Gj>98<69 .ȯ(d'٭WT>pFgkz{|0f;iW@LntM(@z>\Gpu'#32#kVt&Y tڨLIFwնjOD;dUApV 3Z>Q$л$.ğAM~+JzO=cmrmA.rI$Y,zq%N]I3>ĵkқZٹ|A*g\7mdNMŏ̧/xQ>aB1J^]7yb mEl>Ki֣4;+_|8%ΫuE<|ZEΒq1>-Ld6#'Y,PDЫŘM/,O("t|0>a6yEPW',j֦'3Յy Y":41U:?[F(SL2 s)^&Tv55ٹ99zNS^5 t=c`}hwg lV"q_ꈶmCe'U[iXmBgA;Uk:/'4iI͔5|ąF-)WhR2IWU>ڑ5,]YcXSc5FՈFYm  էn;}//TSJGEÊa)hXJ)4,a4,䒊#pbh'B4?BLl܃Z>5ȾGQ44ݏ R62Oۄ]H|;{-Y[yvs!9:s"1< #guLꠖK='VmшGSIO2jegH;ȮdG.aVⲂr v\z=#9gF'\:sޝAnG̰"1V#ݒq׷fbD䜏NnQܪr{˪3i2^I\9WG{G78Km>z#z%DGǢD"cؓDq7|YCY(1q,w}:kX}ͯYbtk4fQ*~n:oO2I5,RYxOFC&:i[$'[ Uy:9<*0YCO,1)p#KG6.(xQFDcy5sӒ(?|dyH՞R|G󸊑rl]eތx5Oi_,/t53W?!ϓ-~Vȗ\̻SSy"l%v| yK"%i20z4%I.%ټ;1/iz5%W?RUٴwHVx^:=y"_RDGL;S3+9_,s53%ETW'QUg9Ga)9y?H9,rNx] ׮vU|Cqw/I.g{NDx߇3!O0͛z{rGkw[6 2<ɒe&B[M=I:Wfc)xqy]p`rϡd+m&|{uJLS'ʷښ5~}4-PI ӏD9dU[Wp,SW'LY3{uywl:h`:6vz+_t>-}̚Qь;2қiu2ɪf7v=,^Lr,:Oק; E'Ol&zzuz2«܍&y7Mw4}Hu-G([imii4!.Dๆ>%FdrЗI",'g #2-wN5 $t [  Na}|tvJG+bA,}fHjzRP-ĭQ++WWx\^7r-kBx|$ywۤUol$5$`֖?G;3vc=zzkGL^'Wί^ѣ|6:el?c%θza/qvUtc P*_2gttA~갤:)aKu8S`tzJ]#w ${^x*lK@D\g%FIjx'!E(>rG<@7.AcS|.NI4LGsw3>#LJݥ|*$K_H#vѻ>2OCWfO5Chv2j^FvYS21T:&EMI!YTZf-S2+%IJY!~Ogb-SiYʢee+tɨKMjðn <`:e(ݴ瀧LgMQƗ$ӥ(tb=3VYh3teߨә՜=c=]d! QX+t> ~bN>jՙއoJ‘h^7.Z28Sх$G 6Ex΃Qg4J@ɽ%n67/j? uK16{p W#܃ \9Ρ`{P}:_ RQ"j"fQVQ;==r_ytN`M xS(t3Vz=}aM¯A~DʝAvIk±zFu#&Yrl<؝d~qJ@ЕT(Ep+uGuu6kIB-Ķm9Ui'/x\(bA;T@Q62e! *!:/俦Ge0*ZadU˜՞I%٥ziuiaՐ\qD}#+hoG4dgH4y$\Afg<6b[ xO|HGkxoqXQX[x4F,x%[jIuLGQ#8)*Bŋר1fVud{_GrKP$˨8Y8<VKu8ͅÓ?ZQ鏓M$mciKgQ1 ,eϜŏ\Řivӻ7:'Thos5.>?fbC?="[14=^KI{MθgH~[Ҽ[(-, $T=fdB}ws996dd쯁e0,̯ҳ}DY?UPٻж9'5\\c^cps ULG;yrPBQR1d6@]2}vE.K~* ]~Y ,e_{) 3if~l936ixsF7[k+2;M,zkArΧ9&iUt^;{;9ʦ麦71᥉6,,\ĩEr.vձZj*gkZsr{ MzYƯxo*FH>2L\̓."VKjeڶU{$d!K~$Hf FH2*/a,s,a]㴺:e'4P[0E62U[ԃ僇X<XƤ/!GЯK w kømGZ.]۩]>Λ:}ska`[e2nap3jY[C)z Fr]9FWnMOlue(;xu} ru5}tgހB\koauN~]J`[{P6Zp%'GI%;9lVV貆6&ЁC&Z ǐsYa9,1&̚f(f llظA 6^OƌW#8vjt,!t<5OS_Zvj^_‡/ɃfGMIД$vƆ!l7Wɕ69C!]}DN> $Z0&kKk櫷N/vmF)F[ {JzƜ6P~rGvH2K[igκL: dC bJZ +w>PY+;N)q)=Fsq<7msJz|KE=G`:&up{zqe]|g3 cCѳ@chLI1hnShV`T*G@ Qޡy4RK`lAԟ02 B6A%! 0[ WЉ4q$ksQ`QqrG>Q;alt0 YԶE:L:NY{%OהqbCN0Zpã$| YRckR<&62o'NBbI "4]$sp\ewhCBn=4†GGW(Oh)V\$}|7Qi}ؤ&WE^$4 -bP`OW-;+dy@\l< eja Ղ"gրpkPp+`L1M?:=sC¹а۾ n-m_lgkE3nq6m#r_{xY&=_%/ NPTMkk 44 ޜw^ ]+,ta JaoqN,tluٷOѫbX4)ܝΚ/K6i +lUczB1y* Vغ"U8YHsZ-hľ6;Tp^kؑ$&:W71HXe|#QK"Ϸ{,4jB˱fa ]X"W~7F?F/p"g9m- 6>.*Ϭ@1}¸ɲB lA8>PIK{!@(OHk'{/.i&E87ehdXxH&o_G}]Eu 3=Auw¾}~MoCK@m#7PE)zkfFWX RrS9vmSC  I'HHlX&OS30܈x>0^BJ2DP;SqOWf{ p邴_WGre rlu`1tL(A]ŝOs/'Q׹+GkJVů1 }WɃE PyZ=#?$i t_BcHfN3k#.>I j!<r@_1<-9jOn<:+MR+A4kz+_18Befّw>"/?5{9QwW"S-p=rFGH VN1hx}*Ј=%5:B_Bfۭ-[hw,tT +]XJVz&Kt<gGpu/b Թ;FwBY?/'ɉze~#5@ |isNT |'`At};^ïQ> qpȷ d;֡.就t0 ++n9%@愱\2&`Ɩ鑧;VKۈ>~|qrJe,!I1'0xD39`.ԄQ|G9B@s)} /4z9߃!xs%vu,8݁5.ȼ ̻07bxZ"/̉! ߛ =/8߆vٸD!$zDStDId%CmU 錔 8I+.q4XP0-I%Cw0%A^cQE"I>0^hqaܫ^ɽ*ytۨGe΢?x%%buZk/Uw64NSG9hY>ÆlV؀>~ 6[ `o0a cYPRwZN]{X;5\&1^iFF|乄:W: }S~[<;ͳ`=2dMyl}߼8>j1<BUYAI}-XO`#zdqsYܳKRgx xRp% @rLXۅ<[dۣQ.Il/x,<;P wwGygeA/Q Ou,fUb{4ΪskJ3&|{:}r =3HO.~_5v]zs <Jr1ub:p9.d4!MnCQ3O/!c0le~|rVZ ^0 tgp2;:?&pX|[fM%&}vc?Q)q[qlZ,G)qyS&p5*\|%=*{ ; #!+'dxM>V3nj+vxD6(ߡc8na [|ldz'ArH7ȯq[w $뷹3BgZ渱:‡;K]:ZP"6a{痬ɑqn6T| ㆢ;膝um| IWBF{k lnm.t2U!r{.22aAt:l36La*v}{ip5Z:F. zzCx|Xƚɭ}/ol -8JAW[M=p =^.ב=<_k ̧f]v kj_ k\E jXmo&̖E]Z^ŶI{CI{0^լ;ꗈꗠ+_"AsJtkW#t+&:u*jt-F+MǬ%Pm\, ȶtlzg(a˵Na hH@e:U(uS6JCQ uut8Jq({<鞈 @ŭ* kXLb zli7[mԃX˖p#ĪXހU/c'ӒضVlJZW+d*HŭW%]L*5aMVŲ҉T\J8[u)\L'RԨ#ͩXA=ۮJ*#*N2*OV^D̲SwOO^6"(؞hp.U-BV*VUH'zP&cP\Lџ@*W*bbUkU" VG;T)W#*} 1WϨ8&? =TrݪLQ1UWP"[ K%%IE)5 :U5G$b"jFd\ 2u^*n#2HRFc94TD*2:3ޚZTE25TOLM&SG1әD.#}rMV!:VIg8H*[cTVd*t)N_cQkU/Ct2tz%Et2uF DZpf8pU}8lU;b#G|H=7N%~$wȀ՜ZNd#Y Iqu'QLHjSTdbuh4gp/J%ٿ8( Q*lt)NN~d&$ /ZWL~ Id&$xeFF=Y$;!NٞF{ѩ6&{+Ǔ“Ј6چOx@ed8RWh4VdORsO4R-^C[#BZ\?ALB=Ѳshh|䷇x76YRxg wI5dU#%aP$sO'Q v9 nJdI)s#` j1aB ~g>BAHi:8 k^yWFPn8bd/Rw6B'P@_:$uY nu.ZD"w>xtάC}l31|4^Ӆ ,nH h< ~KJ3 2)؞Y=l=boH N K );`D}2E$D)_Q4bWz[`Y>ب#;TdQ l}(9g{/a ZD7Ҥ8xcDRu{ ({ ihls|{ME?-խ!fEHkkO8g5_ѳ"#ϔ|z|Y=VňϨ+/dVTO)kczDs_:.}GH\_Bɦ#x9D0)Ξ.B" =N訙uJIM-%(RG&~6XE%'zUt&RCתZF$j\G \;0mÖ gj!kn=7ayG»i’7OAOAF/]=%*I>gua%ֿW63ޟuT̿m>1Kdon`i0Y!=tdk{?oM e&g)6C?+L_~?]o? ԓ_bKo?=BG _K QӏpƱbd-޲D$pakIعxD1=%!Wr}D 1*&^(/Q4 ^+#By]ٰ pSa":b\ۢ%Oi6FUh }WI-.u'e}:ku69l3 fߕ=":mѻ#m;|ZٸuV68w~~[&p_ހg ߦ#yj/`Mw.a4D z~ zcY&VڂcHBtnS4>1lZ+n6d1k;wu5^M!{=nf,*11 /Y g_k$i[Ix~߈ꁗg';**֔Zɪ&W‚Q=ĥMk;sAqQzhӣCp_QI<ɒt\ p =8G({!;H/f@]r\-"dM!K@J@1B'RyL(Y1(#%{ (JvJX"˦G$Or@ɄI) (tyJu s#^R* !~#DxȱJ gae'mcQIj~&qDERxus&=/,Gx:ZUt}^gdQXIkc?ɕ5UT;SWsSV' I7)unUs:]ݬ(ɺSI3k+]}q;(r\+X1^ы;6}RbP6?u䣨諘csG0~ z{]ym~E㐎ht(ќiη cC}} $FgєAfx'SuW(}22{)S;&/jJgiIGd-?mACVau;#ke Z¢"Bg* /kw^M Xazu|¢fmq>S]8K<ᛐ)iKs\ZceS'ADρI<˃qS OF=Ӿe+ʖe[IɁ|󤫣5iҹt)gS9d.N??wEjbOeYQ{M3zg>UyO3 > Fm/_ +qz k-eίhk_v;:T\~}:\eՖk|,)x4SKrBIkLY#G\hhђr}&%ә}^僪YcX5z5u.:5V#kTn@fO>P}NӧH*I-_>tT4H"[AOiJ.h8 '~"(D#=S{E@{/UOmc.󄿯Mۅ~=|ך܁Rga7k;Q3(r࿋>bqVj/snx=$QFqJx$ h(.+(.hNɥ?s:yftu:v .ΡPxi5]?-w}k&A4Jḓ*Ga{:F*e+Duxsud91yt{эӽ棗:'QZnYOtt,JK+b?=IIw~1ȧ5D"WNɲW٧;OeyYꟕ/L&@hV] a$D[-$i4DMlmocyٟ%Oi{PGyXsɳy uiZO&LBk k_"qlD!})t rr8+rTú`)ANApo0xz __MGgml}4G(27чhƏ]x{ ܒ_@zkr{{++Ԋp{oJwMJYƶy_]ORJfmO|ө׊מjvdTu"}[=JgSS-Z9&3V+aOM_og[K:[U>k+8}FGD~aMKÞBT3:VKGܥ:rKNJ%hgȶ$=^ OuV?awRԌsK }{chI9=5DtMP:w03¤]ɧ}Ai+MX4bg+t9tevxZT:-`'#U8o$j%?>/CchQԴLZ8eBk=-RiYkgt&2;%Y,ZfxڱZfKBk}]@nj$T6 립к/]\M{xz9{tv-t|<e|p;N2]H'3:)=jEKX־ =oy\<uFT[f| pOAs/`~P'kC[K_p?R=q}N[ |Ε %:ߧs% %BIɯ&bEaX:Qc!Gm$ NJP:L7aYݴ/:+}AĬow}/6,gdY7Bh!SH7AK ]Me] )h[Pw`^Pg!Ɵ$hNliܖCXvzRX ̅L ),dHee)cq ]@*{Ͱ-Jkz,PVQ 㫢FVE+ix^)T]*Z^Y cF+̝!s|kěN9Bm4#Aw0n"+CK7rk~..qD#JvDGB<8d l'qSh#՟''tJ޺^ek>wNcĢP柄Pg:>Yt5>y-{.QcoU{_Gu$.ď~Ar1PӑlqXW9|q\8B+lWh:!-\GijeOXf 9]WA\\Lf[xilϣTs1H QlHاEt(SAZ_Y X mkBTWx흍8 FSHI!)$FRHnw HYx3ꇤsaaaaxIǏ'U{o_ھgW9 o'GW {>~Jlo߾)*/N\ϱov[iZ_ձaJΝ/:6O- 92b?Tlk%?_21B sY5>:>c=1Ow y^- ڶ,XzusM#גU]>H_yYv!ۉ_mi Rus]Xm_g)YY)m]y,m z1aaaxEߓGקo/Y\k6xjgH|yu.\aæM&wk#ϐ$?]Mo\Ⱦ,/ڥQ@~6s?)}, l gX #vQg Bٙ^uのuhm?}{].~}v_J;xogJY]޳@.)oqC?}>@Xߘ'-(W? źvƔOʙRv[K?[A}?-wmՑ}g\=c}M ggg DŽ-B^k_g?F? v0||؎=ǧHPgs/hؑI t~{n^}ZyD5XWvO)"c0vY Z|~_%/,p\ɹyΰZ/;/xs_9?Pܯ5ݻ\[y|č8gʱL{? 0 0 _k3>z_\S |<)b|7aaaxn.ta?l^Cvkؽ#~e)3<3^kdlc&jK+o"e<.ʞ`^(3zu l+6v<ï k7]/lc[`On}򚄫 G뎱zt^v2)?;Wmr5ocIz?Ozx{&!ez."ѯ 1Gg{+ҏlw<=}GݽFƨ^)zIpG K֜{{e G12ۭqiumf>.}~a? 0 0 [u+7Svq֭y΅ ?ނ}XwŶv?ߩDZۓ-q/?߳=<~#>Fk"qzrQo 9r,nY[;o:)@-`ק-7({߯S@µK9֠ɸ>:n3 _[_*mtcmC>qSL=<6;ǫsaaa{xˌ\ފpx?0׋#5zяc]x^l򼠕(f:~٣^lin59W~\;?vn6erUbS~v^U O7O(|;+SG4|?f*?rW~2oNٟS9~daևmH6mX[J~s.ym4ٶO|Bd/b5ɿyU? 0 0 0 0 0 0 0.P~*1@G\⟿KrKXs2(ߥ纎J8'>X@▼QQbqwx b)_K|v 1M6kee-2Ǜ59?K^E~9ϱQﱮYF8N?~;:=J<-tĒyNAgC \NXKs)'^Kg\~2}6}Գ)n]Or^j~"{p29w6/.z-v:+M{WJYZ굢`% Ҥl9ힶկ#OUz+U?;sd~vND7*.Y+v:ye;8}~|+ÑޅN9}{Bƞ#txխsXɿkSV/uJ=o G<ջL'L:D]6jfgLz/+ؽ[{rCMYq~[{yy czA;w9zszWHVax3 %mkBTx흍) q ĉ8D^>׻gI@XjjgiЃ`0 `0 ?ϟ|:seQ3|ӧO|:2|.};7eGFO6_Qv]T]^ˮg{>pjzkuo{yye?{-x/ D:3D&򈼹e^Hyi#/OGzϪ߯_~ :sMe#M3Y#=2 QЙ[\s=E8}E>GȩT ڲTg-}VfoSVwzV}./>~!?U1<#}=F[ ~QڋBN..+푹^edLo+[\-k dW(}6q$#?z6Bөi?L7!3O_Q}Пuo[=tkȋM!'}/Ƈdr2_Cﲨ: `0 :8o=+8-4}۞cĥXdq{bUq©ήm!ƶg*ΪU\z[GA=^+ru{LV U?)V>ғ)x|Yҁgi\yi^cUo*= !TY?rfgWsʽVn*VX#=Fϫ+[F~yH\L~[O҇h5ݵTow|Sfӟ+);F;:x )/OS yUo2e)Ve3'wgGg=J^`0  ľu kU,Ksؑ5nY,bXw{ w&3QהNQev ]ƷgcH˞i{A3I8hwduwUIWq8I>+@pQşGcZ\ƪUߝ]/:3d;ɫ:gB9R|GW~w2;fzt|+i5nΟgZY|<1NyŬ|E7k?z/k><=Α}N΅>uWydʬdz `0 *\?W8GY:Dgcg< 2+'W6qn؟{ru"wU쏘~c#T?+y{Q,,^qF/Xv8.֩g3}ȸOP ~n%hUG4(_sn|W}Tg&x^c,Fѭ+ <#+}/Uw8BRh_|33!mr\7U9m({ѝpvew[xG]߱?g;,nҽow8]וb?OV=Z_#ve?vN_WrYLo;1g9pV^G~>[_vNOS3 `0Q[ veO\k^8֔v<Zbz\Opbn$~}oz3ј mK vU]^iNWA#x딫jt q :E= z%օq)CcYEqyRG-+u (K\hP'*^ء^q=m=y|Kvūe\rȊ4={W1;=ݷxp;o@>ȘT\Ԏ+C=*ɫ|GJOCW]x1.ﵠ9_Eб Vq)v(ʑ}[GwǺ{-oSdו_˞׃2;iT&w*w:g׭SOsj%Z[~_˯d֮+w]7 `0]kIu+eL]ւoA^;=GR?v쯱;<y o$N1紈=:ߥPVu< <&3KyC/4r)i=*/|Ύ^]QNН1qGw>ù{ ?Kv:A}E:_n+{u=rq͓̳]>>d}+|L01`0 leg:׺񶊝`W,3O?]\9P~[kOWiGc~)-<w.3q}'vuw$Vnv(r52S;Wk_Kϔ8B/hEՠ'9w?K;x:x<|@cϽVyc@ۖSw8Bq]=2lBe6V}eR( VeZT4ade2ޒ+nYBTqSߔ<[&=f[|szP)G}{Zׅ3n7jpWwftEw[ǽ;`l? `0 `0 `{~i`oLy>uoi\qK|}7Svu9G쯿c¾#>,jow{ՆݲL=mW2u_8دjo?kD߱mw>#}E:OۡO;y`$jwymkBT6x횉m0]HI!)$FR?6c>>~sm+vuՑνYu8uN?WP>1JsWiV_uKEϸ/rˆ_gKW]ױEYcl,[TYHT}xL#}A GV7^}>iҞ-i;}LJX&TP3T#ߨgJl e'=?͘ona|7>?ǐU%;/mN/IfQփz{G}?v✽3X~j{zTAO^ʰ>?sy|G)PU{ ..T}6ڳ-F`p]k߅~b  О$wݓٱ|sCoA+q3lOx@(0a+? T,_7s\Ϙ^Bl1)C+k(FyN"8dPC_9>O0&l4Im+nwGrŰ)/tihf ѸX>E)<,6s45zb?J\<OM%O#(76:= ӋYAƒH Ls6MXBcX&ǘJte. 3.je(??Lj=%wZizFTx$kP8Em jAOހ>~؆B9 ֤8UKCvjbL Cy ;mj P. DkwUE€3ܨ8xUJs\ɟ+;}sFQ(KIXݛƨ 1 +KdX];Jģcx$D׷X`i @l̏rnm$^9΄zBGϞQ=nfkDe; <a>,⢞jk0B[p($Ǡp4 nq`XƓ vϵ.xHnorJ5Hu뇗 f a[Z:>36[g RL؍?( &w.7C#~B{] UW 71jk~ecGrD.=K@WDZM0倐0\xvqNZ ># BE )&yA}t?B Ym(WIpɱ |2+\2 )l8tl@Z.Be񅋍RSƃm>dIl'N adĢG3%#)?$s _5=YBR#-k"qGP-e"f%֩-ϓ378M9ϊ,_*n;HEBƱcl~ ˝[/sagIE2,z1t:kLș壋G){7ond{@rP>kwk׽ #kXfyEAB9uM4P=_lgW؇N#_nGpp ,ZUu6ȓVӰ0EK7*|]{75F\ԶzQz! uH>upT٣o3P)[^6` -d&*=%fY<^ط`_6|h3ء>2 Pq7ώ ,NsjF=B` 큳CiU)R鐏@LҮǧmb<2FHRqùFXi䎲OmGA}:*u f:@ʫRH.66jcGOpO- 6HKJU:Jǃv,3DZEƮqq7p?ȌK%ȧ$;?Qr6pP7`a^=R_)m>D3#£ _' Iɭu͋C-Rne㯄ssL<ȭ/R)|Lt_1Lk=rr 4/gEr~PnB[\g[{gYvRW' {Fem1{ wL;7&$xc0 n&u@5sCCձm8Heft x{q(aтa?Q%l4ςxmWI׆GC1kQ3iJh,KRO`ʲ4)%b6B8\pe;u)ko)#WSncRx{[sXv195_0Kՙ7>Tp5ٴl3S"؝LX睫[5m Q="u}pϘ*xbՉ#iM+@Z! Ϯ~jYݬ$?5mtu] %@݅:4h8ۃtu3; ΑO1A/r R*5i&j#Y2:$Z(ad@>'z L뇶6Z8|`6"X1_z' F-я?X^ A:?1;h/KVB' vOnFS ƤQ{=kh7MwXQp\v͓O/. N3HKRlK"q^Wh1wt h@3e6N|I;y?8t[[! $,ήLe"z%IކAkRl!3u8ځy?_W)AbCO!rza5Sn֗#<43y6"R߃CQ&>[# BHǽ{vekOTlq(UH͵h ݔ8,@tՂL{p/*L"d_y k,4 G̖bD>,.ok"D;|7[.DCA#ilϟI֬Dq]+eE _-- ڰc^Lq1~CCC9gNH8BkhJ#Z-`VoMa 9r$պZ-hkh ?C$ ^tď9d(8P݅]ڶw[wl;dn׆oKd Hބ(DInI M_(5)6H/Y1 QRk,nXHʉ?>df&6^EJmt{CCc`0ʅv5x<\9Yc}106"״!֏9dl:' 1H"z'7QqɌ#KR./CVgQȬ\ `?d1yuM6Ƶ8ZX]8^pwQE &1frRKi$GݜЕh3'{;;~FK37ku<pdʎ+C RMzƏ7)nҀ lEGyl:̑IoBS%|ЕsTulebA}Aʹ10A{KʘӺtjdLI=r PRg_LbR Şl?␔)![Fo wi&k^CV(t@pW2{hxHGRn͉eCbxԉ6GQd27\ثdS=\Ff*0ۣOP5(rZߙxQZ>~GAeN-jY7Ҿn;n?ӹ"Px}/NW:݊&׾:x" ꭥу;R펔 c䛅љElmG§a= h¨BG_uYnZ쫭FYs U"zM&:Gnu.DX5Xn;}ԫ%XO?~2&Frjj8 yA*W I9/ub)Zl: s 85J>~iI3Yԕ;:#hELם[ROd^GA˩f~Y!En0~/A Km>^WYq"<цF*c:xw|͞w%ehRgd9̕v3v Dgh>>?3hYDkgC(ʹƒԕSԜ| 2Q94(?OGQ34 fccPopTYaW(>@tX4`LGٞpɄaŰl\[9c26U M6f,'C4i?W~psϠ?kAKrŵk@I|>^xs?\`,D̒5W^w DMXf_8<%|8_왉pP1Wlm߃f?4:́_Ԕv M;k:p_sj؎qw]$F}y ,b'N=o0, ~M YR46+!}@~ujctCP.Y(x׎z?70WXFܣo3z0c8RGg0 TU򄽻w"/4֏CQ`[{Ocn]+{{ N!33+5]qpj' r9FDȬ)~: 9Gmx2-?sraG"yvUpa;Ră A\& ?#n 0eed~oq嶭!!DzP^H)>oȑ.ļԶ=Hy7S-M ?8ycߧq|#5"2Б lm#UeΤVbM͘jAc7Z ]> 4gb s 2WRsKg6 's8qzTT[R[w)I95xWj #!nN+zPڔ KgTE,?{^RDݥ=Ru^zîc&D'i74SJߔ&HUG[crͦ<׿~4}څh;lpAZ%XZ;tQ?yk1+Ƴu6[ Dc4Ɯ*dB#!}e>samhG3c^8u9󼵕⸈߂UyB;f "Yi=D =4&|C3g]~WgjhSIXU"1A5Fr4{AljwTt6</N \Rta| i>T.Wo>>xϯY{緷m,J{gg}v~)]s!?wXGFl!7U|Cnfﳅ:.@mq%臔Ru?.:aBֺE#Gg'yXDuSWNJD)21ѵVagWPqȒ s?¶@g")s\T{f3go^w:^"{d#!φt},nyWFKv„X4|VB~,˘_&fjp/WԍwaO H 3I`u1ͤ+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_Wݚw)2iTXtXML:com.adobe.xmp Adobe Fireworks CS3 2007-10-06T22:15:44Z 2007-10-07T00:39:07Z image/png 9-)IDATx_\=suQ%M_bBA>_$}KAӇBA lZ(>t-Iy1Eۂ"L yPN i05ӇΚh>/33w_=1 l,! KD%d-;`ͥ;:03GaIJ8VONN(Wrf//'Տ2?:-[9Nc m !8g`2Kdi}7T^_{ݶuSi(Q].r9`1ˢc` $Aŵ#N>zg+M nŇs* 8 DQQG>W!xƥ21JPJhXs羪֮41=-gKqb0!B><υR0f0@kD)$BBK慝jWX5~Z=`4cӦĈ!!m fY6BKZcz1HImbq><}|hPR2[sEy ff"ąaއ:Bs~y-F88ߕBz9,vzů[VYŁ! q; |\ m?Bx+˜!8r> q?맟c[mn:aG>džme13!l[qlcqeREu.nH)aYZBn,Y(|1[m\x%x== !d}Yb-89|ɪ lhuRR@pF3-!S1 eAp)mۼ7b|ݫ2]+)_̪ nKRJRBʑk0!2\Y9BpeaL._,{gm} 3p!k !ӳl̚8[zwXV(j Yd3hK(ff13f2C΄1 IT%^Z-T#U J)6 )L gZjϸ~ |07Bj||쉬3[9tިtI@)40Zidh$QtVػ>?BAEUH˄W-.ܷyhU[6ڝDA]rs 2J+e~\3g?o4[h6h;vP5z B C RoͿ-_MG֡˗VmN)hh;{:ژ YxjuTQoUКKzfHknWU;oҸp׏+ťjZ:J-ߥ}^B&[{Wtw_IWW wQGg%dFڨ7O|DirectoryEditor, the TabularEditor and the CodeEditor used to create a simple Python source browser: - Use the DirectoryEditor on the left to navigate to and select directories containing Python source files. - Use the TabularEditor on the top-right to view information about and to select Python source files in the currently selected directory. - View the currently selected Python source file's contents in the CodeEditor in the bottom-right. As an extra feature, the TabularEditor also displays a: - Red ball if the file size > 64KB. - Blue ball if the file size > 16KB. """ import traits from time \ import localtime, strftime from os \ import listdir from os.path \ import getsize, getmtime, isfile, join, splitext, basename, dirname from traits.api \ import HasPrivateTraits, Str, Float, List, Directory, File, Code, \ Instance, Property, Font, cached_property from traitsui.api \ import View, Item, HSplit, VSplit, TabularEditor from traitsui.tabular_adapter \ import TabularAdapter from pyface.image_resource \ import ImageResource #-- Constants ------------------------------------------------------------------ # Necessary because of the dynamic way in which the demos are loaded: search_path = [ join( dirname( traits.api.__file__ ), '..', '..', 'examples', 'demo', 'Applications' ) ] #-- FileInfo Class Definition -------------------------------------------------- class FileInfo ( HasPrivateTraits ): file_name = File name = Property size = Property time = Property date = Property @cached_property def _get_name ( self ): return basename( self.file_name ) @cached_property def _get_size ( self ): return getsize( self.file_name ) @cached_property def _get_time ( self ): return strftime( '%I:%M:%S %p', localtime( getmtime( self.file_name ) ) ) @cached_property def _get_date ( self ): return strftime( '%m/%d/%Y', localtime( getmtime( self.file_name ) ) ) #-- Tabular Adapter Definition ------------------------------------------------- class FileInfoAdapter ( TabularAdapter ): columns = [ ( 'File Name', 'name' ), ( 'Size', 'size' ), ( '', 'big' ), ( 'Time', 'time' ), ( 'Date', 'date' ) ] even_bg_color = ( 201, 223, 241 ) # FIXME: Font fails with wx in OSX; see traitsui issue #13: font = Font('Courier 10') size_alignment = Str( 'right' ) time_alignment = Str( 'right' ) date_alignment = Str( 'right' ) big_text = Str big_width = Float( 18 ) big_image = Property def _get_big_image ( self ): size = self.item.size if size > 65536: return 'red_ball' return ( None, 'blue_ball' )[ size > 16384 ] #-- Tabular Editor Definition -------------------------------------------------- tabular_editor = TabularEditor( editable = False, selected = 'file_info', adapter = FileInfoAdapter(), operations = [], images = [ ImageResource( 'blue_ball', search_path = search_path ), ImageResource( 'red_ball', search_path = search_path ) ] ) #-- PythonBrowser Class Definition --------------------------------------------- class PythonBrowser ( HasPrivateTraits ): #-- Trait Definitions ------------------------------------------------------ dir = Directory files = List( FileInfo ) file_info = Instance( FileInfo ) code = Code #-- Traits View Definitions ------------------------------------------------ view = View( HSplit( Item( 'dir', style = 'custom' ), VSplit( Item( 'files', editor = tabular_editor ), Item( 'code', style = 'readonly' ), show_labels = False ), show_labels = False ), resizable = True, width = 0.75, height = 0.75 ) #-- Event Handlers --------------------------------------------------------- def _dir_changed ( self, dir ): self.files = [ FileInfo( file_name = join( dir, name ) ) for name in listdir( dir ) if ((splitext( name )[1] == '.py') and isfile( join( dir, name ) )) ] def _file_info_changed ( self, file_info ): fh = None try: fh = open( file_info.file_name, 'rb' ) self.code = fh.read() except: pass if fh is not None: fh.close() # Create the demo: demo = PythonBrowser( dir = dirname( traits.api.__file__ ) ) # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Applications/converter.py0000644000175100001440000000615411674463545024137 0ustar ischnellusers00000000000000""" Tiny application: convert length measurements from one unit system to another Select the input and output units using the drop down combo-boxes in the *Input:* and *Output:* sections respectively. Type the input quantity to convert into the left most text box. The output value corresponding to the current input value will automatically be updated in the *Output:* section. Use the *Undo* and *ReDo* buttons to undo and redo changes you have made to any of the input fields. Note that other than the 'output_amount' property implementation, the rest of the code is simply declarative. """ # FIXME: Help is broken in QT from traits.api import HasStrictTraits, Trait, CFloat, Property from traitsui.api import View, VGroup, HGroup, Item # Help text: ViewHelp = """ This program converts length measurements from one unit system to another. Select the input and output units using the drop down combo-boxes in the *Input:* and *Output:* sections respectively. Type the input quantity to convert into the left most text box. The output value corresponding to the current input value will automatically be updated in the *Output:* section. Use the *Undo* and *ReDo* buttons to undo and redo changes you have made to any of the input fields. """ # Units trait maps all units to centimeters: Units = Trait( 'inches', { 'inches': 2.54, 'feet': (12 * 2.54), 'yards': (36 * 2.54), 'miles': (5280 * 12 * 2.54), 'millimeters': 0.1, 'centimeters': 1.0, 'meters': 100.0, 'kilometers': 100000.0 } ) # Converter Class: class Converter ( HasStrictTraits ): # Trait definitions: input_amount = CFloat( 12.0, desc = "the input quantity" ) input_units = Units( 'inches', desc = "the input quantity's units" ) output_amount = Property( depends_on = [ 'input_amount', 'input_units', 'output_units' ], desc = "the output quantity" ) output_units = Units( 'feet', desc = "the output quantity's units" ) # User interface views: traits_view = View( VGroup( HGroup( Item( 'input_amount', springy = True ), Item( 'input_units', show_label = False ), label = 'Input', show_border = True ), HGroup( Item( 'output_amount', style = 'readonly', springy = True ), Item( 'output_units', show_label = False ), label = 'Output', show_border = True ), help = ViewHelp ), title = 'Units Converter', buttons = [ 'Undo', 'OK', 'Help' ] ) # Property implementations def _get_output_amount ( self ): return ((self.input_amount * self.input_units_) / self.output_units_) # Create the demo: popup = Converter() # Run the demo (if invoked from the command line): if __name__ == '__main__': popup.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/0000755000175100001440000000000011674463545022353 5ustar ischnellusers00000000000000traitsui-4.1.0/examples/demo/Standard_Editors/TupleEditor_demo.py0000644000175100001440000000231611674463545026173 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. """ Implementation of a TupleEditor demo plugin for Traits UI demo program. This demo shows each of the four styles of the TupleEditor """ # Imports: from traits.api \ import HasTraits, Tuple, Color, Range, Str from traitsui.api \ import Item, Group, View # The main demo class: class TupleEditorDemo ( HasTraits ): """ Defines the TupleEditor demo class. """ # Define a trait to view: tuple = Tuple( Color, Range( 1, 4 ), Str ) # Display specification (one Item per editor style): tuple_group = Group( Item( 'tuple', style = 'simple', label = 'Simple' ), Item( '_' ), Item( 'tuple', style = 'custom', label = 'Custom' ), Item( '_' ), Item( 'tuple', style = 'text', label = 'Text' ), Item( '_' ), Item( 'tuple', style = 'readonly', label = 'ReadOnly' ) ) # Demo view view = View( tuple_group, title = 'TupleEditor', buttons = [ 'OK' ], resizable = True ) # Create the demo: demo = TupleEditorDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/FontEditor_demo.py0000644000175100001440000000304111674463545026004 0ustar ischnellusers00000000000000""" Font editor A Font editor in a Traits UI allows the user to select a font from the operating system. Typically, you then pass the Font trait to another UI editor, which uses it to display text. You can also read the Font trait as a string, or access its individual attributes (note that these attributes are specific to the UI toolkit -- QT or WX.) The default 'simple' Font editor style is usually the most useful and powerful style - it pops up a font selection dialog which is specific to the OS and toolkit. This example also displays some other less common style choices. """ # Imports: from traits.api import HasTraits, Font from traitsui.api import Item, Group, View class FontEditorDemo ( HasTraits ): """ Defines the main FontEditor demo class. """ # Define a Font trait to view: my_font_trait = Font # Display specification (one Item per editor style): font_group = Group( Item( 'my_font_trait', style = 'simple', label = 'Simple' ), Item( '_' ), Item( 'my_font_trait', style = 'custom', label = 'Custom' ), Item( '_' ), Item( 'my_font_trait', style = 'text', label = 'Text' ), Item( '_' ), Item( 'my_font_trait', style = 'readonly', label = 'ReadOnly' ) ) # Demo view: view = View( font_group, title = 'FontEditor', buttons = ['OK'], resizable = True ) # Create the demo: demo = FontEditorDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/Popup_versions/0000755000175100001440000000000011674463545025406 5ustar ischnellusers00000000000000traitsui-4.1.0/examples/demo/Standard_Editors/Popup_versions/TupleEditor_demo.py0000644000175100001440000000260411674463545031226 0ustar ischnellusers00000000000000""" Implementation of a TupleEditor demo plugin for Traits UI demo program. This demo shows each of the four styles of the TupleEditor. """ from traits.api import HasTraits, Tuple, Color, Range, Str from traitsui.api import Item, Group, View #------------------------------------------------------------------------------- # Demo Class #------------------------------------------------------------------------------- class TupleEditorDemo ( HasTraits ): """ This class specifies the details of the TupleEditor demo. """ # To demonstrate any given Trait editor, an appropriate Trait is required. tuple = Tuple( Color, Range( 1, 4 ), Str ) # Display specification (one Item per editor style) tuple_group = Group( Item('tuple', style = 'simple', label = 'Simple'), Item('_'), Item('tuple', style = 'custom', label = 'Custom'), Item('_'), Item('tuple', style = 'text', label = 'Text'), Item('_'), Item('tuple', style = 'readonly', label = 'ReadOnly')) # Demo view view1 = View( tuple_group, title = 'TupleEditor', buttons = ['OK'] ) # Create the demo: popup = TupleEditorDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': popup.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/Popup_versions/FontEditor_demo.py0000644000175100001440000000263011674463545031042 0ustar ischnellusers00000000000000""" Implementation of a FontEditor demo plugin for Traits UI demo program. This demo shows each of the four styles of the FontEditor. """ from traits.api import HasTraits, Font from traitsui.api import Item, Group, View #------------------------------------------------------------------------------- # Demo Class #------------------------------------------------------------------------------- class FontEditorDemo ( HasTraits ): """ This class specifies the details of the FontEditor demo. """ # To demonstrate any given Trait editor, an appropriate Trait is required. font_trait = Font # Display specification (one Item per editor style) font_group = Group( Item('font_trait', style = 'simple', label = 'Simple'), Item('_'), Item('font_trait', style = 'custom', label = 'Custom'), Item('_'), Item('font_trait', style = 'text', label = 'Text'), Item('_'), Item('font_trait', style = 'readonly', label = 'ReadOnly')) # Demo view view1 = View( font_group, title = 'FontEditor', buttons = ['OK'] ) # Create the demo: popup = FontEditorDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': popup.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/Popup_versions/CheckListEditor_demo.py0000644000175100001440000000610511674463545032006 0ustar ischnellusers00000000000000""" Implementation of a CheckListEditor demo plugin for the Traits UI demo program. For each of three CheckListEditor column formations, this demo shows each of the four styles of the CheckListEditor. """ from traits.api import HasTraits, List from traitsui.api import Item, Group, View, CheckListEditor #------------------------------------------------------------------------------- # Demo Class #------------------------------------------------------------------------------- class CheckListEditorDemo ( HasTraits ): """ This class specifies the details of the CheckListEditor demo. """ # Define a trait for each of three formations checklist_4col = List( editor = CheckListEditor( values = [ 'one', 'two', 'three', 'four' ], cols = 4 ) ) checklist_2col = List( editor = CheckListEditor( values=[ 'one', 'two', 'three', 'four' ], cols = 2 ) ) checklist_1col = List( editor = CheckListEditor( values=[ 'one', 'two', 'three', 'four' ], cols = 1 ) ) # CheckListEditor display with four columns cl_4_group = Group( Item('checklist_4col', style='simple', label='Simple'), Item('_'), Item('checklist_4col', style='custom', label='Custom'), Item('_'), Item('checklist_4col', style='text', label='Text'), Item('_'), Item('checklist_4col', style='readonly', label='ReadOnly'), label='4-column' ) # CheckListEditor display with two columns cl_2_group = Group( Item('checklist_2col', style='simple', label='Simple'), Item('_'), Item('checklist_2col', style='custom', label='Custom'), Item('_'), Item('checklist_2col', style='text', label='Text'), Item('_'), Item('checklist_2col', style='readonly', label='ReadOnly'), label='2-column' ) # CheckListEditor display with one column cl_1_group = Group( Item('checklist_1col', style='simple', label='Simple'), Item('_'), Item('checklist_1col', style='custom', label='Custom'), Item('_'), Item('checklist_1col', style='text', label='Text'), Item('_'), Item('checklist_1col', style='readonly', label='ReadOnly'), label='1-column' ) # The view includes one group per column formation. These will be displayed # on separate tabbed panels. view1 = View( cl_4_group, cl_2_group, cl_1_group, title = 'CheckListEditor', buttons = ['OK']) # Create the demo: popup = CheckListEditorDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': popup.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/Popup_versions/CompoundEditor_demo.py0000644000175100001440000000277611674463545031733 0ustar ischnellusers00000000000000""" Implementation of a CompoundEditor demo plugin for Traits UI demo program. This demo shows each of the four styles of the CompoundEditor. """ from traits.api import HasTraits, Trait, Range from traitsui.api import Item, Group, View #------------------------------------------------------------------------------- # Demo Class #------------------------------------------------------------------------------- class CompoundEditorDemo ( HasTraits ): """ This class specifies the details of the CompoundEditor demo. """ # To demonstrate any given Trait editor, an appropriate Trait is required. compound_trait = Trait( 1, Range( 1, 6 ), 'a', 'b', 'c', 'd', 'e', 'f' ) # Display specification (one Item per editor style) comp_group = Group( Item('compound_trait', style = 'simple', label = 'Simple'), Item('_'), Item('compound_trait', style = 'custom', label = 'Custom'), Item('_'), Item('compound_trait', style = 'text', label = 'Text'), Item('_'), Item('compound_trait', style = 'readonly', label = 'ReadOnly')) # Demo view view1 = View( comp_group, title = 'CompoundEditor', buttons = ['OK'] ) # Create the demo: popup = CompoundEditorDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': popup.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/Popup_versions/ColorEditor_demo.py0000644000175100001440000000257411674463545031221 0ustar ischnellusers00000000000000""" Implementation of a ColorEditor demo plugin for Traits UI demo program. This demo shows each of the four styles of the ColorEditor. """ from traits.api import HasTraits, Color from traitsui.api import Item, Group, View #------------------------------------------------------------------------------- # Demo Class #------------------------------------------------------------------------------- class ColorEditorDemo ( HasTraits ): """ This class specifies the details of the ColorEditor demo. """ # To demonstrate any given Trait editor, an appropriate Trait is required. color_trait = Color # Items are used to define the demo display - one item per # editor style color_group = Group( Item('color_trait', style='simple', label='Simple'), Item('_'), Item('color_trait', style='custom', label='Custom'), Item('_'), Item('color_trait', style='text', label='Text'), Item('_'), Item('color_trait', style='readonly', label='ReadOnly')) # Demo view view1 = View( color_group, title = 'ColorEditor', buttons = ['OK'] ) # Create the demo: popup = ColorEditorDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': popup.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/Popup_versions/EnumEditor_demo.py0000644000175100001440000000262711674463545031046 0ustar ischnellusers00000000000000""" Implementation of an EnumEditor demo for Traits UI This demo shows each of the four styles of the EnumEditor. Fixme: This only shows the capabilities of the old-style EnumEditor """ from traits.api import HasTraits, Enum from traitsui.api import Item, Group, View #------------------------------------------------------------------------------- # Demo Class #------------------------------------------------------------------------------- class EnumEditorDemo ( HasTraits ): """ This class specifies the details of the BooleanEditor demo. """ # The Trait to be displayed in the editor name_list = Enum('A-495', 'A-498', 'R-1226', 'TS-17', 'TS-18') # Items are used to define the display; one Item per editor style. enum_group = Group( Item('name_list', style='simple', label='Simple'), Item('_'), Item('name_list', style='custom', label='Custom'), Item('_'), Item('name_list', style='text', label='Text'), Item('_'), Item('name_list', style='readonly', label='ReadOnly')) # Demo view view1 = View( enum_group, title = 'EnumEditor', buttons = ['OK'] ) # Create the demo: popup = EnumEditorDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': popup.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/Popup_versions/ImageEnumEditor_demo.py0000644000175100001440000000454611674463545032013 0ustar ischnellusers00000000000000""" Implementation of an ImageEnumEditor demo plugin for the Traits UI demo program. This demo shows each of the four styles of the ImageEnumEditor. """ from traits.api import HasTraits, Str, Trait from traitsui.api import Item, Group, View, ImageEnumEditor #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- # This list of image names (with the standard suffix "_origin") is used to # construct an image enumeration trait to demonstrate the ImageEnumEditor. image_list = [ 'top left', 'top right', 'bottom left', 'bottom right' ] #------------------------------------------------------------------------------- # Classes: #------------------------------------------------------------------------------- class Dummy(HasTraits): """ Dummy class for ImageEnumEditor """ x = Str view = View(" ") class ImageEnumEditorDemo( HasTraits ): """ This class specifies the details of the ImageEnumEditor demo. """ # To demonstrate any given Trait editor, an appropriate Trait is required. image_from_list = Trait( editor = ImageEnumEditor( values = image_list, prefix = '@icons:', suffix = '_origin', cols = 4, klass = Dummy ), *image_list ) # Items are used to define the demo display - one Item per # editor style img_group = Group( Item('image_from_list', style='simple', label='Simple'), Item('_'), Item('image_from_list', style='custom', label='Custom'), Item('_'), Item('image_from_list', style='text', label='Text'), Item('_'), Item('image_from_list', style='readonly', label='ReadOnly')) #Demo view view1 = View( img_group, title='ImageEnumEditor', buttons=['OK'] ) # Create the demo: popup = ImageEnumEditorDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': popup.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/Popup_versions/TextEditor_demo.py0000644000175100001440000000610511674463545031061 0ustar ischnellusers00000000000000""" Implementation of a TextEditor demo plugin for the Traits UI demo program. For each of three data types for which TextEditor is used, this demo shows each of the four styles of the TextEditor. """ from traits.api import HasTraits, Str, Int, Password from traitsui.api import Item, Group, View #------------------------------------------------------------------------------- # Demo Class #------------------------------------------------------------------------------- class TextEditorDemo ( HasTraits ): """ This class specifies the details of the TextEditor demo. """ # Define a trait for each of three variants string_trait = Str( "sample string" ) int_trait = Int( 1 ) password = Password # TextEditor display without multi-line capability (for various traits): text_int_group = Group( Item('int_trait', style='simple', label='Simple'), Item('_'), Item('int_trait', style='custom', label='Custom'), Item('_'), Item('int_trait', style='text', label='Text'), Item('_'), Item('int_trait', style='readonly', label='ReadOnly'), label='Integer' ) # TextEditor display with multi-line capability (for various traits): text_str_group = Group( Item('string_trait', style='simple', label='Simple'), Item('_'), Item('string_trait', style='custom', label='Custom'), Item('_'), Item('string_trait', style='text', label='Text'), Item('_'), Item('string_trait', style='readonly', label='ReadOnly'), label='String' ) # TextEditor display with secret typing capability (for Password traits): text_pass_group = Group( Item('password', style='simple', label='Simple'), Item('_'), Item('password', style='custom', label='Custom'), Item('_'), Item('password', style='text', label='Text'), Item('_'), Item('password', style='readonly', label='ReadOnly'), label='Password' ) # The view includes one group per data type. These will be displayed # on separate tabbed panels. view1 = View(text_int_group, text_str_group, text_pass_group, title = 'TextEditor', buttons = ['OK']) # Create the demo: popup = TextEditorDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': popup.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/Popup_versions/SetEditor_demo.py0000644000175100001440000000646211674463545030676 0ustar ischnellusers00000000000000""" Implementation of a SetEditor demo plugin for the Traits UI demo program. The four tabs of this demo show variations on the interface as follows: Unord I: Creates an alphabetized subset, has no "move all" options Unord II: Creates an alphabetized subset, has "move all" options Ord I: Creates a set whose order is specified by the user, no "move all" Ord II: Creates a set whose order is specifed by the user, has "move all" """ from traits.api import HasTraits, List from traitsui.api import Item, Group, View, SetEditor #------------------------------------------------------------------------------- # Demo Class #------------------------------------------------------------------------------- class SetEditorDemo ( HasTraits ): """ This class specifies the details of the SetEditor demo. """ # Define a trait each for four variants unord_nma_set = List( editor = SetEditor( values = [ 'kumquats', 'pomegranates', 'kiwi' ], can_move_all = False, left_column_title = 'Available Fruit', right_column_title = 'Exotic Fruit Bowl' ) ) unord_ma_set = List( editor = SetEditor( values = [ 'kumquats', 'pomegranates', 'kiwi' ], left_column_title = 'Available Fruit', right_column_title = 'Exotic Fruit Bowl' ) ) ord_nma_set = List( editor = SetEditor( values = ['apples', 'berries', 'cantaloupe' ], ordered = True, can_move_all = False, left_column_title = 'Available Fruit', right_column_title = 'Fruit Bowl' ) ) ord_ma_set = List( editor = SetEditor( values = ['apples', 'berries', 'cantaloupe' ], ordered = True, left_column_title = 'Available Fruit', right_column_title = 'Fruit Bowl' ) ) # SetEditor display, unordered, no move-all buttons. no_nma_group = Group( Item('unord_nma_set', style='simple'), label='Unord I', show_labels=False) # SetEditor display, unordered, move-all buttons. no_ma_group = Group( Item('unord_ma_set', style='simple'), label='Unord II', show_labels=False) # SetEditor display, ordered, no move-all buttons. o_nma_group = Group( Item('ord_nma_set', style='simple'), label='Ord I', show_labels=False) # SetEditor display, ordered, move-all buttons. o_ma_group = Group( Item('ord_ma_set', style='simple'), label='Ord II', show_labels=False) # The view includes one group per data type. These will be displayed # on separate tabbed panels. view1 = View( no_nma_group, no_ma_group, o_nma_group, o_ma_group, title = 'SetEditor', buttons = ['OK']) # Create the demo: popup = SetEditorDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': popup.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/Popup_versions/InstanceEditor_demo.py0000644000175100001440000000476211674463545031710 0ustar ischnellusers00000000000000""" Implementation of an InstanceEditor demo plugin for the Traits UI demo program. This demo shows each of the four styles of the InstanceEditor. Fixme: This version of the demo only shows the old-style InstanceEditor capabilities. """ from traits.api import HasTraits, Str, Range, Bool, Trait from traitsui.api import Item, Group, View #------------------------------------------------------------------------------- # Classes: #------------------------------------------------------------------------------- class SampleClass ( HasTraits ): """ This Sample class is used to demonstrate the InstanceEditor demo. """ #-------------------------------------------------------------------------- # The actual attributes don't matter here; we just need an assortment # to demonstrate the InstanceEditor's capabilities. #-------------------------------------------------------------------------- name = Str occupation = Str age = Range( 21,65 ) registered_voter = Bool #-------------------------------------------------------------------------- # The InstanceEditor uses whatever view is defined for the class. The # default view lists the fields alphabetically, so it's best to define one # explicitly. #-------------------------------------------------------------------------- view = View( 'name', 'occupation', 'age', 'registered_voter' ) class InstanceEditorDemo ( HasTraits ): """ This class specifies the details of the InstanceEditor demo. """ # To demonstrate any given Trait editor, an appropriate Trait is required. sample_instance = Trait( SampleClass() ) # Items are used to define the demo display - one item per # editor style inst_group = Group( Item('sample_instance', style='simple', label='Simple'), Item('_'), Item('sample_instance', style='custom', label='Custom'), Item('_'), Item('sample_instance', style='text', label='Text'), Item('_'), Item('sample_instance', style='readonly', label='ReadOnly')) # Demo View view1 = View( inst_group, title='InstanceEditor', buttons=['OK'] ) # Create the demo: popup = InstanceEditorDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': popup.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/Popup_versions/ListEditor_demo.py0000644000175100001440000000273411674463545031054 0ustar ischnellusers00000000000000""" Implemention of a ListEditor demo plugin for Traits UI demo program This demo shows each of the four styles of ListEditor. """ from traits.api import HasTraits, List, Str from traitsui.api import Item, Group, View #------------------------------------------------------------------------------- # Demo Class #------------------------------------------------------------------------------- class ListEditorDemo ( HasTraits ): """ This class specifies the details of the BooleanEditor demo. """ # The Trait to be displayed in the editor play_list = List( Str, ["The Merchant of Venice", "Hamlet", "MacBeth"]) # Items are used to define display; one per editor style. list_group = Group( Item('play_list', style='simple', label='Simple'), Item('_'), Item('play_list', style='custom', label='Custom'), Item('_'), Item('play_list', style='text', label='Text'), Item('_'), Item('play_list', style='readonly', label='ReadOnly')) # Demo view view1 = View( list_group, title = 'ListEditor', buttons = ['OK'], height=400, width=400 ) # Create the demo: popup = ListEditorDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': popup.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/Popup_versions/BooleanEditor_demo.py0000644000175100001440000000265411674463545031521 0ustar ischnellusers00000000000000""" Implementation of a BooleanEditor demo plugin for Traits UI demo program. This demo shows each of the four styles of the BooleanEditor """ #------------------------------------------------------------------------------- # Demo Class #------------------------------------------------------------------------------- from traits.api import HasTraits, Bool from traitsui.api import Item, Group, View class BooleanEditorDemo ( HasTraits ): """ This class specifies the details of the BooleanEditor demo. """ # To demonstrate any given Trait editor, an appropriate Trait is required. boolean_trait = Bool # Items are used to define the demo display - one Item per # editor style bool_group = Group( Item('boolean_trait', style='simple', label='Simple'), Item('_'), Item('boolean_trait', style='custom', label='Custom'), Item('_'), Item('boolean_trait', style='text', label='Text'), Item('_'), Item('boolean_trait', style='readonly', label='ReadOnly')) # Demo view view1 = View( bool_group, title = 'BooleanEditor', buttons = ['OK'], width = 300 ) # Hook for 'demo.py' popup = BooleanEditorDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': popup.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/Popup_versions/TableEditor_demo.py0000644000175100001440000000545011674463545031166 0ustar ischnellusers00000000000000""" Implementation of a TableEditor demo plugin for Traits UI demo program This demo shows the full behavior of a straightforward TableEditor. Only one style of TableEditor is implemented, so that is the one shown. """ # Imports: from traits.api \ import HasTraits, HasStrictTraits, Str, Int, Regex, List, Enum from traitsui.api \ import View, Group, Item, TableEditor from traitsui.table_column \ import ObjectColumn from traitsui.table_filter \ import EvalFilterTemplate, MenuFilterTemplate, RuleFilterTemplate, \ RuleTableFilter # A helper class for 'Department' below: class Employee ( HasTraits ): name = Str age = Int gender = Enum( 'Male', 'Female' ) phone = Regex( value = '000-0000', regex = '\d\d\d[-]\d\d\d\d') traits_view = View( 'name', 'age', 'phone', title = 'Create new employee', width = 0.18, buttons = [ 'OK', 'Cancel' ] ) # For readability, the parameters of the demo TableEditor are set here, rather # than in the View: table_editor = TableEditor( columns = [ ObjectColumn( name = 'name', width = 0.30 ), ObjectColumn( name = 'age', width = 0.20 ), ObjectColumn( name = 'gender', width = 0.25 ), ObjectColumn( name = 'phone', width = 0.25 ) ], auto_size = False, deletable = True, sort_model = True, orientation = 'vertical', edit_view = View( Group( 'name', 'age', 'phone', show_border=True), resizable = True ), filters = [ EvalFilterTemplate, MenuFilterTemplate, RuleFilterTemplate ], search = RuleTableFilter(), row_factory = Employee ) # The class to be edited with the TableEditor: class Department ( HasStrictTraits ): employees = List( Employee ) traits_view = View( Group( Item( 'employees', editor = table_editor), show_border=True, show_labels=False), title = 'Department Personnel', width = .4, height = .4, resizable = True, buttons = [ 'OK', 'Cancel', 'Undo' ], kind = 'live' ) # Create some employees: jas = Employee( name = 'Jason', age = 32, phone = '555-1111' ) mike = Employee( name = 'Mike', age = 34, phone = '555-2222' ) dave = Employee( name = 'Dave', age = 42, phone = '555-3333' ) lyn = Employee( name = 'Lyn', age = 40, phone = '555-4444' ) greg = Employee( name = 'Greg', age = 45, phone = '555-5555' ) # Create the demo: popup = Department( employees = [ jas, mike, dave, lyn, greg ] ) # Run the demo (if invoked from the command line): if __name__ == '__main__': popup.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/Popup_versions/ButtonEditor_demo.py0000644000175100001440000000306211674463545031407 0ustar ischnellusers00000000000000""" Implementation of a ButtonEditor demo plugin for Traits UI demo program. This demo shows each of the two styles of the ButtonEditor. (As of this writing, they are identical.) """ from traits.api import HasTraits, Button from traitsui.api import Item, View, Group from traitsui.message import message #------------------------------------------------------------------------------- # Demo Class #------------------------------------------------------------------------------- class ButtonEditorDemo ( HasTraits ): """ This class specifies the details of the ButtonEditor demo. """ # To demonstrate any given Trait editor, an appropriate Trait is required. fire_event = Button('Click Me') def _fire_event_fired(): message("Button clicked!") # ButtonEditor display # (Note that Text and ReadOnly versions are not applicable) event_group = Group( Item('fire_event', style='simple', label='Simple'), Item('_'), Item('fire_event', style='custom', label='Custom'), Item('_'), Item(label='[text style unavailable]'), Item('_'), Item(label='[read only style unavailable]')) # Demo view view1 = View( event_group, title = 'ButtonEditor', buttons = ['OK'], width = 250 ) # Create the demo: popup = ButtonEditorDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': popup.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/Popup_versions/RangeEditor_demo.py0000644000175100001440000001137011674463545031171 0ustar ischnellusers00000000000000""" Implementation of a RangeEditor demo plugin for the Traits UI demo program. This demo shows each of the four styles of the RangeEditor Variations for a small integer range, a medium-sized integer range, a large integer range and a float range are demonstrated on separate tabs. """ from traits.api import HasTraits, Range from traitsui.api import Item, Group, View #------------------------------------------------------------------------------- # Demo Class #------------------------------------------------------------------------------- class RangeEditorDemo ( HasTraits ): """ This class specifies the details of the RangeEditor demo. """ # Define a trait for each of four variants small_int_range = Range( 1, 16 ) medium_int_range = Range( 1, 25 ) large_int_range = Range( 1, 150 ) float_range = Range( 0.0, 150.0 ) # RangeEditor display for narrow integer Range traits (< 17 wide): int_range_group1 = Group( Item('small_int_range', style='simple', label='Simple'), Item('_'), Item('small_int_range', style='custom', label='Custom'), Item('_'), Item('small_int_range', style='text', label='Text'), Item('_'), Item('small_int_range', style='readonly', label='ReadOnly'), label = "Small Int") # RangeEditor display for medium-width integer Range traits (17 to 100): int_range_group2 = Group( Item('medium_int_range', style='simple', label='Simple'), Item('_'), Item('medium_int_range', style='custom', label='Custom'), Item('_'), Item('medium_int_range', style='text', label='Text'), Item('_'), Item('medium_int_range', style='readonly', label='ReadOnly'), label = "Medium Int") # RangeEditor display for wide integer Range traits (> 100): int_range_group3 = Group( Item('large_int_range', style='simple', label='Simple'), Item('_'), Item('large_int_range', style='custom', label='Custom'), Item('_'), Item('large_int_range', style='text', label='Text'), Item('_'), Item('large_int_range', style='readonly', label='ReadOnly'), label = "Large Int") # RangeEditor display for float Range traits: float_range_group = Group( Item('float_range', style='simple', label='Simple'), Item('_'), Item('float_range', style='custom', label='Custom'), Item('_'), Item('float_range', style='text', label='Text'), Item('_'), Item('float_range', style='readonly', label='ReadOnly'), label = "Float") # The view includes one group per data type. These will be displayed # on separate tabbed panels. view1 = View(int_range_group1, int_range_group2, int_range_group3, float_range_group, title = 'RangeEditor', buttons = ['OK']) # Create the demo: popup = RangeEditorDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': popup.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/Popup_versions/CodeEditor_demo.py0000644000175100001440000000260111674463545031004 0ustar ischnellusers00000000000000""" Implementation of a CodeEditor demo plugin for Traits UI demo program. This demo shows each of the four styles of the CodeEditor. """ from traits.api import HasTraits, Code from traitsui.api import Item, Group, View #------------------------------------------------------------------------------- # Demo Class #------------------------------------------------------------------------------- class CodeEditorDemo ( HasTraits ): """ This class specifies the details of the CodeEditor demo. """ # To demonstrate any given Trait editor, an appropriate Trait is required. code_sample = Code( 'import sys\n\nsys.print("hello world!")' ) # Display specification code_group = Group( Item('code_sample', style='simple', label='Simple'), Item('_'), Item('code_sample', style='custom', label='Custom'), Item('_'), Item('code_sample', style='text', label='Text'), Item('_'), Item('code_sample', style='readonly', label='ReadOnly')) # Demo view view1 = View( code_group, title = 'CodeEditor', width = 350, buttons = ['OK'] ) # Create the demo: popup = CodeEditorDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': popup.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/Popup_versions/TreeEditor_demo.py0000644000175100001440000000737111674463545031042 0ustar ischnellusers00000000000000""" Demonstrates using the TreeEditor to display a hierarchically organized data structure. In this case, the tree has the following hierarchy: - Partner - Company - Department - Employee """ from traits.api \ import HasTraits, Str, Regex, List, Instance from traitsui.api \ import Item, View, TreeEditor, TreeNode class Employee ( HasTraits ): name = Str( '' ) title = Str phone = Regex( regex = r'\d\d\d-\d\d\d\d' ) def default_title ( self ): self.title = 'Senior Engineer' class Department ( HasTraits ): name = Str( '' ) employees = List( Employee ) class Company ( HasTraits ): name = Str( '' ) departments = List( Department ) employees = List( Employee ) # Create an empty view for objects that have no data to display: no_view = View() # Define the TreeEditor used to display the hierarchy: tree_editor = TreeEditor( nodes = [ TreeNode( node_for = [ Company ], auto_open = True, children = '', label = 'name', view = View( [ 'name' ] ) ), TreeNode( node_for = [ Company ], auto_open = True, children = 'departments', label = '=Departments', view = no_view, add = [ Department ] ), TreeNode( node_for = [ Company ], auto_open = True, children = 'employees', label = '=Employees', view = no_view, add = [ Employee ] ), TreeNode( node_for = [ Department ], auto_open = True, children = 'employees', label = 'name', view = View( [ 'name' ] ), add = [ Employee ] ), TreeNode( node_for = [ Employee ], auto_open = True, label = 'name', view = View( [ 'name', 'title', 'phone' ] ) ) ] ) class Partner ( HasTraits ): name = Str( '' ) company = Instance( Company ) view = View( Item( name = 'company', editor = tree_editor, show_label = False ), title = 'Company Structure', buttons = [ 'OK' ], resizable = True, style = 'custom', width = .3, height = .3 ) # Create an example data structure: jason = Employee( name = 'Jason', title = 'Senior Engineer', phone = '536-1057' ) mike = Employee( name = 'Mike', title = 'Senior Engineer', phone = '536-1057' ) dave = Employee( name = 'Dave', title = 'Senior Software Developer', phone = '536-1057' ) martin = Employee( name = 'Martin', title = 'Senior Engineer', phone = '536-1057' ) duncan = Employee( name = 'Duncan', title = 'Consultant', phone = '526-1057' ) # Create the demo: popup = Partner( name = 'Enthought, Inc.', company = Company( name = 'Enthought', employees = [ dave, martin, duncan, jason, mike ], departments = [ Department( name = 'Business', employees = [ jason, mike ] ), Department( name = 'Scientific', employees = [ dave, martin, duncan ] ) ] ) ) # Run the demo (if invoked from the command line): if __name__ == '__main__': popup.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/Popup_versions/DirectoryEditor_demo.py0000644000175100001440000000262311674463545032102 0ustar ischnellusers00000000000000""" Implementation of a DirectoryEditor demo plugin for Traits UI demo program. This demo shows each of the four styles of the DirectoryEditor. """ from traits.api import HasTraits, Directory from traitsui.api import Item, Group, View #------------------------------------------------------------------------------- # Demo Class #------------------------------------------------------------------------------- class DirectoryEditorDemo ( HasTraits ): """ This class specifies the details of the DirectoryEditor demo. """ # To demonstrate any given Trait editor, an appropriate Trait is required. dir_name = Directory # Display specification (one Item per editor style) dir_group = Group( Item('dir_name', style = 'simple', label = 'Simple'), Item('_'), Item('dir_name', style = 'custom', label = 'Custom'), Item('_'), Item('dir_name', style = 'text', label = 'Text'), Item('_'), Item('dir_name', style = 'readonly', label = 'ReadOnly')) # Demo view view1 = View( dir_group, title = 'DirectoryEditor', width = 400, buttons = ['OK'] ) # Create the demo: popup = DirectoryEditorDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': popup.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/Popup_versions/FileEditor_demo.py0000644000175100001440000000256711674463545031024 0ustar ischnellusers00000000000000""" Implementation of a FileEditor demo plugin for Traits UI demo program. This demo shows each of the four styles of the FileEditor. """ from traits.api import HasTraits, File from traitsui.api import Item, Group, View #------------------------------------------------------------------------------- # Demo Class #------------------------------------------------------------------------------- class FileEditorDemo ( HasTraits ): """ This class specifies the details of the FileEditor demo. """ # To demonstrate any given Trait editor, an appropriate Trait is required. file_name = File # Display specification (one Item per editor style) file_group = Group( Item('file_name', style = 'simple', label = 'Simple'), Item('_'), Item('file_name', style = 'custom', label = 'Custom'), Item('_'), Item('file_name', style = 'text', label = 'Text'), Item('_'), Item('file_name', style = 'readonly', label = 'ReadOnly')) # Demo view view1 = View( file_group, title = 'FileEditor', width = 400, buttons = ['OK'] ) # Create the demo: popup = FileEditorDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': popup.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/CheckListEditor_demo.py0000644000175100001440000000551111674463545026753 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. """ Implementation of a CheckListEditor demo plugin for the Traits UI demo program. For each of three CheckListEditor column formations, this demo shows each of the four styles of the CheckListEditor. """ # Imports: from traits.api \ import HasTraits, List from traitsui.api \ import Item, Group, View, CheckListEditor # Define the demo class: class CheckListEditorDemo ( HasTraits ): """ Define the main CheckListEditor demo class. """ # Define a trait for each of three formations: checklist_4col = List( editor = CheckListEditor( values = [ 'one', 'two', 'three', 'four' ], cols = 4 ) ) checklist_2col = List( editor = CheckListEditor( values = [ 'one', 'two', 'three', 'four' ], cols = 2 ) ) checklist_1col = List( editor = CheckListEditor( values = [ 'one', 'two', 'three', 'four' ], cols = 1 ) ) # CheckListEditor display with four columns: cl_4_group = Group( Item( 'checklist_4col', style = 'simple', label = 'Simple' ), Item( '_' ), Item( 'checklist_4col', style = 'custom', label = 'Custom' ), Item( '_' ), Item( 'checklist_4col', style = 'text', label = 'Text' ), Item( '_' ), Item( 'checklist_4col', style = 'readonly', label = 'ReadOnly' ), label = '4-column' ) # CheckListEditor display with two columns: cl_2_group = Group( Item( 'checklist_2col', style = 'simple', label = 'Simple' ), Item( '_' ), Item( 'checklist_2col', style = 'custom', label = 'Custom' ), Item( '_' ), Item( 'checklist_2col', style = 'text', label = 'Text' ), Item( '_' ), Item( 'checklist_2col', style = 'readonly', label = 'ReadOnly' ), label = '2-column' ) # CheckListEditor display with one column: cl_1_group = Group( Item( 'checklist_1col', style = 'simple', label = 'Simple' ), Item( '_' ), Item( 'checklist_1col', style = 'custom', label = 'Custom' ), Item( '_' ), Item( 'checklist_1col', style = 'text', label = 'Text' ), Item( '_' ), Item( 'checklist_1col', style = 'readonly', label = 'ReadOnly' ), label = '1-column' ) # The view includes one group per column formation. These will be displayed # on separate tabbed panels. view1 = View( cl_4_group, cl_2_group, cl_1_group, title = 'CheckListEditor', buttons = [ 'OK' ], resizable = True ) # Create the demo: demo = CheckListEditorDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/CompoundEditor_demo.py0000644000175100001440000000244111674463545026665 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. """ Implementation of a CompoundEditor demo plugin for Traits UI demo program. This demo shows each of the four styles of the CompoundEditor """ # Imports: from traits.api \ import HasTraits, Trait, Range from traitsui.api \ import Item, Group, View # Define the demo class: class CompoundEditorDemo ( HasTraits ): """ Defines the main CompoundEditor demo class. """ # Define a compund trait to view: compound_trait = Trait( 1, Range( 1, 6 ), 'a', 'b', 'c', 'd', 'e', 'f' ) # Display specification (one Item per editor style): comp_group = Group( Item( 'compound_trait', style = 'simple', label = 'Simple' ), Item( '_' ), Item( 'compound_trait', style = 'custom', label = 'Custom' ), Item( '_' ), Item( 'compound_trait', style = 'text', label = 'Text' ), Item( '_' ), Item( 'compound_trait', style = 'readonly', label = 'ReadOnly' ) ) # Demo view: view = View( comp_group, title = 'CompoundEditor', buttons = ['OK'], resizable = True ) # Create the demo: demo = CompoundEditorDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/CheckListEditor_simple_demo.py0000644000175100001440000000401311674463545030320 0ustar ischnellusers00000000000000""" Checklist editor for a List of strings The checklist editor provides a simple way for the user to select multiple items from a list of known strings. This example demonstrates the checklist editor's two most useful styles: * 'custom' displays all the strings in columns next to checkboxes. * 'readonly' displays only the selected strings, as a Python list of strings. We do *not* demonstrate two styles which are not as useful for this editor: * 'text' is like 'readonly' except editable. It will accept a list of strings or numbers or even expressions. This is useful for quick, non-production data entry, but it ignores the editor's list of valid 'values'. * 'simple' (the default) only lets you select one item at a time, from a drop-down widget. """ from traits.api import HasTraits, List from traitsui.api import UItem, Group, View, CheckListEditor, Label class CheckListEditorDemo ( HasTraits ): """ Define the main CheckListEditor simple demo class. """ # Specify the strings to be displayed in the checklist: checklist = List( editor = CheckListEditor( values = [ 'one', 'two', 'three', 'four', 'five', 'six'], cols = 2 ) ) # CheckListEditor display with two columns: checklist_group = Group( '10', # insert vertical space Label('The custom style lets you select items from a checklist:'), UItem( 'checklist', style = 'custom'), '10','_','10', # a horizontal line with 10 empty pixels above and below Label('The readonly style shows you which items are selected, ' 'as a Python list:'), UItem( 'checklist', style = 'readonly'), ) traits_view = View( checklist_group, title = 'CheckListEditor', buttons = [ 'OK' ], resizable = True ) # Create the demo: demo = CheckListEditorDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/ColorEditor_demo.py0000644000175100001440000000231511674463545026157 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. """ Implementation of a ColorEditor demo plugin for Traits UI demo program. This demo shows each of the four styles of the ColorEditor """ # Imports: from traits.api \ import HasTraits, Color from traitsui.api \ import Item, Group, View # Demo class definition: class ColorEditorDemo ( HasTraits ): """ Defines the main ColorEditor demo. """ # Define a Color trait to view: color_trait = Color # Items are used to define the demo display, one item per editor style: color_group = Group( Item( 'color_trait', style = 'simple', label = 'Simple' ), Item( '_' ), Item( 'color_trait', style = 'custom', label = 'Custom' ), Item( '_'), Item( 'color_trait', style = 'text', label = 'Text' ), Item( '_'), Item( 'color_trait', style = 'readonly', label = 'ReadOnly' ) ) # Demo view view1 = View( color_group, title = 'ColorEditor', buttons = ['OK'], resizable = True ) # Create the demo: demo = ColorEditorDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/EnumEditor_demo.py0000644000175100001440000000431511674463545026007 0ustar ischnellusers00000000000000""" Enum editor The Enum editor provides a simple way for the user to choose one item from a list of known values (normally strings or numbers). An Enum trait can take any value from a specified list of values. These values are typically strings, integers, or floats, but can also be None or hashable tuples. An Enum can be displayed / edited in one of five styles: * 'simple' displays a drop-down list of allowed values * 'custom' by default, displays one or more columns of radio buttons (only one of which is selected at a time). * 'custom' in 'list' mode (see source code below), displays a list of all the allowed values at once. * 'readonly' displays the current value as non-editable text. * 'text' displays the current value as text. You can also edit this text, but your text must be in the list of allowed values. """ # Imports: from traits.api import HasTraits, Enum from traitsui.api import Item, Group, View, EnumEditor class EnumEditorDemo ( HasTraits ): """ Defines the main EnumEditor demo class. """ # Define an Enum trait to view. name_list = Enum( 'A-495', 'A-498', 'R-1226', 'TS-17', 'TS-18', 'Foo', 12345, (11,7), None ) # Items are used to define the display, one Item per editor style: enum_group = Group( Item( 'name_list', style = 'simple', label = 'Simple' ), Item( '_' ), # The custom style defaults to radio button mode: Item( 'name_list', style = 'custom', label = 'Custom radio' ), Item( '_' ), # The custom style can also display in list mode, with extra work: Item( 'name_list', style = 'custom', label = 'Custom list', editor= EnumEditor(values=name_list.values, mode='list') ), Item( '_' ), Item( 'name_list', style = 'readonly', label = 'ReadOnly' ), Item( '_' ), Item( 'name_list', style = 'text', label = 'Text' ) ) # Demo view: traits_view = View( enum_group, title = 'EnumEditor', buttons = ['OK'], resizable = True ) # Create the demo: demo = EnumEditorDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/ImageEnumEditor_demo.py0000644000175100001440000000370211674463545026751 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. """ Implementation of an ImageEnumEditor demo plugin for the Traits UI demo program. This demo shows each of the four styles of the ImageEnumEditor. """ # Imports: from traits.api \ import HasTraits, Str, Trait from traitsui.api \ import Item, Group, View, ImageEnumEditor # This list of image names (with the standard suffix "_origin") is used to # construct an image enumeration trait to demonstrate the ImageEnumEditor: image_list = [ 'top left', 'top right', 'bottom left', 'bottom right' ] class Dummy ( HasTraits ): """ Dummy class for ImageEnumEditor """ x = Str view = View() class ImageEnumEditorDemo ( HasTraits ): """ Defines the ImageEnumEditor demo class. """ # Define a trait to view: image_from_list = Trait( editor = ImageEnumEditor( values = image_list, prefix = '@icons:', suffix = '_origin', cols = 4, klass = Dummy ), *image_list ) # Items are used to define the demo display, one Item per editor style: img_group = Group( Item( 'image_from_list', style = 'simple', label = 'Simple' ), Item( '_' ), Item( 'image_from_list', style = 'custom', label = 'Custom' ), Item( '_' ), Item( 'image_from_list', style = 'text', label = 'Text' ), Item( '_' ), Item( 'image_from_list', style = 'readonly', label = 'ReadOnly' ) ) # Demo view: view = View( img_group, title = 'ImageEnumEditor', buttons = [ 'OK' ], resizable = True ) # Create the demo: demo = ImageEnumEditorDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/TextEditor_demo.py0000644000175100001440000000444611674463545026034 0ustar ischnellusers00000000000000""" Edit a string, password, or integer The TextEditor displays a Str, Password, or Int trait for the user to edit. When editing a Str, consider styles 'simple' (one-line), 'custom' (multi-line), or read-only (multi-line). When editing a Password, use style 'simple' (shows asterisks). When editing an Int, consider styles 'simple' and 'readonly'. """ # FIXME:? as of 7/1/2011, Password style 'text' showed typed characters. # It no longer does. Should it? # Imports: from traits.api import HasTraits, Str, Int, Password from traitsui.api import Item, Group, View # The main demo class: class TextEditorDemo ( HasTraits ): """ Defines the TextEditor demo class. """ # Define a trait for each of three TextEditor variants: string_trait = Str( "sample string" ) int_trait = Int( 1 ) password = Password # TextEditor display with multi-line capability (for a string): text_str_group = Group( Item( 'string_trait', style = 'simple', label = 'Simple' ), Item( '_' ), Item( 'string_trait', style = 'custom', label = 'Custom' ), Item( '_' ), # text style is the same as simple, not shown. Item( 'string_trait', style = 'readonly', label = 'ReadOnly' ), label = 'String' ) # TextEditor display without multi-line capability (for an integer): text_int_group = Group( Item( 'int_trait', style = 'simple', label = 'Simple' ), # custom and text styles are not useful for editing integers, not shown: Item( '_' ), Item( 'int_trait', style = 'readonly', label = 'ReadOnly' ), label = 'Integer' ) # TextEditor display with secret typing capability (for Password traits): text_pass_group = Group( Item( 'password', style = 'simple', label = 'Simple' ), # custom and text style are the same as simple, not shown. label = 'Password' ) # The view includes one group per data type. These will be displayed # on separate tabbed panels: traits_view = View( text_str_group, text_pass_group, text_int_group, title = 'TextEditor', buttons = [ 'OK' ] ) # Create the demo: demo = TextEditorDemo() # Run the demo (if invoked from the command line): if __name__ == "__main__": demo.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/SetEditor_demo.py0000644000175100001440000000630211674463545025634 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. """ Implementation of a SetEditor demo plugin for the Traits UI demo program. The four tabs of this demo show variations on the interface as follows: Unord I: Creates an alphabetized subset, has no "move all" options Unord II: Creates an alphabetized subset, has "move all" options Ord I: Creates a set whose order is specified by the user, no "move all" Ord II: Creates a set whose order is specifed by the user, has "move all" """ # Imports: from traits.api \ import HasTraits, List from traitsui.api \ import Item, Group, View, SetEditor # Define the main demo class: class SetEditorDemo ( HasTraits ): """ Defines the SetEditor demo class. """ # Define a trait each for four SetEditor variants: unord_nma_set = List( editor = SetEditor( values = [ 'kumquats', 'pomegranates', 'kiwi' ], can_move_all = False, left_column_title = 'Available Fruit', right_column_title = 'Exotic Fruit Bowl' ) ) unord_ma_set = List( editor = SetEditor( values = [ 'kumquats', 'pomegranates', 'kiwi' ], left_column_title = 'Available Fruit', right_column_title = 'Exotic Fruit Bowl' ) ) ord_nma_set = List( editor = SetEditor( values = ['apples', 'berries', 'cantaloupe' ], ordered = True, can_move_all = False, left_column_title = 'Available Fruit', right_column_title = 'Fruit Bowl' ) ) ord_ma_set = List( editor = SetEditor( values = ['apples', 'berries', 'cantaloupe' ], ordered = True, left_column_title = 'Available Fruit', right_column_title = 'Fruit Bowl' ) ) # SetEditor display, unordered, no move-all buttons: no_nma_group = Group( Item( 'unord_nma_set', style = 'simple' ), label = 'Unord I', show_labels = False ) # SetEditor display, unordered, move-all buttons: no_ma_group = Group( Item( 'unord_ma_set', style = 'simple' ), label = 'Unord II', show_labels = False ) # SetEditor display, ordered, no move-all buttons: o_nma_group = Group( Item( 'ord_nma_set', style = 'simple' ), label = 'Ord I', show_labels = False ) # SetEditor display, ordered, move-all buttons: o_ma_group = Group( Item( 'ord_ma_set', style = 'simple' ), label = 'Ord II', show_labels = False ) # The view includes one group per data type. These will be displayed # on separate tabbed panels: view = View( no_nma_group, no_ma_group, o_nma_group, o_ma_group, title = 'SetEditor', buttons = ['OK'] ) # Create the demo: demo = SetEditorDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/InstanceEditor_demo.py0000644000175100001440000000421411674463545026645 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. """ Implementation of an InstanceEditor demo plugin for the Traits UI demo program. This demo shows each of the four styles of the InstanceEditor Fixme: This version of the demo only shows the old-style InstanceEditor capabilities. """ # Imports: from traits.api \ import HasTraits, Str, Range, Bool, Instance from traitsui.api \ import Item, Group, View #------------------------------------------------------------------------------- # Classes: #------------------------------------------------------------------------------- class SampleClass ( HasTraits ): """ This Sample class is used to demonstrate the InstanceEditor demo. """ # The actual attributes don't matter here; we just need an assortment # to demonstrate the InstanceEditor's capabilities.: name = Str occupation = Str age = Range( 21, 65 ) registered_voter = Bool # The InstanceEditor uses whatever view is defined for the class. The # default view lists the fields alphabetically, so it's best to define one # explicitly: view = View( 'name', 'occupation', 'age', 'registered_voter' ) class InstanceEditorDemo ( HasTraits ): """ This class specifies the details of the InstanceEditor demo. """ # Create an Instance trait to view: sample_instance = Instance( SampleClass, () ) # Items are used to define the demo display, one item per editor style: inst_group = Group( Item( 'sample_instance', style = 'simple', label = 'Simple' ), Item( '_' ), Item( 'sample_instance', style = 'custom', label = 'Custom' ), Item( '_' ), Item( 'sample_instance', style = 'text', label = 'Text' ), Item( '_' ), Item( 'sample_instance', style = 'readonly', label = 'ReadOnly' ) ) # Demo View: view = View( inst_group, title = 'InstanceEditor', buttons = [ 'OK' ], resizable = True ) # Create the demo: demo = InstanceEditorDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/ListEditor_demo.py0000644000175100001440000000237311674463545026020 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. """ Implemention of a ListEditor demo plugin for Traits UI demo program This demo shows each of the four styles of ListEditor """ # Imports: from traits.api \ import HasTraits, List, Str from traitsui.api \ import Item, Group, View # Define the demo class: class ListEditorDemo ( HasTraits ): """ Defines the main ListEditor demo class. """ # Define a List trait to display: play_list = List( Str, [ "The Merchant of Venice", "Hamlet", "MacBeth" ] ) # Items are used to define display, one per editor style: list_group = Group( Item( 'play_list', style = 'simple', label = 'Simple', height = 75 ), Item( '_' ), Item( 'play_list', style = 'custom', label = 'Custom' ), Item( '_' ), Item( 'play_list', style = 'text', label = 'Text' ), Item( '_' ), Item( 'play_list', style = 'readonly', label = 'ReadOnly' ) ) # Demo view: view = View( list_group, title = 'ListEditor', buttons = [ 'OK' ], resizable = True ) # Create the demo: demo = ListEditorDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/RGBColorEditor_demo.py0000644000175100001440000000232311674463545026511 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. """ Implementation of a ColorEditor demo plugin for Traits UI demo program. This demo shows each of the four styles of the ColorEditor """ # Imports: from traits.api \ import HasTraits, RGBColor from traitsui.api \ import Item, Group, View # Demo class definition: class ColorEditorDemo ( HasTraits ): """ Defines the main ColorEditor demo. """ # Define a Color trait to view: color_trait = RGBColor # Items are used to define the demo display, one item per editor style: color_group = Group( Item( 'color_trait', style = 'simple', label = 'Simple' ), Item( '_' ), Item( 'color_trait', style = 'custom', label = 'Custom' ), Item( '_'), Item( 'color_trait', style = 'text', label = 'Text' ), Item( '_'), Item( 'color_trait', style = 'readonly', label = 'ReadOnly' ) ) # Demo view view1 = View( color_group, title = 'ColorEditor', buttons = ['OK'], resizable = True ) # Create the demo: demo = ColorEditorDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/BooleanEditor_demo.py0000644000175100001440000000410411674463545026456 0ustar ischnellusers00000000000000""" Boolean editor (checkbox or text) A Boolean (True/False) trait is displayed and edited as a checkbox, by default. It can also be displayed as text 'True' / 'False', either editable or read-only. This example also shows how to listen for a change in a trait, and take action when its value changes. It also demonstrates how to add vertical space and a Label (plain text which is not editable.) """ from traits.api import HasTraits, Bool, Int from traitsui.api import Item, Label, Group, View class BooleanEditorDemo (HasTraits): """ Defines the main BooleanEditor demo class. """ # a boolean trait to view: my_boolean_trait = Bool count_changes = Int(0) # When the trait's value changes, do something. # The listener method is named '_TraitName_changed', where # 'TraitName' is the name of the trait being monitored. def _my_boolean_trait_changed(self): self.count_changes += 1 # Demo view traits_view = View( '10', # vertical space # The trait to be displayed / edited, in default format. # To edit a simple trait, this is the only line needed inside the View. # This is shorthand for Item('my_boolean_trait', style = 'simple') 'my_boolean_trait', '10', # vertical space # We put this label in its own group so that it will be left justified. # Otherwise it will line up with other edit fields (indented): Group( Label('The same Boolean trait can also be displayed and edited as ' 'text (True/False):') ), '10', # vertical space Item( 'my_boolean_trait', style = 'readonly', label = 'Read-only style' ), Item( 'my_boolean_trait', style = 'text', label = 'Text style' ), '10', 'count_changes', title = 'Boolean trait', buttons = ['OK'], resizable = True ) # Create the demo view (but do not yet display it): demo = BooleanEditorDemo() # Display and edit the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/TableEditor_demo.py0000644000175100001440000000653511674463545026140 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. """ Implementation of a TableEditor demo plugin for Traits UI demo program This demo shows the full behavior of a straightforward TableEditor. Only one style of TableEditor is implemented, so that is the one shown. """ # Import statements: from traits.api \ import HasTraits, HasStrictTraits, Str, Int, Regex, List from traitsui.api \ import View, Group, Item, TableEditor from traitsui.table_column \ import ObjectColumn, ExpressionColumn from traitsui.table_filter \ import EvalFilterTemplate, MenuFilterTemplate, RuleFilterTemplate, \ EvalTableFilter # A helper class for the 'Department' class below: class Employee ( HasTraits ): first_name = Str last_name = Str age = Int phone = Regex( value = '000-0000', regex = '\d\d\d[-]\d\d\d\d' ) traits_view = View( 'first_name', 'last_name', 'age', 'phone', title = 'Create new employee', width = 0.18, buttons = [ 'OK', 'Cancel' ] ) # The definition of the demo TableEditor: table_editor = TableEditor( columns = [ ObjectColumn( name = 'first_name', width = 0.20 ), ObjectColumn( name = 'last_name', width = 0.20 ), ExpressionColumn( label = 'Full Name', width = 0.30, expression = "'%s %s' % (object.first_name, " "object.last_name )" ), ObjectColumn( name = 'age', width = 0.10, horizontal_alignment = 'center' ), ObjectColumn( name = 'phone', width = 0.20 ) ], deletable = True, sort_model = True, auto_size = False, orientation = 'vertical', edit_view = View( Group( 'first_name', 'last_name', 'age', 'phone', show_border = True ), resizable = True ), filters = [ EvalFilterTemplate, MenuFilterTemplate, RuleFilterTemplate ], search = EvalTableFilter(), show_toolbar = True, row_factory = Employee ) # The class to be edited with the TableEditor: class Department ( HasStrictTraits ): employees = List( Employee ) traits_view = View( Group( Item( 'employees', show_label = False, editor = table_editor ), show_border = True, ), title = 'TableEditor', width = .4, height = .4, resizable = True, buttons = [ 'OK' ], kind = 'live' ) # Create some employees: employees = [ Employee( first_name = 'Jason', last_name = 'Smith', age = 32, phone = '555-1111' ), Employee( first_name = 'Mike', last_name = 'Tollan', age = 34, phone = '555-2222' ), Employee( first_name = 'Dave', last_name = 'Richards', age = 42, phone = '555-3333' ), Employee( first_name = 'Lyn', last_name = 'Spitz', age = 40, phone = '555-4444' ), Employee( first_name = 'Greg', last_name = 'Andrews', age = 45, phone = '555-5555' ) ] # Create the demo: demo = Department( employees = employees ) # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/CSVListEditor_demo.py0000644000175100001440000001216411674463545026373 0ustar ischnellusers00000000000000""" Demonstrate the CSVListEditor class.

    This editor allows the user to enter a *single* line of input text, containing comma-separated values (or another separator may be specified). Your program specifies an element Trait type of Int, Float, Str, Enum, or Range. """ from traits.api import HasTraits, List, Int, Float, Enum, Range, Str, Button, \ Property from traitsui.api import View, Item, Label, Heading, VGroup, HGroup, UItem, \ spring, TextEditor, CSVListEditor class Demo(HasTraits): list1 = List(Int) list2 = List(Float) list3 = List(Str, maxlen=3) list4 = List(Enum('red', 'green', 'blue', 2, 3)) list5 = List(Range(low=0.0, high=10.0)) # 'low' and 'high' are used to demonstrate lists containing dynamic ranges. low = Float(0.0) high = Float(1.0) list6 = List(Range(low=-1.0, high='high')) list7 = List(Range(low='low', high='high')) pop1 = Button("Pop from first list") sort1 = Button("Sort first list") # This will be str(self.list1). list1str = Property(Str, depends_on='list1') traits_view = \ View( HGroup( # This VGroup forms the column of CSVListEditor examples. VGroup( Item('list1', label="List(Int)", editor=CSVListEditor(ignore_trailing_sep=False), tooltip='options: ignore_trailing_sep=False'), Item('list1', label="List(Int)", style='readonly', editor=CSVListEditor()), Item('list2', label="List(Float)", editor=CSVListEditor(enter_set=True, auto_set=False), tooltip='options: enter_set=True, auto_set=False'), Item('list3', label="List(Str, maxlen=3)", editor=CSVListEditor()), Item('list4', label="List(Enum('red', 'green', 'blue', 2, 3))", editor=CSVListEditor(sep=None), tooltip='options: sep=None'), Item('list5', label="List(Range(low=0.0, high=10.0))", editor=CSVListEditor()), Item('list6', label="List(Range(low=-1.0, high='high'))", editor=CSVListEditor()), Item('list7', label="List(Range(low='low', high='high'))", editor=CSVListEditor()), springy=True, ), # This VGroup forms the right column; it will display the # Python str representation of the lists. VGroup( UItem('list1str', editor=TextEditor(), enabled_when='False', width=240), UItem('list1str', editor=TextEditor(), enabled_when='False', width=240), UItem('list2', editor=TextEditor(), enabled_when='False', width=240), UItem('list3', editor=TextEditor(), enabled_when='False', width=240), UItem('list4', editor=TextEditor(), enabled_when='False', width=240), UItem('list5', editor=TextEditor(), enabled_when='False', width=240), UItem('list6', editor=TextEditor(), enabled_when='False', width=240), UItem('list7', editor=TextEditor(), enabled_when='False', width=240), ), ), '_', HGroup('low', 'high', spring, UItem('pop1'), UItem('sort1')), Heading("Notes"), Label("Hover over a list to see which editor options are set, " "if any."), Label("The editor of the first list, List(Int), uses " "ignore_trailing_sep=False, so a trailing comma is " "an error."), Label("The second list is a read-only view of the first list."), Label("The editor of the List(Float) example has enter_set=True " "and auto_set=False; press Enter to validate."), Label("The List(Str) example will accept at most 3 elements."), Label("The editor of the List(Enum(...)) example uses sep=None, " "i.e. whitespace acts as a separator."), Label("The last two List(Range(...)) examples take one or both " "of their limits from the Low and High fields below."), width=720, title="CSVListEditor Demonstration", ) def _list1_default(self): return [1, 4, 0, 10] def _get_list1str(self): return str(self.list1) def _pop1_fired(self): if len(self.list1) > 0: x = self.list1.pop() print x def _sort1_fired(self): self.list1.sort() if __name__ == "__main__": demo = Demo() demo.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/ButtonEditor_demo.py0000644000175100001440000000206411674463545026355 0ustar ischnellusers00000000000000""" Button editor A Button trait is displayed as a button in a Traits UI view. When the button is clicked, Traits UI will execute a method of your choice (a 'listener'). In this example, the listener just increments a click counter. """ from traits.api import HasTraits, Button, Int from traitsui.api import View class ButtonEditorDemo(HasTraits): """ Defines the main ButtonEditor demo class. """ # Define a Button trait: my_button_trait = Button('Click Me') click_counter = Int # When the button is clicked, do something. # The listener method is named '_TraitName_fired', where # 'TraitName' is the name of the button trait. def _my_button_trait_fired(self): self.click_counter += 1 # Demo view: traits_view = View( 'my_button_trait', 'click_counter', title = 'ButtonEditor', buttons = [ 'OK' ], resizable = True ) # Create the demo: demo = ButtonEditorDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/File_Dialog/0000755000175100001440000000000011674463545024511 5ustar ischnellusers00000000000000traitsui-4.1.0/examples/demo/Standard_Editors/File_Dialog/File_Open_with_FileInfo_Extension.py0000644000175100001440000000363011674463545033567 0ustar ischnellusers00000000000000""" This demonstrates using the Traits file dialog with a file dialog extension, in this case, the FileInfo extension, which displays information about the currently selected file, such as: - File size. - Date and time last accessed. - Date and time last modified. - Date and time last created. For more information about why you would want to use the Traits file dialog over the standard OS file dialog, select the File Open demo. For a demonstration of writing a custom file dialog extension, select the File Open with Custom Extension demo. """ #-- Imports -------------------------------------------------------------------- from traits.api \ import HasTraits, File, Button from traitsui.api \ import View, HGroup, Item from traitsui.file_dialog \ import open_file, FileInfo #-- FileDialogDemo Class ------------------------------------------------------- # Demo specific file dialig id: demo_id = 'traitsui.demo.standard_editors.file_dialog.file_info' class FileDialogDemo ( HasTraits ): # The name of the selected file: file_name = File # The button used to display the file dialog: open = Button( 'Open...' ) #-- Traits View Definitions ------------------------------------------------ view = View( HGroup( Item( 'open', show_label = False ), '_', Item( 'file_name', style = 'readonly', springy = True ) ), width = 0.5 ) #-- Traits Event Handlers -------------------------------------------------- def _open_changed ( self ): """ Handles the user clicking the 'Open...' button. """ file_name = open_file( extensions = FileInfo(), id = demo_id ) if file_name != '': self.file_name = file_name # Create the demo: demo = FileDialogDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/File_Dialog/File_Open_with_ImageInfo_Extension.py0000644000175100001440000000454511674463545033740 0ustar ischnellusers00000000000000""" This demonstrates using the Traits file dialog with a file dialog extension, in this case, the ImageInfo extension, which displays (if possible) the contents, width and height information for the currently selected image file so that the user can quickly verify they are opening the correct file before leaving the file dialog. For more information about why you would want to use the Traits file dialog over the standard OS file dialog, select the File Open demo. For a demonstration of writing a custom file dialog extension, select the File Open with Custom Extension demo. This example also shows setting a file name filter which only allows common image file formats (i.e. *.png, *.gif, *.jpg, *.jpeg) files to be viewed and selected. """ #-- Imports -------------------------------------------------------------------- from traits.api \ import HasTraits, File, Button from traitsui.api \ import View, HGroup, Item from traitsui.file_dialog \ import open_file, ImageInfo #-- FileDialogDemo Class ------------------------------------------------------- # Demo specific file dialig id: demo_id = 'traitsui.demo.standard_editors.file_dialog.image_info' # The image filters description: filters = [ 'PNG file (*.png)|*.png', 'GIF file (*.gif)|*.gif', 'JPG file (*.jpg)|*.jpg', 'JPEG file (*.jpeg)|*.jpeg' ] class FileDialogDemo ( HasTraits ): # The name of the selected file: file_name = File # The button used to display the file dialog: open = Button( 'Open...' ) #-- Traits View Definitions ------------------------------------------------ view = View( HGroup( Item( 'open', show_label = False ), '_', Item( 'file_name', style = 'readonly', springy = True ) ), width = 0.5 ) #-- Traits Event Handlers -------------------------------------------------- def _open_changed ( self ): """ Handles the user clicking the 'Open...' button. """ file_name = open_file( extensions = ImageInfo(), filter = filters, id = demo_id ) if file_name != '': self.file_name = file_name # Create the demo: demo = FileDialogDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/File_Dialog/File_Open_with_Multiple_Extensions.py0000644000175100001440000000452411674463545034055 0ustar ischnellusers00000000000000""" This demonstrates using the Traits file dialog with multiple file dialog extensions, in this case, the FileInfo, TextInfo and ImageInfo extensions. For more information about why you would want to use the Traits file dialog over the standard OS file dialog, select the File Open demo. For a demonstration of writing a custom file dialog extension, select the File Open with Custom Extension demo. Suggestion: Try resizing the dialog and dragging the various file dialog extensions around to create a better arrangement than the rather cramped default vertical arrangement. Close the dialog, then re-open it to see that your new arrangement has been correctly restored. Try a different file dialog demo to verify that the customizations are not affected by any of the other demos because this demo specifies a custom id when invoking the file dialog. """ #-- Imports -------------------------------------------------------------------- from traits.api \ import HasTraits, File, Button from traitsui.api \ import View, HGroup, Item from traitsui.file_dialog \ import open_file, FileInfo, TextInfo, ImageInfo #-- FileDialogDemo Class ------------------------------------------------------- # Demo specific file dialig id: demo_id = 'traitsui.demo.standard_editors.file_dialog.multiple_info' # The list of file dialog extensions to use: extensions = [ FileInfo(), TextInfo(), ImageInfo() ] class FileDialogDemo ( HasTraits ): # The name of the selected file: file_name = File # The button used to display the file dialog: open = Button( 'Open...' ) #-- Traits View Definitions ------------------------------------------------ view = View( HGroup( Item( 'open', show_label = False ), '_', Item( 'file_name', style = 'readonly', springy = True ) ), width = 0.5 ) #-- Traits Event Handlers -------------------------------------------------- def _open_changed ( self ): """ Handles the user clicking the 'Open...' button. """ file_name = open_file( extensions = extensions, id = demo_id ) if file_name != '': self.file_name = file_name # Create the demo: demo = FileDialogDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/File_Dialog/File_Open.py0000644000175100001440000001032111674463545026720 0ustar ischnellusers00000000000000""" This demonstrates one of the simplest cases of using the Traits file dialog to select a file for opening (i.e. reading or editing). The first question of course is why use the Traits file dialog at all, when the standard OS file dialog is also available? And the answer is that you can use either, but the advantages of using the Traits file dialog are: - It supports history. That is, each time the user selects a file for opening, the file is added to a persistent history list, similar to many applications Open recent... function, but built directly into the file dialog. The amount of history remembered can be specified by the developer, with the default being the last 10 files opened. - It is resizable. Some standard OS file dialogs are not resizable, which can be very annoying to the user trying to select a file through a tiny peephole view of the file system. In addition, if the user resizes the dialog, the new size and position will be persisted, so that the file dialog will appear in the same location the next time the user wants to open a file. - There is a very nice synergy between the file system view and the history list. Quite often users shuttle between several favorite locations in the file system when opening files. The Traits file dialog automatically discovers these favorite locations just by the user opening files. When a user opens the file dialog, they can select a previously opened file from the history list, which then automatically causes the file system view to expand the selected file's containing folder, thus allowing them to select a different file in the same location. Since the history list is updated each time a user selects a file, It tends to automatically discover a working set of favorite directories just through simple use, without the user having to explicitly designate them as such. - It's customizable. The Traits file dialog accepts extension objects which can be used to display additional file information or even modify the selection behavior of the dialog. Several extensions are provided with Traits (and are demonstrated in some of the other examples), and you are free to write your own by implementing a very simple interface. - The history and user settings are customizable per application. Just by setting a unique id in the file dialog request, you can specify that the history and window size and position information are specific to your application. If you have file dialog extensions added, the user can reorder, resize and reconfigure the overall file dialog layout, including your extensions, and have their custom settings restored each time they use the file dialog. If you do not specify a unique id, then the history and user settings default to the system-wide settings for the file dialog. It's your choice. - It's easy to use. That's what this particular example is all about. So take a look at the source code for this example to see how easy it is... """ #-- Imports -------------------------------------------------------------------- from traits.api \ import HasTraits, File, Button from traitsui.api \ import View, HGroup, Item from traitsui.file_dialog \ import open_file #-- FileDialogDemo Class ------------------------------------------------------- class FileDialogDemo ( HasTraits ): # The name of the selected file: file_name = File # The button used to display the file dialog: open = Button( 'Open...' ) #-- Traits View Definitions ------------------------------------------------ view = View( HGroup( Item( 'open', show_label = False ), '_', Item( 'file_name', style = 'readonly', springy = True ) ), width = 0.5 ) #-- Traits Event Handlers -------------------------------------------------- def _open_changed ( self ): """ Handles the user clicking the 'Open...' button. """ file_name = open_file() if file_name != '': self.file_name = file_name # Create the demo: demo = FileDialogDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/File_Dialog/File_Open_with_Custom_Extension.py0000644000175100001440000000601111674463545033342 0ustar ischnellusers00000000000000""" This demonstrates using the Traits file dialog with a custom written file dialog extension, in this case an extension called LineCountInfo, which displays the number of text lines in the currently selected file. For more information about why you would want to use the Traits file dialog over the standard OS file dialog, select the File Open demo. """ #-- Imports -------------------------------------------------------------------- from os.path \ import getsize from traits.api \ import HasTraits, File, Button, Property, cached_property from traitsui.api \ import View, VGroup, HGroup, Item from traitsui.file_dialog \ import open_file, MFileDialogModel from traitsui.helper \ import commatize #-- LineCountInfo Class -------------------------------------------------------- class LineCountInfo ( MFileDialogModel ): """ Defines a file dialog extension that displays the number of text lines in the currently selected file. """ # The number of text lines in the currently selected file: lines = Property( depends_on = 'file_name' ) #-- Traits View Definitions ------------------------------------------------ view = View( VGroup( Item( 'lines', style = 'readonly' ), label = 'Line Count Info', show_border = True ) ) #-- Property Implementations ----------------------------------------------- @cached_property def _get_lines ( self ): try: if getsize( self.file_name ) > 10000000: return 'File too big...' fh = file( self.file_name, 'rb' ) data = fh.read() fh.close() except: return '' if (data.find( '\x00' ) >= 0) or (data.find( '\xFF' ) >= 0): return 'File contains binary data...' return ('%s lines' % commatize( len( data.splitlines() ) )) #-- FileDialogDemo Class ------------------------------------------------------- # Demo specific file dialig id: demo_id = ('traitsui.demo.standard_editors.file_dialog.' 'line_count_info') class FileDialogDemo ( HasTraits ): # The name of the selected file: file_name = File # The button used to display the file dialog: open = Button( 'Open...' ) #-- Traits View Definitions ------------------------------------------------ view = View( HGroup( Item( 'open', show_label = False ), '_', Item( 'file_name', style = 'readonly', springy = True ) ), width = 0.5 ) #-- Traits Event Handlers -------------------------------------------------- def _open_changed ( self ): """ Handles the user clicking the 'Open...' button. """ file_name = open_file( extensions = LineCountInfo(), id = demo_id ) if file_name != '': self.file_name = file_name # Create the demo: demo = FileDialogDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/File_Dialog/File_Open_with_TextInfo_Extension.py0000644000175100001440000000422711674463545033637 0ustar ischnellusers00000000000000""" This demonstrates using the Traits file dialog with a file dialog extension, in this case, the TextInfo extension, which displays (if possible) the contents of the currently selected file in a read-only text editor so the user can quickly verify they are opening the correct file before leaving the file dialog. For more information about why you would want to use the Traits file dialog over the standard OS file dialog, select the File Open demo. For a demonstration of writing a custom file dialog extension, select the File Open with Custom Extension demo. This example also shows setting a file name filter which only allows Python source (i.e. *.py) files to be viewed and selected. """ #-- Imports -------------------------------------------------------------------- from traits.api \ import HasTraits, File, Button from traitsui.api \ import View, HGroup, Item from traitsui.file_dialog \ import open_file, TextInfo #-- FileDialogDemo Class ------------------------------------------------------- # Demo specific file dialig id: demo_id = 'traitsui.demo.standard_editors.file_dialog.text_info' class FileDialogDemo ( HasTraits ): # The name of the selected file: file_name = File # The button used to display the file dialog: open = Button( 'Open...' ) #-- Traits View Definitions ------------------------------------------------ view = View( HGroup( Item( 'open', show_label = False ), '_', Item( 'file_name', style = 'readonly', springy = True ) ), width = 0.5 ) #-- Traits Event Handlers -------------------------------------------------- def _open_changed ( self ): """ Handles the user clicking the 'Open...' button. """ file_name = open_file( extensions = TextInfo(), filter = 'Python file (*.py)|*.py', id = demo_id ) if file_name != '': self.file_name = file_name # Create the demo: demo = FileDialogDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/RangeEditor_demo.py0000644000175100001440000000635511674463545026145 0ustar ischnellusers00000000000000""" Range editor A Range Trait holds a numeric value which is restricted to a specified range. This example shows how the RangeEditor's simple and custom styles vary depending on the type (integer or float) and size (small, medium, or large integer) of the specified range. The example also shows how multiple Groups at the top level of a View are automatically placed into separate tabs. For an example of how to dynamically vary the bounds of a Range trait, see the *Dynamic Range Editor* example. """ from traits.api import HasTraits, Range from traitsui.api import Item, Group, View class RangeEditorDemo ( HasTraits ): """ Defines the RangeEditor demo class. """ # Define a trait for each of four range variants: small_int_range = Range( 1, 16 ) medium_int_range = Range( 1, 25 ) large_int_range = Range( 1, 150 ) float_range = Range( 0.0, 150.0 ) # RangeEditor display for narrow integer Range traits (< 17 wide): int_range_group1 = Group( Item( 'small_int_range', style = 'simple', label = 'Simple' ), Item( '_' ), Item( 'small_int_range', style = 'custom', label = 'Custom' ), Item( '_' ), Item( 'small_int_range', style = 'text', label = 'Text' ), Item( '_' ), Item( 'small_int_range', style = 'readonly', label = 'ReadOnly' ), label = 'Small Int' ) # RangeEditor display for medium-width integer Range traits (17 to 100): int_range_group2 = Group( Item( 'medium_int_range', style = 'simple', label = 'Simple' ), Item( '_' ), Item( 'medium_int_range', style = 'custom', label = 'Custom' ), Item( '_' ), Item( 'medium_int_range', style = 'text', label = 'Text' ), Item( '_' ), Item( 'medium_int_range', style = 'readonly', label = 'ReadOnly' ), label = 'Medium Int' ) # RangeEditor display for wide integer Range traits (> 100): int_range_group3 = Group( Item( 'large_int_range', style = 'simple', label = 'Simple' ), Item( '_' ), Item( 'large_int_range', style = 'custom', label = 'Custom' ), Item( '_' ), Item( 'large_int_range', style = 'text', label = 'Text' ), Item( '_' ), Item( 'large_int_range', style = 'readonly', label = 'ReadOnly' ), label = 'Large Int' ) # RangeEditor display for float Range traits: float_range_group = Group( Item( 'float_range', style = 'simple', label = 'Simple' ), Item( '_' ), Item( 'float_range', style = 'custom', label = 'Custom' ), Item( '_' ), Item( 'float_range', style = 'text', label = 'Text' ), Item( '_' ), Item( 'float_range', style = 'readonly', label = 'ReadOnly' ), label = 'Float' ) # The view includes one group per data type. These will be displayed # on separate tabbed panels: traits_view = View( int_range_group1, int_range_group2, int_range_group3, float_range_group, title = 'RangeEditor', buttons = [ 'OK' ], resizable = True ) # Create the demo: demo = RangeEditorDemo() # Run the demo (if invoked from the comand line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/CodeEditor_demo.py0000644000175100001440000000224011674463545025750 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. """ Implementation of a CodeEditor demo plugin for Traits UI demo program. This demo shows each of the four styles of the CodeEditor """ # Imports: from traits.api \ import HasTraits, Code from traitsui.api \ import Item, Group, View # The main demo class: class CodeEditorDemo ( HasTraits ): """ Defines the CodeEditor demo class. """ # Define a trait to view: code_sample = Code( 'import sys\n\nsys.print("hello world!")' ) # Display specification: code_group = Group( Item( 'code_sample', style = 'simple', label = 'Simple' ), Item( '_' ), Item( 'code_sample', style = 'custom', label = 'Custom' ), Item( '_' ), Item( 'code_sample', style = 'text', label = 'Text' ), Item( '_' ), Item( 'code_sample', style = 'readonly', label = 'ReadOnly' ) ) # Demo view: view = View( code_group, title = 'CodeEditor', buttons = [ 'OK' ] ) # Create the demo: demo = CodeEditorDemo() # Run the demo (if invoked from the command line): if __name__ == "__main__": demo.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/TitleEditor_demo.py0000644000175100001440000000646011674463545026167 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. """ Demonstrates the use of the TitleEditor. A TitleEditor can be used to dynamically label sections of a user interface. The text displayed by the TitleEditor is specified by a trait associated with the view. This demonstration shows three variations of using a TitleEditor: * In the first example, the TitleEditor values are supplied by an Enum trait. Simply select a new value for the title from the drop-down list to cause the title to change. * In the second example, the TitleEditor values are supplied by a Str trait. Simply type a new value into the title field to cause the title to change. * In the third example, the TitleEditor values are supplied by a Property whose value is derived from a calculation on a Float trait. Type a number into the value field to cause the title to changed. """ # Imports: from traits.api \ import HasTraits, Enum, Str, Float, Property, cached_property from traitsui.api \ import View, VGroup, HGroup, Item, TitleEditor class TitleEditorDemo ( HasTraits ): # Define the selection of titles that can be displayed: title = Enum( 'Select a new title from the drop down list below', 'This is the TitleEditor demonstration', 'Acme Widgets Sales for Each Quarter', 'This is Not Intended to be a Real Application' ) # A user settable version of the title: title_2 = Str( 'Type into the text field below to change this title' ) # A title driven by the result of a calculation: title_3 = Property( depends_on = 'value' ) # The number used to drive the calculation: value = Float # Define the test view: view = View( VGroup( VGroup( HGroup( Item( 'title', show_label = False, springy = True, editor = TitleEditor() ) ), Item( 'title' ), show_border = True ), VGroup( HGroup( Item( 'title_2', show_label = False, springy = True, editor = TitleEditor() ) ), Item( 'title_2', label = 'Title' ), show_border = True ), VGroup( HGroup( Item( 'title_3', show_label = False, springy = True, editor = TitleEditor() ) ), Item( 'value' ), show_border = True ) ), width = 0.4 ) #-- Property Implementations ----------------------------------------------- @cached_property def _get_title_3 ( self ): try: return ('The square root of %s is %s' % ( self.value, self.value ** 0.5 )) except: return ('The square root of %s is %si' % ( self.value, (-self.value) ** 0.5 )) # Create the demo: demo = TitleEditorDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/TreeEditor_demo.py0000644000175100001440000001230611674463545026001 0ustar ischnellusers00000000000000""" Tree editor for hierarchal data Demonstrates using the TreeEditor to display a hierarchically organized data structure. In this case, the tree has the following hierarchy: - Partner - Company - Department - Employee The TreeEditor generates a hierarchical tree control, consisting of nodes. It is useful for cases where objects contain lists of other objects. The tree control is displayed in one pane of the editor, and a user interface for the selected object is displayed in the other pane. The layout orientation of the tree and the object editor is determined by the *orientation* parameter of TreeEditor(), which can be 'horizontal' or 'vertical'. You must specify the types of nodes that can appear in the tree using the *nodes* parameter, which must be a list of instances of TreeNode (or of subclasses of TreeNode). You must specify the classes whose instances the node type applies to. Use the **node_for** attribute of TreeNode to specify a list of classes; often, this list contains only one class. You can have more than one node type that applies to a particular class; in this case, each object of that class is represented by multiple nodes, one for each applicable node type. See the Traits User Manual for more details. """ # FIXME: provide accessible copy or equivalent of factories_advanced_extra.rst from traits.api import HasTraits, Str, Regex, List, Instance from traitsui.api import Item, View, TreeEditor, TreeNode class Employee(HasTraits): """ Defines a company employee. """ name = Str('') title = Str phone = Regex(regex = r'\d\d\d-\d\d\d\d') def default_title(self): self.title = 'Senior Engineer' class Department(HasTraits): """ Defines a department with employees. """ name = Str('') employees = List(Employee) class Company(HasTraits): """ Defines a company with departments and employees. """ name = Str('') departments = List(Department) employees = List(Employee) # Create an empty view for objects that have no data to display: no_view = View() # Define the TreeEditor used to display the hierarchy: tree_editor = TreeEditor( nodes = [ # The first node specified is the top level one TreeNode(node_for = [ Company ], auto_open = True, # child nodes are children = '', label = 'name', # label with Company name view = View([ 'name' ]) ), TreeNode(node_for = [ Company ], auto_open = True, children = 'departments', label = '=Departments', # constant label view = no_view, add = [ Department ], ), TreeNode(node_for = [ Company ], auto_open = True, children = 'employees', label = '=Employees', # constant label view = no_view, add = [ Employee ] ), TreeNode(node_for = [ Department ], auto_open = True, children = 'employees', label = 'name', # label with Department name view = View([ 'name' ]), add = [ Employee ] ), TreeNode(node_for = [ Employee ], auto_open = True, label = 'name', # label with Employee name view = View([ 'name', 'title', 'phone' ]) ) ] ) class Partner(HasTraits): """ Defines a business partner.""" name = Str('') company = Instance(Company) view = View( Item(name = 'company', editor = tree_editor, show_label = False ), title = 'Company Structure', buttons = [ 'OK' ], resizable = True, style = 'custom', width = .3, height = 500 ) # Create an example data structure: jason = Employee(name = 'Jason', title = 'Senior Engineer', phone = '536-1057') mike = Employee(name = 'Mike', title = 'Senior Engineer', phone = '536-1057') dave = Employee(name = 'Dave', title = 'Senior Software Developer', phone = '536-1057') martin = Employee(name = 'Martin', title = 'Senior Engineer', phone = '536-1057') duncan = Employee(name = 'Duncan', title = 'Consultant', phone = '526-1057') # Create the demo: demo = Partner( name = 'Enthought, Inc.', company = Company( name = 'Enthought', employees = [ dave, martin, duncan, jason, mike ], departments = [ Department( name = 'Business', employees = [ jason, mike ] ), Department( name = 'Scientific', employees = [ dave, martin, duncan ] ) ] ) ) # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/DirectoryEditor_demo.py0000644000175100001440000000232311674463545027044 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. """ Implementation of a DirectoryEditor demo plugin for Traits UI demo program. This demo shows each of the four styles of the DirectoryEditor """ # Imports: from traits.api \ import HasTraits, Directory from traitsui.api \ import Item, Group, View # Define the demo class: class DirectoryEditorDemo ( HasTraits ): """ Define the main DirectoryEditor demo class. """ # Define a Directory trait to view: dir_name = Directory # Display specification (one Item per editor style): dir_group = Group( Item( 'dir_name', style = 'simple', label = 'Simple' ), Item( '_' ), Item( 'dir_name', style = 'custom', label = 'Custom' ), Item( '_' ), Item( 'dir_name', style = 'text', label = 'Text' ), Item( '_' ), Item( 'dir_name', style = 'readonly', label = 'ReadOnly' ) ) # Demo view: view = View( dir_group, title = 'DirectoryEditor', buttons = ['OK'], resizable = True ) # Create the demo: demo = DirectoryEditorDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/FileEditor_demo.py0000644000175100001440000000225411674463545025762 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. """ Implementation of a FileEditor demo plugin for Traits UI demo program. This demo shows each of the four styles of the FileEditor """ # Imports: from traits.api \ import HasTraits, File from traitsui.api \ import Item, Group, View # Define the demo class: class FileEditorDemo ( HasTraits ): """ Defines the main FileEditor demo class. """ # Define a File trait to view: file_name = File # Display specification (one Item per editor style): file_group = Group( Item( 'file_name', style = 'simple', label = 'Simple' ), Item( '_' ), Item( 'file_name', style = 'custom', label = 'Custom' ), Item( '_' ), Item( 'file_name', style = 'text', label = 'Text' ), Item( '_' ), Item( 'file_name', style = 'readonly', label = 'ReadOnly' ) ) # Demo view: view = View( file_group, title = 'FileEditor', buttons = ['OK'], resizable = True ) # Create the demo: demo = FileEditorDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Standard_Editors/HTMLEditor_demo.py0000644000175100001440000000350711674463545025651 0ustar ischnellusers00000000000000""" HTML editor The HTML editor displays simple formatted HTML text in a Traits UI view. If the text is held in an HTML trait, then the HTMLEditor is the default. If the text is held in a Str trait, then you may specify the HTMLEditor explicitly if you wish to display it as HTML. The supported subset of HTML tags and features depends on the UI toolkit (WX or QT). This editor does not support style sheets. It does not support WYSIWYG editing of the text, though the unformatted text can be edited in a plain text editor. The HTML editor can optionally be configured to do simple formatting of lists and paragraphs without HTML tags, by setting the editor's 'format_text' parameter True. """ from traits.api import HasTraits, HTML from traitsui.api import UItem, View, HTMLEditor # Sample text to display as HTML: header, plus module docstring, plus # some lists. The docstring and lists will be auto-formatted (format_text=True). sample_text = ("""

    HTMLEditor example

    """ + __doc__ + """ Here are some lists formatted in this way: Numbered list: * first * second * third Bulleted list: - eat - drink - be merry """) class HTMLEditorDemo ( HasTraits ): """ Defines the main HTMLEditor demo class. """ # Define a HTML trait to view my_html_trait = HTML(sample_text) # Demo view traits_view = View( UItem('my_html_trait', # we specify the editor explicitly in order to set format_text: editor=HTMLEditor(format_text=True)), title = 'HTMLEditor', buttons = ['OK'], width = 800, height = 600, resizable = True) # Create the demo: demo = HTMLEditorDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Dynamic_Forms/0000755000175100001440000000000011674463545021654 5ustar ischnellusers00000000000000traitsui-4.1.0/examples/demo/Dynamic_Forms/dynamic_selector.py0000644000175100001440000000613611674463545025560 0ustar ischnellusers00000000000000""" Dynamic changing a selection list, using Handler One way to dynamically change the list of values shown by an EnumEditor. This example demonstrates several useful Traits UI concepts. It dynamically changes the values which an EnumEditor presents to the user for selection. It does this with a custom *Handler* which is assigned to the view, listens for changes in a viewed trait, and changes the selection list accordingly. Various implementations of dynamic data retrieval are possible. This example shows how a Handler can interact with the traits in a view, separating model logic from the view implementation. Demo class *Address* has a simple set of attributes: *street_address*, *state* and *city*. The values of *state* and *city* are to be chosen from enumerated lists; however, the user does not want to see every city in the USA, but only those for the chosen state. Note that *city* is simply defined as a trait of type Str. By default, a Str would be displayed using a simple TextEditor, but in this view we explicitly specify that *city* should be displayed with an EnumEditor. The values that appear in the GUI's enumerated list are determined by the *cities* attribute of the view's handler, as specified in the EnumEditor's *name* parameter. """ from traits.api import HasTraits, Str, Enum, List from traitsui.api import View, Item, Handler, EnumEditor # Dictionary of defined states and cities. cities = { 'GA': ['Athens', 'Atlanta', 'Macon', 'Marietta', 'Savannah'], 'TX': ['Austin', 'Amarillo', 'Dallas', 'Houston', 'San Antonio', 'Waco'], 'OR': ['Albany', 'Eugene', 'Portland'] } class AddressHandler(Handler): """ Handler class to redefine the possible values of 'city' based on 'state'. This handler will be assigned to a view of an Address, and can listen and respond to changes in the viewed Address. """ # Current list of available cities: cities = List(Str) def object_state_changed(self, info): """ This method listens for a change in the *state* attribute of the object (Address) being viewed. When this listener method is called, *info.object* is a reference to the viewed object (Address). """ # Change the list of available cities self.cities = cities[info.object.state] # As default value, use the first city in the list: info.object.city = self.cities[0] class Address(HasTraits): """ Demo class for demonstrating dynamic redefinition of valid trait values. """ street_address = Str state = Enum(cities.keys()[0], cities.keys()) city = Str view = View( Item(name = 'street_address'), Item(name = 'state'), Item(name = 'city', editor = EnumEditor(name = 'handler.cities'), ), title = 'Address Information', buttons = ['OK'], resizable = True, handler = AddressHandler ) # Create the demo: demo = Address(street_address="4743 Dudley Lane") # Run the demo (if invoked from the command line): if __name__== '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Dynamic_Forms/visible_when.py0000644000175100001440000000611711674463545024711 0ustar ischnellusers00000000000000""" Dynamic restructuring a user interface using 'visible_when' How to dynamically change which components of a Traits UI view are visible, depending on the value of another trait. The demo class "Person" has a set of attributes that apply to all instances ('first_name', 'last_name', 'age'), a set of attributes that apply only to children (Persons whose age is under 18), and a set of attributes that apply only to adults. As a Person's age changes, only the age-appropriate attributes will be visible. **Detail:** The optional *visible_when* attribute of an Item or Group is a string containing a boolean expression (logical condition) indicating when this Item or Group will be visible. The boolean expression is evaluated for the object being viewed, so that in this example, 'age' refers to the 'age' attribute of the Person being viewed. Compare this to very similar demo of *enabled_when*, and the visually similar, but structurally very different demo of *dynamic restructuring of a user interface using an Instance editor and a Handler*. """ from traits.api import HasTraits, Str, Range, Bool, Enum from traitsui.api import Item, Group, View, Label class Person(HasTraits): """ Example of restructuring a user interface by controlling visibility. """ # General traits: first_name = Str last_name = Str age = Range(0, 120) # Traits for children only: legal_guardian = Str school = Str grade = Range(1, 12) # Traits for adults only: marital_status = Enum('single', 'married', 'divorced', 'widowed') registered_voter = Bool(False) military_service = Bool(False) # Interface for attributes that are always visible in interface: gen_group = Group( Item(name = 'first_name'), Item(name = 'last_name'), Item(name = 'age'), label = 'General Info', show_border = True ) # Interface for attributes of Persons under 18: child_group = Group( Item(name = 'legal_guardian'), Item(name = 'school'), Item(name = 'grade'), label = 'Additional Info for minors', show_border = True, visible_when = 'age < 18', ) # Interface for attributes of Persons 18 and over: adult_group = Group( Item(name = 'marital_status'), Item(name = 'registered_voter'), Item(name = 'military_service'), label = 'Additional Info for adults', show_border = True, visible_when = 'age >= 18', ) # A simple View is sufficient, since the Group definitions do all the work: view = View( Group( gen_group, '10', Label("Using 'visible_when':"), '10', child_group, adult_group ), title = 'Personal Information', resizable = True, buttons = [ 'OK' ] ) # Create the demo: demo = Person( first_name = "Samuel", last_name = "Johnson", age = 16 ) # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Dynamic_Forms/dynamic_range_editor.py0000644000175100001440000001036011674463545026374 0ustar ischnellusers00000000000000""" Dynamic Range editor Demonstrates how to dynamically modify the low and high limits of a Range Trait. In the simple *Range Editor* example, we saw how to define a Range Trait, whose values were restricted to a fixed range. Here, we show how the limits of the range can be changed dynamically using the editor's *low_name* and *high_name* attributes. In this example, these range limits are set with sliders. In practice, the limits would often be calculated from other user input or model data. The demo is divided into three tabs: * A dynamic range using a simple slider. * A dynamic range using a large-range slider. * A dynamic range using a spinner. In each section of the demo, the top-most 'value' trait can have its range end points changed dynamically by modifying the 'low' and 'high' sliders below it. The large-range slider includes low-end and high-end arrows, which are used to step the visible range through the full range, when the latter is too large to be entirely visible. This demo also illustrates how the value, label formatting and label widths can also be specified if desired. """ # Imports: from traits.api import HasPrivateTraits, Float, Range, Int from traitsui.api import View, Group, Item, Label, RangeEditor class DynamicRangeEditor ( HasPrivateTraits ): """ Defines an editor for dynamic ranges (i.e. ranges whose bounds can be changed at run time). """ # The value with the dynamic range: value = Float # This determines the low end of the range: low = Range( 0.0, 10.0, 0.0 ) # This determines the high end of the range: high = Range( 20.0, 100.0, 20.0 ) # An integer value: int_value = Int # This determines the low end of the integer range: int_low = Range( 0, 10, 0 ) # This determines the high end of the range: int_high = Range( 20, 100, 20 ) # Traits view definitions: traits_view = View( # Dynamic simple slider demo: Group( Item( 'value', editor = RangeEditor( low_name = 'low', high_name = 'high', format = '%.1f', label_width = 28, mode = 'auto' ) ), '_', Item( 'low' ), Item( 'high' ), '_', Label( 'Move the Low and High sliders to change the range of ' 'Value.' ), label = 'Simple Slider' ), # Dynamic large range slider demo: Group( Item( 'value', editor = RangeEditor( low_name = 'low', high_name = 'high', format = '%.1f', label_width = 28, mode = 'xslider' ) ), '_', Item( 'low' ), Item( 'high' ), '_', Label( 'Move the Low and High sliders to change the range of ' 'Value.' ), label = 'Large Range Slider' ), # Dynamic spinner demo: Group( Item( 'int_value', editor = RangeEditor( low = 0, high = 20, low_name = 'int_low', high_name = 'int_high', format = '%d', is_float = False, label_width = 28, mode = 'spinner' ) ), '_', Item( 'int_low' ), Item( 'int_high' ), '_', Label( 'Move the Low and High sliders to change the range of ' 'Value.' ), label = 'Spinner' ), title = 'Dynamic Range Editor Demonstration', buttons = [ 'OK' ], resizable = True ) # Create the demo: demo = DynamicRangeEditor() # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Dynamic_Forms/enabled_when.py0000644000175100001440000000572711674463545024654 0ustar ischnellusers00000000000000""" Dynamic enabling parts of a user interface using 'enabled_when' How to dynamically enable or disable components of a Traits UI view, depending on the value of another trait. The demo class "Person" has a set of attributes that apply to all instances ('first_name', 'last_name', 'age'), a set of attributes that apply only to children (Persons whose age is under 18), and a set of attributes that apply only to adults. As a Person's age changes, only the age-appropriate attributes will be enabled (available for editing). **Detail:** The optional *enabled_when* attribute of an Item or Group is a string containing a boolean expression (logical condition) indicating when this Item or Group will be enabled. The boolean expression is evaluated for the object being viewed, so that in this example, 'age' refers to the 'age' attribute of the Person being viewed. Compare this to very similar demo of *visible_when*. """ from traits.api import HasTraits, Str, Range, Bool, Enum from traitsui.api import Item, Group, View, Label class Person( HasTraits ): """ Example of enabling/disabling components of a user interface. """ # General traits: first_name = Str last_name = Str age = Range(0, 120) # Traits for children only: legal_guardian = Str school = Str grade = Range(1, 12) # Traits for adults only: marital_status = Enum('single', 'married', 'divorced', 'widowed') registered_voter = Bool(False) military_service = Bool(False) # Interface for attributes that are always visible in interface: gen_group = Group( Item(name = 'first_name'), Item(name = 'last_name'), Item(name = 'age'), label = 'General Info', show_border = True ) # Interface for attributes of Persons under 18: child_group = Group( Item(name = 'legal_guardian'), Item(name = 'school'), Item(name = 'grade'), label = 'Additional Info for minors', show_border = True, enabled_when = 'age < 18', ) # Interface for attributes of Persons 18 and over: adult_group = Group( Item(name = 'marital_status'), Item(name = 'registered_voter'), Item(name = 'military_service'), '10', label = 'Additional Info for adults', show_border = True, enabled_when = 'age >= 18', ) # A simple View is sufficient, since the Group definitions do all the work: view = View( Group( gen_group, '10', Label("Using 'enabled_when':"), '10', child_group, adult_group ), title = 'Personal Information', resizable = True, buttons = [ 'OK' ] ) # Create the demo: demo = Person( first_name = "Samuel", last_name = "Johnson", age = 16 ) # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Dynamic_Forms/__init__.py0000644000175100001440000000010011674463545023754 0ustar ischnellusers00000000000000""" Implementations of dynamic form behavior using TraitsUI """ traitsui-4.1.0/examples/demo/Dynamic_Forms/dynamic_form_using_instances.py0000644000175100001440000001066311674463545030157 0ustar ischnellusers00000000000000""" Dynamic restructuring a user interface using Instance editor and Handler How to dynamically change the *structure* of a user interface (not merely which components are visible), depending on the value of another trait. This code sample shows a simple implementation of the dynamic restructuring of a View on the basis of some trait attribute's assigned value. The demo class "Person" has attributes that apply to all instances ('first_name', 'last_name', 'age') and a single attribute 'misc' referring to another object whose traits are specific to age group (AdultSpec for adults 18 and over, ChildSpec for children under 18). The 'misc' attribute is re-assigned to a new instance of the appropriate type when a change to 'age' crosses the range boundary. The multi-attribute instance assigned to 'misc' is edited by means of a single InstanceEditor, which is displayed in the 'custom' style so that the dynamic portion of the interface is displayed in a panel rather than a separate window. It is necessary to use a Handler because otherwise when the instance is updated dynamically, Traits UI will not detect the change and the UI will not be reconfigured. This is due to architectural limitations of the current version of Traits UI. Compare this to the simpler, but less powerful demo of *enabled_when*. """ from traits.api import HasTraits, Str, Range, Enum, Bool, Instance from traitsui.api import Item, Group, View, Handler, Label class Spec ( HasTraits ): """ An empty class from which all age-specific trait list classes are derived. """ pass class ChildSpec ( Spec ): """ Trait list for children (assigned to 'misc' for a Person when age < 18). """ legal_guardian = Str school = Str grade = Range( 1, 12 ) traits_view = View( 'legal_guardian', 'school', 'grade' ) class AdultSpec ( Spec ): """ Trait list for adults (assigned to 'misc' for a Person when age >= 18). """ marital_status = Enum( 'single', 'married', 'divorced', 'widowed' ) registered_voter = Bool military_service = Bool traits_view = View( 'marital_status', 'registered_voter', 'military_service' ) class PersonHandler ( Handler ): """ Handler class to perform restructuring action when conditions are met. The restructuring consists of replacing a ChildSpec instance by an AdultSpec instance, or vice-versa. We would not need a handler to listen for a change in age, but we do need a Handler so that Traits UI will respond immediately to changes in the viewed Person, which require immediate restructuring of the UI. """ def object_age_changed ( self, info ): if ((info.object.age >= 18) and (not isinstance( info.object.misc, AdultSpec ))): info.object.misc = AdultSpec() elif ((info.object.age < 18) and (not isinstance( info.object.misc, ChildSpec ))): info.object.misc = ChildSpec() class Person ( HasTraits ): """ Demo class for demonstrating dynamic interface restructuring. """ first_name = Str last_name = Str age = Range( 0, 120 ) misc = Instance( Spec ) # Interface for attributes that are always visible in interface: gen_group = Group( Item( name = 'first_name' ), Item( name = 'last_name' ), Item( name = 'age'), label = 'General Info', show_border = True ) # Interface for attributes that depend on the value of 'age': spec_group = Group( Group( Item( name = 'misc', style = 'custom' ), show_labels = False ), label = 'Additional Info', show_border = True ) # A simple View is enough as long as the right handler is specified: view = View( Group( gen_group, '10', Label("Using Instances and a Handler:"), '10', spec_group ), title = 'Personal Information', buttons = [ 'OK' ], resizable = True, width = 300, handler = PersonHandler() ) # Create the demo: demo = Person( first_name = "Samuel", last_name = "Johnson", age = 18, misc = AdultSpec() ) # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Extras/0000755000175100001440000000000011674463545020370 5ustar ischnellusers00000000000000traitsui-4.1.0/examples/demo/Extras/Image_editor_demo.py0000644000175100001440000000276411674463545024347 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. """ A simple demonstration of how to use the ImageEditor to add a graphic element to a Traits UI View. """ import traits # Imports: from os.path \ import join, dirname from traits.api \ import HasTraits, Str from traitsui.api \ import View, VGroup, Item from traitsui.api \ import ImageEditor from pyface.image_resource \ import ImageResource # Constants: # Necessary because of the dynamic way in which the demos are loaded: search_path = [ join( dirname( traits.api.__file__ ), '..', '..', 'examples', 'demo', 'Extras' ) ] # Define the demo class: class Employee ( HasTraits ): # Define the traits: name = Str dept = Str email = Str # Define the view: view = View( VGroup( VGroup( Item( 'name', show_label = False, editor = ImageEditor( image = ImageResource( 'info', search_path = search_path) ) ) ), VGroup( Item( 'name' ), Item( 'dept' ), Item( 'email' ) ) ) ) # Create the demo: popup = Employee( name = 'William Murchison', dept = 'Receiving', email = 'wmurchison@acme.com' ) # Run the demo (if invoked form the command line): if __name__ == '__main__': popup.configure_traits() traitsui-4.1.0/examples/demo/Extras/images/0000755000175100001440000000000011674463545021635 5ustar ischnellusers00000000000000traitsui-4.1.0/examples/demo/Extras/images/logo_32x32.gif0000644000175100001440000005603311674463545024134 0ustar ischnellusers00000000000000GIF89a Sm%dkq[ m/[ϏW;yxu@\G瑦;?_r&}XسtyF-]ʑͧQaQBFͬ;3l3#,{4 #W5<؂Pj3,+R7@v@ ~&8t,<ʺ$H`~w̄>$@E6<=R@pLIuyφR6 ɌX8kх)&#Z6)"#,#= 1R F)&16I8 >IiY 2bā2Elh B YrҰP7Ҥ=H3-~e h9}5C-k96M4ډ%kQ,8BmVj*ATE(>PMRVP8Ύ5iM a̹ ˊZũm֩ǡUAP͹톊94"ʶy1"2Sۏ(1:-;龜7&?=*)`@wƘ B՗=k\c# I `p  lCѧBk0 l $H` 1hL'  d .#> F#K-u% QAw-d %CqP@! , HPb\"8財!CEHQʙ jլ{0A1"mfjC|lL @SdFQi$ZTdͷ)ek!~ȺtAkFЪRE. JKA3%-r21^ف8ʌ&m Bm"uʇ eq'6UTcqWҜ]‡'hw{LDY94<@O"0jJ*E#u+gb_zb#@f]h#ĶAF9t OElHQx3 @F W^R̎ʴnVb 2:ĚͮT.Am^zr 99 &8|;>cM.܇V[FB_c]>pA.4[)Á* 8 H#>D!a$XBP6s*J#\X`&".eQ x@M2ݳBaC])XcY֥sAd}(5Y_@! , Hp"E,xPb0{ Cml\l=YA(I = Mܻ'mKҐLԤ)ͦ ?}q)SԢmHqQ@T#4\Ȉ@d]2vt;jv|xˇ(LpFe)18X\vӦgsҧkʺ"ԁ`8ͮ "fܘ6+g{(ACwZ=΁kdt,x~!ayp1zckq$ `!<~ H.a")LzHq̓>cL e1W% QxPv$pe! , `AF ;# ^#cT@体M͚ZH$)RH)3&)I!Т$eHfS#A؈6mB&M;F<]9,# 'ce*R֥ba4(t|R 5,@L. 샳=N>Pum`o;mUA(_V6Sed`\ }N] #ճ3ZU0MYeԨ͓;oޓ]><1IäX\CqSl( Z53caQȊ>hlAZSGUZjY]k-;g#*4߿1*C g~z@9?uCױcvf cyG#Ϲvk : ! , )b#m*TCmk6ɛ IA2 RޛJE%fM'S6i2 b(֢?,d3C8.j3i)}4ï~ $^Cc~mHY.Ȳ`Uj+ك(y#)Ʉ@eg1ؼY_bMi˖1Ԗ&wmK6+SADcC].l[|"KfWt3UZĉWaN 3F l*"A\ȃsĽdHpO10tO*dC*\#O7 =96Se! , Ttm()R$ÆQ fBʾ6A\HI=kticGEq,&r2R ? [J6"M.:jc̵8!`TR!MFh42dҐ" uM_4 CxXaKsMݓ.h8e2 .?^S5.pَ\atu!T<4tY WVE "J֍aڇN}4*81&{bBjcGY P!5S @>IF\̽1=Ia0R~HONP I&I#0G+p8T([EP@! , 2RlNF&.E R9" ( {zL iE[ ɱD4'g5א(AhP,ȗrἷsV?A5i N-W(Nx%( #ءUc C&M@ f^aRNHCEpƘ x_nZ.hÁ50n߇. ">ZT B^iTU@23c8:.FAXP\Ao,rF$8_>UK4 `{/姇Iec?a}DEЀ6^xԦi1\ň ЯBH'/FQ܃A X|аMJCe9U.-K k24HK)EEb+CBQQ)A! , (PQF*\HP w{HȰC0)R`bE d÷s:~#5bh5" irA$$143͆Guj"Z$ݛ%(EEȝQȇT EŻYLɇy;Qi0sGOۿ(p>W>Ԧ@4`R C k.t;P5.Ьgd !PQh9R;LC.*$V#t, ]hr2ƙj&bM#FH)䠗3b8iK@8_xcZ{J G NcL?` M[1i4`2Y | 3!&bAŵ7 x"X+ I|2~! , HPQ*\P w\$dHQk`R0,Ċ &M#>hLJbXJp @V.&{PZBdLL fG4XygZd:kV?# j3|ij"FRlb6AB8j8 5Wt'.TI0ax FӦ`2R$*!`g2$B,Y> )Cm.]PUNVa[,6TiՈ9Xdl!x1ůT4[6!`D9h' eqO h~rҐsUPeӀl*3-ipx"T1~pp=Fx#sHA/F^! , H🢃*̾6p-)ܝ8$a?чD$VB@LDh0Բl5#GFITBMq,Hdk BfGFD͌aLf1iP]Μ>)Q.Y20Hħ>CvDEZ aT<UX e66Wcy5s sNzd;ti tԁApҡȻ "ۣ1MFsYV Bz 󅊮",Q^NP{H(S.@:v.`<BDM 4H=k` M9YRܓ? 3`A;gH564G?< u! , Hp"E*ȆfJ NL-i)0 n@bV$Gm S0Pۙ/El TJfBkՒ`+S}"T>F0CVC@ ,&ƁSj25Afz#vpf*9  wn]EQuYU#Ft#-&2!ڧtVn2i ᘣM&ğΒّKd6cCMPN"wZ 6MȚtlCgƉ X@R9h&ȨDT&`P%q4)pz޷F ) `IȳJPz`:nt_`!Cي͡K06#56W`@! , H"F)*Ȱ(F!qfaÆe"(Z 5)0c1Ji#VeTt<2t+ۃZEB gXhedB<8l5Eڬ@{iSgl5sUSfIZ$дj}R6 Lc$65Ȓ֍tl&BO\W2GŒ )C4Ckdڠ6#Vali$9CWGht di( =TԾ2,R )d@X E -D C`LݴDM}5!AaTRXA⊊#aH! , HP"Ep\PQ ܔQȰ"}٤h7GQŃP`A# ‰G 45^m0Î\!81Bx/q-A&c{0( d䏩32.E1cif4Kև+ )҃*NE1d6Κ5C+L6^(XL)0q-"Fi>݁/ .4Q?E\B] T B2j3uD+MowQ7[ݍ:cm\Ѣ:ہ6)PDS7f HHAx+ YaKޓiӐLqo,\1B!NE~_X(A0(Fgi[Ȩ4$)$ i4e[hD9o@m>Shg'7R{{ @-N,.HS @@EVOZq+Z)5Ї(9v2-rR47kCĂ' ~!ÐdS`< *2ڳD881ъ hrP:*&gN4$t22R`hDHq!#N;ߛƉ#vӯN83j a5ФQ O4MEތ5oD=b $`u(GȴD:Y60 1C BH#daIgaA"! , (PA"TTJ(J'\ giPۘ}з#Am>8ٙL(ʐ^bD tF&L YQFՆ~4^6i)RCSRm!?ȹ&C~XS|$4`EfiAC+ 2d i`ڌD7" EŞ2߻׏M Ҥ-dMfF:O[bC@ɂ k8sˁ]fJdlzpԦAL2+OZ* T&$PIgzZ)aX>FH޽!Ϛ&'W 2d.WhҔ[6WP̌5t%!#jcisfkh"q| RA iQL6BBB! , HPE*$ -(PQ1 !E8T?fHgdH姗dgBEp|:pCrhj&D]J"I~GR٤cQљp$K˥͘  I[E XlsVkxsF$ضk*8;>|eڃR̸r=7hOѵrt 7`RX'.8wAہUk ׵>VA`4kYbX{*MGh"ZSt q{,=4FWpLjUĵ1Qp81MWg4G({ m&-#K !^ $eS-ag]wQ!g%mM=Mi0 MIA{R\9q&}) H==CitQFbl^&tXI'Z48|7%UNVYo%NN" klvNDkc,2MN\MH|C^P0 ٭H<{ēI$P602N†;P@! , HP"F *\hPu@0Oۙj8""AEŬxq32qyR$ɒd`r("t85fہaԠQ:4;3 3MjC%@,l#, 9m,J𴘐l`(΄ DXbIYy:"RiêbȤ d a01MAF;E&}J* 2櫄M'oÕ|hb[ZON9Z|,sΌ\X$Ί P4Qy2Sc7 a_Et3Ap.QV, *EJEsr(4("C ,! , HP*TH],[JT%mQ$q"mgxqtd'&ey(5yr5u 8&.&?-6 A,ƒ`R,q@-Ac(Lɒ[cxmթq#N$Ҥ)Q^i],N!EF)x,)QGU62f"[ДƠ' DQaMV% 3`0lq(=ٳfIaGNfEٓ5ahK# VDos6S*#ExD 8Bj-wQDؑ6UhD hdžH@! , Hp&<% u.T԰m(a>pvه82ʥ\5J*TmLxIʛgd*uc@:M*RCl7;jsĵkYD'ܴti+fd.Wd6x!)H!mr wQ2 dH, {*b!ƠG4NN@kV ߾ݓ-2`$P:0!z X)T I:n*_gymAH"\SF)xw/7,Xl%=ǪedK%%|F3r FK*ݘ !7Xac-U2IJ{ |E-вIḦ́oZ}c w\;xȌT02U8aQVkW%v,#'.w&';!G?V [Ͼm_P1O@! , HPj;cØÇQ .?8 A҆6H:@=AQ[ )ZQ$Y!a% gWhlQdJHr%QX16lXƒ%,hCgnhCKDKpV[Fj0ɛ#GʾQd-m8& o"xh?z1Dvݴ3ؙ۸s3ر | aO⊢<.| bnp8wq! ,SH*\H*Jœ9c18p`PsvZ #F(V%on YR QX#^ bU',>iD>{7Dj k~0>6tJ$3·XPRV' C6v(] ByF _E{0*BiC.F +mfATMDF8 K~&LkGwX <(p&+3 JxЅӧ+0Qv,&CЄ>vo*_ $P@!, H*!W &D(DfPu"" o`XH(b(͔)Wˈle•hcieOHK10 ib2JxAڠ*T+G.!m#MBN] $^(6m!ŃQ`ۜk*22kVY= Ӥ[ઠ<] Zͺ7v2mgc2rFo1aY. b3s(B AӪzſP ]~ufBM_W&g[.x fMHPn! , M&GpS2za3 * d%g>J\. HL t.dp^%"PTCeigQ){A'I! YQ #[Qd`hkB UddV&Ҥr +8D2Z`tEd2X1<&!YTaP SA+, H :%.BUtLϺ_B pBFpaD8"EN$ƘHk(@p&'h37lB ܄i Va(Pa\8D.q@cߊ*! , Q<8\p6wȐ ѓف53JBLtcf؂* S@rtqB pcL.tAe[Wn,a n J4dShō^2b"d&d^.դ4),.LE):M"M L*%#֎AKŒ5^%@KΦKZZܴZëQ )UbKd Âݷ&kЛX7tuc@H`\z ?gHi K`Vx #E~IItB! , 8P#E*\HP[VbBȰ?ET sl 3-dN8rM[BڤB%BEs0e8klcғ{451ɱ'*"4AUT\CX dH4QT4I! *҆\S{YL,{nZZhAR( 5Is$#5מBEޛ-!WmR%Ű屁:hcMΦ(0ŀNpȨ  +2*Y'1VĈ& j@s@014" D(f& !(3H.h#8:0v>rd#hX$>rXKr1.eAOP@! , (P6E@("Ȱ!A_LoËIř)yX8PQ ]>|x`JF#/*A@*gDQL@&)5 i"Mo~Y}V0JYRXQoIunB ]M!C^TA2bBXQ)B̀^xaOQM˜E8JpY[5& Ou?dDMӦHѤĩT({ԩ`h6YݻmA7mz[ʑSK80FRQ.wږ4$Ncnj\0N5#0b C 6 X"\&`1p#'N&*fpLb@ bC;2c! ҈*5`! hޗiA! , H"u\`rS$8"  ܜᄆa& nb %w!4rB##R@ 6&Hdfx̐K*h!N(e>@y%nd! , HP6u\p3_xaCEŰpqbEˇjx( 3ZȐuف+*bdDJ idNSV ΁^T(C ,6~,o֬&Rȥ-$8d8j 9gװ\@  7s*Xicf(3PQ5ǽ7vf㿽}1mEVм bN&#/ <뼆#<9!آ38" h.L3jstOk=^Q[1iLyJdf3HKp7gQ2.ɂ' ^c\xB 02A xL!6 ڜP&ҌfPJB2Ԟ12&y`! , H"mgr)*Ȱ"FLfaCp~< . |pF,F /4d\ym17hɇ5>EěYEFK*mdyZŰ KUmqt@Ed4hYEHܛAZqiA̸VZ ڇo%0+ CAYiZ#@L`>z0K Ő" 81w1'>aFlQpH# b!f0b&4r XE!q!>'4rH &76*cC#=2p̓Q6!cB"&A! , HP"mŊ)*Ȑb?L Wa?Z42d]>|pvSva"4i(dy FjXyQ5rqlhSI@UTa@Ae F1 P1zYiƛA5 b+*MHH 16&o1)MnfS3 Ȧo)lEf[2BYbbv)q6aЄuحLf4VD{hZ];LiC 2ѪxE 0"zgP"$01pCw!p$!`2~_d 7' C rL '1ߋx&8GPx9'Pf1G! , HP"m@(*Р""ÎQCi! jY8PC\pdCˇ8]zaH!e l C#]fSN IqĬ?Esd(ŠB81Oa2Dg6TEz!m%+kAF ARtS8Akw_Q`x;S)}"r4sFaATR`: j+  QF0cL0] *Jf}C[ w*3F9^,#@as w10Ј%b r~31l p#F^a#f@lr.aRC W!s 3 xQC&yQ@! , Hp"E,xbĊňAQl\SЂ,d9ۆj` 3Dd]>̌8=DAhr* ªT$$qoMׅCx'حrrM#|1_|8p`]G),)dZ B@Iz04IAB6\2Sc뿨E0zo$?^>Y #EfnM+  WuspHi~=P#=S238 i֫6#(`Uf|ti^EG1%m 8j^kmXm]qmyrm;ty1:v,Ã9gľщ(ZuMܟ$ Nl^{g`# `̂ 6hB )! , H*&oN36`H[5G H(%1a 3&c= )ICˇXQ彘3kv@4ѻ䞴?HjB·5 Tel.*ҖjOarxBʰzxO ctP[5$ +aJkR,X;1Pl4MsCbGeE?`Mcb'h\HZ -XR`U>V8"8O"4BTr2!{}o U;C'nL}0 $1pD1 n&P8HSJ rnH#' 7b &"Nv6D$ -1ߐ'P@! , TH*\\CɋA œ1ɽH,*"N %TT= )ICˇd&LP6afV| 0) A 9dhV9HV]jX驨M*F E6-hk4+0׷1^ 4S4!F QiXi]-A4 9!,h\QLAMNFYU[ }lG͌(O48=B H*f|,]|?t:\{~BE n{ȣ#wŐ !##p@){#nrt [N"4rŒ3rsy+] #"p#vA"a_F+ u! , ڜ(\p h3 *0k= YբW<5 HiҐɜiתɽhB3gYrE ҠEXha<=?P1|Fxzt/ 94"4:*sF0s)b/4{r_`Q48Fk|XQ}8!W<3h+m [ @*fiڥZxr(/׷950sLƲ5B_U#|cqa1 B',A} q3zx!hrQJɃ+%1h&D1?p{@آ>+L.&4r?6 {)2 # ܈!)DV"Q$1>bR Ef! , O"E*$yQ.Yā p̚CZHY&&M2d4І,uYc7c!0g*`%H 9]:;͖NJzLJB"mQ}Z#8LȖ?8X>8)nbFPjX!,І),)| p*F MIv׫fp,lݚfFKY1};7ckEV0^* 6h3욙U4v<$R@@} H|cu*daxgA{IꉧM)0&4@ K!Ckfテ!#Eq] l <(AQรHrOiHsXؤ~O.X֕IP@! , (DE*LL?#.YL rpbBE=.6!E 0s"zTdC=)DA $&d^ HѢY.dpOV$%H 9]>huv \*)ᐕ1tS2E4L!@+ aRIq*+61Ebg8sVS.ړŰl,?F4@*\krTӪfLn6!\1~AEQz=b ~6sH]fTCzE^6HqFSwAdJzp1Ǹw |6AiÃ`  )\.lb&p%6ؤ YE-6&"#q 54r“TBpL#bt3\9vr2G J2.!, 8PE*\HP[~C dHCMfb f5!Ep:VƬU{%DFKYJ,]2d]E1fE.]>| oLѣ̾%Y:;WBRO"AEg}m]֨bJ$?Fh LbX>\x #MhQ`X"dU>|Dy Y09AXLQZ>̬, ʷ2Z5̱AyV9\(aܡW >qo1~ZQ(c\gw"@ m'Dg`Fl!.H` z lȉT NH" '4 ۀ1 7I|b}A#bp"Dzgd#dR;traitsui-4.1.0/examples/demo/Extras/images/logo_64x64.gif0000644000175100001440000016002711674463545024145 0ustar ischnellusers00000000000000GIF89a@@Qj%[eil_"q0\X|ӏ;yvx@񶺾쇾IҐ@[&}>cwXt?Ͱxy-ˑvmH^|QtuwiMz0u=\52'[ɆtiiK*c~m?Wu$yp:n4͢LzUوa0R-XnU[kM{=tY~ɵ݇+ämÇ5=y<$u]Gͤckv}MpHj~Qnz|Yv!h/j1HTk}mor?}0yWr_;izx/Tޠjm2ֆ\z䕖N«ʑ1Oh{*%rDw·쑬dϘH˗jۆ3d|L2^u϶MvfTTG]By#UmjlnZ޸zIؘ_{z.vnG#`};3(cȩjo`xCp! NETSCAPE2.0! ,@@ H*\ȰÇ#JHŋ 5qa#2tرFA`.IQ:/PhIߕx qϞV )v))ӠPna ?IjYrm.h%+e_Xv궞_gKПhQ߿v7&HPM{egW=Mz[S ʀb-F۸kA]\#j# vpZҟ[;wCZ&$n6ǑD(o=;TDe }$'&8ӟ TʅDcDx#$%Z ry9s $@ ~3W)(@wyQ$p P#`v86dYd:c۵`} #KJb:`12.(-4葘tD $iye(i :]BGzbd ~3 B)e:jL5J("~1?pK+ 'pZBN'*򙇤%Ưt$Gښ&ɞ,P^<#TQu&-~8[֎zhG(2Xz+N ڑr[ suPſ{ښ0!̮$QjA`P#Bd*~QKFzrAA4ҁ,WL)FIo-؁BcJGH5˖B[Tt]QW'.;tE&OipZ+EV7w%mjk8ѓ~T%%jMKL-i?9`LY*}$d7`vFN|Y74w/T3Y8Hld-zӂ/gUI0OD2;†g-=xu[Nqw#l`Pn bR]=Џ. 3A / 'v %qЄȂQppC0=0DhN`g o}6|& 9 kbY:GL1$ iqd7T;I<16q $Zdbc>AL"y! , /8 HA5:ȰÆ Yŋy`1<Q/xaKgC3%(4B|XfM(@7sA: eC 3JҞPL>ݰcÆ.,D&S^X[om bE׵x.^a֦yw]חm?<,5(^٫ǗώA `H'9E̵L7Z1ۡ^fW [S "7/p&i$So?yP=|G]\C^<&Qb#c^vBq*5 gd_wQD!*$&4҈zfڇp y>Xbw?N.at. OAC:bbX0܊K"ӆX< ~cϒ5d;й[DKIf:&=z#V#DBEÓ9gV2IzCb8^&#-Ye&!D~oꇠ0$z*@氵QAlzR*@*L2K7."Yr?U`c¹VIgRK4[ NYd@+˹(2?X`o*/o)ɊTAO7ԃ1o5.k3=@-Ht8Օ|Sɵ(H(3;Dw(7tsx@"E8@-;7H]7~=3YB%Z9 AYdz߇M"SxTyBl| lvRm9#l"|iϻm'#BihR#I*RKFe' ϱ~R#@L2*HrixEhaJoͫ "`B[q-UbP#. \c"$ qzCNGD-3e,zFϵL3B^;lNPt(BBLfuI]1k ]KŰk#DH{{C:FYK၎x޵=7>SxԠ˿8AeU(,23ގ<l<8qW酃c?3nb tC0kKHÇkiH7_ YL HN=UbP&;̓kR o`_?.uA 6MdB x4# !6dy! asMb Ģ2ⅱ! , -6 HA wÇyAF3jl$Ȓ8QIlq /cx;yR"E.sB M-S'(L؉ѪVn`S0@YU+h7#c75bݺmhю1ԹZnȻc׮z#!C ΫY+N Ãc0a}qCDfb˖WĘ>]z]C pfp@A%̹EEb^r_ߓ \P(n{'1kE}84+[73vO]q}&$;M d^(. ӀwpСT?KGaBN*Ό&PsItc,6 &8#;r "uI2IN2Θ$$ F.(K tp$;&$e $PG+39B~QBBr&Yg: "ٹ< 'ȁZZDžuŽ$!)B 栨py( S $*(r*TCbZ:2 Э~(򌤍Xy*|ҨC&H rIw^F@G-Y0H xRL5rE%I{?tC:(0H-p{?> KqFc~u28l+b.GD .'Q#i.sC@I/E4ÔsC=oRku3aU#HBOlA#w]VGP(lA 2|}W}'I<"9.h|/Utr-H( #n<3W`7?~#/<FwhX ?3zKbi!EU pD}-$.',r.` ~pI (1 x&63l.WCw! |t|T%. `0A `@A:IxA%@?[ˆA* ~R! , +6 H\Ȱ!FUСņYBWC>h ƌ_ƟHKƒ %x@٫ o2ĉs(:O=ЛP> jϋ:3+קŠ"V޴NݰV; „ʃ-ܷs׫KJo;Kwcz& AA9ʲuWf̒w!qYPP3KO>=@-Ou7v?fP݁Xy 7—v8wE.Q/<_f.~dӂI &TwB.xSH޴ `$RqEE.%h;3z@h @`CΑ>I$Y@)$3ʕWH#KG-Ո InjU% 1,~.ZK! I 4?ȥ7B M|x3ò o/kP A Vf! , *4 HkC:x !J fʘQoWT%/-<(D1+ E'@П gS?a*0bLj \B0ԠoݔNW(u 7. T z6fҤrwa0`Â.<HFVeTxDhM Me&S啨ʑ m͙Da6qk'* $F H0d"ԩbxΞ}&':Q8 E u@7(CXr8%Ġ:B٧ zw"Ԕ?IL(T-BjzbL4hlNw`BQP#~@\ Bn+CyyíwTc8AX+#9P# 8XP#i낃t`upcYl}@rI.قmW?X[Yd |cGތF7Ai-[n?\qs Z=aVWxݒ xea7\]%~llu\/U @lswuRTUoL&OX{S0L. FM72,z2'{Ŏ܈-B5G@! ,%1 HA*<ȰF#1N4B9K3M.5y vhqcbdd ېna\yUYC`Z]_}'`.XJ1/3_G8TX`a(8|Fb y54Cꕰz/ܹ!o  _/Co! , "/ HF*\(S xHHQ3j%Ol"oP&On K4hٝRP C+P_}bϳv‚vQ]P=nޯ}mt@<_p7߶q\]޼O+D87M<0mD$؍,Fh AtHttH!&H!"Ra^΅M+#&Hc)816 *B22Id6 T()eC&`PWVI&aVʓ>Qpysyǝxƙ@ r "M4Ɯ`L8020]$DiuZZC'@:j4b*{*u k"k݊kZ'? kOy>ݴI77AI@G -҂pb-1px`UmE|Od`BTE5PB5ܰx'B,]h2VgB8S,7V75G83:,? odPPh2! , %0 APO5ZȰ#Bl1ЉAmXWx, b† %klbB2i&58ŨƇt>!Cļ|憙Pe*_X̘?auiճTNE0@ 1wXPΜZ*`^mK0avʌC{ZD _|ӌXزfZV([@7JYȑsYrvAoHP\SA8TBuPI]te^ G!C=.ںN|t1DM~3O|6@DD"(P#mҠ%RRBq3 /]06-pvtF4WD@ 9)/U&4OAMxKP6 3^y;`JdR$;Yf G}o*c‰Jr)fOi;T+t&@sJhp)&@!h:Pj)^:rw bJy( qꫮN*(tbBD" 0` P D*CDODS\@xZ;RDBׁKirE4A$ܞe73p1[>-+B& RgfZ 0̵C^d$aMߵPYyY0@@<8lQj?N%hL*pV38[ g\A2UX3PM)>U%sSWbq)"{g]@! ,'2 F *\ȰFU  9_6L$ nU,)#G@93(@d`+[&(X=Hmބӝ`%FHjEZ3dS(x o(0Gƭ ױd -.7vrK0u/aMrZDkַ]ՋFB W.pѠ-5aŒ\/n@6[Duy R e6l#op}\gw`~ޏy05}c<^=tyD.4gF  w- 29m\KV)&^d&#&4ф" Hʈ>D9RA6@( /Ief*:NYp}Rf gH%NG5 袨䙧}N)a>)Es:tꩢ2B,|`駝';=Ȑ'!2 (,֊hs!A@_A8P ֡+m<[h.+a|ҁCLK(z\t @» i[B 'H.1Q¹7t0sD(~2G߸k'{4p=tpP!CtaDv2s7+ /]T[39Bls3IHtVa;QC8R \u5^0Ni7Wjwd/ȵeKZM(jH'?GQ4ēԙE=;vWU;Z- x F> vCNfϊ\[[n!;L5+D8-ڬpS C&|6  G:B ݵؼv$nc؁r(A$芬}{w4JPU& '?m%H1: Fp&H?@-N ŸDA WO};ЁC4M s.t;F޼`#k-?IN0?v6{zb#B(|H\T^v#"ؐ? PQGQIy*Xh!t`1 v( b (dā t/c =Z5:x 1_ArL $H* &Cx!\RD$d6Fj2U'\A<|Bfȃm Z)E7=iMvjơ^"Td3Ԉ=(kn!2Ԉ iQ J)± 3Ij7. .RZj<*ȸю;'搈A=Kĸ2AϚ2hXښA%+... ъ9pHǾ vR]#T,1ipZЀ BIHL3C\sF6c'mmH00sv߰Z4wUrC6$FAT=70X}f( *mG{hmK7̡MGvG0 w` 'qbBtqs'H]K9y垍 xNҳTۀky䨫vMǍ,Fwݶ_ϢQ~+h ǣ5v 7__#[bTb,r~CI0! , .7 H`F:42ȰÇ 3&B3 ey]H`#oH:ذC#Kfl$̎zwtٰa҇E1e>īQ9yBQEЇxkM7@ӆ eћY.$װfmV(xİdUs]x@_D&DP/È#pG\j F@$"Mi9gʼpjֱ7/Mȹh@Q.\|[VJ5oFkP^L&s?ϡOh5 CcN :xzIzuFi/4҈?ݸ+u zE A@Tvq'|ԑ@Ĉ QN~A0cNJm:A,"Ë2؟ @`#ċ/7R#Dc/I-roZMbg!dd2I#MK(c/pYO+Px6X(NC 0ahGճAĞd.#&`=vh$7Ł5|JG &+t'f%JX!+r0P(itcC>-rbK.iKI˜K$CD(l(+#r6.R\H*6! W Pw`ʟ݄?PƎpMd(r"u7g`8țWwNe1@;\?hԳ(KiXXK6<@R=-6PB`=zAܔa7CwsS x|v W V.]S=m9e@6A/ppwM3v#ĠJ;;yѺ;@ K^rH"g :I^w(=ATQC`O- ozoȀ>% ! , .7 HA\ȰFT簢Ł] 3KCxM;6L(FQ+AE5mnؐNd4P,66[4>eA*C.Ŋr(`tjjn|MyZ,((`|P]lk2loc֚^˰7"L?AIpIh><ȉc؉-7EInPgicd&EOpzb{w/ǙK@:*tz?cPc.F (X^.PK9Ew "~*\QT݀*6iDA!ᄹ?bU ly D(!A6E#}x @0 !Ā;'T kd TfIei/Î)#9Ui;@]WxA%ɟn&PBU@pY_BC{v;ghTxqK(PCM:OJ췟+RfvRjCF7I^tj] 7DKXk 7A(PD<;ܳz&*(V bأ-pM*r?뎴oja FG UR#äǏKVS;T2jeK6.gMJ;3%ͭi@Nl͌B}P,Fu̿@q IP#8P;P5r mPQY0XM.c6( wsu/7Bp˽/8HWT7MK85O"1 kU7M)Hx|1X}S=)-z|Ե<{5CQC>"ÓX; #! , -6 H"MPrځٜ3Z Q$ Tw.:tԶm;(; Y]M4ϓ[13*M.N.g-wbIUdkyE%FGO=^u_bIr̙McBu.܈p 3#b.ܴQhA# .U60 7w"="0,ex=f \D0/|px 3DE.=yǣp'^W&((X@( }\s>&0T .iY_b&yHdui (q+5Kj%(3G BBk*g\;y qo~XRij  a #.d92 ݇ d`'::3K( gd\- 3qL-i|AC@-4`?!$;D0Ł!D_ch75}CnJԈ%xlPf'0],R]-UpCjkP`5/ݤnw#427uCԆ?D5л8[ԽC aO.dFCl}"~Huo0H y^_P{AT (+9 7! , )4 H5BȰ!B СE53Fގ1.^1]۱cä+G:l,®+Yn@R\ʲ${168JT1膫0zbd:N&&"Rj ;T2iA Zplk°7s Ԃ4$X\׮ l0aЕ]6v `#"iB* z mvxѺ7W$ZTI8F䂍>}nO/\{ ݍ1$G ' O Q1:0Nʫx0}Wc~ZB}F"M0uIKK!u9o~8HQI6XKy"B qKPlp3Q4 T H_EKHULg"Y#x=f . ÌbgUڝ9Cg%m 8fD0.XU"P&=rצ*h= /xI_^)Uxzpk X 7,(.. ΁&n$ĀD0At@@"DI 9+AzrmA@N wٹ.b0Cgok5n~L0N b6LqQ|?xB10s ,,'1@QOi$!B6D;@O !-S#m> .R=R#Z#D%;ܐuqM",ͧ <͐-Iqz#4%59u^tF܋G^g9r]u ^":I?@ty@! , (3 H!\Ȱ`2[Ë1L̘3]&uɠIOv[cÎ1<]|ب=!Qy6)8dxЁ*7TsR0-F+vLi+ܰÂ$H UX .,N bГs _i_n2^:+K'hP"IAUlNޜI܊'+1l?)xJg0gFEWl{5o*UOu $lxŶh^zje2|&<' rz0]s?J U }Q`ZVDJ(.$!PL^ Ѝwfb%@F~ _"X.@BN -K%o'\\ e-`C</[Z{u㓘,WfXa)6v?AH.Pp曣 KLI40fb%(5(J%BdVr;L2 0d"S7g#YpA柩 .]!,M}6YI5 .W0CQ.L@-`EG $EP8 5bOvI 5#1ƶL2$.1;2ƈ }3.Ќq;@1 D3C '4@F2EXg>H==xp5 WrSIS]g3kOm3pǽW:u; H.-! , $1 H5BȐa#x[ʏ`*T1t2iGE6|XW;rnm 0ꈠBDu^ V'Lm!FDt%4H`5V^656 ګر%F<ؼ:N") Pn%lڗkM0 g(ps4MQK ,[i3YTI&.0#c&`A IfP$CIRgia@Hi! (4@*9$ L`-y`n.EAt&AG0/JvP In5E$`9t'57xX0&)~%ܐԈwU#ߜgF^! , -+ HF *\Ȱ@OI谢ENqeDClNT\areHTӑ$;v&xCAjDӄ wA|ZLJPF-T?dwժ˪%QpsaAl@zaW=AgW= )d1kͭFS<0؁$-Jچڀ-z`Tν|֨ C*W+TU4.;6I2?SF3_koX5j-jI`:(w"&W,ݬbI$ z A oMА.._B12qAArP` gp,GBAU#xJTFhecc "eŘPO.r\F# /@d IKzL @ɣHl3z2 ~QhiB@tFjh)xew5D*z11f%)2q;+z(HF"jtAq2Z+(B|ʼBU#Hx,H#d q[/1 9AT xk#<*[/ . 3 R+L E: 7/xP(-󢜆wl䍏+I5Ag@B *xj& :jr\5 ڭ'مNAh {c lInMkMpwahQ:6ȔOK[DEKUjQl0c7nt]7bF0͢O,F8WS rkzÇ0CS2u7MD< o.TDbEeZt#VD8cDiI)D4AT&!<cK-2tMrc03.A;TpD6L3-ލP@%D1AuC c2e /XS +c 1DL0AO /騣{p.b&<3g8 Eg1\ ~!"4] (R NA$}GIxJS0'| {)[1 $ BTHR-$e;,PC.F(D$-0zix po%UKKLB / /D#C-I¿$lDB¢@"L, 15Ú?F D0 ]|9¤XhtM5bW .|0  O,}zI P 5 ro׍dp"B\Lq35C{7EF7ohN'Dd͌;b%PXoJݔe}79U/Wbsf==B8I! , .) H`2(Ԉo/+o7! , -+ Hy:ȰC<Ë5L"5H`E|H*WFq\,Ydg(̙ 7FpGʖ)eg TyԥU&!gF(͹sV=l,)tYG[KTnfL$D;")tKӓ +`#g]55k ͚N iF%6\u?c&v:LTPmr<{E֜TԨZu^03LSӜY׆D-|lĂ*t<1t3t PDWpC=AՈ🀇ٳя&Dx"HR "$l K iD7Q< ۨ";4E75C+E1<9G ,lH!σ-6f`P BUk졎*`(D!- 0$P8 )lK=X@G"kp 0@tHOn;`y.qb7|N=̣;<;rC=`eƩAsA7ܰC]peFZO":5 99BLEA/W)n$6"? Tp=(xq=Dp&@-n dP0ۀf$cl+˭&K :K Qf#)S&LQYMudcJГi)1ԜT͙A \YԶAqװ0oj4xNy lD$n#s֑ 7gd^Ee'ʗ h7^0{ P"0S$ZO4E('L`#JFP@xc? UT0Xq`4-"Wt/A0äB 1D>N> !O;tQ-ܰ.Fy"$>E8#gCMY/cϊm@9hP2=C`i050` s%H'hp!7`*xR#RP %lstv!S#h({r0_Pl`/PKt1F0 12 L"xo;\<1dKB|k//cȃ`0 P (mA. i҂<  !t 0 rgt72bd5-t%dP27~  e'dbtyDlop\|.:lkӌKyw Ihwυ.5ONAk3y.InDk'1櫷7뵫88 .n'i/uZiW͜8&=+oQqʼn-. ٲ傂"y4SDO5\pvO`Wr&=>^C{Y>:eߵoHJ>ݞK9#uI:{$xϞȨ3l}dvO,T2e 1\!ƚs T@ 6xA72/u3ɥ=p %(J%z܂ 6,75ұ$P\ EPrͯYF]j5 *z霽"Aۜ÷] O,xKz)ۅ<]`j)VWWlp H /̃ %`{@<}C%Wq,` !*-'157sw>6:`ТNݹ+*=f t6(p*h-"5P#UD!Eh1?kPЗ.DpK;k܅Æ6='Lbxq S0ߍ y2$7E!G!5l-]#99B" d@7?\=iO Ple \2Ђv2>;b@| ']tq=S ec:k(C?QPx x ȣ=$г?S!h77晻ޜ'A0>9.azwBB_>@@>'λ'7H! , '2 S*\Ȱ?[6.j\;uK8 xƆzNwdx%cM" ޾ZdKP.7z;F *`U)X[ E+1*lF+W"nKO#XأAO- T`#r4]+B qȌPjAv[zH:h-XDŽqԊjȑ["<:̉\SlN)XF3F |ajՊ͇JӦe>ULٳ5? c|txt) EZ>Z`H"9," !4b p﮻ T 9P4"x +˩1Pr!0>H|3hM a`0ɦn$g-^s =̑d4S1m OgMzpQ /lWA lb(BC&PK-ʹ "ma"x&i_  ,ޢ n#hF>#{zB(OD(ҹ9G(Yd" u".D^;. #CPLϺѻ@p=.0.@x@A~O'ILpA7O|續($ ! , *4 HF*\Ȱ!Fm`„3jP#7l u>&.2Juҡ?.쨸rcwz4{:Cؓ=*ءB5WN(j e}3eFL54P*Y%OY{zVT ECDc*P k^bEf B [V`apSXs"DaΜ>3ElWjTB΋0RnV,.FhF?|3:pģ {Ebr؜!npO<7'`[,L`W"0dOGGB@\ц,(!}H0M=4v؄!xF KTP 4t3 -(1wAͻq o<NdHc=ڻtE6_<3bkt /t ~&,xU C?iù.( ljM(IlgdI(D~o@p<8# " l prG-Dj}~(K/$A~R#CH"6~E-?!HC-=!P`  @<ȐMp !@HBR†t p` ?o a^bD’! ,,5 Hp`*\Ȱ`#d$AذŁD$H`!".,60gJ"ő]b:ta2$̅3(JW*XS˟ɢcjQ\sݻQJET]hw(%.E쁼UҤi•a 2}V֧FmnDg:TMB0(FfĜ=u (ҁ3zHvUG&}2+g͔ `뺳yjHDR9K{\.Pϗμ}EXdwc9"1df1 n?hSXFw@p9=Ȅ>Wh(P#?LBrX_̘[hsE| u;PX zbC]1,rYPl`HK2t Y-5lP \TxYetQ n% P'UBg=Ll)hCĀPЉ;XwCt$+)XڥC`Pj;DFDp6 /5꫍t 5i"pk=X 6x3$AN]~:(*zq 1^r)t1ɝېץ+Onz!h 1]6TKm }]p6zD'EDƭ" j+ĹFk^(D(|AC2'dn6]APG< Xc#HCg\go1 Y@3tL}w$zI|1# CэC: BO0.~0.'A!29"72#ׂqJލ|/< 'iJAD-;zsyl\ܮu`1# p@wo1@ EAH,L  D@AfR ! ,-6 HF *\ȰF A谢Ň %@AC*T a0ȋdQaw:zra#hD@V,)4hQL@j[ 8RJҪSI„ lبPLiݻT)`}Kݝ;F36F?v,2l茕몎F2Sn\KxMn X0Od~vJl#CE Sʬ[,zM l`P5Lx7ΓAHv/W "AtWPAo 66iz3Z! a+[OAMհ7,5"$("CM mL^1@'/4 ^  9$Z  :xŹD9Ԉ?<؁ ApO 0b ~]`6擁Q !MebA$RL"yL^Y$'<+3UYQ#Q/qy"#Bl蠙&tءtI`=cAC (蔷c|7@f$~;-ǃaI~$43#kU`%il38?4V 2I@  YS3Bk ȈCD-/PTtv([K-egt I(F ᄓK.~('墈#o utxGDl. t浭H뛼ۍޚw`#'{"D(L?;"읅#K<M6<폸7G-E뻳](z_۟U(?PH`W"s[ JPh|X_7{d.# \B+d @! ,.8 H`F *\ȰFi䰢EJ`DC*()?YTرCE3A@XtGL4ONAZ1aBӓ:t1%Hс(]ʴL tNng)צ@Jm5j#O veۯru,Rz]Lg^WAQFA ᅍYZ8|}51;5'y*c6pζaew*X_I;v̮WE, @wP:Ti lH>۳/^ k.`R$PӎЍX BN^%PSXw`7cK xqKF=tq0K}Ŏ+u?4b %K7`M PDWuPQ@K/8x;lCYq/ԘA^na DVuӖ;CkERЁjg:S\$(E 6B:4X=׵<6 r;ŢD*aƒ9Г|Ev7ފFB@~7dcKrH7U0 Ky=3 H73\qtf25b :E퐍}52N oI]FЁyPW6Whcv_qw+" #Kd +icgF8&0܇&PE.ftE *h)$ВA VW>\"PXatP.]D r}WB0qt uzGM c ^Oy9*z "*$+,A1â>K +@ S#`k T!IҊXuLJw3 Db캀ػ$b&e%OA'ma+y0&,%Db+MblQ9j0 Saeo!g$8C1 y-"F B3Ձ.D5pbI Bi"4Ј8y@D( G{yaѻ,@0,, V {8! b󥯅 t5vx$B!L7dHDJ b+ [ d'! ,.7 Hy:Ȱà E!ŋ-#"A(14(PyLЪC#;T C?Z1AQ x铤*z|J( t$]ڔ`+|J&N:t(eӟ-1Ď:*Εjy]Lc{7j\1D2iÎ b@Ք9 WSPJP?+@:q7(V͉!>J}R\άWOWm{cȥ@X_p9-Qo)c5f6ZT Aqf_.^v+}x yOZ0 "1؇hA O@PYcφW7P;B]af1.s`?%:6u9RT7_ 2_'8C? Li\1"I\~գ$Sc"x&QP0n)?h8 +Xq,zdFy[< Q" "ײyPHCP#xI|JHo#@}N"~3=6~/p./n] >./Ȼ@!P<pY0#?WpxW[<6d! <&? {`FZH xeυr ϗ6"f\|#bČ (ƀ! ,+6 H\Ȱ!F bE|' Fᅊ Ta0CZ1&ʔ`:\ 8@Mdh|ɘ]%ɛ: j $1ԋlP8VґNj1iǎzwN:t j+J@ٰ!X_@!Q*-Ҍ_lXlif!ϋ"_Q-Shty%6z5ѭIO&AV ;vh Ǩѣ5oÀ'o3H0[#*l] Comλ+ŀLuA1 ҥ7f[t׼Wtgk:P%h(:Eo{z4ExE$ltMugHn[ q;ͯ:|QIwU(VAikC@pX*ye]K zLVij…y UC?p"`;b>R9 .RXZqYAxtb GUu Rb#eW1CD$\$ɜqIݗyظCGdD&,hhd=3L> O#DI R SM<*P#X]=- ;3oq"t4L'UXb ..$~TR<+ G>1iD~PRŶcJ(0k#nA0KxN ;qG=僩 JNJ2A5o֫2x@$P5n#;\s-C7Ƹ\ 5D3/lu]rOb"8 iS@.Y,w=y#{I8P~Ԓ#+7jwP^yYd 3 ŷ3o{7<#H 39z l0vLy##/޻#C㉤,1\o߾9p~z8+:A^ߎ;H,~=!D׵@@%"P@Oį0@(raZTdI@! , (3 H5BȰaAwB5)qx!U 2>Ǖ)Z̛G;v&P%HPF]1L̘]|)N&q"A~dSiҤ ;]7IMP@O*.;SfѪ &eAOԵرL~E (lٳgZV;<_7xc LϢ-+^5L`6pD0Iz"6xC(t- ZP#xҁ3+dg(V+@<۠ $J,1MlDB~JL @ibmIk#LJ`*# +/.bf0]P^+*cff@("CK.Pk1i\m-x<$]yq*0;@*/Q(\3K8sA @ dK.15ʊXNv-Y<& d@=@=8#l &7<\K+v-8"9ۄ`AߗcNxy?.z铻:y{ 훨#DhƟN:/lD|C~2=<BڋbOs"M6_dyS7\ f,U! , %1 H&C  eGh Fhq+? K=tb+T #$؏ >@I]%/8& OU OWLh'-a¡q;CcoeƊv5MMm ^7A_#mVJgs=rBP&.mXPMAUz I%TWfDbTnU@x{AP'X7XO#hU^-xP#XwDClf}p`CBh7T t?pC"]tqc'7xYP %G$ǴhPV XDLJ$!"ZK? #bx b.DB .| ~(n(pcJ&o_ Qbn0b,f+md1kj9q Oۯ$:t n,ݹh'.H-8haHI( \K9#C%(@-#E7F5W3MEj/b@.ݪ#l< rK'. /lb&K_3g#G8_I88L+:K:X;v|l/ ^y깇úI ;+&s9k.t{8HKk1'Iԭc3K(D D吩}_#5%i ! , "/5H6:詡Ç h@'c1ëE /(Q2&Btb8嫧/8pLeGU' M9u3PPi=Pncj=?u_ք2ԪjMXźNӵ{'мlݚ)ͺewA<\cקq2nܢEAR^dE⣝n?ߟ=3[n}͚@GFj>ޠ7vE짃۟Ͱ{Slɗwsq.r7]Tof?`'_#՜08 ]dŋ'gas6}h`#vՖ}Eh8V:b#*@`sHNztGj ~Q#9VH@ŗ`v5Lz(E UX"gGAd^@tzbJi o,2JIdꇣ))vZfPi2H"׈=`2 DSk"nڈ.h-{@H-H{l"z+䂨nVn-њ.˭6Djm {Ch\ `@R(w<:#@ϠY820 /<'3. #l&Go9[rYH/<ћd \<#l85MsY?3d}k'5-`/'tC[}HƮ@xL?nc_.Ho! , %0 l`*\ȰCBԠ-C*Wx"HO&tГ_(rҎIg`M;rv^ =5Z+YnذcG|I Ta@g(MBꫪLC*AD PYVRO Ts ߾P6@Jළ%kte2mrʝ  Kjٲ!y M@)"i=ryDТqTi2nȋ&򆍀`3L@ȃbΒq$ں;x)d|J=uaMcVOH 6 KK 6B\Z^hV=?֠EȘK95oU!A ! zȅ{$5%a=mHP V4bPL⥓?WבA?05Z7RYtsPG5" -zCOI>gk1A]tQyG# 0CaIȺe AKI.ӈ=?TL=W3@ʺP$AMNJZs&oH&66.$ o0ƧFŠ(B~\mɑ:;T#Zr0G3K;Ԣ# y N~D7D%)킿!עQy"Q̴A8xF \}aj -; 4o*ӵ$Q1.N@D.`KG|wVuuZMP(4@EqMfb D% PXG3^I g?db5Kܒ0zYd3Y8H+cIg YDo³ڳ!3$KfH_z;#?" /Rݐm=ͯ~_8D7@rNx4 wMc{ >NYMoBH (  „x# ça ! , *4 HF*\pa#K0`Ëv5>`ƓK<@OQ2(x@@tdž]ΌIq%Hɜ:`RhfF bZ=oC ;M6 eСXۺׄaL8%Z ejVp 0bvP%2.4._ k61;ТP%(Հwȏa"9ТuD3=:;FҠ mR0 uXYsب rCqzJ4U7_Bpa^n BApeEay |e|ƁcbuxGi uPdX=-w7Ml~y\X Xfɲ~:0p`u|Fxatꐊ2pՍ4@y:́1%VE n_X=]y#gt1_o`|X 8 ATaB2s{` y#ADLJO:Pi#ۋ5" z I$"TM,榃vN`t.&k+.0+n IGtpA A *BE#q4AEd j({pT7mLߴm>[gH@|⪱͡䌥$PG-rdmԳ2ͬ@-U@5׵ ٳ\C+uI9=Q.PpwvEݲ,=kˡ.DEk(JDݎLגD(|ԯudxg;K(d $d#;"}-~.A Ν:{;; D d D$Q[> }r[ b"<sDHApTSh bpr |ta 1pl ?\A  '6a.^:A|80EHObXOb! , +5 HP`*\Ȱ7? lH 3~qqŏ-r5dCOjJ2Myh\ara3deÆG`HeOALҴYzXږbӊޘZhY}UF٪AY X_8伅VocpLHfGXY :&Ԣww._8J̮5ul((̡hsPЕҨk f Kզz)lt&rt`KrWRîu9x:w?LRUhXE4"C18`==td:wHvbLȐ'\x}H V,BQ#tXyWa5UO*.$-.rH u"Z-,ؐ?>L&$V^/5M ۜu@Bᥓ1*Xg\E&X(7 ~3 dށyp2A(~)}c3?b~ kv `driʐ?~d49Fߠ,PD@Ǐ Y7-Bж l#@B%p8 1p &"?\"U'biBR+7E qTH2 u"$r\Bv\K;W$PFr>A#ȼ.|tSdOp m\u+Qx<7\¶B @$Hj,f{60\1t@-0yG\Zƞ@TLYԂ_q65]P/lyg38s$o˜-.~Y| E|AD|'A"M2tQ#?gyo7&>|AY8ЁpLf7Mx4[# a/ñ<`o^a:PHdCf @%]4Yx<4mH҄[_xtdž.FZC I0ݰk]"?3v[_v";fP:vmV/J٪3+n 7p`8ᘠÅABȫqURllf&Q^]>m E!83l)G%" "Q- 6u"k١B dٜn*&<ŏ/">Fmc Q@0r@́U[u Fxx%Ņe0Ʉn`FBGrws8auȒ|СrџA^1C"y G\XMFhMɖY2^֣952A``_ݨaQ.DP#`:8)BuxL:uJ.JP懶).$%Kx-z"z"k#*j_>ڪB**>Hq$5 9뷊ࢭ-ܧ_y:`AfC 0a8;," wظd5t&.g$DZKŪ}zsG4v$4.\"yplP('2M$H 5drIVAA3+bIVt愂 HL'x Ѥ&p̄vH" 9I@&1L$ ?($<(~eP*#t  tB &EH@;traitsui-4.1.0/examples/demo/Extras/images/image_LICENSE.txt0000644000175100001440000000135111674463545024622 0ustar ischnellusers00000000000000The icons are mostly derived work from other icons. As such they are licensed accordingly to the original license: Project License File ---------------------------------------------------------------------------- Enthought BSD 3-Clause LICENSE.txt Unless stated in this file, icons are the work of Enthought, and are released under a 3 clause BSD license. Files and orginal authors: ---------------------------------------------------------------------------- examples/demo/Extras/images: info.png | Enthought logo_32x32.gif | Enthought logo_48x48.gif | Enthought logo_64x64.gif | Enthought traitsui-4.1.0/examples/demo/Extras/images/info.png0000644000175100001440000002104711674463545023302 0ustar ischnellusers00000000000000PNG  IHDRuuxF2zTXtDescriptionx /MHMQHTKWp/J,L.VIM k IDATxyTՙ?B44l FF 3L4&&1l31ƘQ!qhb&FTDQhLA6WYꪺۙ? *b穧o{sG|26PGZ&mOQ1E_JM] Д)ImU'S} ~k9:B Wu(IYuH/=^non|/םM*sؾ/H`k/pϭ[dmXM3NwX ]9V^Q5(p}]M *AUUp=?(cgx>7MS!N<^&-}R>bF `'sS?LW/M#Z#ϻ5/ĸY8+%.F&m=m8iZٰM93ntaQ;חbGq,(}34U}N{3lȸIY.ez 2&=G.:$θ{f@aRJM,xaU?j-. yOp r:SNKiuKPy>k7QX4m" |۳-BU\קh7w9!h{VA;9lTLm)%m=ZLUQ,Pt3_5S!py )TB|s#eihn;4Ҩ읦$c1Z:e0dp9&;s(u/I`+HZZȄ#5nt^y ,!eD̯&48dJLNfaԄ;)џ\ilWhLf̘_ amXe9^~5@'_r/T9\eh|AZĶB1oP-G}]-TTd+9).ʌsQc/d2iWrՏCļw B 3oտ [+_|-;z㧑4Δs YUtbSٱ'{muVvnDޕwElz\ܮm;/bm:ҙ8=}| :}#@S'㘁eGd44Y~/Nꨪ|eWM3%iR+䜋d~Ipg'͞}zSc@J3&v5a[NQ6ؽ7ejzض/%/i45dR`5i$4,SOEtRR,z@I0)/³K]59I2 _Ġїy0tUr}ޮΒ/z8K.BH 4|JF3׮`ͪ%\q,_uOΪ$2L\tYKמUmJs _ 5{^ڼ49ιjy/}qr^J\S =/u[m(Z#a#L'sni6+Oc;^wp /랦zv^{^*oPغy'qEof@ 22qQU4MzJ&tqm]שŧ~57=݆úg푒z/n{.ǍߞBK/CWcI*el֕!rL%t*PUB)RI(})lsϓ(t] xE@`{ -̟u=R1I'XU$|1tcϾe5(OЯW MShɻxl5g&,ϗ #]STIG@Lmۣ`*Z(\sa{D6a?κ|_"{QU,C=/~%"NHP@q||?XL93' GT4(]w;8<$XͿ+AJ߸xyUAQE@6?Ӎn COUUB=H@6,эw4MSHA:e`]SdŚ׍)$L(Ry;E b92OVۗH)Cٮ. )F&mУ̢$cbG7IN|zg56H&t4557b%p*LĞ܏^[@  |)C®m+ykٝ1ޢ6e'"W,1 -@m Mx-AF2cBH0mE&HǝEI naIyw=سv6Bm a(55O >*_W4U!{,=L`ߦR></b؞#&PU+x^0Z }dMS?GŠ1g4!:Kh-ڵf,TE'PZu&7Dggše/i c KUDOHWK'u% hTEAS4-hw/%LS?{+RJt]c϶ G.eob oTJ\'Ndδkiq\5BA/aδkIfzWA6rgoCJɰO|9ӮR{գ - ys]A6 9>Uy49nV\L6gcdmZrLl,~|v<"ohV*aiN +A[q\|xTN9kȅ =n<<ry 6h2-.[#@ӂ:َ ]+:|y뗣**t2W*Iuf/^/_˹݁*󝟿=6,y8G﹆Wz o@yIrw غyC`ơ2z8NI&{JXAI|' uɤtL@Q Qlw]/PΗXr1BvoW?@&cYftXy,OrQ`@U *3Z%X޺vih{heJȷC 8 6/̼N$-Y%6Vi {'۶._%f" M\קԢoєkc;>ċugK ؎+$,-Ӳ |45|x45]U@QgA("4># )8Q@WiHcHjVq\_yl.O )Ҵe$7ENj'oIIyiϨ(YĤ$eP^fA2tui},C%:gF ÞEGtRǗ{J8z@ Uċdܞp* .!TlApC<E@ٵF.@%} CÏbV@JEza\L`qkjjE4Zv/kHb S R)#R۩D%6f_=KXZh.X!ڳul)x w& 6/YwE|,ļD].!DZRt>)l*R& D$2BĦj~TVG,Fg,wUC]Q4&;8QCyG?5D2_%pR`GS¸_>V"nt)'A7X |TU=ntF-򜎢B5 #4쎄1 &&G"qKG/D@k[~y/uCHtn£8 N-`AxT I  Cs[Z7H)zW)76p?|c(4-_!iֺq?Nm,;x , \J蒽}_I y|K)%vlXܘ@L;Zc]Qt5)?.2UleH ͤ  +%%>xKyұmǩc;nBU1Z4JxmŮ  ̑Q_v6>?Uļ78bVdf*'?Fa%KPX̳dT3O>Ɯ { .v^x;_C( dbHASFgMm/Wq :3jSdׄc*;X9FQtD=%Gv׫NUHȳ~Q/Kska\v%,JplA{4]UÃ<$XV,b͛s)oӴkov׫( wPsNJKػ{HwAgn@hOxmP~Udʫ{0^־"*ذq CE}8cGQw>׀CF`؍"= 9QU-"($:oο8xU'^?9).o38zXV̟1<]$wH{q@#JST~twX͛0+=/a)xp;}s?S0j̩Z93nB^ڶCS&/ރ@ܣ7X(ǫcRfuZjA;ͽtJD SQAnh9hH)_ްa< ؎ۡu{oHj<Ƕ-ى(lE쩦Ύm54P bѡXz[î+|fsj^Sy3?A C[ulfe|))\.G>_vV6Gߑp0>$X4{q[kV>u{;uɵ8qA+<)Tv/ի}ٲ;n:uyr<uuٽ!1&;OhST@I8 aOҜmBo|@m}%jk] kqwlYvd~oi)}T{g8Z|-v *PT2L]m?n§'VM d;7-zó(j j,T눞EѢSG*ul=*0`P,xk;,~‡8k—٫_lݼ^}ӫw_Ȃ?,*xWqO3椳sY<m.b*ޘθ/%JSZ֓{9(Xh:2~io|#D5ijkv" 6dM0pIJ񬷯 fev}ɟћehmDz` t4}}cYv9r0pX)İѾ|KLGQGZh:gM={w:^Qq_d*Dԉ5Xt~=Vc*o[zhkjf<f G ZK'28FSc]86hm@hi[dwS ,C -)6n254Se14YesQJEC3d˦uhF )=,||Q"ن]xRcǦ6a*+;Tz I֠TU }qݕc ,#^1)-1)ɘSɄߴ(tV[j+X){UQ[ V`DҏOG2BçoeАѬ_))e .ڜH>*jxm2)R' )dRFI m{Q ]W%.v<7 ضGvq?VkbB% q_);M'IN0Ab)*z-M62$dk(0b[[VpQ"JlyE%WkHzH9MC /V]Rv._J|O25Z@ikZ"p/@F^i]S,-IDATv+ m,J\70C.`Ra1`ZpPNU%a F S(i=UzW[ _)9p6Q=2ا*"m}w/ʲx{/~u0 pgu(V[ҽttx(BhEJ ] Nv(kXAq~ ( HB5CWH&t|-p)ڦ0^p[߃fjrV߇wKC;p87Tpݲ> ]1@viG+>)_*!#r::T)AW$"0uhsr :7|rItFcF{(w**y<84Gw%{@wnt>%xIENDB`traitsui-4.1.0/examples/demo/Extras/images/logo_48x48.gif0000644000175100001440000011516611674463545024155 0ustar ischnellusers00000000000000GIF89a00Qi*\lnqd!l/[֏];yxx@\ѐ@E?&}W~ző;bvtl-PysuwNG^|s/r[<x'[Rj2A燜\燧sΑo6s,c}5%yMiTƅbZsEJy0@pi[>Q†ljS2cyG;ߞnϗGݜd%u8ؐ{,YpLizjwn{~ۢJOo>hYv"g4}/yzm燮+lqv?},iZz|S賵.ϜSІZxxz|֫ʐN*&r]Dy÷dH`#`|D˘kLi5`uog;z~Uo0zBcvoRwMv/vXz(cȿ탪3g3̇1d4ϝk}Lt1Z"r! NETSCAPE2.0! ,00 H*\ȰÇ#6ċxbW; Y+O9n,G ybFʆ)9ECOJ𨼉Jy$$J>NaZ)(J帬[zU[( |.ָ[ɴ [ G#v$B=uKSeMLHM?)iP5Vl”fSzk7Wk9n;sYkenm*)=H>زJN\k ͯϿ)݂$'ЦMi9g.w䨁^ۛ8,ȒCq_F]v;@s'"t)_9ІmdW 7b~_Ȣ"-ԎI4iwх"^H8$nR76JT\j) F)p4U@ٍxUX)'IT'$9V Z/nt͊ jbK v'h6s&-C '32S-NAI~b!q\m3O >D<03o1 ,3CpH+!N;{d ;訸,pԁwt;aD; ( ֓|I@};@c~(tFP;x%<QX~P6BĀI))*ȠCc6<"}IXH#$|7EY[LHye,|iwx2f6eOHYlSz6g#q"UP;PZg6*5S3 'Cz_ +3BHΣ6'<9+h:YZ`0(5ŒcOBASL$>q4Nf ɢĬ#4B. H<qBK p QHl2:q\Կ4"? \5̨:!AcA! ,#* H ? *\_X},kHQk|+gaCŏ|X+IJC<~\ EyB+%#̘4L G-㍣DgР5j@Li] t` @Gk|$-5$ڌ+nY:\ږo9q[% mo _F#!49A|~a:uˬɄk5gph@]Pp8ήM2[/ҺRĆ$.<{H<&ȼT6rOG BR_da|oOȨnj6mQlǟz&G;3]z 4q8wwb_;xa!0)5A֬"2BY'rb;aD} ͆a#<=<!&x"pd[$4ftHaF6H6YGE&xY "PN!g(m՛ { ~tHgpQlPƙ3v R; 0SSHBkr3D%@ZSP`!pjQz }(5Lc.c^=F%"!EL4h[^ %|A0ӊ 4rĜЯP]s gKH*Tɨ*R 5"P))RP*! >wL43@l(HS,]H! ,"* H`?*\x2HOX|8ba"?(+;<*tE1dI?aNѰTC.P! >si t_VPg M>Ev 4;CʂگPPn][n!v੠_^ۆMv7PI7AQed'両*Plj[bdž7U4)Zc&C)A~"h2a-~$!ȼ1`x@08O P<UpHj)'W@24Xy3!̳%ڊ!ฺ-S3qG,mL+pn>%,cM\3 *4ryr/TRr`C+Nr5 |'u_P!ct<R;p?>4*A4`R)A -RA=P@! ,"( H`?ܴ3ȰAi@Ë!Jl.E:0:xGRyP@9$2&MI,bDDL)ijh*FѧD֘5,VbEGݼpmʖ*b֨jߺVOg[vމXCBǷ@!ߟ8r"^= 2c 5A3'&nk)3 WngnȓP bmAܔ+I{""k?nۢT-yw ǀb{8( A^y~`G#- (y&$`~tt@D#,G,!) #pLe$ V<Í b6:= ~" T]AJf@\d#&Zf@ģ "xEנGvBo dC.=t@FB̐/UA6dsJYSr/p!DҀE"TI#03ɠ8mSt4dsH=MS5 ~a!(|J:XESw< 3*Le) PP*Q" JxwY+*B!鮻Kb *F>!Q-yGpfC6̈́p y(1 ]"|$L?! ,  ( HA*\8'HxbHϟ v9Vc,-bܕC<(cbŋsrʔ()}@PSK,Zii%CS$lY%uP+IZ;M5Q20pG}KlP5 %1 @ FHF0%XRI)R_UY/aX'T`tGSO/&L/@fx$ 'sb@(gE^8nzG@! , % C*H۷oTf'O j\A4'iƌqdo$G`_sj9g 1 _,-Ӻb/9x-䄱\gϟwW^%95o4ij-?xy*϶ݻo u rQaNEۭmB7<*5KbTy5$鱅L,඘7Lן`X [0P& h 6҃6fÅ&!xGH'AG- 4n!l(E,ӎ' ab/V(61 6*T:@<mC\ )_id]B}mANN 眔MAxC>ZY]@qBm8EĠTN9:]x:@}5EHx~D$oOO%լ} 2É$ ԳAMU`ij˰氊 }i۔:O@! , & džv\Ȱ!CvU.7qBja;hQvkjA)8IF 1n3k9Eg \H1s5]O+RKRcD"͔蜑.BRd5k9%2|1!Ipk0z yt:ŕ\>1*$EkNN▶ [R C[QO YK$`bIЃ  !;d͆h{&( Xc:<-@"v&8e|G3/(c|Q_R< 7@X5p@mxđ ͍1,X`P!,|>@(ZW8U2Nt 4t)FAx=`c-B@) aaEE쐎o", ;]K 3 (' SR;AAvXE AvVlQ[J&Yi|Ʌ]I J5%|+n|'Z݄kOx ;VƲJ:|s`9MS[M9*|9.pc@7)H9Y@S$ rδ0(]3Fpz>S] 0{eu5ICE1‰4 T*j߬b뭮Fp*'Z5źD߰Q5 ,C3`k h\֭l0uZ z{nXk ,„yP@! , #) Hp\Ȱ!?:UСņԨ7O /]..Ȇn89X|iP6La %4JZ4x`·ufҼ9%J߆D@ƔVj}g 6q&)Yk+_(m@ IъQJ40mjR"%a48B +p2PmEWNq:klR|3N'A'$ ~S;5pNY0C}̬b067G! , #* H?<\ȰA<и㰢?\-Kfh4Dɏ- eLS4с3@7&FS SW(  uJV6GR'b:R GfYWY*['ySc&d!*8DP8aSpڅsd0A >pJQd mb 1OSOOQ+Wǟ?ȭTmxg}Z]eSG8ө2f (ӮM摱 GБh] )_|K%|XSA8]u)ps-"Z5_C"݅*v<(L|05V@zjfB" PʼnMnY7-":`#^ŽNxa) W VLz͔qUdy5K;zdPCL d@69!C dAQ\0|qͣ=PN 0QY@P蜅yJhPC\J@AI5@Ac%A9 ' pi^ Q7FS46ue;P;$H,:"P.AqK/ኻA ﯞ {,ӰYGP@! , #* H? *\OX}taHC]jTX?ֆ̫QCqx&znۼ.bqBOCWI*m9N% J1PR ),1U'ւ C'VBL Sص5=L;/P'YcJ)ɗr(o`hӖ 3t=5j5p#Ѧ׀J?:np9pPT+A5!B0N Hs(@(2E ciE5@a lê B1y9NZ맲E{쬬5;b &sm%^cAZnP2úN@cͿ9i@! , ") H?cC< 3.5B۠?[Rv&3uF@ t54hcLRx>r$Y݄ ڬĩaɴ ӃO',Ptʔ_> zz$)Sj0Ķq" XrPB SOmC9L,̢FFf! , ") H? *\O;k$XcHQCh.Sŏ]]k^':Kn! ,  ' H`?m0Ȱ@֨p3w0 5.ɘϬ>`b?kg:)i0Z̈́I#Vl\ˇ40$H`ʔOm.54LSbR$ ;ҷ6T@;*VD)v!B JʝuAGcNR)yj?%Opݶ]AT*OLyIS}M)YрDxv:)|Rp\}zśjUܶ:i4Bn@4eB&fSS&},(Q_UVI8a9p0B (@㙠 VEU<wu([BQ/C@ds0 4vOmM,W$C4B%ȡC$ pEp'y %PQhȠ6-3w685dWZЦ5fjMh`68'f@p&ևD?H"z *4! , & H?DӦTg];0a—/w6>ք#Ryi/i0^&&hT"4i3 r :5W~y25@v ȡh?s5UL2H!^EUc,:lG>\d!=IDP5N"W:A;brDP;hGqtQg8U(G|Bۢz J(yb-R7~j*jyJС*ACTp# B Z'jX身@ָ+Ay! , % H\h5$ݕ+=lhډ.j $0aE˹:M`Ԗ8nO=!j?7  "**ԄxiiAAGKՄ}STALn2f)3nU79YCJxyCpUjO-K<xL_NVL08pNh3f_yXe(Dir& _Rq(eYނ[O9@LE)"m9x8A&b]x8sG|@~R*ܓDm Cp \S:;ahCy Vh9=)< r,ٝ|jDfB  qs pB. >.! , #Hp࿃,(O#r .'! C`?G%H`ʔm-0.SlȒ&ؤ.5dbsI*hRøތ$i΄=]L""U#:0-ѫ6uuMS$&et ЊM)~%Yr,O4ڟM8P.c`v-ASL 0֘1TէvvDKJZ/O=(iD?EGHdnY7KQ~ҲypY!:*?|>%ܨ8TpwAИSC5hKޑ}S.hOVfϹpfGwk9 ?C6/t<2PmO̺v͍u'"M?ko4àkJ8SW)5Ф -S  XJir%YzyPpJw˅PWh 6 ,n!/$F]N`|A5x  ;|C79# 3P*K<Ă@ gQ fiX| spֹ yĥg~ cӟeF4&~&bY&' ˠfjC! , # ݟ*\σ^Pac-A5jz,aFO:&0e* 1 ! Q2ur/n0q~[j ]~D,MjWg?tvtdFv^"˭7rW".V5s0aN3؎4hX'_2Y`j5LeIq[;Sv1*i;P+bOMQ;wB () c~+C! ,  " o!ȰÁ 1* jdخ׎ ԘPiƓ~hiDv&*T+M%P&CkVLB,& Сrk2@Sr@φ͓Z nQN5MEl;2 uflgoK%}: Ԗ!A <2kwL|r#a  ҄f]1S TSՙzsL2V_x m^)SC! B X ^5%\'u]iS!"+b=ɀE'ЅY1'ܣNP- aDP K)8 xH[xyLA -_)?qx(Y*_B<NՎߐ]G#.yQ 7E3L@M@ĐNЕX>>q@n& vFXǼGj78qMc$Fjz.&(k'L8kC I&+:k! ,!" 8?*\Ȑ^@ذb?v$ -g톶 LQ Ȇhh;/+)-3ѥC;|8㣡D+O1hIk&Qbt`!rAW%4PvPĊ[璞4eb N~\0wׄ9]!X 3,|4pҽ?5eh90b3M*5hRY_fL)ХM9RINYnF8"_ԃr M5EXӇ Y`BC/x 8 w&|؂yT D'An|F&- iM!Lڇk 8Cb ~P"_d؝ky2'HaSrv"A|%(;BG? )hv7@n.! OO_P&)(lPP/ Gbe35l0 )@b|.XiL*cAd9)sXe#8Q Nă*-A$BjQ;whͭ/D6 lJ{Z ! ,"  H>)ȰÁ*B‡;'A{glboiK`JML$K6JLSfAk v4eG>;'c$r tC%!ƍoTv]*К5qɽ ׁPK gEWn:Tbu"L*D)=uOR7p CdxG&uR5h7d418iǺqɈ|aM] ט|Yet~IAL$SBn|3ΐO ?2')G$kDI$xRA0.,\ rL$_R(n` /8qT8Zt@ p3 kR&GS${WR&A\EmFQ"nkR|3Ĵ:D"6! ,# HPk|)ȰÁ$ELË #jӖ*bi- LJ@ȇH@S,\dخ؛5M£s'vGlLi m'ʦO l-^;[.Nv CD*OcUnJ҆tw# \~)Wy$D` Wiy()Rh!OP؋谦~#PG(L@ b4摇"hGD4,:/L2 q}A%E"oKbK i0F3ŞȂ <>li!$^NW')Biǰ ^K3< Vl@0MH"ǣJ펼!Sf?<6o:sd$%tz׎0쑩қo<}ik)-^%Έ֗RecVa;9 :.lWl'Zhm].P(EݮjYG-tufbHig.Hb@Wtԁ갉<{ ,O -ct ~U\;ƽ2Mhjq}!eӂyOko7٦ך4E bzJ|&^`;*᜗-hr ? PvSL(`n8"d sdF>pA~(G<ad@v18\" +b;SBP)!% <8w}AyAIL7,?b@ 0EC:!I(P_ d$`0K`NϤ°~IJDf;'$/8RA?y3^\nşit /C[!B}P;hJ,DG uKPc:æyz"OB vtP~ {;<|1 B"3gZt5M^A! ,# H? *\P`F64)z 񑐢LJiKʃ+^|dS&zPA;F43.5-Ja$tMysGΝ&L֮&A,4'v`zZ$%2۱ g-$2l˖tcf tKQvPiqUc(L5>Z'桫Av>UgL4n/:@.$Q5J/5fs /  "ܚkؔ17 S"MT!}sW573p,t^A]pX Hz^H9xBLÁzQ)1_p!'p(!_ KY~Z<I𣁔 ,WBʋ($7˜/ȀG,LᏔ_,-5 ]"$u_o-!B0 QJ'$`(Ptb* (l8tl!B''Zuu6Ư &-`)5׶J5ECFW TgÔoH-]|#ak_J$4ݺ~Ͷ b(cÖk\@"z3E$|姁< kĽ0E =TXQ,pax8ŌSȰ(2AC|H4NO3*‡,>! @! xH\30ԁ_\$ ;"CdIt9̒," (Dr\PCobL\॑^zEDE0ś0Ġ,sP'_I V x"х,@]*(j 3WmlJf^*T1 Ie|"YK~dގk5KQ'vxjO[2jaD?eĈ˳p$ܴztwk65Z4,- d o5FB@g1J!Vİ<àf% qȆvAGC`AS[rRE#J '^]43 nȄ<ȉHbtG]qkWڙAqtS]5?Xp\j:`Hه߁S /ܐSmP<!SĈ B C0χ!?S 982%MWE$/dKI&a(|'0>#\ d$/iÇx,_|1,D¦'UpޜS%GFzz  Tz2SD(FLSCj]_y4%P;بkC* n9UࣙFi4_f, Ր'&j„>,zM],&I<|ƻ&yüfI;! ,"! H`?61ȰAxT`͡Ń"VУ-A3.:(͎MeP@:UxǔL QtDQ& Ւ!Bk~[&=o5&I<55#'3ꪩ{GUxϬvv,U ý\+֥@OVPB=5kuvV +TInE`9~4L]:5jt]M6l1@_~凟5hP/!M:V\!e O"\b} ]@}MUrax %|r]\E|3FNqA> ϖ!y] D|L i pBɑ.c %P)נ Rr` Ȁ43|"GS",ds״IÇ%l:WC;Mh#_y?C|!K6+Aįʎå(̒jy" )^-lk#B ޒ).! , " H? *\HGhaHQ BAF[#*ȹ4ovh[ k"sL-FAkeS@<85OVZFO7 jDv=pɊKEGjL$RbA=Yk Bn`Г$Jd]ƒo.QIo{Iȴ!\n $-V,%Wxr# bE*_=J`;vKjUâOD*,̂:pY8v!Z#Qb܌cJ7ovJTF

    b-(Q_5XbCm ~7p!F&a[lP`⧁U7"3NN:d1O ]Ԡ;xT!p}D"L$8hSS%7|A,`߉rQRBɕVX l9fs?Ta%%a)nAJ> ?CP],<18rQDYVƐ',hU(ki** U _@n64K(l* B<묵[-MŶ*,< .閻5;! ," H ?6XÂyZXp ?3(-Z@&A " y-5>╥ -2nhгԂzL1#A7LsiDjbpok$2y%+ JH72 Sbۂx:6iS;!˲0aCo!KڑGwىě#1F٠鱋KGq܂3dƞ(;cu y4/3n+ٰE#:5 ^AD 0;`_ X1OdA LBCDN֠hcMN8\0?09œs9hp?>OHIɓ`N011_\] yPBI(rG쒘'yB l 7T!T\#B2Mm:GiB&Dcv iy«8ȂB>t*jkA bר C<{- ! ,# H`?4O;O6ʠb4n]EO)BL76kĕ&\bgŲ F{dž'ѩ{,F=2>[Ϟɳd) {je5O%yZq0YAe_,,p3Zv 1bXSN}X:.t ؊^OZyƓɚ!1{K8/bG{uֻ1co zaMG<*<EWR n8Xs+֜Qt(tZdRb`^VXa@B|0yA=fTB0@@:l<NhNgDYqB8ml<]`#:H'B PRϐCHbhPLp#`$CJ2U E(3 " D,UvY,_rMks e&BXmz矌F)_@jhL .t Z5*(h)J]¥C˞aI8o; Yg8JcƜ8!C" T"QL"eԓ6a_D  4WaCD0MASD"%P_ctQÌvq/O|l(n%iSX!F[9HPw7AC1="x"H,NmdApKQKcF'QH2/bH A$ # b;䑇?.Sta?`C86Sp.$3h`83?xݡ D'tJPFs )qyB,,(C`J\;_4↧@s&KP;(*B:kB@*vz+H\+:l;< :>$! ,& *ǏbT‹=FN.QafEg7-,-t] >VŃ2Ӄ(K\xcbś9Yp{Hc@..-3iYT P/!)a 2bϩM栵z`x19R>R%[Z-Ybgv|//PlɇxQ)73fPSJ`cJbiJ;" Q/V(2 <Xx#'dhP rH㶋]Iu̘262C8|C5 yӏ(,  "}pć?Na]KDAdK3+U7.,AS(ePQDaB#6]C>"q?a3 PO=5#0C.r3Ï]td864r^TiB9TQcs2yNyb7DLp!pvA"($ȰCу><-|Q`, Ѧ Z\٠OG2&7-&km|󆎘eA.XnkܰtZjf!CQitBO2@&5Ldl4fǭB pKSIIR`RB$I*rEɥZ+$a :zX BA(Pv|]p:^iG^d 1xL\P]#?Gdl p 9D~ BdAA?ErN?Th'2P?B8ؐqL%8 "\p9$xߠ!$$]aC=Y  |!Zkn|3/ 9E c V`6k=@̐b xF$}hǡsq7pActa h*l^t)C1A;P,A5v )D| *d]y2,&lLÌ'r,(ʰVK p0sHZC|q!P6mȒ 3LmdC B68LKqC1s]3r! ,!( 8\Ȱ! 60РPË -6b(xC܃GlƔ͓)w@k) Deaτ Gq6je dJS%#FKmjF9nij"ɯj2CG8F,I@L:lŕ;W'7mIr/Q.85DCw|88t1*1?}3@՘?(:S- eBI5V 01ΎDd7f7tU(/` ZLdvQM(@P@29&1"KD|A>R@,G;)5R >_Gă,q@6*Lix4n6B ̴ v +K#(14+, 44p0 ;,)Ғ,̴nKD#_! ٜnf 30c G60sVo#BK3 fl ]s<5ƾ (r! ,#) Hp>\Ȱ!?P2AË bJTT*b"GS hӦ'$j g”͔+wXq 3fIk'L5UJm:yhK&5Lc^lT[šFʪhdZZ^=ĖFBk!ډWMcAh{€qGX['tfݛz%)iA]ZvׄzFib; L]C@n.5jLa8g8<5Li.а=pm%_^/*pVC99f3}>|B7:E  ;E`v [0-AaՀ ,rXIsA)G5"$x#&bLI$S\#`2 YȂB# (tC J !Ebs+)(:Kon2M+n¬‘ \k+~!!˃,D4 <4̵ѡf-30bédEs p4ԛƗJ6hT!"vJ@ÃZ\ȑ ِReLt@7q"@v9g]z \ēC |xlj͈biN(APQaJ((@ң 60,C]3,:4aH< u6iAHJ*'dӊ [5Ӻj?\!B[ G#\bH+r+˻!l  xM6_42pL]ll oOc3p o a{ͳD 2f"7ehCK0@Bd#GP;?0ɐWY;@}DtpPMqtY@5tiL v} `i9ui'(pL(פĩD4҈ıA2̴R@5(0Bj(\E K,yª)2 Ҫ@-E~>L3 *4r Yl#42*p ٫l6d %e ̮|՚ k3lLTArp RBZqD{2]2{7B6D 2K77 ! ,") H`? *\O;3Ga/xNj?ё5 9HP;`,$15E98CkL$UTp-uǗ  L D4A3EQ|oVG{SpA~7'| ɀ j)c*C*h6؎<&?. kLӊ DZ^H#>KD6H^.(4!2-).M̼o+pLZ{ro + Bɢ /nL\ZN-+ g5TP˖z2/,_P@! , ' H`?|lcC=W/O3F\Sh+AO:8O  N#xu"@[/_?7-DF t|RhHm;0$O\yL4TUaF(WvjϩNEȬ[zb!7,٨Plk~p_)si'?<[b&Mk}Ǒw(ȕfdXs ^Lov!Z7l.TjXIDk{$j#Z~Y8Dat'ֿf&c;|xP2QkZY.i;hpX Ptא' '99dN /cCPS5ta ~ =tbUpP#@PE}(JN98|AIC_beB ?x9,&55ag#K9$,aMBIi{Nd;n҈>nوz)(4r b,nqd2sH+`l+uf# pȴӴƪpd{H^klllJ;.׶rHD@<4 n24di4 3ِrM&AC#M#C1W6ÞƂA&! ,& H\h0Aa?鈷=qBqCc xL0e*Am<C.n9QnŔY<;sCuF!UL;?yX-U&bҼIrXЪz)'lSU:zb֟cFO<?>ۼV ;Jj2PXSj.X=~g'lWc;q+ ӸX>+ =+L}onzm x:-{sDyU\%V :`\Y,-}|rB EcTq |RpEE0 5C @Pi1gP;<" Rb(6l6'qE%i]dHP;~Ix.gt)K6P;@#@F &%@ 03KR͝j* v2s *Pj竲LZ+3LcfH0#!J+$_j6BK4" S+.X{!l0뮭0 IB=pR56(YrOLP@! ,% HyamßQPx,v& _z#CɮoD5ʘ1b2a”Pm_<@LP[H5Ѭk{3[ b!<0SkD@ \)(|\#d#By! , $ Hߟ"AÇJ(XEbQH؆J9~]С'MjLLp2EC*Ʉ hDΞ@ hyKSQI29ROS5UzVvz1D['7x@̳v <&ڠ!I-Oz 714vzyN8vejfJ<k9r,1_9.ڄ٘uHv%*POIN|t0|LxiWɽ5tkk{МϨ ?U?:Sŀ\nq3@ 17Ap HP;px':D8)_TGy$@ĉYnB/჌hcD4Ȏ<N"dCd3AK6dGJ (4G6NB)PSpb6B^#%jAd(dr|~nMf̢4Њ,R$LcH*B(Hdfhj+:*!,'f^yi6p8 xsFP@! , $c͍ ڵð#F'NAoĨ(ѡ „ !h/O)S4ԨPnKe˕+YjuGv@,\pA$Xn8:8-@8ĉQBIqzG/N@,xT@/ƈL됐%)$8z۠#Dp?od#I8_ ~C IDڠ)餪agKH ~#&z6i`ybfL,rA' yL4l6"'DDM2sȷLcH+*&`4z-n!ކʼP,![o{z5Cf4kope  ςc@! ,& gC?*\poK4\2…_"QSF< IR %‰lcrar4̩SM&Lw# IR)ӝNoA5aTzdN5j)@&c&ƏB3F*K %lEO) P ڐ'#kVێsk=Nݶ =6ڠd쁱M.k=Rjnqa,k.bpN~ Eh~^{G6}cCGJvmgjXs%4[d ؆7]tT)768x2)u D:4G)Cݱ.( pBX@-NQ6ZCaJ,l C2p\QFqcP_09D ?NUH6xi6`ǔD1hh 9dF:]`e#i7s[ͫ¶訯qfՎ,M\H1E̐!+* WSw#!Ez1 j@S@53!rS̹-4 +bsNj2A=Sz|J9U ر&LM`1s7Ćp ޽|Qm@cWt3Ǎb%ԘwZdFG‹7[5yM%ж\;4Lm6dd?ۂߑB%X7]-{CMg:5Y{l@iwwC`SPlG+,GBdqH~iS[/r:ȏj8{`x% =! Y:q_ 3fp.G;<}fGmcD4҈:]hCij22-dMHB禜:Нa'Zf+E>#٠0PSJ2ЧQ?dJ0pÍeQ$w!2 3>S l<amN!{f<44d 045Pm7o+P@h1Ũ 5(! ,") Hߟ*\XP]0Ȱ]\r򁐢v(oʌ":zTGIy4LѠb%G)yLY(.cDQq83@'[cQ1$T EVplYx[aJCf-nidHCX\'tA \|0_~1.TtPb<AȦR'HD+vfdJ2j KGsj -ljm; ÎQ6,F6G Yg[:ng;\n0g^,1QzG]#]5%A?Q4vKr t6Є5" \Bў;@CM(ˉp!x0s5&@pX~?+|#>@_iCG1a 7\cHfY=XҎ_H#cܣSȢgh Ý" G2QpO֜P,Ƒ{fM;yF PDn NZ %}w fl1G)Cn$i6DD=(Pn3`KJN щ0 pn l :J&e &< 3pLn;rD;EC#2!hqS@Bs1ǭв 0*e2arHpAn0A6@` +ƶ !,$* H  *\Pa; EyJذbÇ1p呱 ŏ/)wpH+P tA7t) 2!H,)[,E ({έ> T;traitsui-4.1.0/examples/demo/Extras/windows/0000755000175100001440000000000011674463545022062 5ustar ischnellusers00000000000000traitsui-4.1.0/examples/demo/Extras/windows/flash.py0000644000175100001440000000272611674463545023540 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. """ Demo showing how to use the Windows specific Flash editor. """ # Imports: from traitsui.wx.extra.windows.flash_editor \ import FlashEditor from traits.api \ import Enum, HasTraits from traitsui.api \ import View, HGroup, Item # The demo class: class FlashDemo ( HasTraits ): # The Flash file to display: flash = Enum( 'http://www.ianag.com/arcade/swf/sudoku.swf', 'http://www.ianag.com/arcade/swf/f-336.swf', 'http://www.ianag.com/arcade/swf/f-3D-Reversi-1612.swf', 'http://www.ianag.com/arcade/swf/game_234.swf', 'http://www.ianag.com/arcade/swf/flashmanwm.swf', 'http://www.ianag.com/arcade/swf/2379_gyroball.swf', 'http://www.ianag.com/arcade/swf/f-1416.swf', 'http://www.ianag.com/arcade/swf/mah_jongg.swf', 'http://www.ianag.com/arcade/swf/game_e4fe4e55fedc2f502be627ee6df716c5.swf', 'http://www.ianag.com/arcade/swf/rhumb.swf' ) # The view to display: view = View( HGroup( Item( 'flash', label = 'Pick a game to play' ) ), '_', Item( 'flash', show_label = False, editor = FlashEditor() ) ) # Create the demo: demo = FlashDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Extras/windows/internet_explorer.py0000644000175100001440000000515511674463545026212 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. """ Demo showing how to use the Windows specific Internet Explorer editor. """ # Imports: from traitsui.wx.extra.windows.ie_html_editor \ import IEHTMLEditor from traits.api \ import Str, List, Button, HasTraits from traitsui.api \ import View, VGroup, HGroup, Item, TextEditor, ListEditor # The web page class: class WebPage ( HasTraits ): # The URL to display: url = Str( 'http://code.enthought.com' ) # The page title: title = Str # The page status: status = Str # The browser navigation buttons: back = Button( '<--' ) forward = Button( '-->' ) home = Button( 'Home' ) stop = Button( 'Stop' ) refresh = Button( 'Refresh' ) search = Button( 'Search' ) # The view to display: view = View( HGroup( 'back', 'forward', 'home', 'stop', 'refresh', 'search', '_', Item( 'status', style = 'readonly' ), show_labels = False ), Item( 'url', show_label = False, editor = IEHTMLEditor( home = 'home', back = 'back', forward = 'forward', stop = 'stop', refresh = 'refresh', search = 'search', title = 'title', status = 'status' ) ) ) # The demo class: class InternetExplorerDemo ( HasTraits ): # A URL to display: url = Str( 'http://' ) # The list of web pages being browsed: pages = List( WebPage ) # The view to display: view = View( VGroup( Item( 'url', label = 'Location', editor = TextEditor( auto_set = False, enter_set = True ) ) ), Item( 'pages', show_label = False, style = 'custom', editor = ListEditor( use_notebook = True, deletable = True, dock_style = 'tab', export = 'DockWindowShell', page_name = '.title' ) ) ) # Event handlers: def _url_changed ( self, url ): self.pages.append( WebPage( url = url.strip() ) ) # Create the demo: demo = InternetExplorerDemo( pages = [ WebPage(url='http://code.enthought.com/projects/traits/'), WebPage(url='http://dmorrill.com') ] ) # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Extras/LED_display.py0000644000175100001440000000601511674463545023075 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. """ This demo illustrates use of the LEDEditor for displaying numeric values using a simulated LED display control. """ from threading \ import Thread from time \ import sleep from traits.api \ import HasTraits, Instance, Int, Bool, Float from traitsui.api \ import View, Item, HGroup, Handler, UIInfo, spring from traitsui.wx.extra.led_editor \ import LEDEditor # Handler class for the LEDDemo class view: class LEDDemoHandler ( Handler ): # The UIInfo object associated with the UI: info = Instance( UIInfo ) # Is the demo currently running: running = Bool( True ) # Is the thread still alive? alive = Bool( True ) def init ( self, info ): self.info = info Thread( target = self._update_counter ).start() def closed ( self, info, is_ok ): self.running = False while self.alive: sleep( .05 ) def _update_counter ( self ): while self.running: self.info.object.counter1 += 1 self.info.object.counter2 += .001 sleep( .01 ) self.alive = False # The main demo class: class LEDDemo ( HasTraits ): # A counter to display: counter1 = Int # A floating point value to display: counter2 = Float # The traits view: view = View( Item( 'counter1', label = 'Left aligned', editor = LEDEditor( alignment = 'left' ) ), Item( 'counter1', label = 'Center aligned', editor = LEDEditor( alignment = 'center' ) ), Item( 'counter1', label = 'Right aligned', editor = LEDEditor() # default = 'right' aligned ), Item( 'counter2', label = 'Float value', editor = LEDEditor( format_str = '%.3f' ) ), '_', HGroup( Item( 'counter1', label = 'Left', height = -40, width = 120, editor = LEDEditor( alignment = 'left' ) ), spring, Item( 'counter1', label = 'Center', height = -40, width = 120, editor = LEDEditor( alignment = 'center' ) ), spring, Item( 'counter1', label = 'Right', height = -40, width = 120, editor = LEDEditor() # default = 'right' aligned ), spring, Item( 'counter2', label = 'Float', height = -40, width = 120, editor = LEDEditor( format_str = '%.3f' ) ) ), title = 'LED Editor Demo', buttons = [ 'OK' ], handler = LEDDemoHandler ) # Create the demo: demo = LEDDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Extras/animated_GIF.py0000644000175100001440000000260411674463545023213 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. """ This demo shows you how to use animated GIF files in a traits user interface. """ from os.path import join, dirname, abspath from traits.api import HasTraits, File, Bool from traitsui.api import View, VGroup, HGroup, Item, EnumEditor from traitsui.wx.animated_gif_editor import AnimatedGIFEditor # Some sample animated GIF files: base_path = join(dirname(__file__), 'images') files = [ abspath(join(base_path, 'logo_64x64.gif')), abspath(join(base_path, 'logo_48x48.gif')), abspath(join(base_path, 'logo_32x32.gif')) ] class AnimatedGIFDemo(HasTraits): # The animated GIF file to display: gif_file = File(files[0]) # Is the animation playing or not? playing = Bool(True) # The traits view: view = View( VGroup( HGroup( Item('gif_file', editor=AnimatedGIFEditor(playing='playing'), show_label=False), Item('playing'), ), '_', Item('gif_file', label='GIF File', editor=EnumEditor(values=files) ) ), title='Animated GIF Demo', buttons=['OK'] ) # Create the demo: demo = AnimatedGIFDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/traits_ui_demo.jpg0000644000175100001440000012430311674463545022636 0ustar ischnellusers00000000000000JFIFC     C   " P(@rAT@QDPQ :e Aqt#R *( z/,>Ksi:G8n> dTPE@pJOؚpt)i;_ޣJ .Ik_|vO8r.zg;r5[JrxfWw>o-UQ [ؐqt=ԷO yaR /xуx]5M/~O3\*Ǔ}T߹|V~gzaox]R;5m+'y$_qy9#7P RFj9gRp J}=} /Q>&l_&_ϱ<O6O0&C|͖ۨW4aX|>o>;q˄wj"'0c^Ѩ:;YQz'O^/^LMz>y o*ns>y_9jIξOfa]"M~Ƕg;{&ȸMzƃW!(ahHTߤPQPAADQ@U4+AfsDD1A5s:9+0{D} %Wp0[Nr^w>g~_F}wnj[UAk|on3=vxvk߼|<8%DIr#tWrŘ (((x')b#c5[Ӽ\y\Uc<&n_+> -fa>1F *4\TZw5?Vǩ|nA߰@QAE#W!XH!QZj>֭Б隸eg.|oRZŷV+n9./G<<^?c9*#?=Weݟ.폗k]<=+iPt˰)qMqiz}'+Osb:ܝFS<7P8;C E$ckn>X~e$gNVJ̮ZXVVqyk}Ͻoz_~ I~f~:K+2KQ<P 5zM9'c)}-Vr7oNWO?G#GyЯjZ $dl{ESd?BXssib'ik@ pVoU +!jz3Lֵ'z|1@Q@ĿH*^C*K?/g./P;|wv( $BB[ u+<$l{ګ=[8yÕr}:9I^˹.Xᤍ0D1o= QoP ONpye{aq_929b8Z&ןcy/"_'?+_kr>;y HHt+]U,} ޅSjvKqfEV׌l{qM)9]XFm((kzlw*YA^X!:f\>qZeÙnO[y_S6}GT4z~o;9F84cJJzOƀ.ɞׯ:L'?Gz6-gqUF +u>wq"f(2%IbzgE? f\NiiMy!lj+ῧ*';osTYɩёYQ4aEא *+մ41jR..c?D7"}:^1S+VDS%E.`D="b ~$~82uDMwQ _L^1χ?A d[pu O|=7.QWgYjd-M%/\jʾ=s d  !y' lXN]Y5% N9^HxS+.OWZjf)2EuE䫕k U#ڹTHWÝ=sg-YHrm~5fW 2fĉ7m"ڹ _PNեT_HWz=u]6o^nv+5LKֳ$Y;TȞMvoú2ڝ]mqFe .>b%^ FXhfidM ^E8}Xr~ؙɠᡶ#T݊Zmt\s>i $H!'Tj;}F>9 ֘0`PUs%$/b dRNݥУ&hH!#U KCM-i vS)̚$iu  0`Eb#ֳ)j7QwFpAE_C_Kr`]e+qPa]Hy5 w?'a@ J#0`jK6KK-N圪z"2߈V$d^''bvY]l'erW95J 9?ezP ehsPn $-IL0`i 3*}CIG:KdG% *#墼WD߶rXryz *'kM44Q}94,7 F4<%c|P8 #1: ԅSpM}c.L0`heH.64\܍2IA a?C@?նJq'U!b bDԵ< PxjɍÈ CrLm#yC~&tm"ɵ5߂^ 0`i ilst43(4I)@ldF70G=Yg?rn>ԜRoT+Թ %`ұxy R]!P)$!p8>G֥G11~wK~0T[aT#X<$9n23Hᑸ@dJVd[~+_rBbͲkx}Nz$g qk!a$lѨc ^q)~"  >bs7H'3U4k.pBn-#kqR jCEC^^QdN\c0ˆ70C?rq|5`ĭ%`}L u!3'Ӗ3Do~b{A#  DAD 0}4̭[GoJeІGhl ܉g5!C~׽"_01r?Q.#Fȅu> XfW~,;4*Lu)㓲e>@>DhBӱ b 8 sP(E;p@ D(JN8J7&dH,dNB"B?//D{]_ji0KXn:xI(lFZ[aUrH99(4M?_Ht'Ҫa7@8BE.3a1jԠmw3dbFEx:  DAA@OSv{&X{`z46HLj5D_H^;fR$[h{unbk< kvJ[cY+F"ٿ뛆E\Z!RfjW[:+J%>L@"@ ERq <:T>MH8 fkCjXm@b.(^R$_~if =6&0P1<9W|$A8 m!j O:IC~'tt D" pB7# qJQ6IVChYs?h|OHH:7<0a$vN1HP̥ɬ& BT |-a5 `z@"@  L{<33RS+p5 (Ѵm^ Ye=+yXB,U8D14}S K1xiJȫ_ɳ:w="  1ܺ֍\]OѴmFсs10*0lP?*8G>ޓԲ<CkEo2H.siNI)(! -H@$H,,((0}mbd፪Lp8 @Lt"IIYN3zBMrDo^Y^m QCX\`I6#Scikc%K!3$qi2 @A$AFaF >89@2:7Y#222222&/219^ >oXmP?0d"UH´dfcl)qJ@?b< @BBH$H)AF`ϤFfBWjon> x }Ⱦ}_i@D[E'ډILd)[Rٚ#FRȒ1n!n1)ER܍՟GP?3Mq#{cM> gAn\21wnFn,09ilIim)A ݍկGEA^f:4ۤ8ؓ5Cx7 y$ @BBBBz tᚈl*!^xo,Ϙnm0BbiE~z h#\VtU܀̥?( I&@ʖ01 @ +K2f(0HJz22227 p "GP?#h6h6h\$$$$$#Ȫ/Ϸ#########p2 AF%"z8}>@ h6h6h6 y A!!!!!>EX3aBP#bϽ$ D4&eLfF3ZMŢ1.ʅ7 Pn7MO&NN^Q* TuҔ&rGBiܵNQbWoibz_d&ڝJ&,[(fzy2lmjTHHHHHG_FFFFFFFFFFz2 „FI,_>BڙNDOQP)mD|ʑzzleZ|S~z0v,K\fXK; %xzrۺ[v+sPsڜةsS/zVȐ 9[FܙHHHHOje}1bS`0H2222 "WϬ@"@ IIf(n6o*Ę/D= ܛ)r]qm~A$HIp8 Xä7CYlL0dRwKRQ(ֽjA׹FnĤq޲g2l6= @I23. D 6h6H4H2AD 2@ Fa&H @III$H$h6  @ `0 16!01A2@ "3PQaBpq$R?lߓ!'(M4=1s4rߩ&&s"aW=- ?uτh|' l> S_Uo#fV&p:ϼ,4)<^|I*C?Bݺ2;sƭ naS \F튮p4?{-eqyf8ò}s.S O/[Tnu1ݸN!eemtܰݵIrz7_V7kOji)@`" 7ibdk BrWUOiqf&Ld͗u*.Y󍠄g}>?@ 51 9'OJov0p)vA("`\.-[QO;R$QRlv:v$}SQ ݃nC~S ,R?ij$o<6@ -c]]-&BZ_%7 Q݂l9Ag5C"sXԪ*sK If.^JYz㯰ut9oFF~sL!b_vXKw ?t*ˆP=,CVc,ǞxP/tâ7`? :X8=]f6Y7ff b24YxiXk,֬֡#I bڃ6B6-Ph, >UZ llbmM1{Y'ebwB#t" t7+(u~Qe~SXZK !1AQq "2@a#03BRbr$P`sC%t4Sc5p?+ƪ!ii ($c p { '3>$xQ&gPڣXe&_;Ģb*J!*^;qZ8:8FJ1a~-pMk$ b6z|qn_٢l"=[5s({VbGcP20 lp1`86({W|׎IڤHE3surwHAekwYwuF!4Kk7P\ SbSZbc웬lE-$fI?* mCiCgyqOW^ٝ?~y7d݊ROIpcܥ-+;[wxR>,A_")-x՘BM JZ]MS`T.3}q*WsV _j=O g I(n2Gp[mFZwV5ͨHMh)xVXJej) 5QKgx\`ɮ uЃFCEPbJ='@R Z]vA"7/KWSbn(ֿ1ax_M6bP%{3B#loN 6s7(fuŦf/R+FbZkGcc|OGM7븊^աJ[=׮%„7ruGus+,ӱ/"#Uqfҏk;}VlzGWJإkspDNAZsl*]pTD5&]T1A+[ ƃlSe$o(x৔J9Һ2LNUB[$J1qT 9语"N$C@'@VZ"WݟQ7>.U:EJc%}WjكG?hw44j#8zn`̠Ƌ@ BWQtܭ$S0INt g4{ydX8|Yyvc\_pxel 6F6HjہP63]*>iB0B8]zޑ̧lhv7]+_ ֞l ) \>hxNE o(XM Qvy1D#cI!YL,)$M'3>qӑ<cFvUcbK;J'1d5sgD}[m缫Y٢m4ڻӂkȢ$6 ;ޢXҊ[Y.$V8(c+]f5*Y]Fm.k6;lrIbV=E);b m_Gf(ƍ jVGb3`Naʺ]ho @x&\~ӒgZr&g9U@kbVv~hLyK1o`;/FO V,pD>Pj#C]68d|ʻj-o̮g8%]n.U骣:#7&;di Mci+T&bȪ:,Lυs5p'+j,l!ʕV"k ?se;,J 4~@ RW+8wr v,fN@T5E9@B?Eu>A]nwh!wU;՛Y#tڎ+=-_U.a .Xk[c!A-^r%{kޱ?6Wʠh7)V~ڟ[*(N+/q{̓uI(rNA`Y"tؕ%bWIt8 ;i!cu7Od`fScnc}Kz ϨOnz W4~#)Ggb6N5q\Wwr 䎯޾($8R _RANKT@O s;?tBxSkyцW9Xի XcABwWωޥ!`A]l1 #8#`s8,ǬD=촕w9Q>Kr*t SnWq4L|åsBkCNEQ\lN!s]*hs-W!s>U Kw$+綞}l:4\z}߹;{IRQ5EvX/kFDiT^CUlDj !>i2<ԉ.ss)P.\v87*gpN$Ӱio q-j °̴GsqشkV"ek_[X8,]x{خ| 8+M5O\= ~Mj wkϑ^BCəwhGf GwV(lߕɗ[dWyRڟT4c74̽[`}Viy \nR@5ADvO#s {XUlakEͰM`~Or =Ǩ4{!= uZzʧy1 '@'8%;~65,#`>k/ߚƽXNpsn3HO衳ڝlopUuīL|AC&Ql& zіՏ˗:\$yN^5:`eO-?}>Eۥi)9. ʋ m9o|>.A yirw8|h4kA-vU9o$ΡrcNEӠYr>~>}F],XaK'v6֓`ĕYP軔xU^pv ȡqgE' ^N"wH#wnۋrhSl~gllދc}MtՑYe^N梳.ah4̦Tԡ%4 =wWIfŒ.[4Q]wj.C*>cބu0GY ]mbCm뒻]h MOVH;tr + &5ϪSދoJ(3;"-2\Uޙjqiλx6*[C BP ,^eh@7\j6L| 3V;,Ki"^+%eײ^pHK\i[2guڢ(]KԝǪ7T]s] aEe ڟVfD^ˆ7Ҙ$J~9y7SF#j7je42FSbt,1Vsty/aLT"l7pQ6kQBB#7x%"Q5вWCv'DzMiwj39@k5, b7􉪞Ӫk"Cw(L Ǧ,< 77zYl`n0H>bsVF맆4SG}TY&ſ/O-ص2cޛeȢ-{K\6#r9sM,+%2d~pʊ3⥜ 3ª~%X-(#G5-,jUceE5"/k5eq"S{0ˠ!l@nR^migy&m/kM IaܭRj#]c/wjXIs mG5r}b4v3dkMmSf\Xܼ+ "k\#tN*L݆\ddgUhH2 %]%d*Cر{s49 ]qN 69sF\M{P+G?418d^7^oo\Zwzob]Ī %9ANvx恾({\s^Mghq?+!1AQaq 0@P`?!_ZX]PFt\r-,ݼ%`*f$4f[xG Vl14|w#35„53-e@BF6%|g|Q1&Cpfϳ;lr6Nl10h/^u%vtDin1gBR ]!)|k(>GWiB+Uh{ Ff]j#}=^3͓oDSU GzwVŬlS]X?G[Iڼݦqp]1~kMZnާf8t¦\` W"-ҧܢm o7 "ѱkC\pʥ!11ݪә,%yCh4?ݣ o0Ǝ+N.sw ;L$5͌xg0vy79 .PNsYcNc{NaGPl L$a,CQSEDeD鬹~W~_ÑЌ6JY8(]C;|ׁƸZJ!+o'u_kmt2H`6r b$X[0 TիLnZ3PU@sT \OG1z k]RҲ/G>O6Um~׏Tlf6Et"]aekU   sܥ zCϾQ?+T\GH ց?ى>\nvTۇ\˿{`71'X_)VS8_JI]F&`*ig#uOcң,#lF"t09%ZNrZ i&8^[{ ȵ0 2=aHPT7Ku"ݒU5VK=Hј@] PŤ\pNRun !MJm65G0`F{&?BŠ"4@ r\%._w ҪN.8![Z`XCWnVq ֲ0IvW`u:)6< \on9'_rhnTVadv+2Yذ-e{R+Gyث?=9hSI"ԊȨ"F}~}fu-PەO4mbWɼ*9IAڍeAXkWUr @#\KJk=k~ s>Ăө_F]?~ -CeBΥd -r?%JYB" 2m'EϬ~Q)r>|%pAiM(tztcgR$HeV^J],0[sDӬ$tvscĴ|_[tBV7s"+42<7s2{  <*dOD/,6 rl7>j[8jגhW]a؇7 ~ܾ\#*Q݈{M5>d%hYJBl]`f,Yx4cˇQ ׿X ~Q"6lzx=.}▪ݒwESOld9u3^N7e((2j2x:"҃4ūTkh0 ezR(@ W,ueJ-]+v' q0LBa{YvcEA1CȺ@XN#cZůE|LVw֮?\puLiQ`'=^lEym1)NА4kmҪfLsv7&m0gkH3t2Z};?k/0̄H:@ԏčhy@QkW'tWR<3M{?L$c΍E1ʳ|L c\+yccsk ny?+^IEg`Hq/2ĥ[o)S̓{n>s5%AsDy) 0qUZ>c>D,! ~5h wy*m|MxASGjbzBT2q_<7u/j rr|8ǎ|BPNHR .ksdr!Y~zc߆MpCHy`i %kCX(M"6fL~~xc}cE.tJ?.hs5k;2D>:p/W=@ hf}u2mr 憭{4WcʓcrCե(F/?Tp9vXYZ\K55¥xcכ~>z2[xWme Z-~9ARy3K湱j 10)wmE]qbS1q#>y|.Ȏ.CxIbJ&'?H5dR 6wOY7YuI?S=6̓Sٖ1I;kO}ȤMz#C)44"kqv?Jpx/;JzbߜYXM2gFyg%b :3L$.V=5Z0,A% faņ/Znδ/.% 1W~P5߁7 |,@ Dgɫ>RJμ弡qhJ)]br~:ܡyATyJzir%rf?<<ÆI~[уQG&ӝ@gd "&oTOH5mtϴ}J @#DžkgNF7h:uD+L "i-trS |;, }UF-N,% yLsX uEyż,qs+cǃVRLC `,*aA͖sv K!ΒguD~fe I_̋=x;!j)w Jj!4,vјJ0A*!p<:[̝Q֨QMY`Q E5F]XRq!> A7^8\ɯo uM#+S350K`}\^x)O f_ @ xQc)UL'd_ }*wW MJl0LgYNՆ3=(x%LVt3eù~Ox#= :.}j?,5+1G۴p[`p+G)>pG!xLJS5hiVEu;@.uH0@9oⲂA [5fcG%q'NFߪȔm߹H5rb<~R@a<:?\}>Qa@{c1K!YU5e|#]CGhzYWt8 J JYnzNħ>S)d4s;(h~;h hu~d <:/ s _vU|9ߋ39W)CuBeuʠ@<@#1:>՚IfZs lE5j%!(sv/&E=ZF<4 K5#\.PP2)}ȃsH6䛿Zz}yxN?О 1rPHUޮf.!K+[˙2ue=n}kXhʈz<*tj YWh:n fT] H8EM5#xH2&yBELr^z1@r::zYj/bo3 \jlrJku`@NCH9YL'5.\qL&)hq:NШA8PfL䕸s15G9~G)>}MU?Ϗ  #yy¸G"84գЉ4JQqud)T>%M%P>՛5y{П}}&v}QD0 qE3?k)KlOcQk\L{Rŋ.\w5M <ϳ&iS-x_ܝ=b|mOsfr2h~*TIL7;yAOvP&2%q0 H/h^\k;J\d!BRu-Y/>x<蚱d/"8UL ėS)4;%ԁ'} yw/! a>^  !{~ XS3^Yx#|l9%볩RJ*,ޒ+4K; 6F2W{wCnRyCJ@AaaVŏzٔtw7=.eK*TR,B# y:5&SVayChU:*TBa!,XX: S"0b/65c;4c_f38S5 J*T^8ǖ9OHי5!by*T\!0 c,b6m6+Kc{y,*XL|/w4RJE^:KYqRJ`,XxuuHV[){*eq"KB_3Yn4_fbZ! = TAǑP򊧺WU83M))+="TR@A0bǍoNE4Hm{43| ,O{&;hypHqH&G $OavT{SyP YDI{gJCuMIt.-S}o{7E3,QT!A$IeJ*egFY|5pv B<H 0,*T>q;2 ?Dqf,O/8 lj`iZ4?+eW,*R2 e4: /\&-HHX,^X=ǻ_(ۊURVc+,<ݣ {NpaBU ht-}b;U}br*"aa6F[=#WXwX ]%ȜcFÜ{ܹhROhr}AZ9<&8~9~!G,a[ AB.d9Io_y40mȀr8QϪaX+-$,A,Uˡ+%uXckK")G`!c+o(r Xk6g8T& <0Vͽصh4 ٨"7*-MCq:~DJ*EHΆ-t09g*+(?V](jM E%]0,y_G7!>_’AI XmN;"NQ&xua#aLLjn&f:HB6MbD8/Up39sBy7 êUa Syc @<5nn]z7KUnufXS45yzB_QY +߼eYD\h-`mM p+X-/lD"Ռ[{#.)tEg-w77buJSJyGT*}Ew6'A L9{6βЃhٙǧ^̩@*6rV_ (]S;ah'Jo|E!xjZ*2~zGiPen-αLolR" E).F긯\yꯒ* Zkc=m\JeC[Ѣ Ct;hsZPmOsUUdE2Hp(pAԡ^~j#!8a`*q?LBb?  {{k$ᄁ< oϼ3Oo{Lyooq> z,2믾(>Yon8IZ8҂WPᆱ->8ӏz曆ﺺ!  boqH>G]~,n8/;᠞Jk850 M>џ@hbl?>~8n{HY(xeSlGZ8 x//+ȭ_A kŔgT8g싿yF3(i_YBݵoﶺ<~x&* AkyBG#`*,nm3c4p6Nƥ46+[!\oWN]9ݫe")(P6%rjywnj (tD"סZ"Hb>~i†c8!. @痱亗/S?&xq8*{x M5-4%+螣3vH 6b۫AXH;)k* 4TP #{gaYnXj.l)Ӊ " h{0G*9/U[<_rz- KAO*k5oI-/{b{k' 1EȆ)㢢[gՂ[[>9c*b.(/*!10AQa @qPp?1# f~ ט9} -o_̝>7[m+Pr~u|IGZeV8hލY=b hk+31;쩳aG״2h^ f8뉘><)N>'Rkf ;y%Vˊ :Sxm16V//ٔn_oK7⭄vb5qDT9NھDeDl_G[^UQ0|_*߅c0&[,WKGQ6 :Ap |ܨ*?,Mz#qxO8q3Wn g 7%0\-zǦ`(Rj[Ct~x.9#ݕ c(c\DZTFa)a SK7x?,`BT]G{ond A cT5@*DUsӓDj*_(7qFep[P'W)-Q(j܅fO Fʉ\V\åhNK^C&JMƠ-I[OMK}r˗.\rr*T11+Z%J*TIRJ*T_*!1A0Qa q@P?ᅉJش\ ʈK u 'Dʵv~&KHWł2M9p @ 1G j"YIL°~{v`:~ Ak_Ή Se:3drƨ0J%HTh9~?sNbQVe0tX!B-e :62`}ai* 67[X-9Sw) {#^f_GL%/ eX`/i]!bUNg Iv\Z@6Zblo2L@D Z7t୘bHwADXV@*b6e0@ xĮfϷ7hGpiՌk'k-ՈH WId,[jr|b[7~ aq/{*'4X1`."m4;ndDjD\Ϝ(5 ˗._p=tRkE`e~_ НbރGBxKbbh (n 1tl,~HifuSFWzژie˹=*eVadԆ6F]!":5^Cꔴ@؃`xӲol;NfM2Lr%'Q:i"\RH2 rXF[j?FKq%Wr_ R _;һlxTSFQzkӉ3QJri+1jp*:1A<ਣEǸV'/qq_Ȝ` x\uU+j Y[ 9~:ifKm )+apnm]?=7p̻mMȵ\)XPbS[x|88Ғ1()bDL Q8'f}j̏#uNL Ym6XwExwO^Q%aڐ@\` F;SAjz69p҉vDU~4. U#( 0x[ouaQA|..@<"%NyI30U78/(%+ZY۶' Ba_.B2#V˱ %rxFfP9^N` \Ro _p.$/P)o=D F0YPZH"L5߬OTEE{sɵ%]rV",(٧6ٓHrin)mB[ 'Q 7W?.z\K7V"WUno_HEJzWNq-h+RrPO,GMX= .UkV?o PͮS+ WK:#)Dcˁ]`HL3Cx; crZޓfT$ ha߈OMwbBC\yC!bZ[2B0gg8ѝ0YA'd?:w ;eѵ༼=LTMKA*&Tl|ywvW~=(]).Tw̗OPR{UýVHr+Fu6(u-Ӄkm:W0Уye49xm*1{s7CvZ[@yYH29X+XDڻ]F?%q H³WqDk')~PĪmz/xCNrE {g9Զ峺r< U+IURby Y7A0T.AcP^X&BV.&Ә ŧ,B.Q'rl9MWs\+s靜jJ Wfn-N1@dy+Tz80yB˪dID ]dE.% ߬JTsIX J -[$e'x$bx/Mö&Jٲ]#$RUB뤤[Ӄ ^kMit҄L!,Mw&JicX @ڈhGRaT; k ##"%@trr\6&z7ei >bb/Ơ~UPR"$ޗԴlmlIj*@*ijIOS Slڜ<0#b]AĆLˌ" !13-&/b@(R"2dȬ/PV4bV˴i&R`r`dM Ov]W3%P#92k34ac{&AyU- 3>aYMAΠR;N/n°4ǜDZK$Q-x4CK]&A1lhڐ(U]ePCe3XI QWPSaz8PȀ% G {XJmUB|rû[_C͞[NN~ҌPm" |r t;lT¤wTi}2/?CN1e[mH ޻;1WG 4,?DvU7{wUKEy^F/e L' "eUXop .M)QtKbQ%=]wpU*w(Xeux؁1x0bFX"E=m È~blҒN̩rz%F[h4֎XWQ6vӛ6B|,:œPN"D^`ø~\( @_y Dh<ΰ3J9Jը| p*kt .)ySN B6.qWlBޝqv>pPJ5QX L0G@]CLG00)d+S/f.G Պz&9B݊PŭTo&m(_x3cFSnب`+ۦ>Ѻ~z1OYA]TC@0 J1LvoDxmp .Aq-Ÿ|hgfV \7Esv]ݹUվTM:#z+r65zwׯ{WB8ap,fXN8C'_w7XK2!gqfloԨ^%-MWb=e_F C@<3o }1M [ĢyYe/ Pj. .;{w_ua}3~lZОry"\yc:<Aq(c:G"œBt^F/fDۗTP)()`Migr/Bؕ.Ƭgm3ATܼx|}"r\㵽ÉKڡhZ!Uyr+,uXRis`QY]bꤹXĭ58F -y}7.N Rֹe]Ee ᆼ % \ A^X6G׈ukܿӝ`)E+OcKqAx DהRQp](K_3۪%dZ^![n>Å96}0"?@.ýA(P ǤC#Q:?!|zFmk!qrI};LtyK(5l+uQT׼Y5+:-:a߈) h=;BP.KGP 3>RAUeZ|+ZAlJ@ :#<@ lv,~+sNyiJ-* '1NiVe _:ԣeغ6=]2;scqeе{@L50=w,E1Zf"ƋJ_h4Hkx@n+g3GA਩mn5#,PQ3pp蜒(1DQѓ{T(< HdÿC+98Ɔ(sS 2 x'q>7!Gy>#-aɋ!O)μq =,(?W t}ԨߣF9;CoA؛VV- @7@E|  v*oG1M%*P_)53k@UB;^w &X Dӟy+߻MQV^hh fhQ+)CoO6;r +#m꤇*Bi-kv*9Mq8"ދ|A6[})oflm;IUV`S7*1zkڍCTbrʨIAk9Juޓ|\RsJ_ B*%=?3Ho&ٿ &f?r &} /f"3t,װI 7R)!pEDdT*4oy#WվxI*%~ px&^-_2>LF)V4"{ETC˦R=FSX?\ȕ ?HP*[՝uh ol.0 :z41v-˻'5Y&npq /%Y^j3fc_\k[Dea{\^wg*TA^),vJ ^$ E+AGuIҭ׬|x.l'GUz|?6yҬ.+'+`dwNC_0Rx-.%y5-fY}f(0UK~%)rࢇ[.-Pw@(X1j7|u,7Gc6/ᄥJ꒯DK^FoUWx !?\u310E͎t`'rI~}F߸>\{̊|2D٬kS ߕKW2#kAy ~S HӒUKߒĺ`fʘ^洽kSUpA.6Gv_U/ kϕX&7,\ TrNh?Sˉm{h *|'D.c>C6C WOwcHepz:2CgAVN亼r=swH FX3 w|P>ٸ;s|8Id^!Rf > a.@~JfбF v ƹ$x_ݟk|2Dz-|ÐҏaZ &ZLj.^l׉Yx(pf({q7G>jO zt O1w'{QB}C\Y8@raP``Nr@_ -iĦŗ{|'wEbM+JݟSOEhmS EwS6[lk4 ̫G펆^)mݧ焣x#C8AYʓ얻4o#+إDǤ5S +@>l`N a@ga(lSsygU燚zKW5H'1EbqMkB\R(OqKs~8zf}MW tEVT=(HVu*'̬&F%N3ݎP F2Mi+Ἰ<ӼF W ઄7 GFjm(wVv ;*(u6O5D g>mXLBV }[rnjt)Kjhr9/V{hUF%w5~t[r bP wd\̢4oo^ cŢZ$7F[ǜ.d|Ɲ TTL1!(J;dc-W)&^LHe Q-ZҖQ OZ@N\/!P˃(F%[yPyt[W|)\3 A{}"}Pf pq}s,5pwfm/ Ew2bO=)+"j<\2T:,=c K/ .=10G^ rgk*E~7ec!r\;%@Ԍ)Nw6DpZkfZ:W"k6Ev*L|R8_ҁqGlvg-K[WApYS\5Mm[r|S KiROa !qp5CXr*6:@ǺyǾ6'WKVbU`|p K2/͖nppp Ρ*u>iQ[ 1 Hv=Y݊sYLJn3C<# :38WEL}}-k/B\؜ΟN|/KJ'^ulĉߔu; _߷]913neٙ cYGl @.4N̹C-M5P sݿ]zr[l  Rj#@a39',0뇓Qc ۅ~J nA&nTDVg>L_9D:ʜNYrL+2Д>X2B~A_۝؇d=pddav/F (a 䜼nYan-\qwgrwc{u9m/cce"bx&?0;3ĭ;l{x=ٝڕr,rEZ&0n,Gs⬲Fpfٝ=:1).!vKwhyc u#2Cͫ VE+l:2DD Ǥ Uc8l^@CzDnt/`EsԳ}~![3@4=t9`=۳%TȭsU(ťJcCExp%P8‰&Kj/3ʒ_~<23us4Jjifr-Av(`' &#=gGCHCܜ}`g.Lq SʌxV~]Kk:щg)ڎcNz|6^ϫ% dEە`pDA-nvjn N\ c TkZDӼs>"J>%MMs\ŭ~(v ?D# ?2 T?l4ɇ03K+|<DBZՙ h8m)d:ǾMBMZElHDd)B])2sНՁ UL_{,/ Q@ΘȾ Ff=ӭԛ)s%@['9Yr$]0N-X-jQt+Aj-:̠TjpJa4Z$s*yA'RwcD@M` )h}2J5ǻUX C!3 JE=t DZyb%s_T4qs;ЛJY~sJq=7*RHܱC\4NTLMDFgeGRR @%u4'ùTPT/.,`XF* tzbF?oHpt{BlylOv%[lݕl_7sm/3u-ۢ).[:\@(sG?Vv&ΑaźvaZ5Dՙ;ᨿ+rJ 0AW7!N8=ڔ,= $"g<Ş5wg?. !0A|++sG;2ŮjvNw~'&4`M\straitsui-4.1.0/examples/demo/examples.cfg0000644000175100001440000000030111674463545021413 0ustar ischnellusers00000000000000[global] destdir = TraitsUI [Traits UI Uber-demo] files = demo.py, traits_ui_demo.jpg, Advanced/*, Applications/*, Dynamic Forms/*, Extras/*, Standard Editors/*, Tools/*, Useful/*, images/* traitsui-4.1.0/examples/demo/__init__.py0000644000175100001440000000000111674463545021222 0ustar ischnellusers00000000000000 traitsui-4.1.0/examples/demo/Advanced/0000755000175100001440000000000011674463545020627 5ustar ischnellusers00000000000000traitsui-4.1.0/examples/demo/Advanced/Multi_select_string_list.py0000644000175100001440000000524211674463545026256 0ustar ischnellusers00000000000000""" Creating a multi-select list box How to use a TabularEditor to create a multi-select list box. This demo uses two TabularEditors, side-by-side. Selections from the left table are shown in the right table. Each table has only one column. """ from traits.api import HasPrivateTraits, List, Str, Property from traitsui.api import View, HGroup, UItem, TabularEditor from traitsui.tabular_adapter import TabularAdapter class MultiSelectAdapter(TabularAdapter): """ This adapter is used by both the left and right tables """ # Titles and column names for each column of a table. # In this example, each table has only one column. columns = [ ('', 'myvalue') ] # Magically named trait which gives the display text of the column named # 'myvalue'. This is done using a Traits Property and its getter: myvalue_text = Property # The getter for Property 'myvalue_text' simply takes the value of the # corresponding item in the list being displayed in this table. # A more complicated example could format the item before displaying it. def _get_myvalue_text(self): return self.item class MultiSelect(HasPrivateTraits): """ This is the class used to view two tables """ # FIXME (TraitsUI defect #14): When multi-select is done by keyboard # (shift+arrow), the 'selected' trait list does not update. # FIXME (TraitsUI defect #15): In Windows wx, when show_titles is False, # left table does not draw until selection passes through all rows. # (Workaround here: set show_titles True and make column titles empty.) choices = List(Str) selected = List(Str) view = View( HGroup( UItem('choices', editor = TabularEditor( show_titles = True, selected = 'selected', editable = False, multi_select = True, adapter = MultiSelectAdapter()) ), UItem('selected', editor = TabularEditor( show_titles = True, editable = False, adapter = MultiSelectAdapter()) ) ), resizable=True, width=200, height=300 ) # Create the demo: demo = MultiSelect(choices = [ 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten' ]) # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Advanced/Apply_Revert_handler_demo.py0000644000175100001440000000434611674463545026325 0ustar ischnellusers00000000000000""" Apply / Revert Provides support in a dialog box for an "Apply" button which modifies the object being viewed, and a "Revert" button, which returns the object to its starting state (before any "Apply"). Note that this does not automatically provide a full (multi-step incremental) Undo capability. """ from traits.api import HasTraits, Str, List from traitsui.api import Item, View, Handler, HGroup, VGroup # 'ApplyRevert_Handler' class: class ApplyRevert_Handler(Handler): def apply(self, info): object = info.object object.stack.insert(0, object.input) object.queue.append(object.input) def revert(self, info): # Do something exciting here... print 'revert called...' # 'ApplyRevertDemo' class: class ApplyRevertDemo(HasTraits): # Trait definitions: input = Str stack = List queue = List # Traits view definitions: traits_view = View( VGroup( VGroup( Item('input', show_label = False ), label = 'Input', show_border = True ), HGroup( VGroup( Item('stack', show_label = False, height = 50, width = 100, style = 'readonly' ), label = 'Stack', show_border = True ), VGroup( Item('queue', show_label = False, height = 50, width = 100, style = 'readonly' ), label = 'Queue', show_border = True ) ) ), resizable = True, height = 300, title = 'Apply/Revert example', buttons = [ 'Apply', 'Revert' ], kind = 'modal', handler = ApplyRevert_Handler ) # Create the demo: modal_popup = ApplyRevertDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': modal_popup.configure_traits() traitsui-4.1.0/examples/demo/Advanced/Popup_Dialog_demo.py0000644000175100001440000000572511674463545024600 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. """ Demonstrates using a popup view within another view. Try changing the gender of the person from 'Male' to 'Female' using the drop-down list. When the person's gender is changed, a pop-up dialog is displayed immediately below the gender field providing you with the opportunity to cancel the gender change. If you click the Cancel button, the person's gender will return to its previous value. If you click anywhere else outside of the pop-up dialog, the pop-up dialog will simply disappear, leaving the person's new gender value as is. The main items of interest in this demo are: - The: kind = 'popup' trait set in the PersonHandler View which marks the view as being a popup view. - The parent = info.gender.control value passed to the edit_traits method when the popup dialog is created in the object_gender_changed method. This value specifies the control that the popup dialog should be positioned near. Notes: - Traits UI will automatically position the popup dialog near the specified control in such a way that the pop-up dialog will not overlay the control and will be entirely on the screen (as long as these two conditions do not conflict). """ #-- Imports -------------------------------------------------------------------- from traits.api \ import HasPrivateTraits, Str, Int, Enum, Instance, Button from traitsui.api \ import View, HGroup, Item, Handler, UIInfo, spring #-- The PersonHandler class ---------------------------------------------------- class PersonHandler ( Handler ): # The UIInfo object associated with the view: info = Instance( UIInfo ) # The cancel button used to revert an unintentional gender change: cancel = Button( 'Cancel' ) # The pop-up customization view: view = View( HGroup( spring, Item( 'cancel', show_label = False ), ), kind = 'popup' ) # Event handlers: def object_gender_changed ( self, info ): if info.initialized: self.info = info self._ui = self.edit_traits( parent = info.gender.control ) def _cancel_changed ( self ): object = self.info.object object.gender = [ 'Male', 'Female' ][ object.gender == 'Male' ] self._ui.dispose() #-- The Person class ----------------------------------------------------------- class Person ( HasPrivateTraits ): # The person's name, age and gender: name = Str age = Int gender = Enum( 'Male', 'Female' ) # The traits UI view: traits_view = View( Item( 'name' ), Item( 'age' ), Item( 'gender' ), title = 'Button Popup Demo', handler = PersonHandler ) #-- Create and run the demo ---------------------------------------------------- # Create the demo: demo = Person( name = 'Mike Thomas', age = 32 ) # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Advanced/Dynamic_range_trait_and_editor.py0000644000175100001440000001473311674463545027344 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. """ This program demonstrates defining and visualizing dynamic ranges. A dynamic range is a range whose low or high limit can be modified dynamically at run time. You can define a dynamic range using the standard Range trait and specifying the name of other traits as either the low or high limit value (or both). In fact, it is even possible to specify the default value of the range trait as another trait if desired. The traits used as low, high or default values need not be defined on the same object, but can be defined on any object reachable from the object (i.e. it allows use of extended trait names). In this completely artificial example, we present an example of the first hotel at the North Pole. The hotel guarantees that each room will be heated to a certain minimum temperature. However, that minimum value is determined both by the time of year and the current cost of heating fuel, so it can vary; but each room is guaranteed the same minimum temperature. Each guest of the hotel can choose among several different plans that allow them to control the maximum room temperature. Higher maximum room temperatures correspond to higher plan costs. Thus each guest must decide which plan (and highest maximum room temperature) to pay for. And finally, each guest is free to set the current room temperature anywhere between the hotel minimum value and the guest's maximum plan value. The demo is organized as a series of tabs corresponding to each guest of the hotel, with access to the plan they have chosen and the current room temperature setting. In addition, there is a master set of hotel information displayed at the top of the view which allows you to change the season of the year and the current fuel cost. There is also a button to allow more guests to be added to the hotel. Notes: - The dynamic range trait is the 'temperature' trait in the Guest class. It depends upon traits defined both in the Guest instance as well as in the containing Hotel object. - As with most traits code and examples, observe how much of the code is 'declarative' versus 'imperative'. Note also the use of properties and 'depends_on' metadata, as well as 'cached_property' and 'on_trait_change' method decorators. - Try dragging the guest tabs around so that you can see multiple guests simultaneously, and then watch the behavior of the guest's 'temperature' slider as you adjust the hotel 'season', 'fuel cost' and each guest's 'plan'. """ #-- Imports -------------------------------------------------------------------- import logging, sys logging.basicConfig(stream=sys.stderr) from random \ import choice from traits.api \ import HasPrivateTraits, Str, Enum, Range, List, Button, Instance, \ Property, cached_property, on_trait_change from traitsui.api \ import View, VGroup, HGroup, Item, ListEditor, spring #-- The Hotel class ------------------------------------------------------------ class Hotel ( HasPrivateTraits ): # The season of the year: season = Enum( 'Winter', 'Spring', 'Summer', 'Fall' ) # The current cost of heating fuel (in dollars/gallon): fuel_cost = Range( 2.00, 10.00, 4.00 ) # The current minimum temparature allowed by the hotel: min_temperature = Property( depends_on = 'season, fuel_cost' ) # The guests currently staying at the hotel: guests = List # ( Instance( 'Guest' ) ) # Add a new guest to the hotel: add_guest = Button( 'Add Guest' ) # The view of the hotel: view = View( VGroup( HGroup( Item( 'season' ), '20', Item( 'fuel_cost', width = 300 ), spring, Item( 'add_guest', show_label = False ), show_border = True, label = 'Hotel Information' ), VGroup( Item( 'guests', style = 'custom', editor = ListEditor( use_notebook = True, deletable = True, dock_style = 'tab', page_name = '.name' ) ), show_labels = False, show_border = True, label = 'Guests' ) ), title = 'The Belmont Hotel Dashboard', width = 0.6, height = 0.2, resizable = True ) # Property implementations: @cached_property def _get_min_temperature ( self ): return ({ 'Winter': 32, 'Spring': 40, 'Summer': 45, 'Fall': 40 }[ self.season ] + min( int( 60.00 / self.fuel_cost ), 15 )) # Event handlers: @on_trait_change( 'guests[]' ) def _guests_modified ( self, removed, added ): for guest in added: guest.hotel = self def _add_guest_changed ( self ): self.guests.append( Guest() ) #-- The Guest class ------------------------------------------------------------ class Guest ( HasPrivateTraits ): # The name of the guest: name = Str # The hotel the guest is staying at: hotel = Instance( Hotel ) # The room plan the guest has chosen: plan = Enum( 'Flop house', 'Cheap', 'Cozy', 'Deluxe' ) # The maximum temperature allowed by the guest's plan: max_temperature = Property( depends_on = 'plan' ) # The current room temperature as set by the guest: temperature = Range( 'hotel.min_temperature', 'max_temperature' ) # The view of the guest: view = View( Item( 'plan' ), Item( 'temperature' ) ) # Property implementations: @cached_property def _get_max_temperature ( self ): return { 'Flop house': 62, 'Cheap': 66, 'Cozy': 75, 'Deluxe': 85 }[ self.plan ] # Default values: def _name_default ( self ): return choice( [ 'Leah', 'Vibha', 'Janet', 'Jody', 'Dave', 'Evan', 'Ilan', 'Gael', 'Peter', 'Robert', 'Judah', 'Eric', 'Travis', 'Mike', 'Bryce', 'Chris' ] ) #-- Create the demo ------------------------------------------------------------ # Create the demo object: demo = Hotel( guests = [ Guest() for i in range( 5 ) ] ) # Run the demo (if invoked from the command line): if __name__ == '__main__': logging.info('Start!') demo.configure_traits() traitsui-4.1.0/examples/demo/Advanced/Settable_cached_property.py0000644000175100001440000001025311674463545026200 0ustar ischnellusers00000000000000""" Creating settable cached Property in Traits How to create a Traits Property which is cached but is not read-only. The example demonstrates how to create a 'settable cached' property. The example itself is nonsensical, and is provided mainly to show how to set up such a property, and how it differs from a standard 'cached' property. A normal 'cached' property does not have a 'setter' method, meaning that the property is read-only. It usually represents a value which depends upon the state of other traits for its value. The cached property provides both a mechanism for remembering (i.e. caching) the current value of the property as well as a means of automatically detecting when the value of the property changes (which causes the cache to be flushed), and notifying any associated trait listeners that the value of the property has changed. Normally there is no 'setter' for such a property because the value is derived from the value of other traits. However, it is possible to define a 'settable cached' property which in addition to the capabilities of a normal 'cached' property, also allows the property's value to be explicitly set. To accomplish this, simply set the 'settable' argument to the 'property_depends_on' decorator to True (see the '_get_c' method in the example code). When set this way, an appropriate 'setter' method is automatically generated for the associated property. This allows code to set the value of the property directly if desired, subject to any constraints specified in the property declaration. For example, in the example, the 'c' trait is a 'settable cached' property whose value must be an integer. Attempting to set a non-integer value of the property will raise an exception, just like any other trait would. If any of the traits which the property depends upon change value, the current value of the property will be flushed from the cache and a change notification for the property will be generated. Any code that then attempts to read the value of the property will result in the cache being reloaded with the new value returned by the property's 'getter' method. In the example, trait 'c' is a 'settable cached' property which returns the product of 'a' times 'b', and trait 'd' is a normal 'cached' property that returns double the value of 'c'. To see the effect of these traits in action, try moving the 'a' and 'b' sliders and watching the 'c' and 'd' traits update. This demonstrates how 'c' and 'd' are properties that depend upon the values of other traits. Now try changing the value of the 'c' trait by moving the slider or typing a new value into the text entry field. You will see that the 'd' trait updates as well, illustrating that the 'c' trait can be set directly, as well as indirectly by changes to 'a' and 'b'. Also, try typing non-numeric values into the 'c' field and you will see that any values set are being type checked as well (i.e. they must be integer values). Now try typing a value into the 'd' trait and you will see that an error results (indicated by the text entry field turning red), because this is a normal 'cached' trait that has no 'setter' method defined. """ from traits.api import HasTraits, Int, Range, Property, property_depends_on from traitsui.api import View, Item, RangeEditor #-- Demo Class ----------------------------------------------------------------- class SettableCachedProperty(HasTraits): a = Range(1, 10) b = Range(1, 10) c = Property(Int) d = Property view = View( Item('a'), Item('b'), '_', Item('c', editor = RangeEditor(low = 1, high = 100, mode = 'slider')), Item('c'), '_', Item('d', editor = RangeEditor(low = 1, high = 400, mode = 'slider')), Item('d'), width = 0.3 ) @property_depends_on('a,b', settable = True) def _get_c(self): return (self.a * self.b) @property_depends_on('c') def _get_d(self): return (self.c + self.c) #-- Run the demo --------------------------------------------------------------- # Create the demo: demo = SettableCachedProperty() # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Advanced/MVC_demo.py0000644000175100001440000000572311674463545022641 0ustar ischnellusers00000000000000""" Supporting Model/View/Controller (MVC) pattern Demonstrates one approach to writing Model/View/Controller (MVC)-based applications using Traits UI. This example contains a trivial model containing only one data object, the string 'myname'. In this example, the Controller contains the View. A more rigorous example would separate these. A few key points: - the Controller itself accesses the model as self.model - the Controller's View can access model traits directly ('myname') """ from traits.api import HasTraits, Str, Bool, TraitError from traitsui.api import View, VGroup, HGroup, Item, Controller class MyModel(HasTraits): """ Define a simple model containing a single string, 'myname' """ # Simple model data: myname = Str class MyViewController(Controller): """ Define a combined controller/view class that validates that MyModel.myname is consistent with the 'allow_empty_string' flag. """ # When False, the model.myname trait is not allowed to be empty: allow_empty_string = Bool # Last attempted value of model.myname to be set by user: last_name = Str # Define the view associated with this controller: view = View( VGroup( HGroup( Item('myname', springy = True), '10', Item('controller.allow_empty_string', label = 'Allow Empty') ), # Add an empty vertical group so the above items don't end up # centered vertically: VGroup() ), resizable = True ) #-- Handler Interface ------------------------------------------------------ def myname_setattr(self, info, object, traitname, value): """ Validate the request to change the named trait on object to the specified value. Validation errors raise TraitError, which by default causes the editor's entry field to be shown in red. (This is a specially named method _setattr, which is available inside a Controller.) """ self.last_name = value if (not self.allow_empty_string) and (value.strip() == ''): raise TraitError('Empty string not allowed.') return super(MyViewController, self).setattr(info, object, traitname, value) #-- Event handlers --------------------------------------------------------- def controller_allow_empty_string_changed(self, info): """ 'allow_empty_string' has changed, check the myname trait to ensure that it is consistent with the current setting. """ if (not self.allow_empty_string) and (self.model.myname == ''): self.model.myname = '?' else: self.model.myname = self.last_name # Create the model and (demo) view/controller: demo = MyViewController(MyModel()) # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Advanced/Invalid_state_handling.py0000644000175100001440000001224011674463545025632 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. """ Sometimes the inputs to a model are not correlated. That is, any valid model input produces a corresponding valid model state. However, in other cases, some or all of the model inputs are correlated. That is, there may exist one or more combinations of individually valid model inputs which produce invalid model states. In cases where this can happen, it is very often desirable to warn the user if a particular combination of input values will not produce a usable result. This problem cannot be solved solely though the use of carefully chosen trait types and editors, because each individual input may be valid, but it is the combination of inputs which is invalid. Solving this problem therefore typically requires providing a way of determining whether or not the model is in a valid state, and then communicating that information to the user via the user interface. This demonstration provides an example of doing this using the TraitEditor's 'invalid' trait. Each trait editor has an 'invalid' trait which can be set equal to the name of a trait in the user interface context which contains a boolean value reflecting whether or not the user interface (and underlying model) are in a invalid state or not. A True value for the trait indicates that the editor's current value produces an invalid model state. By associating the same 'invalid' trait with one or more editors in the user interface, the resulting user interface can indicate to the user which combination of input values is producing the invalid state. In this example, we have a very simple model which allows the user to control the mass and velocity of a system. The model also defines the kinetic energy of the resulting system. For safety reasons, the kinetic energy of the system should not exceed a certain threshold. If it does, the user should be warned so that they can reduce either or both of the system mass and velocity back down to a safe level. In the model, an 'error' property is defined which is True whenever the kinetic energy level of the system exceeds the safety threshold. This trait is then synchronized with the user interface's 'mass', velocity' and 'status' editors, turning them red whenever the model enters an invalid state. The 'status' trait is another property, based on the 'error' trait, which provides a human readable description of the current system state. Note that in this example, we synchronize the 'error' trait with the user interface using 'sync_to_view' metadata, whose value is a list of user interface editor traits the trait should be synchronized 'to' (i.e. changes to the 'error' trait will be copied to the corresponding trait in the editor, but not vice versa). We could also have explicitly set the 'invalid' trait of each corresponding editor in the view definition to 'error' as well. To use the demo, simply use the 'mass' and 'velocity' sliders and observe the changes to the 'kinetic_energy' of the system. When the kinetic energy exceeds 50,000, notice how the 'mass', 'velocity' and 'status' fields turn red, and that when the kinetic energy drops below 50,000, the fields return to their normal color. """ #-- Imports -------------------------------------------------------------------- from traits.api \ import HasTraits, Range, Float, Bool, Str, Property, property_depends_on from traitsui.api \ import View, VGroup, Item #-- System Class --------------------------------------------------------------- class System ( HasTraits ): # The mass of the system: mass = Range( 0.0, 100.0 ) # The velocity of the system: velocity = Range( 0.0, 100.0 ) # The kinetic energy of the system: kinetic_energy = Property( Float ) # The current error status of the system: error = Property( Bool, sync_to_view = 'mass.invalid, velocity.invalid, status.invalid' ) # The current status of the system: status = Property( Str ) view = View( VGroup( VGroup( Item( 'mass' ), Item( 'velocity' ), Item( 'kinetic_energy', style = 'readonly', format_str = '%.0f' ), label = 'System', show_border = True ), VGroup( Item( 'status', style = 'readonly', show_label = False ), label = 'Status', show_border = True ), ) ) @property_depends_on( 'mass, velocity' ) def _get_kinetic_energy ( self ): return (self.mass * self.velocity * self.velocity) / 2.0 @property_depends_on( 'kinetic_energy' ) def _get_error ( self ): return (self.kinetic_energy > 50000.0) @property_depends_on( 'error' ) def _get_status ( self ): if self.error: return 'The kinetic energy of the system is too high.' return '' #-- Create and run the demo ---------------------------------------------------- # Create the demo: demo = System() # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Advanced/HDF5_tree_demo.py0000644000175100001440000001124411674463545023714 0ustar ischnellusers00000000000000"""This demo shows how to use Traits TreeEditors with PyTables to walk the heirarchy of an HDF5 file. This only picks out arrays and groups, but could easily be extended to other structures, like tables. In the demo, the path to the selected item is printed whenever the selection changes. In order to run, a path to an existing HDF5 database must be given at the bottom of this file. """ from traits.api import HasTraits, Str, List, Instance from traitsui.api import TreeEditor, TreeNode, View, Item, Group import tables as tb # View for objects that aren't edited no_view = View() # HDF5 Nodes in the tree class Hdf5ArrayNode(HasTraits): name = Str( '' ) path = Str( '' ) parent_path = Str( '' ) class Hdf5GroupNode(HasTraits): name = Str( '' ) path = Str( '' ) parent_path = Str( '' ) # Can't have recursive traits? Really? #groups = List( Hdf5GroupNode ) groups = List arrays = List( Hdf5ArrayNode ) groups_and_arrays = List class Hdf5FileNode(HasTraits): name = Str( '' ) path = Str( '/' ) groups = List( Hdf5GroupNode ) arrays = List( Hdf5ArrayNode ) groups_and_arrays = List # Recurssively build tree, there is probably a better way of doing this. def _get_sub_arrays(group, h5file): """Return a list of all arrays immediately below a group in an HDF5 file.""" l = [] for array in h5file.iterNodes(group, classname='Array'): a = Hdf5ArrayNode( name = array._v_name, path = array._v_pathname, parent_path = array._v_parent._v_pathname, ) l.append(a) return l def _get_sub_groups(group, h5file): """Return a list of all groups and arrays immediately below a group in an HDF5 file.""" l = [] for subgroup in h5file.iterNodes(group, classname='Group'): g = Hdf5GroupNode( name = subgroup._v_name, path = subgroup._v_pathname, parent_path = subgroup._v_parent._v_pathname, ) subarrays = _get_sub_arrays(subgroup, h5file) if subarrays != []: g.arrays = subarrays subgroups = _get_sub_groups(subgroup, h5file) if subgroups != []: g.groups = subgroups g.groups_and_arrays = [] g.groups_and_arrays.extend(subgroups) g.groups_and_arrays.extend(subarrays) l.append(g) return l def _hdf5_tree(filename): """Return a list of all groups and arrays below the root group of an HDF5 file.""" h5file = tb.openFile(filename, 'r') file_tree = Hdf5FileNode( name = filename, groups = _get_sub_groups(h5file.root, h5file), arrays = _get_sub_arrays(h5file.root, h5file), ) file_tree.groups_and_arrays = [] file_tree.groups_and_arrays.extend(file_tree.groups) file_tree.groups_and_arrays.extend(file_tree.arrays) h5file.close() return file_tree # Get a tree editor def _hdf5_tree_editor(selected=''): """Return a TreeEditor specifically for HDF5 file trees.""" return TreeEditor( nodes = [ TreeNode( node_for = [ Hdf5FileNode ], auto_open = True, children = 'groups_and_arrays', label = 'name', view = no_view, ), TreeNode( node_for = [ Hdf5GroupNode ], auto_open = False, children = 'groups_and_arrays', label = 'name', view = no_view, ), TreeNode( node_for = [ Hdf5ArrayNode ], auto_open = False, children = '', label = 'name', view = no_view, ), ], editable = False, selected = selected, ) if __name__ == '__main__': from traits.api import Any class ATree(HasTraits): h5_tree = Instance(Hdf5FileNode) node = Any traits_view =View( Group( Item('h5_tree', editor = _hdf5_tree_editor(selected='node'), resizable =True ), orientation = 'vertical', ), title = 'HDF5 Tree Example', buttons = [ 'Undo', 'OK', 'Cancel' ], resizable = True, width = .3, height = .3 ) def _node_changed(self): print self.node.path a_tree = ATree( h5_tree = _hdf5_tree('/path/to/file.h5') ) a_tree.configure_traits() # a_tree.edit_traits() traitsui-4.1.0/examples/demo/Advanced/Adapted_tree_editor_demo.py0000644000175100001440000001001311674463545026127 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. """ Demonstrates an alternative method of defining a TreeEditor by creating ITreeNodeAdapter subclasses. To run this demonstration successfully, you must have the AppTools egg installed. Using ITreeNodeAdapters can be useful in cases where the kind of content of the tree is not always known ahead of time. For example, you might be creating a reusable tool or component which can display its data in a tree view, but you do not know what kind of data it will be asked to display when you write the code. Therefore, it may be impossible for you to specify a TreeEditor with a correct set of TreeNode objects that will work in all possible future cases. Using ITreeNodeAdapter subclasses, you can allow the clients of your code to solve this problem by providing one of more ITreeNodeAdapters that can be used to provide the correct tree node information for each type of data that will appear in the TreeEditor view. In this demo, we define an ITreeNodeAdapter subclass that adapts the apptools.io.file.File class to be displayed in a file explorer style tree view. """ #-- Imports -------------------------------------------------------------------- from os \ import getcwd from traits.api \ import HasTraits, Property, Directory, adapts, property_depends_on from traitsui.api \ import View, VGroup, Item, TreeEditor, ITreeNode, ITreeNodeAdapter from apptools.io.api \ import File #-- FileAdapter Class ---------------------------------------------------------- class FileAdapter ( ITreeNodeAdapter ): adapts( File, ITreeNode ) #-- ITreeNodeAdapter Method Overrides -------------------------------------- def allows_children ( self ): """ Returns whether this object can have children. """ return self.adaptee.is_folder def has_children ( self ): """ Returns whether the object has children. """ children = self.adaptee.children return ((children is not None) and (len( children ) > 0)) def get_children ( self ): """ Gets the object's children. """ return self.adaptee.children def get_label ( self ): """ Gets the label to display for a specified object. """ return self.adaptee.name + self.adaptee.ext def get_tooltip ( self ): """ Gets the tooltip to display for a specified object. """ return self.adaptee.absolute_path def get_icon ( self, is_expanded ): """ Returns the icon for a specified object. """ if self.adaptee.is_file: return '' if is_expanded: return '' return '' def can_auto_close ( self ): """ Returns whether the object's children should be automatically closed. """ return True #-- FileTreeDemo Class --------------------------------------------------------- class FileTreeDemo ( HasTraits ): # The path to the file tree root: root_path = Directory( entries = 10 ) # The root of the file tree: root = Property # The traits view to display: view = View( VGroup( Item( 'root_path' ), Item( 'root', editor = TreeEditor( editable = False, auto_open = 1 ) ), show_labels = False ), width = 0.33, height = 0.50, resizable = True ) #-- Traits Default Value Methods ------------------------------------------- def _root_path_default ( self ): return getcwd() #-- Property Implementations ----------------------------------------------- @property_depends_on( 'root_path' ) def _get_root ( self ): return File( path = self.root_path ) #-- Create and run the demo ---------------------------------------------------- demo = FileTreeDemo() # Run the demo (if invoked form the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Advanced/Multi_thread_demo.py0000644000175100001440000000354411674463545024634 0ustar ischnellusers00000000000000""" Monitoring threads in the user interface Shows a simple user interface being updated by multiple threads. When the *Start Threads* button is pressed, the program starts three independent threads running. Each thread counts from 0 to 199, updating its own thread-specific trait, and performs a sleep of a thread-specific duration between each update. The *Start Threads* button is disabled while the threads are running, and becomes active again once all threads have finished running. """ from threading import Thread from time import sleep from traits.api import HasTraits, Int, Button from traitsui.api import View, Item, VGroup class ThreadDemo(HasTraits): # The thread specific counters: thread_0 = Int thread_1 = Int thread_2 = Int # The button used to start the threads running: start = Button('Start Threads') # The count of how many threads ae currently running: running = Int view = View( VGroup( Item('thread_0', style = 'readonly'), Item('thread_1', style = 'readonly'), Item('thread_2', style = 'readonly'), ), '_', Item('start', show_label = False, width = -90, enabled_when = 'running == 0' ), resizable = True, width = 250, title = 'Monitoring threads' ) def _start_changed(self): for i in range(3): Thread(target = self.counter, args = ('thread_%d' % i, (i*10 + 10)/1000.0)).start() def counter(self, name, interval): self.running += 1 count = 0 for i in range( 200 ): setattr(self, name, count) count += 1 sleep(interval) self.running -= 1 # Create the demo: demo = ThreadDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Advanced/Auto_editable_readonly_table_cells.py0000644000175100001440000001202111674463545030164 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. """ This example shows how to define a read-only, auto-edit table column using a custom pop-up view. The example displays a list of integer values from 1 to n, where 'n' can be set using the slider at the top of the view. Each entry in the list shows the value of the integer and the number of unique factors it has. Mousing over the number of factors for a particular integer displays a pop-up list containing the unique factors for the integer. Mousing out of the cell causes the pop-up list to be removed (and perhaps causes a new pop-up list to be displayed, depending upon whether the mouse entered a new cell or not). Creating the auto pop-up effect is achieved by setting the 'auto_editable' trait of the associated ObjectColumn to True and also specifying a view to display on mouse over as the value of the ObjectColumn's 'view' trait. Note that this style of auto pop-up view can only be used with non-editable table editor fields. If the field is editable, then setting 'auto_editable' to True will cause the editor associated with the ObjectColumn to be automatically activated on mouse over, rather than the pop-up view specified by the 'view' trait. """ #-- Imports -------------------------------------------------------------------- from traits.api \ import HasTraits, Int, List, Range, Property, property_depends_on from traitsui.api \ import View, VGroup, Item, TableEditor from traitsui.table_column \ import ObjectColumn #-- Integer Class -------------------------------------------------------------- class Integer ( HasTraits ): # The value: n = Int #-- Factor Class --------------------------------------------------------------- class Factor ( HasTraits ): # The number being factored: n = Int # The list of factors of 'n': factors = Property( List ) @property_depends_on( 'n' ) def _get_factors ( self ): n = self.n i = 1 result = [] while (i * i) <= n: j = n / i if (i * j) == n: result.append( Integer( n = i ) ) if i != j: result.append( Integer( n = j ) ) i += 1 result.sort( lambda l, r: cmp( l.n, r.n ) ) return result #-- The table editor used for the pop-up view ---------------------------------- factor_table_editor = TableEditor( columns = [ ObjectColumn( name = 'n', width = 1.0, editable = False, horizontal_alignment = 'center' ) ], sortable = False, auto_size = False, show_toolbar = False, show_column_labels = False ) #-- The table editor used for the main view ------------------------------------ factors_view = View( Item( 'factors', id = 'factors', show_label = False, editor = factor_table_editor ), id = 'traits.examples.demo.Advanced.factors_view', kind = 'info', height = 0.30, ) factors_table_editor = TableEditor( columns = [ ObjectColumn( name = 'n', width = 0.5, editable = False, horizontal_alignment = 'center' ), ObjectColumn( name = 'factors', width = 0.5, editable = False, horizontal_alignment = 'center', auto_editable = True, format_func = lambda f: '%s factors' % len( f ), view = factors_view ), ], sortable = False, auto_size = False, show_toolbar = False ) #-- Factors Class -------------------------------------------------------------- class Factors ( HasTraits ): # The maximum number to include in the table: max_n = Range( 1, 1000, 20, mode = 'slider' ) # The list of Factor objects: factors = Property( List ) # The view of the list of Factor objects: view = View( VGroup( VGroup( Item( 'max_n' ), show_labels = False, show_border = True, label = 'Maximum Number' ), VGroup( Item( 'factors', show_label = False, editor = factors_table_editor ), ) ), title = 'List of numbers and their factors', width = 0.2, height = 0.4, resizable = True ) @property_depends_on( 'max_n' ) def _get_factors ( self ): return [ Factor( n = i + 1 ) for i in xrange( self.max_n ) ] #-- Create and run the demo ---------------------------------------------------- # Create the demo: demo = Factors() # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Advanced/Auto_update_TabularEditor_demo.py0000644000175100001440000000546711674463545027314 0ustar ischnellusers00000000000000""" Auto-update from a list to a TabularEditor Demonstrates using a TabularEditor with the 'auto_update' feature enabled, which allows the tabular editor to automatically update itself when the content of any object in the list associated with the editor is modified. To interact with the demo: - Select an employee from the list. - Adjust their salary increase. - Click the Give raise button. - Observe that the table automatically updates to reflect the employees new salary. In order for auto-update to work correctly, the editor trait should be a list of objects derived from HasTraits. Also, performance can be affected when very long lists are used, since enabling this feature adds and removed Traits listeners to each item in the list. """ from traits.api import HasTraits, Str, Float, List, Instance, Button from traitsui.api import View, HGroup, Item, TabularEditor, spring from traitsui.tabular_adapter import TabularAdapter #-- EmployeeAdapter Class ------------------------------------------------------ class EmployeeAdapter(TabularAdapter): columns = [('Name', 'name'), ('Salary', 'salary') ] def get_default_value(self, object, trait): return Employee(salary = 30000) #-- Employee Class ------------------------------------------------------------- class Employee(HasTraits): name = Str salary = Float #-- Company Class -------------------------------------------------------------- class Company(HasTraits): employees = List(Employee) employee = Instance(Employee) increase = Float give_raise = Button('Give raise') view = View( Item('employees', show_label = False, editor = TabularEditor(adapter = EmployeeAdapter(), selected = 'employee', auto_update = True) ), HGroup( spring, Item('increase'), Item('give_raise', show_label = False, enabled_when = 'employee is not None') ), title = 'Auto Update Tabular Editor demo', height = 0.25, width = 0.30, resizable = True ) def _give_raise_changed(self): self.employee.salary += self.increase self.employee = None #-- Set up the demo ------------------------------------------------------------ demo = Company(increase = 1000, employees = [ Employee(name = 'Fred', salary = 45000), Employee(name = 'Sally', salary = 52000), Employee(name = 'Jim', salary = 39000), Employee(name = 'Helen', salary = 41000), Employee(name = 'George', salary = 49000), Employee(name = 'Betty', salary = 46000) ]) # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Advanced/Time_editor_demo.py0000644000175100001440000000173511674463545024457 0ustar ischnellusers00000000000000""" A timer editor Display or edit a time. You can edit the time directly, or by using only the arrow keys (left & right to navigate, up & down to change). """ import datetime from traits.api import HasTraits, Time from traitsui.api import View, Item, TimeEditor class TimeEditorDemo(HasTraits): """ Demo class. """ time = Time(datetime.time(12, 0, 0)) view = View(Item('time', label='Simple Editor'), Item('time', label='Readonly Editor', style='readonly', # Show 24-hour mode instead of default 12 hour. editor=TimeEditor(strftime='%H:%M:%S') ), resizable=True) def _time_changed(self): """ Print each time the time value is changed in the editor. """ print self.time #-- Set Up The Demo ------------------------------------------------------------ demo = TimeEditorDemo() if __name__ == "__main__": demo.configure_traits() traitsui-4.1.0/examples/demo/Advanced/Table_editor_with_context_menu_demo.py0000644000175100001440000001237211674463545030432 0ustar ischnellusers00000000000000""" Defining column-specific context menu in a Table Shows a TableEditor which has column-specific context menus. The demo is a simple baseball scoring system, which lists each player and their current batting statistics. After a given player has an at bat, you right-click on the table cell corresponding to the player and the result of the at-bat (e.g. 'S' = single) and select the 'Add' menu option to register that the player hit a single and update the player's overall statistics. This demo also illustrates the use of Property traits, and how using 'event' meta-data can simplify event handling by collapsing an event that can occur on a number of traits into a category of event, which can be handled by a single event handler defined for the category (in this case, the category is 'affects_average'). """ from random import randint from traits.api import HasStrictTraits, Str, Int, Float, List, Property from traitsui.api import View, Item, TableEditor from traitsui.menu import Menu, Action from traitsui.table_column import ObjectColumn # Define a custom table column for handling items which affect the player's # batting average: class AffectsAverageColumn(ObjectColumn): # Define the context menu for the column: menu = Menu(Action(name = 'Add', action = 'column.add(object)'), Action(name = 'Sub', action = 'column.sub(object)')) # Right-align numeric values (override): horizontal_alignment = 'center' # Column width (override): width = 0.09 # Don't allow the data to be edited directly: editable = False # Action methods for the context menu items: def add(self, object): """ Increment the affected player statistic. """ setattr(object, self.name, getattr(object, self.name) + 1) def sub(self, object): """ Decrement the affected player statistic. """ setattr(object, self.name, getattr(object, self.name) - 1) # The 'players' trait table editor: player_editor = TableEditor( editable = True, sortable = True, auto_size = False, columns = [ ObjectColumn(name = 'name', editable = False, width = 0.28), AffectsAverageColumn(name = 'at_bats', label = 'AB'), AffectsAverageColumn(name = 'strike_outs', label = 'SO'), AffectsAverageColumn(name = 'singles', label = 'S'), AffectsAverageColumn(name = 'doubles', label = 'D'), AffectsAverageColumn(name = 'triples', label = 'T'), AffectsAverageColumn(name = 'home_runs', label = 'HR'), AffectsAverageColumn(name = 'walks', label = 'W'), ObjectColumn(name = 'average', label = 'Ave', editable = False, width = 0.09, horizontal_alignment = 'center', format = '%0.3f') ] ) # 'Player' class: class Player(HasStrictTraits): # Trait definitions: name = Str at_bats = Int strike_outs = Int(event = 'affects_average') singles = Int(event = 'affects_average') doubles = Int(event = 'affects_average') triples = Int(event = 'affects_average') home_runs = Int(event = 'affects_average') walks = Int average = Property(Float) def _get_average(self): """ Computes the player's batting average from the current statistics. """ if self.at_bats == 0: return 0.0 return float(self.singles + self.doubles + self.triples + self.home_runs) / self.at_bats def _affects_average_changed(self): """ Handles an event that affects the player's batting average. """ self.at_bats += 1 class Team(HasStrictTraits): # Trait definitions: players = List(Player) # Trait view definitions: traits_view = View( Item('players', show_label = False, editor = player_editor ), title = 'Baseball Scoring Demo', width = 0.5, height = 0.5, resizable = True ) def random_player(name): """ Generates and returns a random player. """ p = Player(name = name, strike_outs = randint(0, 50), singles = randint(0, 50), doubles = randint(0, 20), triples = randint(0, 5), home_runs = randint(0, 30), walks = randint(0, 50)) return p.trait_set(at_bats = p.strike_outs + p.singles + p.doubles + p.triples + p.home_runs + randint(100, 200)) # Create the demo: demo = view = Team(players = [ random_player(name) for name in [ 'Dave', 'Mike', 'Joe', 'Tom', 'Dick', 'Harry', 'Dirk', 'Fields', 'Stretch' ] ]) # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Advanced/Statusbar_demo.py0000644000175100001440000000455411674463545024165 0ustar ischnellusers00000000000000""" Displaying a statusbar in a Traits UI A statusbar may contain one or more fields, of fixed or variable size. Fixed width fields are specified in pixels, while variable width fields are specified as fractional values relative to other variable width fields. The content of a statusbar field is specified via the extended trait name of the object attribute that will contain the statusbar information. In this example, there are two statusbar fields: - The current length of the text input data (variable width) - The current time (fixed width, updated once per second). Note the use of a timer thread to update the status bar once per second. """ from time import sleep, strftime from threading import Thread from traits.api import HasPrivateTraits, Str, Property from traitsui.api import View, Item, StatusItem, Label #-- The demo class ------------------------------------------------------------- class TextEditor(HasPrivateTraits): # The text being edited: text = Str # The current length of the text being edited: length = Property(depends_on = 'text') # The current time: time = Str # The view definition: view = View( Label('Type into the text editor box:'), Item('text', style = 'custom', show_label = False), title = 'Text Editor', id = 'traitsui.demo.advanced.statusbar_demo', width = 0.4, height = 0.4, resizable = True, statusbar = [ StatusItem(name = 'length', width = 0.5), StatusItem(name = 'time', width = 85) ] ) #-- Property Implementations ----------------------------------------------- def _get_length(self): return ('Length: %d characters' % len(self.text)) #-- Default Trait Values --------------------------------------------------- def _time_default(self): thread = Thread(target = self._clock) thread.setDaemon(True) thread.start() return '' #-- Private Methods -------------------------------------------------------- def _clock(self): """ Update the statusbar time once every second. """ while True: self.time = strftime('%I:%M:%S %p') sleep(1.0) # Create the demo object: popup = TextEditor() # Run the demo (if invoked from the command line): if __name__ == '__main__': popup.configure_traits() traitsui-4.1.0/examples/demo/Advanced/Table_editor_with_checkbox_column.py0000644000175100001440000000726011674463545030061 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. """ This shows a table editor which has a checkbox column in addition to normal data columns. """ # Imports: from random \ import randint from traits.api \ import HasStrictTraits, Str, Int, Float, List, Bool, Property from traitsui.api \ import View, Item, TableEditor from traitsui.table_column \ import ObjectColumn from traitsui.extras.checkbox_column \ import CheckboxColumn # Create a specialized column to set the text color differently based upon # whether or not the player is in the lineup: class PlayerColumn ( ObjectColumn ): # Override some default settings for the column: width = 0.08 horizontal_alignment = 'center' def get_text_color ( self, object ): return [ 'light grey', 'black' ][ object.in_lineup ] # The 'players' trait table editor: player_editor = TableEditor( sortable = False, configurable = False, auto_size = False, columns = [ CheckboxColumn( name = 'in_lineup', label = 'In Lineup', width = 0.12 ), PlayerColumn( name = 'name', editable = False, width = 0.24, horizontal_alignment = 'left' ), PlayerColumn( name = 'at_bats', label = 'AB' ), PlayerColumn( name = 'strike_outs', label = 'SO' ), PlayerColumn( name = 'singles', label = 'S' ), PlayerColumn( name = 'doubles', label = 'D' ), PlayerColumn( name = 'triples', label = 'T' ), PlayerColumn( name = 'home_runs', label = 'HR' ), PlayerColumn( name = 'walks', label = 'W' ), PlayerColumn( name = 'average', label = 'Ave', editable = False, format = '%0.3f' ) ] ) # 'Player' class: class Player ( HasStrictTraits ): # Trait definitions: in_lineup = Bool( True ) name = Str at_bats = Int strike_outs = Int singles = Int doubles = Int triples = Int home_runs = Int walks = Int average = Property( Float ) def _get_average ( self ): """ Computes the player's batting average from the current statistics. """ if self.at_bats == 0: return 0.0 return float( self.singles + self.doubles + self.triples + self.home_runs ) / self.at_bats class Team ( HasStrictTraits ): # Trait definitions: players = List( Player ) # Trait view definitions: traits_view = View( Item( 'players', show_label = False, editor = player_editor ), title = 'Baseball Team Roster Demo', width = 0.5, height = 0.5, resizable = True ) def random_player ( name ): """ Generates and returns a random player. """ p = Player( name = name, strike_outs = randint( 0, 50 ), singles = randint( 0, 50 ), doubles = randint( 0, 20 ), triples = randint( 0, 5 ), home_runs = randint( 0, 30 ), walks = randint( 0, 50 ) ) return p.trait_set( at_bats = p.strike_outs + p.singles + p.doubles + p.triples + p.home_runs + randint( 100, 200 ) ) # Create the demo: demo = view = Team( players = [ random_player( name ) for name in [ 'Dave', 'Mike', 'Joe', 'Tom', 'Dick', 'Harry', 'Dirk', 'Fields', 'Stretch' ] ] ) # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Advanced/Table_editor_with_live_search_and_cell_editor.py0000644000175100001440000003561411674463545032375 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. """ This example demonstrates how to implement 'live search' using a TableEditor, as well as how to embed more sophisticated editors, such as a CodeEditor, within a table cell. This example also makes extensive use of cached properties. The example is a fairly simple source code file search utility. You determine which files to search and what to search for using the various controls spread across the top line of the view. You specify the root directory to search for files in using the 'Path' field. You can either: - Type in a directory name. - Click the '...' button and select a directory from the drop-down tree view that is displayed. - Click on the directory name drop-down to display a history list of the 10 most recently visited directories, and select a directory from the list. You can specify whether sub-directories should be included or not by toggling the 'Recursive' checkbox on or off. You can specify the types of files to be searched by clicking on the 'Type' drop-down and selecting a file type such as Python or C from the list. You can specify what string to search for by typing into the 'Search' field. The set of source files containing the search string is automatically updated as you type (this is the 'live search' feature). The search field also maintains a history of previous searches, so you can click on the drop-down arrow to display and select a previous search. Note that entries are only added to the search history when the enter key is pressed. This prevents each partial substring typed from being added to the history as a separate entry. You can specify whether the search is case sensitive or not by toggling the 'Case sensitive' checkbox on or off. The results of the search are displayed in a table below the input fields. The table contains four columns: - #: The number of lines matching the search string in the file. - Matches: A list of all lines containing search string matches in the file. Normally, only the first match is displayed, but you can click on this field to display the entire list of matches (the table row will expand and a CodeEditor will be displayed showing the complete list of matching source code file lines). You can click on or cursor to lines in the code editor to display the corresponding source code line in context in the code editor that appears at the bottom of the view. - Name: Displays the base name of the source file with no path information. - Path: Displays the portion of the source file path not included in the the root directory being used for the search. Selecting a line in the table editor will display the contents of the corresponding source file in the Code Editor displayed at the bottom of the view. After clicking on a 'Matches' column entry you can use the cursor up and down keys to select the various matching source code lines displayed in the table cell editor. You can move to the next or previous 'Matches' entry by pressing the Ctrl-Up and Ctrl-Down cursor keys. You can also use the Ctrl-Left and Ctrl-Right cursor keys to move to the previous or next column on the same line. You can also exit the 'Matches' code editor by pressing the Escape key. Finally: - You can click and drag the little circle to the right of the currently selected file to drag and drop the file. This can be useful, for example, to drag and drop the file into your favorite text editor. - Similarly, you can also drag the contents of the 'Name' column into your favorite text editor to edit the file corresponding to that line in the table. """ #-- Imports -------------------------------------------------------------------- from os \ import walk, getcwd, listdir from os.path \ import basename, dirname, splitext, join from traits.api \ import HasTraits, File, Directory, Str, Bool, Int, Enum, Instance, \ Property, Any, property_depends_on from traitsui.api \ import View, VGroup, VSplit, HGroup, Item, TableEditor, CodeEditor, \ TitleEditor, HistoryEditor, DNDEditor from traitsui.table_column \ import ObjectColumn #-- Constants ------------------------------------------------------------------ FileTypes = { 'Python': [ '.py' ], 'C': [ '.c', '.h' ], 'C++': [ '.cpp', '.h' ], 'Java': [ '.java' ], 'Ruby': [ '.rb' ] } #-- The Live Search table editor definition ------------------------------------ class MatchesColumn1 ( ObjectColumn ): def get_value ( self, object ): n = len( self.get_raw_value( object ) ) if n == 0: return '' return str( n ) class MatchesColumn2 ( ObjectColumn ): def is_editable ( self, object ): return (len( object.matches ) > 0) class FileColumn ( ObjectColumn ): def get_drag_value ( self, object ): return object.full_name table_editor = TableEditor( columns = [ MatchesColumn1( name = 'matches', label = '#', editable = False, width = 0.05, horizontal_alignment = 'center' ), MatchesColumn2( name = 'matches', width = 0.35, format_func = lambda x: (x + [ '' ])[0].strip(), editor = CodeEditor( line = 'object.live_search.selected_match', selected_line = 'object.live_search.selected_match' ), style = 'readonly', edit_width = 0.95, edit_height = 0.33 ), FileColumn( name = 'base_name', label = 'Name', width = 0.30, editable = False ), ObjectColumn( name = 'ext_path', label = 'Path', width = 0.30, editable = False ), ], filter_name = 'filter', auto_size = False, show_toolbar = False, selected = 'selected', selection_color = 0x000000, selection_bg_color = 0xFBD391 ) #-- LiveSearch class ----------------------------------------------------------- class LiveSearch ( HasTraits ): # The currenty root directory being searched: root = Directory( getcwd(), entries = 10 ) # Should sub directories be included in the search: recursive = Bool( True ) # The file types to include in the search: file_type = Enum( 'Python', 'C', 'C++', 'Java', 'Ruby' ) # The current search string: search = Str # Is the search case sensitive? case_sensitive = Bool( False ) # The live search table filter: filter = Property # Instance( TableFilter ) # The current list of source files being searched: source_files = Property # List( SourceFile ) # The currently selected source file: selected = Any # Instance( SourceFile ) # The contents of the currently selected source file: selected_contents = Property # List( Str ) # The currently selected match: selected_match = Int # The text line corresponding to the selected match: selected_line = Property # Int # The full name of the currently selected source file: selected_full_name = Property # File # The list of marked lines for the currently selected file: mark_lines = Property # List( Int ) # Summary of current number of files and matches: summary = Property # Str #-- Traits UI Views -------------------------------------------------------- view = View( VGroup( HGroup( Item( 'root', id = 'root', label = 'Path', width = 0.5 ), Item( 'recursive' ), Item( 'file_type', label = 'Type' ), Item( 'search', id = 'search', width = 0.5, editor = HistoryEditor( auto_set = True ) ), Item( 'case_sensitive' ) ), VSplit( VGroup( Item( 'summary', editor = TitleEditor() ), Item( 'source_files', id = 'source_files', editor = table_editor ), dock = 'horizontal', show_labels = False ), VGroup( HGroup( Item( 'selected_full_name', editor = TitleEditor(), springy = True ), Item( 'selected_full_name', editor = DNDEditor(), tooltip = 'Drag this file' ), show_labels = False ), Item( 'selected_contents', style = 'readonly', editor = CodeEditor( mark_lines = 'mark_lines', line = 'selected_line', selected_line = 'selected_line' ) ), dock = 'horizontal', show_labels = False ), id = 'splitter' ) ), title = 'Live File Search', id = 'enthought.examples.demo.Advanced.' 'Table_editor_with_live_search_and_cell_editor.LiveSearch', width = 0.75, height = 0.67, resizable = True ) #-- Property Implementations ----------------------------------------------- @property_depends_on( 'search, case_sensitive' ) def _get_filter ( self ): if len( self.search ) == 0: return lambda x: True return lambda x: len( x.matches ) > 0 @property_depends_on( 'root, recursive, file_type' ) def _get_source_files ( self ): root = self.root if root == '': root = getcwd() file_types = FileTypes[ self.file_type ] if self.recursive: result = [] for dir_path, dir_names, file_names in walk( root ): for file_name in file_names: if splitext( file_name )[1] in file_types: result.append( SourceFile( live_search = self, full_name = join( dir_path, file_name ) ) ) return result return [ SourceFile( live_search = self, full_name = join( root, file_name ) ) for file_name in listdir( root ) if splitext( file_name )[1] in file_types ] @property_depends_on( 'selected' ) def _get_selected_contents ( self ): if self.selected is None: return '' return ''.join( self.selected.contents ) @property_depends_on( 'selected' ) def _get_mark_lines ( self ): if self.selected is None: return [] return [ int( match.split( ':', 1 )[0] ) for match in self.selected.matches ] @property_depends_on( 'selected, selected_match' ) def _get_selected_line ( self ): selected = self.selected if (selected is None) or (len( selected.matches ) == 0): return 1 return int( selected.matches[ self.selected_match - 1 ].split( ':', 1 )[0] ) @property_depends_on( 'selected' ) def _get_selected_full_name ( self ): if self.selected is None: return '' return self.selected.full_name @property_depends_on( 'source_files, search, case_sensitive' ) def _get_summary ( self ): source_files = self.source_files search = self.search if search == '': return 'A total of %d files.' % len( source_files ) files = 0 matches = 0 for source_file in source_files: n = len( source_file.matches ) if n > 0: files += 1 matches += n return 'A total of %d files with %d files containing %d matches.' % ( len( source_files ), files, matches ) #-- Traits Event Handlers -------------------------------------------------- def _selected_changed ( self ): self.selected_match = 1 def _source_files_changed ( self ): if len( self.source_files ) > 0: self.selected = self.source_files[0] else: self.selected = None #-- SourceFile class ----------------------------------------------------------- class SourceFile ( HasTraits ): # The search object this source file is associated with: live_search = Instance( LiveSearch ) # The full path and file name of the source file: full_name = File # The base file name of the source file: base_name = Property # Str # The portion of the file path beyond the root search path: ext_path = Property # Str # The contents of the source file: contents = Property # List( Str ) # The list of matches for the current search criteria: matches = Property # List( Str ) #-- Property Implementations ----------------------------------------------- @property_depends_on( 'full_name' ) def _get_base_name ( self ): return basename( self.full_name ) @property_depends_on( 'full_name' ) def _get_ext_path ( self ): return dirname( self.full_name )[ len( self.live_search.root ): ] @property_depends_on( 'full_name' ) def _get_contents ( self ): try: fh = open( self.full_name, 'rb' ) contents = fh.readlines() fh.close() return contents except: return '' @property_depends_on( 'full_name, live_search.[search, case_sensitive]' ) def _get_matches ( self ): search = self.live_search.search if search == '': return [] case_sensitive = self.live_search.case_sensitive if case_sensitive: return [ '%5d: %s' % ( (i + 1), line.strip() ) for i, line in enumerate( self.contents ) if line.find( search ) >= 0 ] search = search.lower() return [ '%5d: %s' % ( (i + 1), line.strip() ) for i, line in enumerate( self.contents ) if line.lower().find( search ) >= 0 ] #-- Set up and run the demo ---------------------------------------------------- # Create the demo object: demo = LiveSearch() # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Advanced/Multi_thread_demo_2.py0000644000175100001440000000503311674463545025050 0ustar ischnellusers00000000000000""" Monitoring a dynamic number of threads Shows a simple user interface being updated by a dynamic number of threads. When the *Create Threads* button is pressed, the *count* method is dispatched on a new thread. It then creates a new *Counter* object and adds it to the *counters* list (which causes the *Counter* to appear in the user interface. It then counts by incrementing the *Counter* object's *count* trait (which again causes a user interface update each time the counter is incremented). After it reaches its maximum count, it removes the *Counter* from the *counter* list (causing the counter to be removed from the user interface) and exits (terminating the thread). Note that repeated clicking of the *Create Thread* button will create additional threads. """ from time import sleep from traits.api import HasTraits, Int, Button, List from traitsui.api import View, Item, ListEditor #-- The Counter objects used to keep track of the current count ---------------- class Counter(HasTraits): # The current count: count = Int view = View(Item('count', style = 'readonly')) #-- The main 'ThreadDemo' class ------------------------------------------------ class ThreadDemo(HasTraits): # The button used to start a new thread running: create = Button('Create Thread') # The set of counter objects currently running: counters = List(Counter) view = View( Item('create', show_label = False, width = -100), '_', Item('counters', style = 'custom', show_label = False, editor = ListEditor(use_notebook = True, dock_style = 'tab')), resizable = True, width = 300, height = 150, title = 'Dynamic threads' ) def __init__(self, **traits): super(HasTraits, self).__init__(**traits) # Set up the notification handler for the 'Create Thread' button so # that it is run on a new thread: self.on_trait_change(self.count, 'create', dispatch = 'new') def count(self): """ This method is dispatched on a new thread each time the 'Create Thread' button is pressed. """ counter = Counter() self.counters.append(counter) for i in range(1000): counter.count += 1 sleep(0.030) self.counters.remove(counter) # Create the demo: demo = ThreadDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Advanced/NumPy_array_tabular_editor_demo.py0000644000175100001440000000361611674463545027541 0ustar ischnellusers00000000000000""" Displaying large NumPy arrays with TabularEditor A demonstration of how the TabularEditor can be used to display (large) NumPy arrays, in this case 100,000 random 3D points from a unit cube. In addition to showing the coordinates of each point, it also displays the index of each point in the array, as well as a red flag if the point lies within 0.25 of the center of the cube. """ #-- Imports -------------------------------------------------------------------- from numpy import sqrt from numpy.random import random from traits.api import HasTraits, Property, Array, Font from traitsui.api import View, Item, TabularEditor from traitsui.tabular_adapter import TabularAdapter #-- Tabular Adapter Definition ------------------------------------------------- class ArrayAdapter(TabularAdapter): columns = [('i', 'index'), ('x', 0), ('y', 1), ('z', 2)] # Font fails with wx in OSX; see traitsui issue #13: # font = Font('Courier 10') alignment = 'right' format = '%.4f' index_text = Property index_image = Property def _get_index_text(self): return str(self.row) def _get_index_image(self): x, y, z = self.item if sqrt((x - 0.5) ** 2 + (y - 0.5) ** 2 + (z - 0.5) ** 2) <= 0.25: return '@icons:red_ball' return None #-- ShowArray Class Definition ------------------------------------------------- class ShowArray(HasTraits): data = Array view = View( Item('data', show_label = False, style = 'readonly', editor = TabularEditor(adapter = ArrayAdapter()) ), title = 'Array Viewer', width = 0.3, height = 0.8, resizable = True ) # Create the demo: demo = ShowArray(data = random((100000, 3))) # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Advanced/Property_List_demo.py0000644000175100001440000001122411674463545025024 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. """ This demo shows the proper way to create a Property whose value is a list, especially when the value of the Property will be used in a user interface, such as with the TableEditor. Most of the demo is just the machinery to set up the example. The key thing to note is the declaration of the people trait: people = Property( List, depends_on = 'ticker' ) In this case, by defining the Property as having a value of type List, you are ensuring that the computed value of the property will be validated using the List type, which in addition to verifying that the value is indeed a list, also guarantees that it will be converted to a TraitListObject, which is necessary for correct interaction with various Traits UI editors in a user interface. Note also the use of the depends_on metadata to trigger a trait property change whenever the ticker trait changes (in this case, it is changed every three seconds by a background thread). Finally, the use of the @cached_property decorator simplifies the implementation of the property by allowing the _get_people getter method to perform the expensive generation of a new list of people only when the ticker event fires, not every time it is accessed. """ #-- Imports -------------------------------------------------------------------- from random \ import randint, choice from threading \ import Thread from time \ import sleep from traits.api \ import HasStrictTraits, HasPrivateTraits, Str, Int, Enum, List, Event, \ Property, cached_property from traitsui.api \ import View, Item, TableEditor from traitsui.table_column \ import ObjectColumn #-- Person Class --------------------------------------------------------------- class Person ( HasStrictTraits ): """ Defines some sample data to display in the TableEditor. """ name = Str age = Int gender = Enum( 'Male', 'Female' ) #-- PropertyListDemo Class ----------------------------------------------------- class PropertyListDemo ( HasPrivateTraits ): """ Displays a random list of Person objects in a TableEditor that is refreshed every 3 seconds by a background thread. """ # An event used to trigger a Property value update: ticker = Event # The property being display in the TableEditor: people = Property( List, depends_on = 'ticker' ) # Tiny hack to allow starting the background thread easily: begin = Int #-- Traits View Definitions ------------------------------------------------ view = View( Item( 'people', show_label = False, editor = TableEditor( columns = [ ObjectColumn( name = 'name', editable = False, width = 0.50 ), ObjectColumn( name = 'age', editable = False, width = 0.15 ), ObjectColumn( name = 'gender', editable = False, width = 0.35 ) ], auto_size = False, show_toolbar = False ) ), title = 'Property List Demo', width = 0.25, height = 0.33, resizable = True ) #-- Property Implementations ----------------------------------------------- @cached_property def _get_people ( self ): """ Returns the value for the 'people' property. """ return [ Person( name = '%s %s' % ( choice( [ 'Tom', 'Dick', 'Harry', 'Alice', 'Lia', 'Vibha' ] ), choice( [ 'Thomas', 'Jones', 'Smith', 'Adams', 'Johnson' ] ) ), age = randint( 21, 75 ), gender = choice( [ 'Male', 'Female' ] ) ) for i in xrange( randint( 10, 20 ) ) ] #-- Default Value Implementations ------------------------------------------ def _begin_default ( self ): """ Starts the background thread running. """ thread = Thread( target = self._timer ) thread.setDaemon( True ) thread.start() return 0 #-- Private Methods -------------------------------------------------------- def _timer ( self ): """ Triggers a property update every 3 seconds for 30 seconds. """ for i in range( 10 ): sleep( 3 ) self.ticker = True # Create the demo: demo = PropertyListDemo() demo.begin # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Advanced/Tabular_editor_demo.py0000644000175100001440000001521011674463545025144 0ustar ischnellusers00000000000000""" Tabular editor The TabularEditor can be used for many of the same purposes as the TableEditor, that is, for displaying a table of attributes of lists or arrays of objects. While similar in function, the tabular editor has advantages and disadvantages relative to the table editor. See the Traits UI User Manual for details. This example defines three classes: - *Person*: A single person. - *MarriedPerson*: A married person (subclass of Person). - *Report*: Defines a report based on a list of single and married people. It creates a tabular display of 10,000 single and married people showing the following information: - Name of the person. - Age of the person. - The person's address. - The name of the person's spouse (if any). In addition: - It uses a Courier 10 point font for each line in the table. - It displays age column right, instead of left, justified. - If the person is a minor (age < 18) and married, it displays a red flag image in the age column. - If the person is married, it makes the background color for that row a light blue. This example demonstrates: - How to set up a *TabularEditor*. - The display speed of the *TabularEditor*. - How to create a *TabularAdapter* that meets each of the specified display requirements. Additional notes: - You can change the current selection using the up and down arrow keys. - You can move a selected row up and down in the table using the left and right arrow keys. """ from random import randint, choice, shuffle from traits.api import HasTraits, Str, Int, List, Instance, Property, Constant, Color from traitsui.api import View, Group, Item, TabularEditor from traitsui.tabular_adapter import TabularAdapter #-- Person Class Definition ---------------------------------------------------- class Person(HasTraits): name = Str address = Str age = Int #-- MarriedPerson Class Definition --------------------------------------------- class MarriedPerson(Person): partner = Instance(Person) #-- Tabular Adapter Definition ------------------------------------------------- class ReportAdapter(TabularAdapter): columns = [ ('Name', 'name'), ('Age', 'age'), ('Address', 'address'), ('Spouse', 'spouse') ] # Font fails with wx in OSX; see traitsui issue #13: # font = 'Courier 10' age_alignment = Constant('right') MarriedPerson_age_image = Property MarriedPerson_bg_color = Color(0xE0E0FF) MarriedPerson_spouse_text = Property Person_spouse_text = Constant('') def _get_MarriedPerson_age_image(self): if self.item.age < 18: return '@icons:red_ball' return None def _get_MarriedPerson_spouse_text(self): return self.item.partner.name #-- Tabular Editor Definition -------------------------------------------------- tabular_editor = TabularEditor( adapter = ReportAdapter(), operations = [ 'move' ], ) #-- Report Class Definition ---------------------------------------------------- class Report(HasTraits): people = List(Person) view = View( Group( Item('people', id = 'table', editor = tabular_editor), show_labels = False ), title = 'Tabular Editor Demo', id = 'traitsui.demo.Applications.tabular_editor_demo', width = 0.60, height = 0.75, resizable = True ) #-- Generate 10,000 random single and married people --------------------------- male_names = [ 'Michael', 'Edward', 'Timothy', 'James', 'George', 'Ralph', 'David', 'Martin', 'Bryce', 'Richard', 'Eric', 'Travis', 'Robert', 'Bryan', 'Alan', 'Harold', 'John', 'Stephen', 'Gael', 'Frederic', 'Eli', 'Scott', 'Samuel', 'Alexander', 'Tobias', 'Sven', 'Peter', 'Albert', 'Thomas', 'Horatio', 'Julius', 'Henry', 'Walter', 'Woodrow', 'Dylan', 'Elmer' ] female_names = [ 'Leah', 'Jaya', 'Katrina', 'Vibha', 'Diane', 'Lisa', 'Jean', 'Alice', 'Rebecca', 'Delia', 'Christine', 'Marie', 'Dorothy', 'Ellen', 'Victoria', 'Elizabeth', 'Margaret', 'Joyce', 'Sally', 'Ethel', 'Esther', 'Suzanne', 'Monica', 'Hortense', 'Samantha', 'Tabitha', 'Judith', 'Ariel', 'Helen', 'Mary', 'Jane', 'Janet', 'Jennifer', 'Rita', 'Rena', 'Rianna' ] all_names = male_names + female_names male_name = lambda: choice(male_names) female_name = lambda: choice(female_names) any_name = lambda: choice(all_names) age = lambda: randint(15, 72) family_name = lambda: choice([ 'Jones', 'Smith', 'Thompson', 'Hayes', 'Thomas', 'Boyle', "O'Reilly", 'Lebowski', 'Lennon', 'Starr', 'McCartney', 'Harrison', 'Harrelson', 'Steinbeck', 'Rand', 'Hemingway', 'Zhivago', 'Clemens', 'Heinlien', 'Farmer', 'Niven', 'Van Vogt', 'Sturbridge', 'Washington', 'Adams', 'Bush', 'Kennedy', 'Ford', 'Lincoln', 'Jackson', 'Johnson', 'Eisenhower', 'Truman', 'Roosevelt', 'Wilson', 'Coolidge', 'Mack', 'Moon', 'Monroe', 'Springsteen', 'Rigby', "O'Neil", 'Philips', 'Clinton', 'Clapton', 'Santana', 'Midler', 'Flack', 'Conner', 'Bond', 'Seinfeld', 'Costanza', 'Kramer', 'Falk', 'Moore', 'Cramdon', 'Baird', 'Baer', 'Spears', 'Simmons', 'Roberts', 'Michaels', 'Stuart', 'Montague', 'Miller' ]) address = lambda: '%d %s %s' % (randint(11, 999), choice([ 'Spring', 'Summer', 'Moonlight', 'Winding', 'Windy', 'Whispering', 'Falling', 'Roaring', 'Hummingbird', 'Mockingbird', 'Bluebird', 'Robin', 'Babbling', 'Cedar', 'Pine', 'Ash', 'Maple', 'Oak', 'Birch', 'Cherry', 'Blossom', 'Rosewood', 'Apple', 'Peach', 'Blackberry', 'Strawberry', 'Starlight', 'Wilderness', 'Dappled', 'Beaver', 'Acorn', 'Pecan', 'Pheasant', 'Owl' ]), choice([ 'Way', 'Lane', 'Boulevard', 'Street', 'Drive', 'Circle', 'Avenue', 'Trail' ])) people = [ Person(name = '%s %s' % (any_name(), family_name()), age = age(), address = address()) for i in range(5000) ] marrieds = [ (MarriedPerson(name = '%s %s' % (female_name(), last_name), age = age(), address = address), MarriedPerson(name = '%s %s' % (male_name(), last_name), age = age(), address = address)) for last_name, address in [ (family_name(), address()) for i in range(2500) ] ] for female, male in marrieds: female.partner = male male.partner = female people.extend([ female, male ]) shuffle(people) # Create the demo: demo = Report(people = people) # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Advanced/List_editor_notebook_selection_demo.py0000644000175100001440000000736011674463545030441 0ustar ischnellusers00000000000000""" Displaying a list of objects in notebook tabs A list of objects can be displayed in a tabbed notebook, one object per tab. This example also shows how the currently active notebook tab of a ListEditor can be controlled using the ListEditor's 'selected' trait. Note the interaction between the spinner control (for the 'index' trait) and the currently selected notebook tab. Try changing the spinner value, then try clicking on various notebook tabs. Finally, note that the ListEditor will automatically scroll the tabs to make the selected tab completely visible. """ # The following text was removed from the module docstring (only works in wx): # Also note that rearranging the notebook tabs (using drag and drop) does not # affect the correspondence between the index value and its associated notebook # tab. The correspondence is determined by the contents of the 'people' trait, # and not by the physical layout of the notebook tabs. from traits.api import HasStrictTraits, Str, Int, Regex, List, Instance, Range from traitsui.api import View, VGroup, Item, ListEditor #-- Person Class --------------------------------------------------------------- class Person(HasStrictTraits): # Trait definitions: name = Str age = Int phone = Regex(value = '000-0000', regex = '\d\d\d[-]\d\d\d\d') # Traits view definition: traits_view = View('name', 'age', 'phone', width = 0.18, buttons = [ 'OK', 'Cancel' ]) #-- Sample Data ---------------------------------------------------------------- people = [ Person(name = 'Dave Chomsky', age = 39, phone = '555-1212'), Person(name = 'Mike Wakowski', age = 28, phone = '555-3526'), Person(name = 'Joe Higginbotham', age = 34, phone = '555-6943'), Person(name = 'Tom Derringer', age = 22, phone = '555-7586'), Person(name = 'Dick Van Der Hooten', age = 63, phone = '555-3895'), Person(name = 'Harry McCallum', age = 46, phone = '555-3285'), Person(name = 'Sally Johnson', age = 43, phone = '555-8797'), Person(name = 'Fields Timberlawn', age = 31, phone = '555-3547') ] #-- ListEditorNotebookSelectionDemo Class -------------------------------------- class ListEditorNotebookSelectionDemo(HasStrictTraits): #-- Trait Definitions ------------------------------------------------------ # List of people: people = List(Person) # The currently selected person: selected = Instance(Person) # The index of the currently selected person: index = Range(0, 7, mode = 'spinner') #-- Traits View Definitions ------------------------------------------------ traits_view = View( Item('index'), '_', VGroup( Item('people@', id = 'notebook', show_label = False, editor = ListEditor(use_notebook = True, deletable = False, selected = 'selected', export = 'DockWindowShell', page_name = '.name') ) ), id = 'traitsui.demo.Traits UI Demo.Advanced.' 'List_editor_notebook_selection_demo', dock = 'horizontal') #-- Trait Event Handlers --------------------------------------------------- def _selected_changed(self, selected): self.index = self.people.index(selected) def _index_changed(self, index): self.selected = self.people[ index ] #-- Set Up The Demo ------------------------------------------------------------ demo = ListEditorNotebookSelectionDemo(people = people) if __name__ == "__main__": demo.configure_traits() traitsui-4.1.0/examples/demo/Advanced/History_demo.py0000644000175100001440000000451511674463545023653 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. """ This program demonstrates the use of editors that support history. A history is a persistent record of the last 'n' values the user has entered or selected for a particular trait. In order for the history to be recorded correctly, you must specify an id for both the Item containing the history editor and the View containing the Item. The maximum number of history entries recorded is specified by the value of the history editor's entries trait. If entries is less than or equal to 0, then a normal, non-history, version of the editor will be used. A history editor also attempts to restore the last value set as the current value for the trait if the current value of the trait is the empty string. You can see this for yourself by setting some values in the fields, selecting a different demo, then reselecting this demo. Each field should have the same value it had when the demo was run the previous time. """ #-- Imports -------------------------------------------------------------------- from traits.api \ import HasTraits, Str, File, Directory from traitsui.api \ import View, Item, FileEditor, DirectoryEditor, HistoryEditor #-- HistoryDemo Class ---------------------------------------------------------- class HistoryDemo ( HasTraits ): name = Str file = File directory = Directory view = View( Item( 'name', id = 'name', editor = HistoryEditor( entries = 5 ) ), Item( 'file', id = 'file1', editor = FileEditor( entries = 10 ) ), Item( 'file', id = 'file2', editor = FileEditor( entries = 10, filter = [ 'All files (*.*)|*.*', 'Python files (*.py)|*.py' ] ) ), Item( 'directory', id = 'directory', editor = DirectoryEditor( entries = 10 ) ), title = 'History Editor Demo', id = 'enthought.test.history_demo.HistoryDemo', width = 0.33, resizable = True ) # Create the demo: demo = HistoryDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Advanced/Dynamic_views_demo.py0000644000175100001440000001113311674463545025005 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. """ Demonstrates how to use the Dynamic Views facility. """ from traits.api \ import Bool, HasTraits, Str, Instance, Button from traitsui.api \ import View, HGroup, Group, Item, Handler, Label, spring from traits.has_dynamic_views \ import DynamicView, HasDynamicViews class HasFooView ( HasDynamicViews ): """ A base class declaring the existence of the 'foo' dynamic view. """ def __init__ ( self, *args, **traits ): """ Constructor. Extended to declare our dynamic foo view. """ super( HasFooView, self ).__init__( *args, **traits ) # Declare and add our dynamic view: declaration = DynamicView( name = 'foo', id = 'traitsui.demos.dynamic_views', keywords = { 'buttons': [ 'OK' ], 'dock': 'tab', 'height': 0.4, 'width': 0.4, 'resizable': True, 'scrollable': True, }, use_as_default = True, ) self.declare_dynamic_view( declaration ) class MyInfoHandler ( Handler ): def object_first_changed ( self, info ): info.object.derived = info.object.first class BaseFoo ( HasFooView ): """ A base class that puts some content in the 'foo' dynamic view. """ first = Str( 'My first name' ) last = Str( 'My last name' ) # A derived trait set by the handler associated with out dynamic view # contribution: derived = Str ui_person = Group( Item(label='On this tab, notice how the sub-handler keeps\n' 'the derived value equal to the first name.\n\n' 'On the next tab, change the selection in order to\n' 'control which tabs are visible when the ui is \n' 'displayed for the 2nd time.' ), spring, 'first', 'last', spring, 'derived', label = 'My Info', _foo_order = 5, _foo_priority = 1, _foo_handler = MyInfoHandler(), ) class FatherInfoHandler ( Handler ): def object_father_first_name_changed ( self, info ): info.object.father_derived = info.object.father_first_name class DerivedFoo ( BaseFoo ): """ A derived class that puts additional content in the 'foo' dynamic view. Note that the additional content could also have been added via a traits category contribution, or even dynamic manipulation of metadata on a UI subelement. The key is what the metadata represents when the view is *created* """ knows_mother = Bool( False ) mother_first_name = Str( "My mother's first name" ) mother_last_name = Str( "My mother's last name" ) knows_father = Bool( True ) father_first_name = Str( "My father's first name" ) father_last_name = Str( "My father's last name" ) father_derived = Str ui_parents = Group( 'knows_mother', 'knows_father', label = 'Parents?', _foo_order = 7, _foo_priority = 1, ) ui_mother = Group( 'mother_first_name', 'mother_last_name', label = "Mother's Info", _foo_priority = 1, ) ui_father = Group( 'father_first_name', 'father_last_name', spring, 'father_derived', label = "Father's Info", _foo_order = 15, _foo_priority = 1, _foo_handler = FatherInfoHandler(), ) def _knows_mother_changed ( self, old, new ): ui_mother = self.trait_view( 'ui_mother' ) if new: ui_mother._foo_order = 10 elif hasattr( ui_mother, '_foo_order' ): del ui_mother._foo_order def _knows_father_changed ( self, old, new ): ui_father = self.trait_view( 'ui_father' ) if new: ui_father._foo_order = 15 elif hasattr( ui_father, '_foo_order' ): del ui_father._foo_order class FooDemo ( HasTraits ): """ Defines a class to run the demo. """ foo = Instance( DerivedFoo, () ) configure = Button( 'Configure' ) view = View( Label( "Try configuring several times, each time changing the items " "on the 'Parents?' tab." ), '_', HGroup( spring, Item( 'configure', show_label = False ) ) ) def _configure_changed ( self ): self.foo.configure_traits() # Create the demo: popup = FooDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': popup.configure_traits() traitsui-4.1.0/examples/demo/Advanced/Scrubber_editor_demo.py0000644000175100001440000001566611674463545025340 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. """ This example demonstrates several different variations on using the ScrubberEditor. A 'scrubber' is a type of widget often seen in certain types of applications, such as video editing, image editing, 3D graphics and animation. These types of programs often have many parameters defined over various ranges that the user can tweak to get varying effects or results. Because the number of parameters is typically fairly large, and the amount of screen real estate is fairly limited, these program often use 'scrubbers' to allow the user to adjust the parameter values. A scrubber often looks like a simple text field. The user can type in new values, if they need a precise setting, or simply drag the mouse over the value to set a new value, much like dragging a slider control. The visual feedback often comes in the form of seeing both the text value of the parameter change and the effect that the new parameter value has on the underlying model. For example, in a 3D graphics program, there might be a scrubber for controlling the rotation of the currently selected object around the Y-axis. As the user scrubs the rotation parameter, they also see the model spin on the screen as well. This visual feedback is what makes a scrubber more useful than a simple text entry field. And the fact that the scrubber takes up no more screen real estate that a text entry field is what makes it more useful than a full-fledged slider in space limited applications. The Traits UI ScrubberEditor works as follows: - When the mouse pointer moves over the scrubber, the cursor pointer changes shape to indicate that the field has some additional control behavior. - The control may optionally change color as well, to visually indicate that the control is 'live'. - If you simply click on the scrubber, an active text entry field is displayed, where you can type a new value for the trait, then press the Enter key. - If you click and drag while over the scrubber, the value of the trait is modified based on the direction you move the mouse. Right and/or up increases the value, left and/or down decreases the value. Holding the Shift key down while scrubbing causes the value to change by 10 times its normal amount. Holding the Control key down while scrubbing changes the value by 0.1 times its normal amount. - Scrubbing is not limited to the area of the scrubber control. You can drag as far as you want in any direction, subject to the maximum limits imposed by the trait or ScrubberEditor definition. The ScrubberEditor also supports several different style and functional variations: - The visual default is to display only the special scrubber pointer to indicate to the user that 'scrubber' functionality is available. - By specifying a 'hover_color' value, you can also have the editor change color when the mouse pointer is over it. - By specifying an 'active_color' value, you can have the editor change color while the user is scrubbing. - By specifying a 'border_color' value, you can display a solid border around the editor to mark it as something other than an ordinary text field. - By specifying an 'increment' value, you can tell the editor what the normal increment value for the scrubber should be. Otherwise, the editor will calculate the increment value itself. Explicitly specifying an increment can be very useful in cases where the underlying trait has an unbounded value, which makes it difficult for the editor to determine what a reasonable increment value might be. - The editor will also correctly handle traits with dynamic ranges (i.e. ranges whose high and low limits are defined by other traits). Besides correctly handling the range limits, the editor will also adjust the default tooltip to display the current range of the scrubber. In this example, several of the variations described above are shown: - A simple integer range with default visual cues. - A float range with both 'hover_color' and 'active_color' values specified. - An unbounded range with a 'border_color' value specified. - A dynamic range using an Item theme. This consists of three scrubbers: one to control the low end of the range, one to control the high end, and one that uses the high and low values to determine its range. For comparison purposes, the example also shows the same traits displayed using their default editors. """ #-- Imports -------------------------------------------------------------------- from traits.api \ import HasTraits, Range, Float from traitsui.api \ import View, VGroup, HGroup, Item, ScrubberEditor, spring from traitsui.ui_traits \ import ATheme #-- Shared Themed Item Definition ---------------------------------------------- class TItem ( Item ): editor = ScrubberEditor() item_theme = ATheme( '@std:LG' ) #-- ScrubberDemo Class --------------------------------------------------------- class ScrubberDemo ( HasTraits ): # Define some sample ranges and values: simple_integer = Range( 0, 100 ) rollover_float = Range( -10.0, 10.0 ) bordered_unbounded = Float themed_dynamic_low = Range( high = -0.01, value = -10.0 ) themed_dynamic_high = Range( low = 0.01, value = 10.0 ) themed_dynamic_value = Range( 'themed_dynamic_low', 'themed_dynamic_high', 0.0 ) # Define the demo view: view = View( HGroup( VGroup( Item( 'simple_integer', editor = ScrubberEditor() ), Item( 'rollover_float', editor = ScrubberEditor( hover_color = 0xFFFFFF, active_color = 0xA0CD9E ) ), Item( 'bordered_unbounded', editor = ScrubberEditor( hover_color = 0xFFFFFF, active_color = 0xA0CD9E, border_color = 0x808080 ) ), TItem( 'themed_dynamic_low' ), TItem( 'themed_dynamic_high' ), TItem( 'themed_dynamic_value' ), show_border = True, label = 'Scrubber Editors' ), VGroup( Item( 'simple_integer' ), Item( 'rollover_float' ), Item( 'bordered_unbounded' ), Item( 'themed_dynamic_low' ), Item( 'themed_dynamic_high' ), Item( 'themed_dynamic_value' ), show_border = True, label = 'Default Editors' ), spring ), title = 'Scrubber Editor Demo' ) #-- Create and run the demo ---------------------------------------------------- # Create the demo: demo = ScrubberDemo() # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Advanced/Date_editor_demo.py0000644000175100001440000000516711674463545024441 0ustar ischnellusers00000000000000# Copyright (c) 2007-2009, Enthought, Inc. # License: BSD Style. """ A Traits UI editor that wraps a WX calendar panel. """ from traits.api import HasTraits, Date, List, Str from traitsui.api import View, Item, DateEditor, Group class DateEditorDemo(HasTraits): """ Demo class to show Date editors. """ single_date = Date multi_date = List(Date) info_string = Str('The editors for Traits Date objects. Showing both '\ 'the defaults, and one with alternate options.') multi_select_editor = DateEditor(multi_select=True, months=2, allow_future=False, padding=30, on_mixed_select='max_change', shift_to_select=False) view = View(Item('info_string', show_label=False, style='readonly'), Group(Item('single_date', label='Simple date editor'), Item('single_date', style='custom', label='Default custom editor'), Item('single_date', style='readonly', editor=DateEditor(strftime='You picked %B %d %Y', message='Click a date above.'), label='ReadOnly editor'), label='Default settings for editors'), Group(Item('multi_date', editor=multi_select_editor, style='custom', label='Multi-select custom editor'), label='More customized editor: multi-select; disallow '\ 'future; two months; padding; selection '\ 'style; etc.'), resizable=True) def _multi_date_changed(self): """ Print each time the date value is changed in the editor. """ print self.multi_date def _simple_date_changed(self): """ Print each time the date value is changed in the editor. """ print self.simple_date, self.single_date def _single_date_changed(self): """ Print each time the date value is changed in the editor. """ print self.single_date #-- Set Up The Demo ------------------------------------------------------------ demo = DateEditorDemo() if __name__ == "__main__": demo.configure_traits() #-- eof ----------------------------------------------------------------------- traitsui-4.1.0/examples/demo/Advanced/String_list_ui_editor.py0000644000175100001440000001004211674463545025542 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. """ Another demo showing how to use a TabularEditor to create a multi-select list box. This demo creates a reusable StringListEditor class and uses that instead of defining the editor as part of the demo class. This approach greatly simplifies the actual demo class and shows how to construct a reusable Traits UI-based editor that can be used in other applications. """ #-- Imports ------------------------------------------------------------------ from traits.api \ import HasPrivateTraits, List, Str, Property, on_trait_change from traitsui.api \ import View, HGroup, Item, TabularEditor from traitsui.tabular_adapter \ import TabularAdapter from traitsui.ui_editor \ import UIEditor from traitsui.basic_editor_factory \ import BasicEditorFactory #-- Define the reusable StringListEditor class and its helper classes -------- # Define the tabular adapter used by the Traits UI string list editor: class MultiSelectAdapter ( TabularAdapter ): # The columns in the table (just the string value): columns = [ ( 'Value', 'value' ) ] # The text property used for the 'value' column: value_text = Property def _get_value_text ( self ): return self.item # Define the actual Traits UI string list editor: class _StringListEditor ( UIEditor ): # Indicate that the editor is scrollable/resizable: scrollable = True # The list of available editor choices: choices = List( Str ) # The list of currently selected items: selected = List( Str ) # The traits UI view used by the editor: view = View( Item( 'choices', show_label = False, editor = TabularEditor( show_titles = False, selected = 'selected', editable = False, multi_select = True, adapter = MultiSelectAdapter() ) ), id = 'string_list_editor', resizable = True ) def init_ui ( self, parent ): self.sync_value( self.factory.choices, 'choices', 'from', is_list = True ) self.selected = self.value return self.edit_traits( parent = parent, kind = 'subpanel' ) @on_trait_change( ' selected' ) def _selected_modified ( self ): self.value = self.selected # Define the StringListEditor class used by client code: class StringListEditor ( BasicEditorFactory ): # The editor implementation class: klass = _StringListEditor # The extended trait name containing the editor's set of choices: choices = Str #-- Define the demo class ---------------------------------------------------- class MultiSelect ( HasPrivateTraits ): """ This class demonstrates using the StringListEditor to select a set of string values from a set of choices. """ # The list of choices to select from: choices = List( Str ) # The currently selected list of choices: selected = List( Str ) # A dummy result so that we can display the selection using the same # StringListEditor: result = List( Str ) # A traits view showing the list of choices on the left-hand side, and # the currently selected choices on the right-hand side: view = View( HGroup( Item( 'selected', show_label = False, editor = StringListEditor( choices = 'choices' ) ), Item( 'result', show_label = False, editor = StringListEditor( choices = 'selected' ) ) ), width = 0.20, height = 0.25 ) # Create the demo: demo = MultiSelect( choices = [ 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten' ], selected = [ 'two', 'five', 'nine' ] ) # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Advanced/__init__.py0000644000175100001440000000013211674463545022734 0ustar ischnellusers00000000000000""" These demonstrations show off some of the more advanced features of and TraitsUI. """ traitsui-4.1.0/examples/demo/Advanced/ListStrEditor_demo.py0000644000175100001440000000247211674463545024765 0ustar ischnellusers00000000000000""" Edit a List of Strings Simple demonstration of the ListStrEditor, which can be used for editing and displaying lists of strings, or other data that can be logically mapped to a list of strings. """ from traits.api import HasTraits, List, Str from traitsui.api import View, Item, ListStrEditor #-- ShoppingListDemo Class ----------------------------------------------------- class ShoppingListDemo (HasTraits): # The list of things to buy at the store: shopping_list = List(Str) #-- Traits View Definitions ------------------------------------------------ view = View( Item('shopping_list', show_label = False, editor = ListStrEditor(title = 'Shopping List', auto_add = True) ), title = 'Shopping List', width = 0.2, height = 0.5, resizable = True ) #-- Set up the Demo ------------------------------------------------------------ demo = ShoppingListDemo(shopping_list = [ 'Carrots', 'Potatoes (5 lb. bag)', 'Cocoa Puffs', 'Ice Cream (French Vanilla)', 'Peanut Butter', 'Whole wheat bread', 'Ground beef (2 lbs.)', 'Paper towels', 'Soup (3 cans)', 'Laundry detergent' ]) # Run the demo (in invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Advanced/Dynamic_EnumEditor_demo.py0000644000175100001440000000763511674463545025737 0ustar ischnellusers00000000000000""" Dynamic changing an Enum selection list, depending on checked items Another way to dynamically change the values shown by an EnumEditor. The scenario is a restaurant that at the beginning of the day has a menu list of entrees based upon a fully stocked kitchen. However, as the day progresses, the kitchen's larder gets depleted, and the kitchen may no longer be able to prepare certain entrees, which must then be deleted from the menu. Similarly, deliveries may allow certain entrees to be added back onto the menu. The demo is divided into two tabs: Order and Kitchen. The Order tab represents a customer's order and consists of a single Entree field, which represents the customer's selection from the drop-down list of entrees that the kitchen can currently prepare. The Kitchen tab represents the current set of entrees that the kitchen can prepare, based upon the current contents of its larder. As entrees are checked on or off from the Kitchen tab, the customer's Entree drop-down is dynamically updated with the current list of available entrees. Notes: - The key point of the demo is the use of the 'name' trait in the EnumEditor definition, which links the list of available entrees from the KitchenCapabilities object to the OrderMenu object's entree EnumEditor. - The design will work with any number of active OrderMenu objects, since they all share a common KitchenCapabilities object. As the KitchenCapabilities object is updated, all OrderMenu UI's will automatically update their associated Entree's drop-down list. - A careful reader will also observe that this example contains only declarative code. No imperative code is required to handle the automatic updating of the Entree list. """ #-- Imports -------------------------------------------------------------------- from traits.api \ import HasPrivateTraits, Str, List, Constant from traitsui.api \ import View, Item, VGroup, HSplit, EnumEditor, CheckListEditor #-- The list of possible entrees ----------------------------------------------- possible_entrees = [ 'Chicken Fried Steak', 'Chicken Fingers', 'Chicken Enchiladas', 'Cheeseburger', 'Pepper Steak', 'Beef Tacos', 'Club Sandwich', 'Ceasar Salad', 'Cobb Salad' ] #-- The KitchenCapabilities class ---------------------------------------------- class KitchenCapabilities ( HasPrivateTraits ): # The current set of entrees the kitchen can make (based on its larder): available = List( possible_entrees ) # The KitchenCapabilities are shared by all waitstaff taking orders: kitchen_capabilities = KitchenCapabilities() #-- The OrderMenu class -------------------------------------------------------- class OrderMenu ( HasPrivateTraits ): # The person's entree order: entree = Str # Reference to the restaurant's current entree capabilities: capabilities = Constant( kitchen_capabilities ) # The user interface view: view = View( HSplit( VGroup( Item( 'entree', editor = EnumEditor( name = 'object.capabilities.available' ) ), label = 'Order', show_border = True, dock = 'tab' ), VGroup( Item( 'object.capabilities.available', show_label = False, style = 'custom', editor = CheckListEditor( values = possible_entrees ) ), label = 'Kitchen', show_border = True, dock = 'tab' ) ), title = 'Dynamic EnumEditor Demo', ) #------------------------------------------------------------------------------- # Create the demo: demo = OrderMenu() # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Advanced/List_editors_demo.py0000644000175100001440000000650011674463545024652 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. """ This shows the three different types of editor that can be applied to a list of objects: - Table - List - Dockable notebook (a list variant) Each editor style is editing the exact same list of objects. Note that any changes made in one editor are automatically reflected in the others. """ # Imports: from traits.api \ import HasStrictTraits, Str, Int, Regex, List, Instance from traitsui.api \ import View, Item, Tabbed, TableEditor, ListEditor from traitsui.table_column \ import ObjectColumn from traitsui.table_filter \ import RuleTableFilter, RuleFilterTemplate, \ MenuFilterTemplate, EvalFilterTemplate # 'Person' class: class Person ( HasStrictTraits ): # Trait definitions: name = Str age = Int phone = Regex( value = '000-0000', regex = '\d\d\d[-]\d\d\d\d' ) # Traits view definition: traits_view = View( 'name', 'age', 'phone', width = 0.18, buttons = [ 'OK', 'Cancel' ] ) # Sample data: people = [ Person( name = 'Dave', age = 39, phone = '555-1212' ), Person( name = 'Mike', age = 28, phone = '555-3526' ), Person( name = 'Joe', age = 34, phone = '555-6943' ), Person( name = 'Tom', age = 22, phone = '555-7586' ), Person( name = 'Dick', age = 63, phone = '555-3895' ), Person( name = 'Harry', age = 46, phone = '555-3285' ), Person( name = 'Sally', age = 43, phone = '555-8797' ), Person( name = 'Fields', age = 31, phone = '555-3547' ) ] # Table editor definition: filters = [ EvalFilterTemplate, MenuFilterTemplate, RuleFilterTemplate ] table_editor = TableEditor( columns = [ ObjectColumn( name = 'name', width = 0.4 ), ObjectColumn( name = 'age', width = 0.2 ), ObjectColumn( name = 'phone', width = 0.4 ) ], editable = True, deletable = True, sortable = True, sort_model = True, auto_size = False, filters = filters, search = RuleTableFilter(), row_factory = Person ) # 'ListTraitTest' class: class ListTraitTest ( HasStrictTraits ): # Trait definitions: people = List( Instance( Person, () ) ) # Traits view definitions: traits_view = View( Tabbed( Item( 'people', label = 'Table', id = 'table', editor = table_editor ), Item( 'people@', label = 'List', id = 'list', editor = ListEditor( style = 'custom', rows = 5 ) ), Item( 'people@', label = 'Notebook', id = 'notebook', editor = ListEditor( use_notebook = True, deletable = True, export = 'DockShellWindow', page_name = '.name' ) ), id = 'splitter', show_labels = False ), id = 'traitsui.demo.Traits UI Demo.Advanced.List_editors_demo', dock = 'horizontal' ) # Create the demo: demo = ListTraitTest( people = people ) # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Advanced/NumPy_array_view_editor_demo.py0000644000175100001440000000514011674463545027053 0ustar ischnellusers00000000000000""" Using ArrayViewEditor to display large NumPy arrays in a table. This example displays 100,000 random 3D points from a unit cube. Note that the ArrayViewEditor has the following traits:: # Should an index column be displayed: show_index = Bool(True) # List of (optional) column titles: titles = List(Str) # Should the array be logically transposed: transpose = Bool(False) # The format used to display each array element: format = Str('%s') By default, the array row index will be shown in column one. If 'show_index' is False, then the row index column is omitted. If the list of 'titles' is empty, no column headers will be displayed. If the number of column headers is less than the number of array columns, then there are two cases: - If (number of array_columns) % (number of titles) == 0, then the titles are used to construct a series of repeating column headers with increasing subscripts (e.g. an (n x 6) array with titles of ['x','y','z'] would result in column headers of: 'x0', 'y0', 'z0', 'x1', 'y1', 'z1'). - In all other cases the titles are used as the column headers for the first set of columns, and the remaining column headers are set to the empty string (e.g. an (n x 5) array with titles of ['x','y','z'] would result in column headers of: 'x', 'y', 'z', '', ''). Setting 'transpose' to True will logically transpose the input array (e.g. an (3 x n) array will be displayed as an (n x 3) array). """ from numpy.random import random from traits.api import HasTraits, Array from traitsui.api import View, Item from traitsui.ui_editors.array_view_editor import ArrayViewEditor #-- ShowArray demo class ------------------------------------------------------- class ShowArray(HasTraits): data = Array view = View( Item('data', show_label = False, editor = ArrayViewEditor(titles = [ 'x', 'y', 'z' ], format = '%.4f', # Font fails with wx in OSX; # see traitsui issue #13: # font = 'Arial 8' ) ), title = 'Array Viewer', width = 0.3, height = 0.8, resizable = True ) #-- Run the demo --------------------------------------------------------------- # Create the demo: demo = ShowArray(data = random((100000, 3))) # Run the demo (if invoked from the command line): if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/image_LICENSE.txt0000644000175100001440000000111411674463545022104 0ustar ischnellusers00000000000000The icons are mostly derived work from other icons. As such they are licensed accordingly to the original license: Project License File ---------------------------------------------------------------------------- Enthought BSD 3-Clause LICENSE.txt Unless stated in this file, icons are the work of Enthought, and are released under a 3 clause BSD license. Files and orginal authors: ---------------------------------------------------------------------------- examples/demo/: traits_ui_demo.jpg | Enthought traitsui-4.1.0/examples/demo/Useful/0000755000175100001440000000000011674463545020365 5ustar ischnellusers00000000000000traitsui-4.1.0/examples/demo/Useful/using_springs.py0000644000175100001440000000477111674463545023642 0ustar ischnellusers00000000000000""" Spacing widgets using springs *Springs* are a simple technique for adding space before, after, or between Traits UI editors (a.k.a. widgets). By default, Traits UI arranges widgets immediately adjacent to each other -- from left to right in a horizontal group, or from top to bottom in a vertical group. Sometimes this works well, but sometimes it results in widgets that are placed confusingly, or have been unattractively stretched to fill available space. When you place a *spring* in a horizontal group, Traits UI will not try to fill that space with an adjacent widget, instead allowing empty space which varies depending on the overall size of the containing group. """ from traits.api import HasTraits, Button from traitsui.api import View, VGroup, HGroup, Item, spring, Label # dummy button which will be used repeatedly to demonstrate widget spacing: button = Item( 'ignore', show_label = False ) class SpringDemo(HasTraits): ignore = Button('Ignore') view = View( VGroup( '10', Label(label='Spring in a horizontal group moves widget right:'), '10', HGroup(button, button, show_border = True, label = 'Left justified (no springs)' ), HGroup(spring, button, button, show_border = True, label = 'Right justified with a spring ' 'before any buttons'), HGroup(button, spring, button, show_border = True, label = 'Left and right justified with a ' 'spring between buttons'), HGroup(button, button, spring, button, button, spring, button, button, show_border = True, label = 'Left, center and right justified ' 'with springs after the 2nd and 4th ' 'buttons'), spring, Label('But spring in vertical group does not move ' 'widget down at present.'), button ), width=600, height=600, resizable=True, title = 'Spring Demo', buttons = [ 'OK' ] ) demo = SpringDemo() if __name__ == '__main__': demo.configure_traits() traitsui-4.1.0/examples/demo/Useful/demo_group_size.py0000644000175100001440000000631511674463545024136 0ustar ischnellusers00000000000000""" Control the height and width of a Group TraitsUI does not permit explicit specification of the height or width of a Group (or its descendants). The workaround is to put each Group whose size you wish to control into its own View class, which can be an Item (hence can be size-controlled) in the larger View. Sometimes it is necessary to repeat such surgery at several levels to get the desired layout. We separate the left and right groups by a splitter (HSplit), and also make the window itself resizable. This demo includes a simple Chaco plot for variety, but it is not a Chaco demo. """ from numpy import linspace, pi, sin from traits.api import HasTraits, Instance, Str, Int # UItem is Unlabeled Item from traitsui.api import View, Item, UItem, HSplit, InstanceEditor, \ VGroup, HGroup from chaco.api import Plot, AbstractPlotData, ArrayPlotData from enable.component_editor import ComponentEditor class InstanceUItem(UItem): """Convenience class for including an Instance in a View""" style = Str('custom') editor = Instance(InstanceEditor,()) class PlotView(HasTraits): """Defines a sub-view whose size we wish to explicitly control.""" n = Int(123) data = Instance(AbstractPlotData) plot1 = Instance(Plot) view = View( # This HGroup keeps 'n' from over-widening, by implicitly placing # a spring to the right of the item. HGroup(Item('n')), UItem('plot1', editor=ComponentEditor()), resizable=True, ) def create_plot(self, data, name, color): p = Plot(self.data) p.plot(data, name=name, color=color) return p def _data_changed(self): self.plot1 = self.create_plot(("x", "y1"), "sin plot", "red") class VerticalBar(HasTraits): """Defines a sub-view whose size we wish to explicitly control.""" a = Str('abcdefg') b = Int(123) view = View( VGroup( Item('a'), Item('b'), show_border=True, ), ) class BigView(HasTraits): """Defines the top-level view. It contains two side-by-side panels (a vertical bar and a plot under an integer) whose relative sizes we wish to control explicitly. If these were simply defined as Groups, we could not control their sizes. But by extracting them as separate classes with their own views, the resizing becomes possible, because they are loaded as Items now. """ bar = Instance(VerticalBar, ()) plot = Instance(PlotView) view = View( HSplit( # Specify pixel width of each sub-view. (Or, to specify # proportionate width, use a width < 1.0) # We specify the height here for sake of demonstration; # it could also be specified for the top-level view. InstanceUItem('bar', width=150), InstanceUItem('plot', width=500, height=500), show_border=True, ), resizable=True, ) x = linspace(-2*pi, 2*pi, 100) pv = PlotView(data = ArrayPlotData(x=x, y1=sin(x))) bv = BigView(plot=pv) bv.configure_traits()traitsui-4.1.0/examples/demo/demo.py0000644000175100001440000000130411674463545020416 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2005, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 09/15/2005 # #------------------------------------------------------------------------------- """ Run the Traits UI demo. """ from traitsui.extras.demo import demo demo() traitsui-4.1.0/examples/tutorials/0000755000175100001440000000000011674463545020224 5ustar ischnellusers00000000000000traitsui-4.1.0/examples/tutorials/tutor.py0000644000175100001440000016755611674463545021777 0ustar ischnellusers00000000000000#------------------------------------------------------------------------------- # # Copyright (c) 2007, Enthought, Inc. # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in enthought/LICENSE.txt and may be redistributed only # under the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # # Author: David C. Morrill # Date: 03/30/2007 # # fixme: # - Get custom tree view images. # - Write a program to create a directory structure from a lesson plan file. # #------------------------------------------------------------------------------- """ A framework for creating interactive Python tutorials. """ #------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- import sys import os import re from string \ import capwords from traits.api \ import HasPrivateTraits, HasTraits, File, Directory, Instance, Int, Str, \ List, Bool, Dict, Any, Property, Delegate, Button, cached_property from traitsui.api \ import View, VGroup, HGroup, VSplit, HSplit, Tabbed, Item, Heading, \ Handler, ListEditor, CodeEditor, EnumEditor, HTMLEditor, \ TreeEditor, TitleEditor, ValueEditor, ShellEditor from traitsui.menu \ import NoButtons from traitsui.tree_node \ import TreeNode from pyface.image_resource \ import ImageResource try: from traitsui.wx.extra.windows.ie_html_editor \ import IEHTMLEditor from traitsui.wx.extra.windows.flash_editor \ import FlashEditor except: IEHTMLEditor = FlashEditor = None #------------------------------------------------------------------------------- # Constants: #------------------------------------------------------------------------------- # Correct program usage information: Usage = """ Correct usage is: tutor.py [root_dir] where: root_dir = Path to root of the tutorial tree If omitted, 'root_dir' defaults to the current directory.""" # The standard list editor used: list_editor = ListEditor( use_notebook = True, deletable = False, page_name = '.title', export = 'DockWindowShell', dock_style = 'fixed' ) # The standard code snippet editor used: snippet_editor = ListEditor( use_notebook = True, deletable = False, page_name = '.title', export = 'DockWindowShell', dock_style = 'tab', selected = 'snippet' ) # Regular expressions used to match section directories: dir_pat1 = re.compile( r'^(\d\d\d\d)_(.*)$' ) dir_pat2 = re.compile( r'^(.*)_(\d+\.\d+)$' ) # Regular expression used to match section header in a Python source file: section_pat1 = re.compile( r'^#-*\[(.*)\]' ) # Normal section_pat2 = re.compile( r'^#-*<(.*)>' ) # Hidden section_pat3 = re.compile( r'^#-*\((.*)\)' ) # Description # Regular expression used to extract item titles from URLs: url_pat1 = re.compile( r'^(.*)\[(.*)\](.*)$' ) # Normal # Is this running on the Windows platform? is_windows = (sys.platform in ( 'win32', 'win64' )) # Python file section types: IsCode = 0 IsHiddenCode = 1 IsDescription = 2 # HTML template for a default lecture: DefaultLecture = """

    This section contains the following topics:

      %s
    """ # HTML template for displaying a .wmv/.avi movie file: WMVMovieTemplate = """

    """ # HTML template for displaying a QuickTime.mov movie file: QTMovieTemplate = """

    """ # HTML template for displaying an image file: ImageTemplate = """ """ # HTML template for playing an MP3 audio file: MP3Template = """

     

    """ #------------------------------------------------------------------------------- # Returns the contents of a specified text file (or None): #------------------------------------------------------------------------------- def read_file ( path, mode = 'rb' ): """ Returns the contents of a specified text file (or None). """ fh = result = None try: fh = file( path, mode ) result = fh.read() except: pass if fh is not None: try: fh.close() except: pass return result #------------------------------------------------------------------------------- # Creates a title from a specified string: #------------------------------------------------------------------------------- def title_for ( title ): """ Creates a title from a specified string. """ return capwords( title.replace( '_', ' ' ) ) #------------------------------------------------------------------------------- # Returns a relative CSS style sheet path for a specified path and parent # section: #------------------------------------------------------------------------------- def css_path_for ( path, parent ): """ Returns a relative CSS style sheet path for a specified path and parent section. """ if os.path.isfile( os.path.join( path, 'default.css' ) ): return 'default.css' if parent is not None: result = parent.css_path if result != '': if path != parent.path: result = os.path.join( '..', result ) return result return '' #------------------------------------------------------------------------------- # 'StdOut' class: #------------------------------------------------------------------------------- class StdOut ( object ): """ Simulate stdout, but redirect the output to the 'output' string supplied by some 'owner' object. """ def __init__ ( self, owner ): self.owner = owner def write ( self, data ): """ Adds the specified data to the output log. """ self.owner.output += data def flush ( self ): """ Flushes all current data to the output log. """ pass #------------------------------------------------------------------------------- # 'NoDemo' class: #------------------------------------------------------------------------------- class NoDemo ( HasPrivateTraits ): #-- Traits View Definitions ------------------------------------------------ view = View( Heading( 'No demo defined for this lab.' ), resizable = True ) #------------------------------------------------------------------------------- # 'DemoPane' class: #------------------------------------------------------------------------------- class DemoPane ( HasPrivateTraits ): """ Displays the contents of a Python lab's *demo* value. """ #-- Trait Definitions ------------------------------------------------------ demo = Instance( HasTraits, factory = NoDemo ) #-- Traits View Definitions ------------------------------------------------ view = View( Item( 'demo', id = 'demo', show_label = False, style = 'custom', resizable = True ), id = 'enthought.tutor.demo', resizable = True ) #------------------------------------------------------------------------------- # 'ATutorialItem' class: #------------------------------------------------------------------------------- class ATutorialItem ( HasPrivateTraits ): """ Defines the abstract base class for each type of item (HTML, Flash, text, code) displayed within the tutor. """ #-- Traits Definitions ----------------------------------------------------- # The title for the item: title = Str # The path to the item: path = File # The displayable content for the item: content = Property #------------------------------------------------------------------------------- # 'ADescriptionItem' class: #------------------------------------------------------------------------------- class ADescriptionItem ( ATutorialItem ): """ Defines a common base class for all description items. """ #-- Event Handlers --------------------------------------------------------- def _path_changed ( self, path ): """ Sets the title for the item based on the item's path name. """ self.title = title_for( os.path.splitext( os.path.basename( path ) )[0] ) #------------------------------------------------------------------------------- # 'HTMLItem' class: #------------------------------------------------------------------------------- class HTMLItem ( ADescriptionItem ): """ Defines a class used for displaying a single HTML page within the tutor using the default Traits HTML editor. """ #-- Traits Definitions ----------------------------------------------------- url = Str #-- Traits View Definitions ------------------------------------------------ view = View( Item( 'content', style = 'readonly', show_label = False, editor = HTMLEditor() ) ) #-- Event Handlers --------------------------------------------------------- def _url_changed ( self, url ): """ Sets the item title when the 'url' is changed. """ match = url_pat1.match( url ) if match is not None: title = match.group(2).strip() else: title = url.strip() col = title.rfind( '/' ) if col >= 0: title = os.path.splitext( title[ col + 1: ] )[0] self.title = title #-- Property Implementations ----------------------------------------------- @cached_property def _get_content ( self ): """ Returns the item content. """ url = self.url if url != '': match = url_pat1.match( url ) if match is not None: url = match.group(1) + match.group(3) return url return read_file( self.path ) def _set_content ( self, content ): """ Sets the item content. """ self._content = content #------------------------------------------------------------------------------- # 'HTMLStrItem' class: #------------------------------------------------------------------------------- class HTMLStrItem ( HTMLItem ): """ Defines a class used for displaying a single HTML text string within the tutor using the default Traits HTML editor. """ # Make the content a real trait rather than a property: content = Str #------------------------------------------------------------------------------- # 'IEHTMLItem' class: #------------------------------------------------------------------------------- class IEHTMLItem ( HTMLItem ): """ Defines a class used for displaying a single HTML page within the tutor using the Traits Internet Explorer HTML editor. """ #-- Traits View Definitions ------------------------------------------------ view = View( Item( 'content', style = 'readonly', show_label = False, editor = IEHTMLEditor() ) ) #------------------------------------------------------------------------------- # 'IEHTMLStrItem' class: #------------------------------------------------------------------------------- class IEHTMLStrItem ( IEHTMLItem ): """ Defines a class used for displaying a single HTML text string within the tutor using the Traits Internet Explorer HTML editor. """ # Make the content a real trait rather than a property: content = Str #------------------------------------------------------------------------------- # 'FlashItem' class: #------------------------------------------------------------------------------- class FlashItem ( HTMLItem ): """ Defines a class used for displaying a Flash-based animation or video within the tutor. """ #-- Traits View Definitions ------------------------------------------------ view = View( Item( 'content', style = 'readonly', show_label = False, editor = FlashEditor() ) ) #------------------------------------------------------------------------------- # 'TextItem' class: #------------------------------------------------------------------------------- class TextItem ( ADescriptionItem ): """ Defines a class used for displaying a text file within the tutor. """ #-- Traits View Definitions ------------------------------------------------ view = View( Item( 'content', style = 'readonly', show_label = False, editor = CodeEditor( show_line_numbers = False, selected_color = 0xFFFFFF ) ) ) #-- Property Implementations ----------------------------------------------- @cached_property def _get_content ( self ): """ Returns the item content. """ return read_file( self.path ) #------------------------------------------------------------------------------- # 'TextStrItem' class: #------------------------------------------------------------------------------- class TextStrItem ( TextItem ): """ Defines a class used for displaying a text file within the tutor. """ # Make the content a real trait, rather than a property: content = Str #------------------------------------------------------------------------------- # 'CodeItem' class: #------------------------------------------------------------------------------- class CodeItem ( ATutorialItem ): """ Defines a class used for displaying a Python source code fragment within the tutor. """ #-- Trait Definitions ------------------------------------------------------ # The displayable content for the item (override): content = Str # The starting line of the code snippet within the original file: start_line = Int # The currently selected line: selected_line = Int # Should this section normally be hidden? hidden = Bool #-- Traits View Definitions ------------------------------------------------ view = View( Item( 'content', style = 'custom', show_label = False, editor = CodeEditor( selected_line = 'selected_line' ) ) ) #------------------------------------------------------------------------------- # 'ASection' abstract base class: #------------------------------------------------------------------------------- class ASection ( HasPrivateTraits ): """ Defines an abstract base class for a single section of a tutorial. """ #-- Traits Definitions ----------------------------------------------------- # The title of the section: title = Str # The path to this section: path = Directory # The parent section of this section (if any): parent = Instance( 'ASection' ) # Optional table of contents (can be used to define/locate the subsections): toc = List( Str ) # The path to the CSS style sheet to use for this section: css_path = Property # The list of subsections contained in this section: subsections = Property # List( ASection ) # This section can be executed: is_runnable = Bool( True ) # Should the Python code be automatically executed on start-up? auto_run = Bool( False ) #-- Property Implementations ----------------------------------------------- @cached_property def _get_subsections ( self ): """ Returns the subsections for this section: """ if len( self.toc ) > 0: self._load_toc() else: self._load_dirs() # Return the cached list of sections: return self._subsections @cached_property def _get_css_path ( self ): """ Returns the path to the CSS style sheet for this section. """ return css_path_for( self.path, self.parent ) #-- Private Methods -------------------------------------------------------- def _load_dirs ( self ): """ Defines the section's subsections by analyzing all of the section's sub-directories. """ # No value cached yet: dirs = [] path = self.path # Find every sub-directory whose name begins with a number of the # form ddd, or ends with a number of the form _ddd.ddd (used for # sorting them into the correct presentation order): for name in os.listdir( path ): dir = os.path.join( path, name ) if os.path.isdir( dir ): match = dir_pat1.match( name ) if match is not None: dirs.append( ( float( match.group(1) ), match.group(2), dir ) ) else: match = dir_pat2.match( name ) if match is not None: dirs.append( ( float( match.group(2) ), match.group(1), dir ) ) # Sort the directories by their index value: dirs.sort( lambda l, r: cmp( l[0], r[0] ) ) # Create the appropriate type of section for each valid directory: self._subsections = [ sf.section for sf in [ SectionFactory( title = title_for( title ), parent = self ).set( path = dir ) for index, title, dir in dirs ] if sf.section is not None ] def _load_toc ( self ): """ Defines the section's subsections by finding matches for the items defined in the section's table of contents. """ toc = self.toc base_names = [ item.split( ':', 1 )[0] for item in toc ] subsections = [ None ] * len( base_names ) path = self.path # Classify all file names that match a base name in the table of # contents: for name in os.listdir( path ): try: base_name = os.path.splitext( os.path.basename( name ) )[0] index = base_names.index( base_name ) if subsections[ index ] is None: subsections[ index ] = [] subsections[ index ].append( name ) except: pass # Try to convert each group of names into a section: for i, names in enumerate( subsections ): # Only process items for which we found at least one matching file # name: if names is not None: # Get the title for the section from its table of contents # entry: parts = toc[i].split( ':', 1 ) if len( parts ) == 1: title = title_for( parts[0].strip() ) else: title = parts[1].strip() # Handle an item with one file which is a directory as a normal # section: if len( names ) == 1: dir = os.path.join( path, names[0] ) if os.path.isdir( dir ): subsections[i] = SectionFactory( title = title, parent = self ).set( path = dir ).section continue # Otherwise, create a section from the list of matching files: subsections[i] = SectionFactory( title = title, parent = self, files = names ).set( path = path ).section # Set the subsections to the non-None values that are left: self._subsections = [ subsection for subsection in subsections if subsection is not None ] #------------------------------------------------------------------------------- # 'Lecture' class: #------------------------------------------------------------------------------- class Lecture ( ASection ): """ Defines a lecture, which is a section of a tutorial with descriptive information, but no associated Python code. Can be used to provide course overviews, introductory sections, or lead-ins to follow-on lessons or labs. """ #-- Trait Definitions------------------------------------------------------- # The list of descriptive items for the lecture: descriptions = List( ATutorialItem ) # This section can be executed (override): is_runnable = False #-- Traits View Definitions ------------------------------------------------ view = View( Item( 'descriptions', style = 'custom', show_label = False, editor = list_editor ), id = 'enthought.tutor.lecture' ) #------------------------------------------------------------------------------- # 'LabHandler' class: #------------------------------------------------------------------------------- class LabHandler ( Handler ): """ Defines the controller functions for the Lab view. """ def init ( self, info ): """ Handles initialization of the view. """ # Run the associated Python code if the 'auto-run' feature is enabled: if info.object.auto_run: info.object.run_code() #------------------------------------------------------------------------------- # 'Lab' class: #------------------------------------------------------------------------------- class Lab ( ASection ): """ Defines a lab, which is a section of a tutorial with only Python code. This type of section might typically follow a lecture which introduced the code being worked on in the lab. """ #-- Trait Definitions------------------------------------------------------- # The set-up code (if any) for the lab: setup = Instance( CodeItem ) # The list of code items for the lab: snippets = List( CodeItem ) # The list of visible code items for the lab: visible_snippets = Property( depends_on = 'visible', cached = True ) # The currently selected snippet: snippet = Instance( CodeItem ) # Should normally hidden code items be shown? visible = Bool( False ) # The dictionary containing the items from the Python code execution: values = Dict #Any( {} ) # The run Python code button: run = Button( image = ImageResource( 'run' ), height_padding = 1 ) # User error message: message = Str # The output produced while the program is running: output = Str # The current demo pane (if any): demo = Instance( DemoPane, () ) #-- Traits View Definitions ------------------------------------------------ view = View( VSplit( VGroup( Item( 'visible_snippets', style = 'custom', show_label = False, editor = snippet_editor ), HGroup( Item( 'run', style = 'custom', show_label = False, tooltip = 'Run the Python code' ), '_', Item( 'message', springy = True, show_label = False, editor = TitleEditor() ), '_', Item( 'visible', label = 'View hidden sections' ) ), ), Tabbed( Item( 'values', id = 'values_1', label = 'Shell', editor = ShellEditor( share = True ), dock = 'tab', export = 'DockWindowShell' ), Item( 'values', id = 'values_2', editor = ValueEditor(), dock = 'tab', export = 'DockWindowShell' ), Item( 'output', style = 'readonly', editor = CodeEditor( show_line_numbers = False, selected_color = 0xFFFFFF ), dock = 'tab', export = 'DockWindowShell' ), Item( 'demo', id = 'demo', style = 'custom', resizable = True, dock = 'tab', export = 'DockWindowShell' ), show_labels = False, ), id = 'splitter', ), id = 'enthought.tutor.lab', handler = LabHandler ) #-- Event Handlers --------------------------------------------------------- def _run_changed ( self ): """ Runs the current set of snippet code. """ self.run_code() #-- Property Implementations ----------------------------------------------- @cached_property def _get_visible_snippets ( self ): """ Returns the list of code items that are currently visible. """ if self.visible: return self.snippets return [ snippet for snippet in self.snippets if (not snippet.hidden) ] #-- Public Methods --------------------------------------------------------- def run_code ( self ): """ Runs all of the code snippets associated with the section. """ # Reconstruct the lab code from the current set of code snippets: start_line = 1 module = '' for snippet in self.snippets: snippet.start_line = start_line module = '%s\n\n%s' % ( module, snippet.content ) start_line += (snippet.content.count( '\n' ) + 2) # Reset any syntax error and message log values: self.message = self.output = '' # Redirect standard out and error to the message log: stdout, stderr = sys.stdout, sys.stderr sys.stdout = sys.stderr = StdOut( self ) try: try: # Get the execution context dictionary: values = self.values # Clear out any special variables defined by the last run: for name in ( 'demo', 'popup' ): if isinstance( values.get( name ), HasTraits ): del values[ name ] # Execute the current lab code: exec module[2:] in values, values # fixme: Hack trying to update the Traits UI view of the dict. self.values = {} self.values = values # Handle a 'demo' value being defined: demo = values.get( 'demo' ) if not isinstance( demo, HasTraits ): demo = NoDemo() self.demo.demo = demo # Handle a 'popup' value being defined: popup = values.get( 'popup' ) if isinstance( popup, HasTraits ): popup.edit_traits( kind = 'livemodal' ) except SyntaxError, excp: # Convert the line number of the syntax error from one in the # composite module to one in the appropriate code snippet: line = excp.lineno if line is not None: snippet = self.snippets[0] for s in self.snippets: if s.start_line > line: break snippet = s line -= (snippet.start_line - 1) # Highlight the line in error: snippet.selected_line = line # Select the correct code snippet: self.snippet = snippet # Display the syntax error message: self.message = '%s in column %s of line %s' % ( excp.msg.capitalize(), excp.offset, line ) else: # Display the syntax error message without line # info: self.message = excp.msg.capitalize() except: import traceback traceback.print_exc() finally: # Restore standard out and error to their original values: sys.stdout, sys.stderr = stdout, stderr #------------------------------------------------------------------------------- # 'Lesson' class: #------------------------------------------------------------------------------- class Lesson ( Lab ): """ Defines a lesson, which is a section of a tutorial with both descriptive information and associated Python code. """ #-- Trait Definitions------------------------------------------------------- # The list of descriptive items for the lesson: descriptions = List( ATutorialItem ) #-- Traits View Definitions ------------------------------------------------ view = View( HSplit( Item( 'descriptions', label = 'Lesson', style = 'custom', show_label = False, dock = 'horizontal', editor = list_editor ), VSplit( VGroup( Item( 'visible_snippets', style = 'custom', show_label = False, editor = snippet_editor ), HGroup( Item( 'run', style = 'custom', show_label = False, tooltip = 'Run the Python code' ), '_', Item( 'message', springy = True, show_label = False, editor = TitleEditor() ), '_', Item( 'visible', label = 'View hidden sections' ) ), label = 'Lab', dock = 'horizontal' ), Tabbed( Item( 'values', id = 'values_1', label = 'Shell', editor = ShellEditor( share = True ), dock = 'tab', export = 'DockWindowShell' ), Item( 'values', id = 'values_2', editor = ValueEditor(), dock = 'tab', export = 'DockWindowShell' ), Item( 'output', style = 'readonly', editor = CodeEditor( show_line_numbers = False, selected_color = 0xFFFFFF ), dock = 'tab', export = 'DockWindowShell' ), Item( 'demo', id = 'demo', style = 'custom', resizable = True, dock = 'tab', export = 'DockWindowShell' ), show_labels = False, ), label = 'Lab', dock = 'horizontal' ), id = 'splitter', ), id = 'enthought.tutor.lesson', handler = LabHandler ) #------------------------------------------------------------------------------- # 'Demo' class: #------------------------------------------------------------------------------- class Demo ( Lesson ): """ Defines a demo, which is a section of a tutorial with both descriptive information and associated Python code which is executed but not shown. """ #-- Traits View Definitions ------------------------------------------------ view = View( HSplit( Item( 'descriptions', label = 'Lesson', style = 'custom', show_label = False, dock = 'horizontal', editor = list_editor ), Item( 'demo', id = 'demo', style = 'custom', show_label = False, resizable = True, dock = 'horizontal', export = 'DockWindowShell' ), id = 'splitter', ), id = 'enthought.tutor.demo', handler = LabHandler ) #------------------------------------------------------------------------------- # 'SectionFactory' class: #------------------------------------------------------------------------------- class SectionFactory ( HasPrivateTraits ): """ Defines a class that creates Lecture, Lesson or Lab sections (or None), based on the content of a specified directory. None is returned if the directory does not contain any recognized files. """ #-- Traits Definitions ----------------------------------------------------- # The path the section is to be created for: path = Directory # The list of files contained in the section: files = List( Str ) # The parent of the section being created: parent = Instance( ASection ) # The section created from the path: section = Instance( ASection ) # The title for the section: title = Str # The optional table of contents for the section: toc = List( Str ) # The list of descriptive items for the section: descriptions = List( ADescriptionItem ) # The list of code snippet items for the section: snippets = List( CodeItem ) # The path to the CSS style sheet for the section: css_path = Property # Should the Python code be automatically executed on start-up? auto_run = Bool( False ) #-- Event Handlers --------------------------------------------------------- def _path_changed ( self, path ): """ Creates the appropriate section based on the value of the path. """ # Get the list of files to process: files = self.files if len( files ) == 0: # If none were specified, then use all files in the directory: files = os.listdir( path ) # Process the description file (if any) first: for name in files: if os.path.splitext( name )[1] == '.desc': self._add_desc_item( os.path.join( path, name ) ) break # Try to convert each file into one or more 'xxxItem' objects: toc = [ item.split( ':', 1 )[0].strip() for item in self.toc ] for name in files: file_name = os.path.join( path, name ) # Only process the ones that are actual files: if os.path.isfile( file_name ): # Use the file extension to determine the file's type: root, ext = os.path.splitext( name ) if (root not in toc) and (len( ext ) > 1): # If we have a handler for the file type, invoke it: method = getattr( self, '_add_%s_item' % ext[1:].lower(), None ) if method is not None: method( file_name ) # Based on the type of items created (if any), create the corresponding # type of section: if len( self.descriptions ) > 0: if len( self.snippets ) > 0: if len( [ snippet for snippet in self.snippets if (not snippet.hidden) ] ) > 0: self.section = Lesson( title = self.title, path = path, toc = self.toc, parent = self.parent, descriptions = self.descriptions, snippets = self.snippets, auto_run = self.auto_run ) else: self.section = Demo( title = self.title, path = path, toc = self.toc, parent = self.parent, descriptions = self.descriptions, snippets = self.snippets, auto_run = True ) else: self.section = Lecture( title = self.title, path = path, toc = self.toc, parent = self.parent, descriptions = self.descriptions ) elif len( self.snippets ) > 0: self.section = Lab( title = self.title, path = path, toc = self.toc, parent = self.parent, snippets = self.snippets, auto_run = self.auto_run ) else: # No descriptions or code snippets were found. Create a lecture # anyway: section = Lecture( title = self.title, path = path, toc = self.toc, parent = self.parent ) # If the lecture has subsections, then return the lecture and add # a default item containing a description of the subsections of the # lecture: if len( section.subsections ) > 0: self._create_html_item( path = path, content = DefaultLecture % ( '\n'.join( [ '
  • %s
  • ' % subsection.title for subsection in section.subsections ] ) ) ) section.descriptions = self.descriptions self.section = section #-- Property Implementations ----------------------------------------------- def _get_css_path ( self ): """ Returns the path to the CSS style sheet for the section. """ return css_path_for( self.path, self.parent ) #-- Factory Methods for Creating Section Items Based on File Type ---------- def _add_py_item ( self, path ): """ Creates the code snippets for a Python source file. """ source = read_file( path ) if source is not None: lines = source.replace( '\r', '' ).split( '\n' ) start_line = 0 title = 'Prologue' type = IsCode for i, line in enumerate( lines ): match = section_pat1.match( line ) if match is not None: next_type = IsCode else: match = section_pat2.match( line ) if match is not None: next_type = IsHiddenCode else: next_type = IsDescription match = section_pat3.match( line ) if match is not None: self._add_snippet( title, path, lines, start_line, i - 1, type ) start_line = i + 1 title = match.group(1).strip() type = next_type self._add_snippet( title, path, lines, start_line, i, type ) def _add_txt_item ( self, path ): """ Creates a description item for a normal text file. """ self.descriptions.append( TextItem( path = path ) ) def _add_htm_item ( self, path ): """ Creates a description item for an HTML file. """ # Check if there is a corresponding .rst (restructured text) file: dir, base_name = os.path.split( path ) rst = os.path.join( dir, os.path.splitext( base_name )[0] + '.rst' ) # If no .rst file exists, just add the file as a normal HTML file: if not os.path.isfile( rst ): self._create_html_item( path = path ) def _add_html_item ( self, path ): """ Creates a description item for an HTML file. """ self._add_htm_item( path ) def _add_url_item ( self, path ): """ Creates a description item for a file containing URLs. """ data = read_file( path ) if data is not None: for url in [ line for line in data.split( '\n' ) if line.strip()[:1] not in ( '', '#' ) ]: self._create_html_item( url = url.strip() ) def _add_rst_item ( self, path ): """ Creates a description item for a ReSTructured text file. """ # If docutils is not installed, just process the file as an ordinary # text file: try: from docutils.core import publish_cmdline except: self._add_txt_item( path ) return # Get the name of the HTML file we will write to: dir, base_name = os.path.split( path ) html = os.path.join( dir, os.path.splitext( base_name )[0] + '.htm' ) # Try to find a CSS style sheet, and set up the docutil overrides if # found: settings = {} css_path = self.css_path if css_path != '': css_path = os.path.join( self.path, css_path ) settings[ 'stylesheet_path' ] = css_path settings[ 'embed_stylesheet' ] = True settings[ 'stylesheet' ] = None else: css_path = path # If the HTML file does not exist, or is older than the restructured # text file, then let docutils convert it to HTML: is_file = os.path.isfile( html ) if ((not is_file) or (os.path.getmtime( path ) > os.path.getmtime( html )) or (os.path.getmtime( css_path ) > os.path.getmtime( html ))): # Delete the current HTML file (if any): if is_file: os.remove( html ) # Let docutils create a new HTML file from the restructured text # file: publish_cmdline( writer_name = 'html', argv = [ path, html ], settings_overrides = settings ) if os.path.isfile( html ): # If there is now a valid HTML file, use it: self._create_html_item( path = html ) else: # Otherwise, just use the original restructured text file: self._add_txt_item( path ) def _add_swf_item ( self, path ): """ Creates a description item for a Flash file. """ if is_windows: self.descriptions.append( FlashItem( path = path ) ) def _add_mov_item ( self, path ): """ Creates a description item for a QuickTime movie file. """ path2 = path.replace( ':', '|' ) self._create_html_item( path = path, content = QTMovieTemplate % ( path2, path2 ) ) def _add_wmv_item ( self, path ): """ Creates a description item for a Windows movie file. """ self._create_html_item( path = path, content = WMVMovieTemplate % ( path, path ) ) def _add_avi_item ( self, path ): """ Creates a description item for an AVI movie file. """ self._add_wmv_item( path ) def _add_jpg_item ( self, path ): """ Creates a description item for a JPEG image file. """ self._create_html_item( path = path, content = ImageTemplate % path ) def _add_jpeg_item ( self, path ): """ Creates a description item for a JPEG image file. """ self._add_jpg_item( path ) def _add_png_item ( self, path ): """ Creates a description item for a PNG image file. """ self._add_jpg_item( path ) def _add_mp3_item ( self, path ): """ Creates a description item for an mp3 audio file. """ self._create_html_item( path = path, content = MP3Template % path ) def _add_desc_item ( self, path ): """ Creates a section title from a description file. """ # If we've already processed a description file, then we're done: if len( self.toc ) > 0: return lines = [] desc = read_file( path ) if desc is not None: # Split the file into lines and save the non-empty, non-comment # lines: for line in desc.split( '\n' ): line = line.strip() if (len( line ) > 0) and (line[0] != '#'): lines.append( line ) if len( lines ) == 0: # If the file didn't have anything useful in it, set a title based # on the description file name: self.title = title_for( os.path.splitext( os.path.basename( path ) )[0] ) else: # Otherwise, set the title and table of contents from the lines in # the file: self.title = lines[0] self.toc = lines[1:] #-- Private Methods -------------------------------------------------------- def _add_snippet ( self, title, path, lines, start_line, end_line, type ): """ Adds a new code snippet or restructured text item to the list of code snippet or description items. """ # Trim leading and trailing blank lines from the snippet: while start_line <= end_line: if lines[ start_line ].strip() != '': break start_line += 1 while end_line >= start_line: if lines[ end_line ].strip() != '': break end_line -= 1 # Only add if the snippet is not empty: if start_line <= end_line: # Check for the title containing the 'auto-run' flag ('*'): if title[:1] == '*': self.auto_run = True title = title[1:].strip() if title[-1:] == '*': self.auto_run = True title = title[:-1].strip() # Extract out just the lines we will use: content_lines = lines[ start_line: end_line + 1 ] if type == IsDescription: # Add the new restructured text description: self._add_description( content_lines, title ) else: # Add the new code snippet: self.snippets.append( CodeItem( title = title or 'Code', path = path, hidden = (type == IsHiddenCode), content = '\n'.join( content_lines ) ) ) def _add_description ( self, lines, title ): """ Converts a restructured text string to HTML and adds it as description item. """ # Scan the lines for any imbedded Python code that should be shown as # a separate snippet: i = 0 while i < len( lines ): if lines[i].strip()[-2:] == '::': i = self._check_embedded_code( lines, i + 1 ) else: i += 1 # Strip off any docstring style triple quotes (if necessary): content = '\n'.join( lines ).strip() if content[:3] in ( '"""', "'''" ): content = content[3:] if content[-3:] in ( '"""', "'''" ): content = content[:-3] content = content.strip() # If docutils is not installed, just add it as a text string item: try: from docutils.core import publish_string except: self.descriptions.append( TextStrItem( content = content, title = title ) ) return # Try to find a CSS style sheet, and set up the docutil overrides if # found: settings = {} css_path = self.css_path if css_path != '': css_path = os.path.join( self.path, css_path ) settings[ 'stylesheet_path' ] = css_path settings[ 'embed_stylesheet' ] = True settings[ 'stylesheet' ] = None # Convert it from restructured text to HTML: html = publish_string( content, writer_name = 'html', settings_overrides = settings ) # Choose the right HTML renderer: if is_windows: item = IEHTMLStrItem( content = html, title = title ) else: item = HTMLStrItem( content = html, title = title ) # Add the resulting item to the descriptions list: self.descriptions.append( item ) def _create_html_item ( self, **traits ): """ Creates a platform specific html item and adds it to the list of descriptions. """ if is_windows: item = IEHTMLItem( **traits ) else: item = HTMLItem( **traits ) self.descriptions.append( item ) def _check_embedded_code ( self, lines, start ): """ Checks for an embedded Python code snippet within a description. """ n = len( lines ) while start < n: line = lines[ start ].strip() if line == '': start += 1 continue if (line[:1] != '[') or (line[-1:] != ']'): break del lines[ start ] n -= 1 title = line[1:-1].strip() line = lines[ start ] + '.' pad = len( line ) - len( line.strip() ) clines = [] while start < n: line = lines[ start ] + '.' len_line = len( line.strip() ) if (len_line > 1) and ((len( line ) - len_line) < pad): break if (len( clines ) > 0) or (len_line > 1): clines.append( line[ pad: -1 ] ) start += 1 # Add the new code snippet: self.snippets.append( CodeItem( title = title or 'Code', content = '\n'.join( clines ) ) ) break return start #------------------------------------------------------------------------------- # Tutor tree editor: #------------------------------------------------------------------------------- tree_editor = TreeEditor( nodes = [ TreeNode( children = 'subsections', label = 'title', rename = False, copy = False, delete = False, delete_me = False, insert = False, auto_open = True, auto_close = False, node_for = [ ASection ], icon_group = '' ) ], editable = False, auto_open = 1, selected = 'section' ) #------------------------------------------------------------------------------- # 'Tutor' class: #------------------------------------------------------------------------------- class Tutor ( HasPrivateTraits ): """ The main tutorial class which manages the presentation and navigation of the entire tutorial. """ #-- Trait Definitions ------------------------------------------------------ # The path to the files distributed with the tutor: home = Directory # The path to the root of the tutorial tree: path = Directory # The root of the tutorial lesson tree: root = Instance( ASection ) # The current section of the tutorial being displayed: section = Instance( ASection ) # The next section: next_section = Property( depends_on = 'section', cached = True ) # The previous section: previous_section = Property( depends_on = 'section', cached = True ) # The previous section button: previous = Button( image = ImageResource( 'previous' ), height_padding = 1 ) # The next section button: next = Button( image = ImageResource( 'next' ), height_padding = 1 ) # The parent section button: parent = Button( image = ImageResource( 'parent' ), height_padding = 1 ) # The reload tutor button: reload = Button( image = ImageResource( 'reload' ), height_padding = 1 ) # The title of the current session: title = Property( depends_on = 'section' ) #-- Traits View Definitions ------------------------------------------------ view = View( VGroup( HGroup( Item( 'previous', style = 'custom', enabled_when = 'previous_section is not None', tooltip = 'Go to previous section' ), Item( 'parent', style = 'custom', enabled_when = '(section is not None) and ' '(section.parent is not None)', tooltip = 'Go up one level' ), Item( 'next', style = 'custom', enabled_when = 'next_section is not None', tooltip = 'Go to next section' ), '_', Item( 'title', springy = True, editor = TitleEditor() ), '_', Item( 'reload', style = 'custom', tooltip = 'Reload the tutorial' ), show_labels = False ), '_', HSplit( Item( 'root', label = 'Table of Contents', editor = tree_editor, dock = 'horizontal', export = 'DockWindowShell' ), Item( 'section', id = 'section', label = 'Current Lesson', style = 'custom', resizable = True, dock = 'horizontal' ), id = 'splitter', show_labels = False ) ), title = 'Python Tutor', id = 'dmorrill.tutor.tutor:1.0', buttons = NoButtons, resizable = True, width = 0.8, height = 0.8 ) #-- Event Handlers --------------------------------------------------------- def _path_changed ( self, path ): """ Handles the tutorial root path being changed. """ self.init_tutor() def _next_changed ( self ): """ Displays the next tutorial section. """ self.section = self.next_section def _previous_changed ( self ): """ Displays the previous tutorial section. """ self.section = self.previous_section def _parent_changed ( self ): """ Displays the parent of the current tutorial section. """ self.section = self.section.parent def _reload_changed ( self ): """ Reloads the tutor from the original path specified. """ self.init_tutor() #-- Property Implementations ----------------------------------------------- @cached_property def _get_next_section ( self ): """ Returns the next section of the tutorial. """ next = None section = self.section if len( section.subsections ) > 0: next = section.subsections[0] else: parent = section.parent while parent is not None: index = parent.subsections.index( section ) if index < (len( parent.subsections ) - 1): next = parent.subsections[ index + 1 ] break parent, section = parent.parent, parent return next @cached_property def _get_previous_section ( self ): """ Returns the previous section of the tutorial. """ previous = None section = self.section parent = section.parent if parent is not None: index = parent.subsections.index( section ) if index > 0: previous = parent.subsections[ index - 1 ] while len( previous.subsections ) > 0: previous = previous.subsections[-1] else: previous = parent return previous def _get_title ( self ): """ Returns the title of the current section. """ section = self.section if section is None: return '' return ('%s: %s' % ( section.__class__.__name__, section.title )) #-- Public Methods --------------------------------------------------------- def init_tutor ( self ): """ Initials the tutor by creating the root section from the specified path. """ path = self.path title = title_for( os.path.splitext( os.path.basename( path ) )[0] ) section = SectionFactory( title = title ).set( path = path ).section if section is not None: self.section = self.root = section #------------------------------------------------------------------------------- # Run the program: #------------------------------------------------------------------------------- # Only run the program if we were invoked from the command line: if __name__ == '__main__': # Validate the command line arguments: if len( sys.argv ) > 2: print Usage sys.exit( 1 ) # Determine the root path to use for the tutorial files: if len( sys.argv ) == 2: path = sys.argv[1] else: path = os.getcwd() # Create a tutor and display the tutorial: tutor = Tutor( home = os.path.dirname( sys.argv[0] ) ).set( path = path ) if tutor.root is not None: tutor.configure_traits() else: print """No traits tutorial found in %s. Correct usage is: python tutor.py [tutorial_path] where: tutorial_path = Path to the root of the traits tutorial. If tutorial_path is omitted, the current directory is assumed to be the root of the tutorial.""" % path traitsui-4.1.0/examples/tutorials/traitsui_4.0/0000755000175100001440000000000011674463545022451 5ustar ischnellusers00000000000000traitsui-4.1.0/examples/tutorials/traitsui_4.0/buttons.py0000644000175100001440000000465011674463545024526 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. #--(View Default Button Changes)------------------------------------------------ """ View Default Button Changes =========================== For the last year or so, use of the following **View** traits for managing the default buttons displayed at the bottom of a view has been deprecated: - apply - revert - undo - ok - cancel Use of these traits has been supplanted by use of the *buttons* trait instead. As part of the ongoing phasing out of these traits, the following changes have been implemented in Traits 3.0: - All use of the *apply*, *revert*, *undo*, *ok* and *cancel* traits have been removed from views contained within the traits package itself, and have been replaced with the *buttons* trait. - The default value for each of the deprecated traits has been changed from **True** to **False**. While use of the deprecated **View** traits is still allowed at the moment, the affect of these changes could cause changes in behavior within existing code that has not yet removed references to the deprecated traits. In particular, the most likely side effect is for some or all of the default **View** buttons to disappear from views which are implicitly relying on the default values for each of the deprecated traits. Views which explicitly set the deprecated **View** traits or use the newer *buttons* trait should not be affected. The correct fix for any **View** which has buttons disappear after installing Traits 3.0 is to add a *buttons* trait with the correct value set to the **View**. Note that in a future release, the deprecated view traits will actually be removed from the **View** class. """ #---------------------------------------------------------------------- from traits.api import * from traitsui.api import * #--[Adder Class]---------------------------------------------------------------- # Click the run button to view the pop-up dialog... class Adder ( HasTraits ): value_1 = Float value_2 = Float sum = Property( depends_on = [ 'value_1', 'value_2' ] ) view = View( Item( 'value_1' ), Item( 'value_2' ), '_', Item( 'sum', style = 'readonly' ), title = 'Adding Machine', buttons = [ 'OK' ] ) def _get_sum ( self ): return (self.value_1 + self.value_2) #---------------------------------------------------------------------- popup = Adder() traitsui-4.1.0/examples/tutorials/traitsui_4.0/items.py0000644000175100001440000002170311674463545024147 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. #--(Extended Traits UI Item and Editor References)------------------------------ """ Extended Traits UI Item and Editor References ============================================= In Traits 3.0, the Traits UI **Item** class and various *editor* classes have been extended to use the new extended trait name support provided by the *on_trait_change* method. In previous Traits versions, for example, **Item** objects could only refer to traits defined directly on a UI context object. For example:: view = View( Item( 'name' ), Item( 'object.age' ), Item( 'handler.status' ) ) In Traits 3.0 this restriction has been lifted, and now **Items** can reference (i.e. edit) any trait reachable from a UI context object:: view = View( Item( 'object.mother.name' ), Item( 'object.axel.chassis.serial_number', style = 'readonly' ) ) Similarly, any Traits UI *editor* classes that previously accepted a trait name now accept an extended trait name:: view = View( Item( 'address' ), Item( 'state', editor = EnumEditor( name = 'handler.country.states' ) ) Because **Items** and *editors* only refer to a single trait, you should not use extended trait references that refer to multiple traits, such as *'foo.[bar,baz]'* or *'foo.+editable'*, since the behavior of such references is not defined. Look at the code tabs for this lesson for a complete example of a Traits UI using extended **Item** and editor references. In particular, the **LeagueModelView Class** tab contains a **View** definition containing extended references. Code Incompatibilities ---------------------- Note that the editor enhancement may cause some incompatibities with editors that previously supported both an *object* and *name* trait, with the *object* trait containing the context object name, and the *name* trait containing the name of the trait on the specified context object. Using the new extended trait references, these have been combined into a single *name* trait. If you encounter such an occurrence in existing code, simply combine the context object name and trait name into a single extended name of the form:: context_object_name.trait_name Warning ------- Avoid extended **Item** references that contain intermediate links that could be *None*. For example, in the following code:: view = View( ... Item( 'object.team.players', ... ) ... ) an exception will be raised if *object.team* is *None*, or is set to *None*, while the view is active, since there is no obvious way to obtain a valid value for *object.team.players* for the associated **Item** *editor* to display. Note that the above example is borrowed from this lesson's demo code, which has additional code written to ensure that *object.team* is not *None*. See the *_model_changed* method in the **LeagueModelView Class** tab, which makes sure that the *team* trait is intialized to a valid value when a new **League** model is set up. """ #---------------------------------------------------------------------- from traits.api \ import * from traitsui.api \ import * from traitsui.table_column \ import * #--[Player Class]--------------------------------------------------------------- # Define a baseball player: class Player ( HasTraits ): # The name of the player: name = Str( '' ) # The number of hits the player made this season: hits = Int #--[Team Class]----------------------------------------------------------------- # Define a baseball team: class Team ( HasTraits ): # The name of the team: name = Str( '' ) # The players on the team: players = List( Player ) # The number of players on the team: num_players = Property( depends_on = 'players' ) def _get_num_players ( self ): """ Implementation of the 'num_players' property. """ return len( self.players ) #--[League Class]--------------------------------------------------------------- # Define a baseball league model: class League ( HasTraits ): # The name of the league: name = Str( '' ) # The teams in the league: teams = List( Team ) #--[LeagueModelView Class]----------------------------------------------------- # Define a ModelView for a League model: class LeagueModelView ( ModelView ): # The currently selected team: team = Instance( Team ) # The currently selected player: player = Instance( Player ) # Button to add a hit to the current player: got_hit = Button( 'Got a Hit' ) # The total number of hits total_hits = Property( depends_on = 'model.teams.players.hits' ) @cached_property def _get_total_hits ( self ): """ Returns the total number of hits across all teams and players. """ return 0 return reduce( add, [ reduce( add, [ p.hits for p in t.players ], 0 ) for t in self.model.teams ], 0 ) view = View( VGroup( HGroup( Item( 'total_hits', style = 'readonly' ), label = 'League Statistics', show_border = True ), VGroup( Item( 'model.teams', show_label = False, editor = TableEditor( columns = [ ObjectColumn( name = 'name', width = 0.70 ), ObjectColumn( name = 'num_players', label = '# Players', editable = False, width = 0.29 ) ], selected = 'object.team', auto_add = True, row_factory = Team, configurable = False, sortable = False ) ), label = 'League Teams', show_border = True ), VGroup( Item( 'object.team.players', # <-- Extended Item name show_label = False, editor = TableEditor( columns = [ ObjectColumn( name = 'name', width = 0.70 ), ObjectColumn( name = 'hits', editable = False, width = 0.29 ) ], selected = 'object.player', auto_add = True, row_factory = Player, configurable = False, sortable = False ) ), '_', HGroup( Item( 'got_hit', show_label = False, enabled_when = 'player is not None' ) ), label = 'Team Players', show_labels = False, show_border = True ) ), resizable = True ) def _model_changed ( self, model ): """ Handles the 'league' model being initialized. """ if len( model.teams ) > 0: self.team = model.teams[0] def _got_hit_changed ( self ): """ Handles the currently selected player making a hit. """ self.player.hits += 1 def _team_changed ( self, team ): """ Handles a new team being selected. """ if len( team.players ) > 0: self.player = team.players[0] else: self.player = None # Function to add two numbers (used with 'reduce'): add = lambda a, b: a + b #--[Example*]------------------------------------------------------------------- # Define some sample teams and players: blue_birds = Team( name = 'Blue Birds', players = [ Player( name = 'Mike Scott', hits = 25 ), Player( name = 'Willy Shofield', hits = 37 ), Player( name = 'Tony Barucci', hits = 19 ) ] ) chicken_hawks = Team( name = 'Chicken Hawks', players = [ Player( name = 'Jimmy Domore', hits = 34 ), Player( name = 'Bill Janks', hits = 16 ), Player( name = 'Tim Saunders', hits = 27 ) ] ) eagles = Team( name = 'Eagles', players = [ Player( name = 'Joe Peppers', hits = 33 ), Player( name = 'Sam Alone', hits = 12 ), Player( name = 'Roger Clemson', hits = 23 ) ] ) # Create a league and its corresponding model view: demo = LeagueModelView( League( name = 'National Baseball Conference', teams = [ blue_birds, chicken_hawks, eagles ] ) ) traitsui-4.1.0/examples/tutorials/traitsui_4.0/default.css0000644000175100001440000000150011674463545024603 0ustar ischnellusers00000000000000body { background-color: #FFFFFF; } h1 { font-family: Arial; font-size: 14pt; color: #303030; background-color: #FCD062; padding-top: 3px; padding-left:8px; padding-bottom: 3px; padding-right: 8px; } h2 { font-family: Arial; font-size: 12pt; color: #303030; background-color: #FCD062; padding-top: 3px; padding-left:8px; padding-bottom: 3px; padding-right: 8px; } pre { border: 1px solid #A0A0A0; background-color: #FDF7E7; padding: 4px; } dl { border: 1px solid #A0A0A0; background-color: #FDF7E7; padding-top: 4px; padding-bottom: 6px; padding-left: 8px; padding-right: 8px; } dl dl { border: 0px solid #A0A0A0; } dt { font-family: Arial; font-weight: bold; dd { padding-bottom: 10px; } traitsui-4.1.0/examples/tutorials/traitsui_4.0/deferred.py0000644000175100001440000000511311674463545024603 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. #--(Deferred UI Notifications)-------------------------------------------------- """ Deferred UI Notifications ========================= In Traits 3.0, a change has been made to the way that events are handled in the Traits UI that should improve the performance and responsive of Traits-based user interfaces in certain important situations. In particular, changes made to the underlying model being displayed by a Traits UI are no longer reflected immediately in the user interface, but are instead queued up to be processed by the UI thread at its first available opportunity. More precisely, the first time that a user interface related model trait is modified, an event requesting a user interface update is generated containing the old and new values of the trait. Subsequent changes to the same model trait result in no new events being generated, but instead simply update the original event information with the latest value of the modified trait. Eventually the UI thread will process the original event, at which point it will update the user interface using the original old value of the trait along with the latest new value. Although this may sound like it should slow down user interface updates, in many cases where a model is being rapidly updated by calculations running either on a background or UI thread, it should actually appear to make the system more responsive, and should in fact, help prevent or reduce situations where the user interface would previously have appeared to be unresponsive due to an excessive number of screen updates. """ #---------------------------------------------------------------------- from traits.api import * from traitsui.api import * #--[Count Class]---------------------------------------------------------------- class Count ( HasTraits ): count = Int go = Button( 'Count' ) view = View( Item( 'count', style = 'readonly' ), Item( 'go', show_label = False ) ) def _go_changed ( self ): # Even though the 'count' trait (which is visible in the UI) is being # rapidly updated here, the UI should show only a single update each # time the 'Count' button is clicked. In previous Traits versions, the # user would actually see the counter update sequentially through all # 10,000 values, during which time the user interface would be # unresponsive: for i in range( 10000 ): self.count += 1 #--------------------------------------------------------------------- demo = Count() traitsui-4.1.0/examples/tutorials/traitsui_4.0/editors/0000755000175100001440000000000011674463545024122 5ustar ischnellusers00000000000000traitsui-4.1.0/examples/tutorials/traitsui_4.0/editors/flash.py0000644000175100001440000000454711674463545025603 0ustar ischnellusers00000000000000#--(Flash Editor (Windows Only))------------------------------------------------ """ Flash Editor (Windows Only) =========================== In Traits 3.0, a new **FlashEditor** has been added to the Traits UI package. The editor allows displaying and interacting with Adobe Flash compatible files. This editor is currently only available for the Windows platform and is located in the wxPython version of the Traits UI in the *traitsui.wx.extras.windows* package. The purpose of the *extras.windows* package is to provide a location for editors which may be toolkit and Windows platform specific, and not necessarily available in all Traits UI toolkit packages or platforms. The **FlashEditor** has no developer settable traits. The value edited by a **FlashEditor** should be a string containing either the URL or file name of the Flash file to display. This is a *read only* value that is not modified by the editor. Changing the value causes the editor to display the Flash file defined by the new value of the trait. """ #--[Imports]-------------------------------------------------------------------- from traitsui.wx.extra.windows.flash_editor \ import FlashEditor from traits.api \ import HasTraits, Enum from traitsui.api \ import View, HGroup, Item #--[FlashDemo Class]------------------------------------------------------------ class FlashDemo ( HasTraits ): # The Flash file to display: flash = Enum( 'http://www.ianag.com/arcade/swf/sudoku.swf', 'http://www.ianag.com/arcade/swf/f-336.swf', 'http://www.ianag.com/arcade/swf/f-3D-Reversi-1612.swf', 'http://www.ianag.com/arcade/swf/game_234.swf', 'http://www.ianag.com/arcade/swf/flashmanwm.swf', 'http://www.ianag.com/arcade/swf/2379_gyroball.swf', 'http://www.ianag.com/arcade/swf/f-1416.swf', 'http://www.ianag.com/arcade/swf/mah_jongg.swf', 'http://www.ianag.com/arcade/swf/game_e4fe4e55fedc2f502be627ee6df716c5.swf', 'http://www.ianag.com/arcade/swf/rhumb.swf' ) # The view to display: view = View( HGroup( Item( 'flash', label = 'Pick a game to play' ) ), '_', Item( 'flash', show_label = False, editor = FlashEditor() ) ) #--------------------------------------------------------------------- demo = FlashDemo() traitsui-4.1.0/examples/tutorials/traitsui_4.0/editors/led.py0000644000175100001440000000773711674463545025256 0ustar ischnellusers00000000000000#--(LED Editor)----------------------------------------------------------------- """ LED Editor ========== In Traits 3.0, a new **LEDEditor** has been added to the Traits UI package. The editor allows displaying (but not editing) numeric values using a set of simulated LEDs. This editor is currently only available in the wxPython version of the Traits UI in the *traitsui.wx.extras* package. The purpose of the *extras* package is to provide a location for editors which may be toolkit specific, and not necessarily available in all Traits UI toolkit packages. The traits supported by the **LEDEditor** editor are as follows: alignment Specifies the alignment of the numeric text within the control. The possible values are: *right* (the default), *left* and *center*. The value edited by an **LEDEditor** should be an integer or float value, or a string value containing only characters that would be found in an interger or float value. """ #--[Imports]-------------------------------------------------------------------- from threading \ import Thread from time \ import sleep from traits.api \ import HasTraits, Instance, Int, Float, Bool from traitsui.api \ import View, Item, HGroup, Handler, UIInfo, spring from traitsui.wx.extra.led_editor \ import LEDEditor #--[LEDDemoHandler Class]------------------------------------------------------- # Handler class for the LEDDemo class view: class LEDDemoHandler ( Handler ): # The UIInfo object associated with the UI: info = Instance( UIInfo ) # Is the demo currently running: running = Bool( True ) # Is the thread still alive? alive = Bool( True ) def init ( self, info ): self.info = info Thread( target = self._update_counter ).start() def closed ( self, info, is_ok ): self.running = False while self.alive: sleep( .05 ) def _update_counter ( self ): while self.running: self.info.object.counter1 += 1 self.info.object.counter2 += .001 sleep( .01 ) self.alive = False #--[LEDDemo Class]-------------------------------------------------------------- # The main demo class: class LEDDemo ( HasTraits ): # A counter to display: counter1 = Int # A floating point value to display: counter2 = Float # The traits view: view = View( Item( 'counter1', label = 'Left aligned', editor = LEDEditor( alignment = 'left' ) ), Item( 'counter1', label = 'Center aligned', editor = LEDEditor( alignment = 'center' ) ), Item( 'counter1', label = 'Right aligned', editor = LEDEditor() # default = 'right' aligned ), Item( 'counter2', label = 'Float value', editor = LEDEditor( format_str = '%.3f' ) ), '_', HGroup( Item( 'counter1', label = 'Left', height = -40, width = 120, editor = LEDEditor( alignment = 'left' ) ), spring, Item( 'counter1', label = 'Center', height = -40, width = 120, editor = LEDEditor( alignment = 'center' ) ), spring, Item( 'counter1', label = 'Right', height = -40, width = 120, editor = LEDEditor() # default = 'right' aligned ), spring, Item( 'counter2', label = 'Float', height = -40, width = 120, editor = LEDEditor( format_str = '%.3f' ) ) ), title = 'LED Editor Demo', buttons = [ 'OK' ], handler = LEDDemoHandler ) #--------------------------------------------------------------------- demo = LEDDemo() traitsui-4.1.0/examples/tutorials/traitsui_4.0/editors/ie_html.py0000644000175100001440000001460311674463545026121 0ustar ischnellusers00000000000000#--(Internet Explorer HTML Editor (Windows Only))------------------------------- """ Internet Explorer HTML Editor (Windows Only) ============================================ In Traits 3.0, a new **IEHTMLEditor** has been added to the Traits UI package. The editor allows displaying (but not editing) HTML pages using the Microsoft Internet Explorer browser. This editor is currently only available for the Windows platform and is located in the wxPython version of the Traits UI in the *traitsui.wx.extras.windows* package. The purpose of the *extras.windows* package is to provide a location for editors which may be toolkit and Windows platform specific, and not necessarily available in all Traits UI toolkit packages or platforms. The traits supported by the **IEHTMLEditor** editor are as follows: home A string specifying the optional extended name of a trait event used to tell Internet Explorer to display the user's home page. Set the specified trait to **True** to cause the browser to display the user's home page. back A string specifying the optional extended name of a trait event used to tell Internet Explorer to display the previous browser page. Set the specified trait to **True** to cause the browser to display the previous browser page. forward A string specifying the optional extended name of a trait event used to tell Internet Explorer to display the next (i.e. forward) browser page. Set the specified trait to **True** to cause the browser to display the next browser page (if available). stop A string specifying the optional extended name of a trait event used to tell Internet Explorer to stop loading the current page. Set the specified trait to **True** to cause the browser to stop loading the current page. refresh A string specifying the optional extended name of a trait event used to tell Internet Explorer to refresh the current page. Set the specified trait to **True** to cause the browser to refresh the current page. search A string specifying the optional extended name of a trait event used to tell Internet Explorer to initiate a search of the current page. Set the specified trait to **True** to cause the browser to start a search of the current page. status A string specifying the optional extended name of a trait used contain the current Internet Explorer status. This trait is automatically updated by the browser as its internal status changes. title A string specifying the optional extended name of a trait used contain the current Internet Explorer page title. This trait is automatically updated by the browser as the current page title is changed. page_loaded A string specifying the optional extended name of a trait used contain the URL of the current Internet Explorer page. This trait is automatically updated by the browser as a page is loaded. html A string specifying the optional extended name of a trait used to get or set the HTML page content of the current Internet Explorer page. This trait is automatically updated by the browser as a page is loaded, and can also be set by an application to cause the browser to display the content provided. The value edited by an **IEHTMLEditor** should be a string containing either the URL or file name of the file that Internet Explorer should display. This is a *read only* value that is not modified by the editor. Changing the value causes the browser to display the page defined by the new value of the trait. """ #--[Imports]-------------------------------------------------------------------- from traitsui.wx.extra.windows.ie_html_editor \ import IEHTMLEditor from traits.api \ import HasTraits, Str, List, Button from traitsui.api \ import View, VGroup, HGroup, Item, TextEditor, ListEditor, spring #--[WebPage Class]-------------------------------------------------------------- class WebPage ( HasTraits ): # The URL to display: url = Str( 'http://code.enthought.com' ) # The page title: title = Str # The page status: status = Str # The browser navigation buttons: back = Button( '<--' ) forward = Button( '-->' ) home = Button( 'Home' ) stop = Button( 'Stop' ) refresh = Button( 'Refresh' ) search = Button( 'Search' ) # The view to display: view = View( HGroup( 'back', 'forward', 'home', 'stop', 'refresh', 'search', '_', Item( 'status', style = 'readonly' ), show_labels = False ), Item( 'url', show_label = False, editor = IEHTMLEditor( home = 'home', back = 'back', forward = 'forward', stop = 'stop', refresh = 'refresh', search = 'search', title = 'title', status = 'status' ) ) ) #--[InternetExplorerDemo Class]------------------------------------------------- class InternetExplorerDemo ( HasTraits ): # A URL to display: url = Str( 'http://' ) # The list of web pages being browsed: pages = List( WebPage ) # The view to display: view = View( VGroup( Item( 'url', label = 'Location', editor = TextEditor( auto_set = False, enter_set = True ) ) ), Item( 'pages', show_label = False, style = 'custom', editor = ListEditor( use_notebook = True, deletable = True, dock_style = 'tab', export = 'DockWindowShell', page_name = '.title' ) ) ) # Event handlers: def _url_changed ( self, url ): self.pages.append( WebPage( url = url.strip() ) ) #--(Demo Notes)----------------------------------------------------------------- """ Demo Notes ========== - Try dragging one of the browser tabs completely out of the tutorial window and see what happens... - Then, just for fun, try dragging it back... """ #--------------------------------------------------------------------- demo = InternetExplorerDemo( pages = [ WebPage( url = 'http://code.enthought.com/traits/' ), WebPage( url = 'http://dmorrill.com' ) ] ) traitsui-4.1.0/examples/tutorials/traitsui_4.0/editors/tutorial.desc0000644000175100001440000000033611674463545026627 0ustar ischnellusers00000000000000New Traits UI Editors animated_gif: Animated GIF Editor led: LED Editor ie_html: Internet Explorer HTML Editor (Windows Only) flash: Flash Editor (Windows Only) tabular_editor: Tabular Editor traitsui-4.1.0/examples/tutorials/traitsui_4.0/editors/tabular_editor/0000755000175100001440000000000011674463545027122 5ustar ischnellusers00000000000000traitsui-4.1.0/examples/tutorials/traitsui_4.0/editors/tabular_editor/python_source_browser.py0000644000175100001440000001323011674463545034137 0ustar ischnellusers00000000000000#--(Python Source Browser Example)---------------------------------------------- """ This lesson shows a combination of the **DirectoryEditor**, the **TabularEditor** and the **CodeEditor** used together to create a very simple Python source browser. In the **Demo** tab you can: - Use the **DirectoryEditor** on the left to navigate to and select directories containing Python source files. - Use the **TabularEditor** on the top-right to view information about and to select Python source files in the currently selected directory. - View the currently selected Python source file's contents in the **CodeEditor** in the bottom-right. As an extra *feature*, the **TabularEditor** also displays a: - Red ball if the file size > 64KB. - Blue ball if the file size > 16KB. As with the *Single and Married Person Example* tutorial, this example shows you how to: - Set up a **TabularEditor**. - Define a **TabularAdapter** subclass that meets the display requirements of the application. In this example, please note the use of the *even_bg_color* trait in the **FileInfoAdapter** adapter class to set up alternating line colors in the table for improved readability. Also note that the *name*, *size*, *time* and *date* columns define *column_id* values which correspond directly with traits defined in the **FileInfo** class, but the *big* column id is an artifical column defined to display the file size related *blue ball* and *red ball* images when the file size exceeds various thresholds. The column id is used simply to provide a name reference for the related trait and property definitions in the adapter class itself. """ #---------------------------------------------------------------------- import traits import traitsui import wx from time \ import localtime, strftime from os \ import listdir from os.path \ import getsize, getmtime, isfile, join, splitext, basename, dirname from traits.api \ import HasPrivateTraits, Str, Float, List, Directory, File, Code, \ Instance, Property, cached_property from traitsui.api \ import View, Item, HSplit, VSplit, TabularEditor from traitsui.tabular_adapter \ import TabularAdapter from pyface.image_resource \ import ImageResource #-------------------------------------------------------------------- # Necessary because of the dynamic way in which the demos are loaded: search_path = [ join( dirname( traitsui.api.__file__ ), 'demo', 'Applications' ) ] #--[FileInfo Class]------------------------------------------------------------- class FileInfo ( HasPrivateTraits ): file_name = File name = Property size = Property time = Property date = Property @cached_property def _get_name ( self ): return basename( self.file_name ) @cached_property def _get_size ( self ): return getsize( self.file_name ) @cached_property def _get_time ( self ): return strftime( '%I:%M:%S %p', localtime( getmtime( self.file_name ) ) ) @cached_property def _get_date ( self ): return strftime( '%m/%d/%Y', localtime( getmtime( self.file_name ) ) ) #--[FileInfoAdapter Class]------------------------------------------------------ class FileInfoAdapter ( TabularAdapter ): columns = [ ( 'File Name', 'name' ), ( 'Size', 'size' ), ( '', 'big' ), ( 'Time', 'time' ), ( 'Date', 'date' ) ] even_bg_color = wx.Colour( 201, 223, 241 ) font = 'Courier 10' size_alignment = Str( 'right' ) time_alignment = Str( 'right' ) date_alignment = Str( 'right' ) big_text = Str big_width = Float( 18 ) big_image = Property def _get_big_image ( self ): size = self.item.size if size > 65536: return 'red_ball' return ( None, 'blue_ball' )[ size > 16384 ] #--[Tabular Editor Definition]-------------------------------------------------- tabular_editor = TabularEditor( editable = False, selected = 'file_info', adapter = FileInfoAdapter(), operations = [], images = [ ImageResource( 'blue_ball', search_path = search_path ), ImageResource( 'red_ball', search_path = search_path ) ] ) #--[PythonBrowser Class]-------------------------------------------------------- class PythonBrowser ( HasPrivateTraits ): dir = Directory files = List( FileInfo ) file_info = Instance( FileInfo ) code = Code view = View( HSplit( Item( 'dir', style = 'custom' ), VSplit( Item( 'files', editor = tabular_editor ), Item( 'code', style = 'readonly' ), show_labels = False ), show_labels = False ), resizable = True, width = 0.75, height = 0.75 ) #-- Event Handlers --------------------------------------------------------- def _dir_changed ( self, dir ): self.files = [ FileInfo( file_name = join( dir, name ) ) for name in listdir( dir ) if ((splitext( name )[1] == '.py') and isfile( join( dir, name ) )) ] def _file_info_changed ( self, file_info ): fh = None try: fh = open( file_info.file_name, 'rb' ) self.code = fh.read() except: pass if fh is not None: fh.close() #--[Example*]------------------------------------------------------------------- demo = PythonBrowser( dir = dirname( traits.api.__file__ ) ) traitsui-4.1.0/examples/tutorials/traitsui_4.0/editors/tabular_editor/sm_person_example.py0000644000175100001440000001624011674463545033217 0ustar ischnellusers00000000000000#--(Single/Married Person Example)---------------------------------------------- """ This lesson contains a tabular editor example based upon the **Person** and **MarriedPerson** example presented in the *Tabular Editor Introduction* tutorial. This example defines three main classes: - **Person**: A single person. - **MarriedPerson**: A married person (a subclass of **Person**). - **Report**: A report based on a list of single and married people. The example code creates a tabular display of 10,000 single and married people showing the following information: - Name of the person. - Age of the person. - The person's address. - The name of the person's spouse (if any). In addition: - It uses a Courier 10 point font for each line in the table. - It displays the age column right, instead of left, justified. - If a person is a minor (age < 18) and married, it displays a red flag image in the age column. - If the person is married, it makes the background color for that row a light blue. This example demonstrates: - How to set up a **TabularEditor**. - The display speed of the **TabularEditor**. - How to create a **TabularAdapter** that meets each of the specified display requirements. Additional notes: - You can change the current selection using the up and down arrow keys. - You can move a selected row up and down in the table using the left and right arrow keys. """ #---------------------------------------------------------------------- from os.path \ import join, dirname from random \ import randint, choice, shuffle from traits.api \ import HasTraits, Str, Int, List, Instance, Property, Constant, Color from traitsui.api \ import View, Group, Item, Margin, TabularEditor from traitsui.tabular_adapter \ import TabularAdapter from traitsui.menu \ import NoButtons from pyface.image_resource \ import ImageResource #-------------------------------------------------------------------- # Necessary because of the dynamic way in which the demos are loaded: import traitsui.api search_path = [ join( dirname( traitsui.api.__file__ ), 'demo', 'Advanced' ) ] #--[Person Class]--------------------------------------------------------------- class Person ( HasTraits ): name = Str address = Str age = Int #--[MarriedPerson Class]-------------------------------------------------------- class MarriedPerson ( Person ): partner = Instance( Person ) #--[Tabular Adapter Definition]------------------------------------------------- class ReportAdapter ( TabularAdapter ): columns = [ ( 'Name', 'name' ), ( 'Age', 'age' ), ( 'Address', 'address' ), ( 'Spouse', 'spouse' ) ] font = 'Courier 10' age_alignment = Constant( 'right' ) MarriedPerson_age_image = Property MarriedPerson_bg_color = Color( 0xE0E0FF ) MarriedPerson_spouse_text = Property Person_spouse_text = Constant( '' ) def _get_MarriedPerson_age_image ( self ): if self.item.age < 18: return 'red_flag' return None def _get_MarriedPerson_spouse_text ( self ): return self.item.partner.name #--[Tabular Editor Definition]-------------------------------------------------- tabular_editor = TabularEditor( adapter = ReportAdapter(), operations = [ 'move' ], images = [ ImageResource( 'red_flag', search_path = search_path ) ], ) #--[Report Class]--------------------------------------------------------------- class Report ( HasTraits ): people = List( Person ) view = View( Group( Item( 'people', id = 'table', editor = tabular_editor ), show_labels = False, ), title = 'Tabular Editor Demo', id = 'traitsui.demo.Applications.tabular_editor_demo', width = 0.60, height = 0.75, resizable = True, buttons = NoButtons ) #-------------------------------------------------------------- male_names = [ 'Michael', 'Edward', 'Timothy', 'James', 'George', 'Ralph', 'David', 'Martin', 'Bryce', 'Richard', 'Eric', 'Travis', 'Robert', 'Bryan', 'Alan', 'Harold', 'John', 'Stephen', 'Gael', 'Frederic', 'Eli', 'Scott', 'Samuel', 'Alexander', 'Tobias', 'Sven', 'Peter', 'Albert', 'Thomas', 'Horatio', 'Julius', 'Henry', 'Walter', 'Woodrow', 'Dylan', 'Elmer' ] female_names = [ 'Leah', 'Jaya', 'Katrina', 'Vibha', 'Diane', 'Lisa', 'Jean', 'Alice', 'Rebecca', 'Delia', 'Christine', 'Marie', 'Dorothy', 'Ellen', 'Victoria', 'Elizabeth', 'Margaret', 'Joyce', 'Sally', 'Ethel', 'Esther', 'Suzanne', 'Monica', 'Hortense', 'Samantha', 'Tabitha', 'Judith', 'Ariel', 'Helen', 'Mary', 'Jane', 'Janet', 'Jennifer', 'Rita', 'Rena', 'Rianna' ] all_names = male_names + female_names male_name = lambda: choice( male_names ) female_name = lambda: choice( female_names ) any_name = lambda: choice( all_names ) age = lambda: randint( 15, 72 ) family_name = lambda: choice( [ 'Jones', 'Smith', 'Thompson', 'Hayes', 'Thomas', 'Boyle', "O'Reilly", 'Lebowski', 'Lennon', 'Starr', 'McCartney', 'Harrison', 'Harrelson', 'Steinbeck', 'Rand', 'Hemingway', 'Zhivago', 'Clemens', 'Heinlien', 'Farmer', 'Niven', 'Van Vogt', 'Sturbridge', 'Washington', 'Adams', 'Bush', 'Kennedy', 'Ford', 'Lincoln', 'Jackson', 'Johnson', 'Eisenhower', 'Truman', 'Roosevelt', 'Wilson', 'Coolidge', 'Mack', 'Moon', 'Monroe', 'Springsteen', 'Rigby', "O'Neil", 'Philips', 'Clinton', 'Clapton', 'Santana', 'Midler', 'Flack', 'Conner', 'Bond', 'Seinfeld', 'Costanza', 'Kramer', 'Falk', 'Moore', 'Cramdon', 'Baird', 'Baer', 'Spears', 'Simmons', 'Roberts', 'Michaels', 'Stuart', 'Montague', 'Miller' ] ) address = lambda: '%d %s %s' % ( randint( 11, 999 ), choice( [ 'Spring', 'Summer', 'Moonlight', 'Winding', 'Windy', 'Whispering', 'Falling', 'Roaring', 'Hummingbird', 'Mockingbird', 'Bluebird', 'Robin', 'Babbling', 'Cedar', 'Pine', 'Ash', 'Maple', 'Oak', 'Birch', 'Cherry', 'Blossom', 'Rosewood', 'Apple', 'Peach', 'Blackberry', 'Strawberry', 'Starlight', 'Wilderness', 'Dappled', 'Beaver', 'Acorn', 'Pecan', 'Pheasant', 'Owl' ] ), choice( [ 'Way', 'Lane', 'Boulevard', 'Street', 'Drive', 'Circle', 'Avenue', 'Trail' ] ) ) people = [ Person( name = '%s %s' % ( any_name(), family_name() ), age = age(), address = address() ) for i in range( 5000 ) ] marrieds = [ ( MarriedPerson( name = '%s %s' % ( female_name(), last_name ), age = age(), address = address ), MarriedPerson( name = '%s %s' % ( male_name(), last_name ), age = age(), address = address ) ) for last_name, address in [ ( family_name(), address() ) for i in range( 2500 ) ] ] for female, male in marrieds: female.partner = male male.partner = female people.extend( [ female, male ] ) shuffle( people ) #--[Example Code*]-------------------------------------------------------------- demo = Report( people = people ) traitsui-4.1.0/examples/tutorials/traitsui_4.0/editors/tabular_editor/numpy_array.py0000644000175100001440000000573211674463545032051 0ustar ischnellusers00000000000000#--(NumPy Array Example)-------------------------------------------------------- """ This lesson demonstrates how the **TabularEditor** can be used to display (large) NumPy arrays. In this example, the array consists of 100,000 random 3D points from a unit cube. In addition to showing the coordinates of each point, the example code also displays the index of each point in the array, as well as a red flag if the point lies within 0.25 of the center of the cube. As with the other tabular editor tutorials, this example shows how to set up a **TabularEditor** and create an appropriate **TabularAdapter** subclass. In this case, it also shows: - An example of using array indices as *column_id* values. - Using the *format* trait to format the numeric values for display. - Creating a *synthetic* index column for displaying the point's array index (the *index_text* property), as well as a flag image for points close to the cube's center (the *index_image* property). """ #---------------------------------------------------------------------- from os.path \ import join, dirname from numpy \ import sqrt from numpy.random \ import random from traits.api \ import HasTraits, Property, Array from traitsui.api \ import View, Item, TabularEditor from traitsui.tabular_adapter \ import TabularAdapter from traitsui.menu \ import NoButtons from pyface.image_resource \ import ImageResource #-------------------------------------------------------------------- # Necessary because of the dynamic way in which the demos are loaded: import traitsui.api search_path = [ join( dirname( traitsui.api.__file__ ), 'demo', 'Advanced' ) ] #--[Tabular Adapter Definition]------------------------------------------------- class ArrayAdapter ( TabularAdapter ): columns = [ ( 'i', 'index' ), ( 'x', 0 ), ( 'y', 1 ), ( 'z', 2 ) ] font = 'Courier 10' alignment = 'right' format = '%.4f' index_text = Property index_image = Property def _get_index_text ( self ): return str( self.row ) def _get_index_image ( self ): x, y, z = self.item if sqrt( (x - 0.5) ** 2 + (y - 0.5) ** 2 + (z - 0.5) ** 2 ) <= 0.25: return 'red_flag' return None #--[Tabular Editor Definition]-------------------------------------------------- tabular_editor = TabularEditor( adapter = ArrayAdapter(), images = [ ImageResource( 'red_flag', search_path = search_path ) ] ) #--[ShowArray Class]------------------------------------------------------------ class ShowArray ( HasTraits ): data = Array view = View( Item( 'data', editor = tabular_editor, show_label = False ), title = 'Array Viewer', width = 0.3, height = 0.8, resizable = True, buttons = NoButtons ) #--[Example Code*]-------------------------------------------------------------- demo = ShowArray( data = random( ( 100000, 3 ) ) ) traitsui-4.1.0/examples/tutorials/traitsui_4.0/editors/tabular_editor/tabular_editor.htm0000644000175100001440000014261211674463545032642 0ustar ischnellusers00000000000000 The TabularEditor

    The TabularEditor

    Traits 3.0 introduces a new editor, called the TabularEditor, located in the traitsui.wx.extras.tabular_editor module that can be used for many of the same purposes as the existing TableEditor. However, while similar in function, each editor has its own particular strengths and weaknesses.

    Some of the strengths of the new TabularEditor are:

    • Very fast. The editor uses a virtual model which only accesses data from the underlying data model as needed. For example, if you have a million element array, but can only view 50 rows at a time, the editor will only request 50 rows at a time.
    • Very flexible data model. The editor uses a new adapter model for interfacing with your underlying data that allows it to easily deal with many types of data representation: from lists of objects, to arrays of numbers, to tuples of tuples, and many other formats as well.
    • Supports a useful set of data operations. The editor includes built-in support for a number of useful data operations, including:
      • Moving the selection up and down using the keyboard arrow keys.
      • Moving rows up and down using the keyboard arrow keys.
      • Inserting and deleting rows using the keyboard.
      • Begin editing table rows using the keyboard.
      • Drag and drop of table items to and from the editor, including support for both copy and move operations for single or multiple table items.
    • Visually appealing. The editor, in general, uses the underlying OS's native table or grid control, and as a result often looks better than the control used by the TableEditor.
    • Supports displaying text and images in any cell. Note however that the images displayed must all be the same size for optimal results.

    Some of the weaknesses of the TabularEditor compared to the TableEditor are:

    • Not as full-featured. The TableEditor includes support for arbitrary data filters and searches and different types of data sorting. The differences here may narrow over time as new features get added to the TabularEditor.
    • Limited data editing capabilities: The TabularEditor only supports editing textual values, unlike the TableEditor, which supports a wide variety of column editors and can be extended with more as needed. This is due to limitations of the underlying native OS control used by the editor.

    Setting up a TabularEditor for use in a Traits UI is divided into two main parts:

    • Configuring the TabularEditor object.
    • Creating a suitable adapter (or adapters) for use with the editor.

    We'll start off first with a description of the TabularEditor class, and describe the adapter interface in a later section.

    The TabularEditor Class

    The TabularEditor class defines a large number of traits which are used to configure the editor. We'll divide the set of traits into several categories, and describe each in turn.

    Visual Traits

    show_titles
    A boolean value which specifies whether or not column headers should be displayed at the top of the table. It defaults to True.
    horizontal_lines
    A boolean value which specifies whether or not horizontal lines should be drawn between rows in the table. It defaults to True.
    vertical_lines
    A boolean value which specifies whether or not vertical lines should be drawn between columns in the table. It defaults to True.

    Control Traits

    editable
    A boolean value that specifies whether or not the user is allowed to edit data in the table. It defaults to True.
    multi_select
    A boolean value that specifies whether or not the user is allowed to select multiple rows in the table at once. It defaults to False.
    operations

    A list of strings that specify what operations the user is allowed to perform on items in the table. The possible values are:

    • delete: The user can delete table rows.
    • insert: The user can insert new table rows at any position in the table.
    • append: The user can append new table rows to the end of the table.
    • edit: The user can edit the contents of table rows.
    • move: The user can move table rows within the table.

    You should include in the list all operations that you want to allow the user to perform (e.g. ['delete','insert','append']).

    drag_move
    A boolean value that specifies whether drag move operations are allowed (True), or should all drag operations be treated as drag copy operations (False). The default is False.
    adapter
    An instance of TabularAdapter that the editor uses to interface to the underlying Item data supplied to the editor. This is normally an instance of a subclass of TabularAdapter specially written for the type of data being edited. This will be described more fully in the TabularAdapter section.
    adapter_name
    An optional string that specifies the extended trait name of a trait that contains the TabularAdapter the editor should used. If the value of the trait changes while the editor is active, the editor will automatically start using the new adapter. Normally you will use either the adapter trait or the adapter_name trait, but not both. However, it is possible to use both together if needed.
    images
    An optional list of ImageResource objects describing a set of images that can be displayed in the table's cells. Specifying a set here allows you to refer to the images by name within the adapter. However, it is also possible for the adapter to supply the ImageResource object directly for any image it wants to display.

    Event Handling Traits

    selected
    An optional string that specifies the extended trait name of a trait that contains the currently selected table items. For a single-select mode editor, this should be a scalar trait, and for a multi-select mode editor, it should be a list trait. The type of the trait should be the same as the type of data being displayed in the table. This trait can be used to both set and get the current table selection.
    selected_row
    An optional string that specifies the extended trait name of a trait that contains the currently selected table item indices. For a single-select mode editor this should be an Int value, and for a multi-select mode editor it should be a List(Int) value. This trait can be used to both set and get the current table selection.
    activated
    An optional string that specifies the extended trait name of a trait that contains the currently activated table item. It should be an instance of the table item data type. The trait can only be used to get the value of the most recently activated table item. An item is activated either by the user double-clicking on it or by pressing the Enter key when the item is selected.
    activated_row
    An optional string that specifies the extended trait name of a trait that contains the currently activated table item index. It should be an Int value. The trait can only be used to get the index of the most recently activated table item. An item is activated either by the user double-clicking on it or by pressing the Enter key when the item is selected.
    clicked
    An optional string that specifies the extended trait name of a trait that contains a TabularEditorEvent object containing the information associated with the most recent left mouse button click within the editor. The trait can only be used to get the TabularEditorEvent object. The TabularEditorEvent object is described in the next section.
    dclicked
    An optional string that specifies the extended trait name of a trait that contains a TabularEditorEvent object containing the information associated with the most recent left mouse button double-click within the editor. The trait can only be used to get the TabularEditorEvent object. The TabularEditorEvent object is described in the next section.
    right_clicked
    An optional string that specifies the extended trait name of a trait that contains a TabularEditorEvent object containing the information associated with the most recent right mouse button click within the editor. The trait can only be used to get the TabularEditorEvent object. The TabularEditorEvent object is described in the next section.
    right_dclicked
    An optional string that specifies the extended trait name of a trait that contains a TabularEditorEvent object containing the information associated with the most recent right mouse button double-click within the editor. The trait can only be used to get the TabularEditorEvent object. The TabularEditorEvent object is described in the next section.

    The TabularEditorEvent Class

    Objects of the TabularEditorEvent class contain information related to a mouse button click that occurs within the editor. The class has no methods, but does define the following traits:

    row
    An integer specifying the index of the table item that was clicked on.
    column
    A value specifying the column id of the table cell that was clicked on. This value will correspond to the second element of the tuple used to define the column in the TabularEditor adapter supplied to the editor. This will be described in a later section.
    item
    The data item corresponding to the table row that was clicked on. The type of this data will depend upon the type of data contained in the underlying data model.

    The TabularEditor User Interface

    Depending upon how you have configured the TabularEditor and its associated adapter, the following user interface features may be available:

    • Up arrow: Move the selection up one line.
    • Down arrow: Move the selection down one line.
    • Page down: Append a new item to the end of the list ('append').
    • Left arrow: Move the current selection up one line ('move').
    • Right arrow: Move the current selection down one line ('move').
    • Backspace, Delete: Delete all items in the current selection from the list ('delete').
    • Enter, Escape: Edit the current selection ('edit').
    • Insert: Insert a new item before the current selection ('insert').

    In the preceding list, the values in parentheses refer to the operation that must be included in the TabularEditor operations trait in order for the specified key to have any effect.

    The append, move, edit and insert operations are only available if a single item is selected. The delete operation works when the selection has one or more items.

    Depending upon how the TabularEditor and adapter are specified, drag and drop operations may also be available. If multiple items are selected and the user drags one of the selected items, all selected items will be included in the drag operation. If the user drags a non-selected item, only that item will be dragged.

    The editor also supports both drag-move and drag-copy semantics. A drag-move operation means that the dragged items will be sent to the target and removed from the list data. A drag-copy operation means that the dragged items will be sent to the target, but will not be deleted from the Item data. Note that in a drag-copy operation, if you do not want the target to receive the same data contained in the list, then you must return a copy or clone of the data when the editor requests the drag data from the adapter.

    You can prevent drag-move operations by making sure that the TabularEditor drag_move trait is set to False (the default).

    Note that the default operation when a user begins a drag operation is drag_move. A drag-copy operation occurs when the user also holds the Ctrl key down during the drag operation (the mouse pointer changes to indicate the change in drag semantics). If drag_move operations are disabled by setting the TabularEditor drag_move trait to False, any drag-move operation is automatically treated as a drag_copy.

    The tabular editor only allows the user to edit the first column of data in the table (a restriction imposed by the underlying OS widget). If the 'edit' operation is enabled, the user can begin editing the first column either by clicking on the row twice, or by selecting the row and pressing the Enter or Escape key.

    Finally, the user can resize columns in the table by dragging the column title dividers left or right with the mouse. Once resized in this manner, the column remains that size until the user resizes the column again. This is true even if you assigned a dynamic width to the column (see the TabularAdapter section for more information about what this means). If the user wants to allow a previously user-sized column to be restored to its original developer specified size again, they must right-click on the column title to release its user specified size and restore its original size.

    If you enable persistence for the editor by specifying a non-empty id trait for the editor's Item and View objects, any user specified column widths will be saved across application sessions.

    The TabularAdapter Class

    The power and flexibility of the tabular editor is mostly a result of the TabularAdapter class, which is the base class from which all tabular editor adapters must be derived.

    The TabularEditor object interfaces between the underlying toolkit widget and your program, while the TabularAdapter object associated with the editor interfaces between the editor and your data.

    The design of the TabularAdapter base class is such that it tries to make simple cases simple and complex cases possible. How it accomplishes this is what we'll be discussing in the following sections.

    The TabularAdapter columns Trait

    First up is the TabularAdapter columns trait, which is a list of values which define, in presentation order, the set of columns to be displayed by the associated TabularEditor.

    Each entry in the columns list can have one of two forms:

    • string
    • ( string, any )

    where string is the user interface name of the column (which will appear in the table column header) and any is any value that you want to use to identify that column to your adapter. Normally this value is either a trait name or an integer index value, but it can be any value you want. If only string is specified, then any is the index of the string within columns.

    For example, say you want to display a table containing a list of tuples, each of which has three values: a name, an age, and a weight. You could then use the following value for the columns trait:

    columns = [ 'Name', 'Age', 'Weight' ]
    

    By default, the any values (also referred to in later sections as the column ids) for the columns will be the corresponding tuple index values.

    Say instead that you have a list of Person objects, with name, age and weight traits that you want to display in the table. Then you could use the following columns value instead:

    columns = [ ( 'Name',   'name' ),
                ( 'Age',    'age' ),
                ( 'Weight', 'weight' ) ]
    

    In this case, the column ids are the names of the traits you want to display in each column.

    Note that it is possible to dynamically modify the contents of the columns trait while the TabularEditor is active. The TabularEditor will automatically modify the table to show the new set of defined columns.

    The Core TabularAdapter Interface

    In this section, we'll describe the core interface to the TabularAdapter class. This is the actual interface used by the TabularEditor to access your data and display attributes. In the most complex data representation cases, these are the methods that you must override in order to have the greatest control over what the editor sees and does.

    However, the base TabularAdapter class provides default implementations for all of these methods. In subsequent sections, we'll look at how these default implementations provide simple means of customizing the adapter to your needs. But for now, let's start by covering the details of the core interface itself.

    To reduce the amount of repetition, we'll use the following definitions in all of the method argument lists that follow in this section:

    object
    The object whose trait is being edited by the TabularEditor.
    trait
    The name of the trait the TabularEditor is editing.
    row
    The row index (starting with 0) of a table item.
    column
    The column index (starting with 0) of a table column.

    The adapter interface consists of a number of methods which can be divided into two main categories: those which are sensitive to the type of a particular table item, and those which are not. We'll begin with the methods that are sensitive to an item's type:

    get_alignment ( object, trait, column )

    Returns the alignment style to use for a specified column.

    The possible values that can be returned are: 'left', 'center' or 'right'. All table items share the same alignment for a specified column.

    get_width ( object, trait, column )

    Returns the width to use for a specified column. The result can either be a float or integer value.

    If the value is <= 0, the column will have a default width, which is the same as specifying a width of 0.1.

    If the value is > 1.0, it is converted to an integer and the result is the width of the column in pixels. This is referred to as a fixed width column.

    If the value is a float such that 0.0 < value <= 1.0, it is treated as the unnormalized fraction of the available space that is to be assigned to the column. What this means requires a little explanation.

    To arrive at the size in pixels of the column at any given time, the editor adds together all of the unnormalized fraction values returned for all columns in the table to arrive at a total value. Each unnormalized fraction is then divided by the total to create a normalized fraction. Each column is then assigned an amount of space in pixels equal to the maximum of 30 or its normalized fraction multiplied by the available space. The available space is defined as the actual width of the table minus the width of all fixed width columns. Note that this calculation is performed each time the table is resized in the user interface, thus allowing columns of this type to increase or decrease their width dynamically, while leaving fixed width columns unchanged.

    get_can_edit ( object, trait, row )

    Returns a boolean value indicating whether the user can edit a specified object.trait[row] item.

    A True result indicates that the value can be edited, while a False result indicates that it cannot.

    get_drag ( object, trait, row )

    Returns the value to be dragged for a specified object.trait[row] item. A result of None means that the item cannot be dragged. Note that the value returned does not have to be the actual row item. It can be any value that you want to drag in its place. In particular, if you want the drag target to receive a copy of the row item, you should return a copy or clone of the item in its place.

    Also note that if multiple items are being dragged, and this method returns None for any item in the set, no drag operation is performed.

    get_can_drop ( object, trait, row, value )

    Returns whether the specified value can be dropped on the specified object.trait[row] item. A value of True means the value can be dropped; and a value of False indicates that it cannot be dropped.

    The result is used to provide the user positive or negative drag feedback while dragging items over the table. Value will always be a single value, even if multiple items are being dragged. The editor handles multiple drag items by making a separate call to get_can_drop for each item being dragged.

    get_dropped ( object, trait, row, value )

    Returns how to handle a specified value being dropped on a specified object.trait[row] item. The possible return values are:

    • 'before': Insert the specified value before the dropped on item.
    • 'after': Insert the specified value after the dropped on item.

    Note there is no result indicating do not drop since you will have already indicated that the object can be dropped by the result returned from a previous call to get_can_drop.

    get_font ( object, trait, row )

    Returns the font to use for displaying a specified object.trait[row] item.

    A result of None means use the default font; otherwise a wx.Font object should be returned. Note that all columns for the specified table row will use the font value returned.

    get_text_color ( object, trait, row )

    Returns the text color to use for a specified object.trait[row] item.

    A result of None means use the default text color; otherwise a wx.Colour object should be returned. Note that all columns for the specified table row will use the text color value returned.

    get_bg_color ( object, trait, row )

    Returns the background color to use for a specified object.trait[row] item.

    A result of None means use the default background color; otherwise a wx.Colour object should be returned. Note that all columns for the specified table row will use the background color value returned.

    get_image ( object, trait, row, column )

    Returns the image to display for a specified object.trait[row].column item.

    A result of None means no image will be displayed in the specified table cell. Otherwise the result should either be the name of the image, or an ImageResource object specifying the image to display.

    A name is allowed in the case where the image is specified in the TabularEditor images trait. In that case, the name should be the same as the string specified in the ImageResource constructor.

    get_format ( object, trait, row, column )

    Returns the Python formatting string to apply to the specified object.trait[row].column item in order to display it in the table.

    The result can be any Python string containing exactly one Python formatting sequence, such as '%.4f' or '(%5.2f)'.

    get_text ( object, trait, row, column )

    Returns a string containing the text to display for a specified object.trait[row].column item.

    If the underlying data representation for a specified item is not a string, then it is your responsibility to convert it to one before returning it as the result.

    set_text ( object, trait, row, text ):

    Sets the value for the specified object.trait[row].column item to the string specified by text.

    If the underlying data does not store the value as text, it is your responsibility to convert text to the correct representation used. This method is called when the user completes an editing operation on a table cell.

    get_tooltip ( object, trait, row, column )

    Returns a string containing the tooltip to display for a specified object.trait[row].column item.

    You should return the empty string if you do not wish to display a tooltip.

    The following are the remaining adapter methods, which are not sensitive to the type of item or column data:

    get_item ( object, trait, row )

    Returns the specified object.trait[row] item.

    The value returned should be the value that exists (or logically exists) at the specified row in your data. If your data is not really a list or array, then you can just use row as an integer key or token that can be used to retrieve a corresponding item. The value of row will always be in the range: 0 <= row < len( object, trait ) (i.e. the result returned by the adapter len method).

    len ( object, trait )

    Returns the number of row items in the specified object.trait list.

    The result should be an integer greater than or equal to 0.

    delete ( object, trait, row )

    Deletes the specified object.trait[row] item.

    This method is only called if the delete operation is specified in the TabularEditor operation trait, and the user requests that the item be deleted from the table. The adapter can still choose not to delete the specified item if desired, although that may prove confusing to the user.

    insert ( object, trait, row, value )

    Inserts value at the specified object.trait[row] index. The specified value can be:

    • An item being moved from one location in the data to another.
    • A new item created by a previous call to get_default_value.
    • An item the adapter previously approved via a call to get_can_drop.

    The adapter can still choose not to insert the item into the data, although that may prove confusing to the user.

    get_default_value ( object, trait )

    Returns a new default value for the specified object.trait list.

    This method is called when insert or append operations are allowed and the user requests that a new item be added to the table. The result should be a new instance of whatever underlying representation is being used for table items.

    Creating a Custom TabularAdapter

    Having just taken a look at the core TabularAdapter interface, you might now be thinking that there are an awful lot of methods that need to be specified to get an adapter up and running. But as we mentioned earlier, TabularAdapter is not an abstract base class. It is a concrete base class with implementations for each of the methods in its interface. And the implementations are written in such a way that you will hopefully hardly ever need to override them.

    In this section, we'll explain the general implementation style used by these methods, and how you can take advantage of them in creating your own adapters.

    One of the things you probably noticed as you read through the core adapter interface section is that most of the methods have names of the form: get_xxx or set_xxx, which is similar to the familiar getter/setter pattern used when defining trait properties. The adapter interface is purposely defined this way so that it can expose and leverage a simple set of design rules.

    The design rules are followed consistently in the implementations of all of the adapter methods described in the first section of the core adapter interface, so that once you understand how they work, you can easily apply the design pattern to all items in that section. Then, only in the case where the design rules will not work for your application will you ever have to override any of those TabularAdapter base class method implementations.

    So the first thing to understand is that if an adapter method name has the form: get_xxx or set_xxx it really is dealing with some kind of trait called xxx, or which contains xxx in its name. For example, the get_alignment method retrieves the value of some alignment trait defined on the adapter. In the following discussion we'll simply refer to an attribute name generically as attribute, but you will need to replace it by an actual attribute name (e.g. alignment) in your adapter.

    The next thing to keep in mind is that the adapter interface is designed to easily deal with items that are not all of the same type. As we just said, the design rules apply to all adapter methods in the first group, which were defined as methods which are sensitive to an item's type. Item type sensitivity plays an important part in the design rules, as we will see shortly.

    With this in mind, we now describe the simple design rules used by the first group of methods in the TabularAdapter class:

    • When getting or setting an adapter attribute, the method first retrieves the underlying item for the specified data row. The item, and type (i.e. class) of the item, are then used in the next rule.

    • The method gets or sets the first trait it finds on the adapter that matches one of the following names:

      • classname_columnid_attribute
      • classsname_attribute
      • columnid_attribute
      • attribute

      where:

      • classname is the name of the class of the item found in the first step, or one of its base class names, searched in the order defined by the mro (method resolution order) for the item's class.
      • columnid is the column id specified by the developer in the adapter's column trait for the specified table column.
      • attribute is the attribute name as described previously (e.g. alignment).

    Note that this last rule always finds a matching trait, since the TabularAdapter base class provides traits that match the simple attribute form for all attributes these rules apply to. Some of these are simple traits, while others are properties. We'll describe the behavior of all these default traits shortly.

    The basic idea is that rather than override the first group of core adapter methods, you simply define one or more simple traits or trait properties on your TabularAdapter subclass that provide or accept the specified information.

    All of the adapter methods in the first group provide a number of arguments, such as object, trait, row and column. In order to define a trait property, which cannot be passed this information directly, the adapter always stores the arguments and values it computes in the following adapter traits, where they can be easily accessed by a trait getter or setter method:

    • row: The table row being accessed.
    • column: The column id of the table column being accessed (not its index).
    • item: The data item for the specified table row (i.e. the item determined in the first step described above).
    • value: In the case of a set_xxx method, the value to be set; otherwise it is None.

    As mentioned previously, the TabularAdapter class provides trait definitions for all of the attributes these rules apply to. You can either use the default values as they are, override the default, set a new value, or completely replace the trait definition in a subclass. A description of the default trait implementation for each attribute is as follows:

    default_value = Any( '' )

    The default value for a new row.

    The default value is the empty string, but you will normally need to assign a different (default) value.

    format = Str( '%s' )

    The default Python formatting string for a column item.

    The default value is '%s' which will simply convert the column item to a displayable string value.

    text = Property

    The text to display for the column item.

    The implementation of the property checks the type of the column's column id:

    • If it is an integer, it returns format%item[column_id].
    • Otherwise, it returns format%item.column_id.

    Note that format refers to the value returned by a call to get_format for the current column item.

    text_color = Property

    The text color for a row item.

    The property implementation checks to see if the current table row is even or odd, and based on the result returns the value of the even_text_color or odd_text_color trait if the value is not None, and the value of the default_text_color trait if it is. The definition of these additional traits are as follows:

    • odd_text_color = Color( None )
    • even_text_color = Color( None )
    • default_text_color = Color( None )

    Remember that a None value means use the default text color.

    bg_color = Property

    The background color for a row item.

    The property implementation checks to see if the current table row is even or odd, and based on the result returns the value of the even_bg_color or odd_bg_color trait if the value is not None, and the value of the default_bg_color trait if it is. The definition of these additional traits are as follows:

    • odd_bg_color = Color( None )
    • even_bg_color = Color( None )
    • default_bg_color = Color( None )

    Remember that a None value means use the default background color.

    alignment = Enum( 'left', 'center', 'right' )

    The alignment to use for a specified column.

    The default value is 'left'.

    width = Float( -1 )

    The width of a specified column.

    The default value is -1, which means a dynamically sized column with an unnormalized fractional value of 0.1.

    can_edit = Bool( True )

    Specifies whether the text value of the current item can be edited.

    The default value is True, which means that the user can edit the value.

    drag = Property

    A property which returns the value to be dragged for a specified row item.

    The property implementation simply returns the current row item.

    can_drop = Bool( False )

    Specifies whether the specified value be dropped on the current item.

    The default value is False, meaning that the value cannot be dropped.

    dropped = Enum( 'after', 'before' )

    Specifies where a dropped item should be placed in the table relative to the item it is dropped on.

    The default value is 'after'.

    font = Font

    The font to use for the current item.

    The default value is the standard default Traits font value.

    image = Str( None )

    The name of the default image to use for a column.

    The default value is None, which means that no image will be displayed for the column.

    # The text of a row/column item: text = Property

    tooltip = Str

    The tooltip information for a column item.

    The default value is the empty string, which means no tooltip information will be displayed for the column.

    The preceding discussion applies to all of the methods defined in the first group of TabularAdapter interface methods. However, the design rules do not apply to the remaining five adapter methods, although they all provide a useful default implementation:

    get_item ( object, trait, row )

    Returns the value of the object.trait[row] item.

    The default implementation assumes the trait defined by object.trait is a sequence and attempts to return the value at index row. If an error occurs, it returns None instead. This definition should work correctly for lists, tuples and arrays, or any other object that is indexable, but will have to be overridden for all other cases.

    Note that this method is the one called in the first design rule described previously to retrieve the item at the current table row.

    len ( object, trait )

    Returns the number of items in the specified object.trait list.

    Again, the default implementation assumes the trait defined by object.trait is a sequence and attempts to return the result of calling len( object.trait ). It will need to be overridden for any type of data which for which len will not work.

    delete ( object, trait, row )

    Deletes the specified object.trait[row] item.

    The default implementation assumes the trait defined by object.trait is a mutable sequence and attempts to perform a del object.trait[row] operation.

    insert ( object, trait, row, value )

    Inserts a new value at the specified object.trait[row] index.

    The default implementation assumes the trait defined by object.trait is a mutable sequence and attempts to perform an object.trait[row:row]=[value] operation.

    get_default_value ( object, trait )

    Returns a new default value for the specified object.trait list.

    The default implementation simply returns the value of the adapter's default_value trait.

    A TabularAdapter Example

    Having now learned about the core adapter interface as well as the design rules supported by the default method implementations, you're probably wondering how you can use a TabularAdapter for creating a real user interface.

    So in this section we'll cover a simple example of creating a TabularAdapter subclass to try and show how all of the pieces fit together.

    In subsequent tutorials, we'll provide complete examples of creating user interfaces using both the TabularEditor and TabularAdapter in combination.

    For this example, let's assume we have the following two classes:

    class Person ( HasTraits ):
    
        name    = Str
        age     = Int
        address = Str
    
    class MarriedPerson ( Person ):
    
        partner = Instance( Person )
    

    where Person represents a single person, and MarriedPerson represents a married person and is derived from Person but adds the partner trait to reference the person they are married to.

    Now, assume we also have the following additional class:

    class Report ( HasTraits ):
    
        people = List( Person )
    

    which has a people trait which contains a list of both Person and MarriedPerson objects, and we want to create a tabular display showing the following information:

    • Name of the person
    • Age of the person
    • The person's address
    • The name of the person's spouse (if any)

    In addition:

    • We want to use a Courier 10 point font for each line in the table.
    • We want the age column to be right, instead of left, justified
    • If the person is a minor (age < 18) and married, we want to show a red flag image in the age column.
    • If the person is married, we want to make the background color for that row a light blue.

    Given this set of requirements, we can now define the following TabularAdapter subclass:

    class ReportAdapter ( TabularAdapter ):
    
        columns = [ ( 'Name',    'name' ),
                    ( 'Age',     'age' ),
                    ( 'Address', 'address' )
                    ( 'Spouse',  'spouse' ) ]
    
        font                      = 'Courier 10'
        age_alignment             = Constant( 'right' )
        MarriedPerson_age_image   = Property
        MarriedPerson_bg_color    = Color( 0xE0E0FF )
        MarriedPerson_spouse_text = Property
        Person_spouse_text        = Constant( '' )
    
        def _get_MarriedPerson_age_image ( self ):
            if self.item.age < 18:
                return 'red_flag'
            return None
    
        def _get_MarriedPerson_spouse_text ( self ):
            return self.item.partner.name
    

    Hopefully, this simple example conveys some of the power and flexibility that the TabularAdapter class provides you. But, just in case it doesn't, let's go over some of the more interesting details:

    • Note the values in the columns trait. The first three values define column ids which map directly to traits defined on our data objects, while the last one defines an arbitrary string which we define so that we can reference it in the MarriedPerson_spouse_text and Person_spouse_text trait definitions.
    • Since the font we want to use applies to all table rows, we just specify a new default value for the existing TabularAdapter font trait.
    • Since we only want to override the default left alignment for the age column, we simply define an age_alignment trait as a constant 'right' value. We could have also used age_alignment = Str('right'), but Constant never requires storage to be used in an object.
    • We define the MarriedPerson_age_image property to handle putting the red flag image in the age column. By including the class name of the items it applies to, we only need to check the age value in determining what value to return.
    • Similary, we use the MarriedPerson_bg_color trait to ensure that each MarriedPerson object has the correct background color in the table.
    • Finally, we use the MarriedPerson_spouse_text and Person_spouse_text traits, one a property and the other a simple constant value, to determine what text to display in the Spouse column for the different object types. Note that even though a MarriedPerson is both a Person and a MarriedPerson, it will correctly use the MarriedPerson_spouse_text trait since the search for a matching trait is always made in mro order.

    Although this is completely subjective, some of the things that the author feels stand out about this approach are:

    • The class definition is short and sweet. Less code is good.
    • The bulk of the code is declarative. Less room for logic errors.
    • There is only one bit of logic in the class (the if statement in the MarriedPerson_age_image property implementation). Again, less logic usually translates into more reliable code).
    • The defined traits and even the property implementation method names read very descriptively. _get_MarriedPerson_age_image pretty much says what you would write in a comment or doc string. The implementation almost is the documentation.

    Look for a complete traits UI example based on this sample problem definition in the Single and Married Person Example tutorial in this section.

    Now, as the complexity of a tabular view increases, the definition of the TabularAdapter class could possibly start to get large and unwieldy. At this point we could begin refactoring our design to use the ITabularAdapter interface and AnITabularAdapter implementation class to create sub-adapters that can be added to our TabularAdapter subclass to extend its functionality even further. Creating sub-adapters and adding them via the TabularAdapter adapters trait is a topic covered in a follow-on tutorial.

    traitsui-4.1.0/examples/tutorials/traitsui_4.0/editors/tabular_editor/tutorial.desc0000644000175100001440000000033411674463545031625 0ustar ischnellusers00000000000000Tabular Editor tabular_editor: Tabular Editor Introduction sm_person_example: Single and Married Person Example python_source_browser: Python Source Browser Example numpy_array: NumPy Array Example traitsui-4.1.0/examples/tutorials/traitsui_4.0/editors/tabular_editor/tabular_editor.rst0000644000175100001440000012373211674463545032664 0ustar ischnellusers00000000000000The TabularEditor ================= Traits 3.0 introduces a new editor, called the **TabularEditor**, located in the *traitsui.wx.extras.tabular_editor* module that can be used for many of the same purposes as the existing **TableEditor**. However, while similar in function, each editor has its own particular strengths and weaknesses. Some of the strengths of the new **TabularEditor** are: - **Very fast**. The editor uses a *virtual* model which only accesses data from the underlying data model as needed. For example, if you have a million element array, but can only view 50 rows at a time, the editor will only request 50 rows at a time. - **Very flexible data model**. The editor uses a new adapter model for interfacing with your underlying data that allows it to easily deal with many types of data representation: from lists of objects, to arrays of numbers, to tuples of tuples, and many other formats as well. - **Supports a useful set of data operations**. The editor includes built-in support for a number of useful data operations, including: - Moving the selection up and down using the keyboard arrow keys. - Moving rows up and down using the keyboard arrow keys. - Inserting and deleting rows using the keyboard. - Begin editing table rows using the keyboard. - Drag and drop of table items to and from the editor, including support for both *copy* and *move* operations for single or multiple table items. - **Visually appealing**. The editor, in general, uses the underlying OS's native table or grid control, and as a result often looks better than the control used by the **TableEditor**. - **Supports displaying text and images in any cell**. Note however that the images displayed must all be the same size for optimal results. Some of the weaknesses of the **TabularEditor** compared to the **TableEditor** are: - **Not as full-featured**. The **TableEditor** includes support for arbitrary data filters and searches and different types of data sorting. The differences here may narrow over time as new features get added to the **TabularEditor**. - **Limited data editing capabilities**: The **TabularEditor** only supports editing textual values, unlike the **TableEditor**, which supports a wide variety of column editors and can be extended with more as needed. This is due to limitations of the underlying native OS control used by the editor. Setting up a **TabularEditor** for use in a Traits UI is divided into two main parts: - Configuring the **TabularEditor** object. - Creating a suitable adapter (or adapters) for use with the editor. We'll start off first with a description of the **TabularEditor** class, and describe the adapter interface in a later section. The TabularEditor Class ----------------------- The **TabularEditor** class defines a large number of traits which are used to configure the editor. We'll divide the set of traits into several categories, and describe each in turn. Visual Traits ------------- show_titles A boolean value which specifies whether or not column headers should be displayed at the top of the table. It defaults to **True**. horizontal_lines A boolean value which specifies whether or not horizontal lines should be drawn between rows in the table. It defaults to **True**. vertical_lines A boolean value which specifies whether or not vertical lines should be drawn between columns in the table. It defaults to **True**. Control Traits -------------- editable A boolean value that specifies whether or not the user is allowed to edit data in the table. It defaults to **True**. multi_select A boolean value that specifies whether or not the user is allowed to select multiple rows in the table at once. It defaults to **False**. operations A list of strings that specify what operations the user is allowed to perform on items in the table. The possible values are: - **delete**: The user can delete table rows. - **insert**: The user can insert new table rows at any position in the table. - **append**: The user can append new table rows to the end of the table. - **edit**: The user can edit the contents of table rows. - **move**: The user can move table rows within the table. You should include in the list all operations that you want to allow the user to perform (e.g. *['delete','insert','append']*). drag_move A boolean value that specifies whether *drag move* operations are allowed (**True**), or should all drag operations be treated as *drag copy* operations (**False**). The default is **False**. adapter An instance of **TabularAdapter** that the editor uses to interface to the underlying **Item** data supplied to the editor. This is normally an instance of a subclass of **TabularAdapter** specially written for the type of data being edited. This will be described more fully in the **TabularAdapter** section. adapter_name An optional string that specifies the extended trait name of a trait that contains the **TabularAdapter** the editor should used. If the value of the trait changes while the editor is active, the editor will automatically start using the new adapter. Normally you will use either the *adapter* trait *or* the *adapter_name* trait, but not both. However, it is possible to use both together if needed. images An optional list of **ImageResource** objects describing a set of images that can be displayed in the table's cells. Specifying a set here allows you to refer to the images by name within the adapter. However, it is also possible for the adapter to supply the **ImageResource** object directly for any image it wants to display. Event Handling Traits --------------------- selected An optional string that specifies the extended trait name of a trait that contains the currently selected table items. For a single-select mode editor, this should be a scalar trait, and for a multi-select mode editor, it should be a list trait. The type of the trait should be the same as the type of data being displayed in the table. This trait can be used to both set and get the current table selection. selected_row An optional string that specifies the extended trait name of a trait that contains the currently selected table item indices. For a single-select mode editor this should be an **Int** value, and for a multi-select mode editor it should be a **List(Int)** value. This trait can be used to both set and get the current table selection. activated An optional string that specifies the extended trait name of a trait that contains the currently activated table item. It should be an instance of the table item data type. The trait can only be used to get the value of the most recently activated table item. An item is activated either by the user double-clicking on it or by pressing the **Enter** key when the item is selected. activated_row An optional string that specifies the extended trait name of a trait that contains the currently activated table item index. It should be an **Int** value. The trait can only be used to get the index of the most recently activated table item. An item is activated either by the user double-clicking on it or by pressing the **Enter** key when the item is selected. clicked An optional string that specifies the extended trait name of a trait that contains a **TabularEditorEvent** object containing the information associated with the most recent left mouse button click within the editor. The trait can only be used to get the **TabularEditorEvent** object. The **TabularEditorEvent** object is described in the next section. dclicked An optional string that specifies the extended trait name of a trait that contains a **TabularEditorEvent** object containing the information associated with the most recent left mouse button double-click within the editor. The trait can only be used to get the **TabularEditorEvent** object. The **TabularEditorEvent** object is described in the next section. right_clicked An optional string that specifies the extended trait name of a trait that contains a **TabularEditorEvent** object containing the information associated with the most recent right mouse button click within the editor. The trait can only be used to get the **TabularEditorEvent** object. The **TabularEditorEvent** object is described in the next section. right_dclicked An optional string that specifies the extended trait name of a trait that contains a **TabularEditorEvent** object containing the information associated with the most recent right mouse button double-click within the editor. The trait can only be used to get the **TabularEditorEvent** object. The **TabularEditorEvent** object is described in the next section. The TabularEditorEvent Class ---------------------------- Objects of the **TabularEditorEvent** class contain information related to a mouse button click that occurs within the editor. The class has no methods, but does define the following traits: row An integer specifying the index of the table item that was clicked on. column A value specifying the column id of the table cell that was clicked on. This value will correspond to the second element of the tuple used to define the column in the **TabularEditor** adapter supplied to the editor. This will be described in a later section. item The data item corresponding to the table row that was clicked on. The type of this data will depend upon the type of data contained in the underlying data model. The TabularEditor User Interface -------------------------------- Depending upon how you have configured the **TabularEditor** and its associated adapter, the following user interface features may be available: - **Up arrow**: Move the selection up one line. - **Down arrow**: Move the selection down one line. - **Page down**: Append a new item to the end of the list (*'append'*). - **Left arrow**: Move the current selection up one line (*'move'*). - **Right arrow**: Move the current selection down one line (*'move'*). - **Backspace, Delete**: Delete all items in the current selection from the list (*'delete'*). - **Enter, Escape**: Edit the current selection (*'edit'*). - **Insert**: Insert a new item before the current selection (*'insert'*). In the preceding list, the values in parentheses refer to the operation that must be included in the **TabularEditor** *operations* trait in order for the specified key to have any effect. The *append*, *move*, *edit* and *insert* operations are only available if a single item is selected. The *delete* operation works when the selection has one or more items. Depending upon how the **TabularEditor** and adapter are specified, drag and drop operations may also be available. If multiple items are selected and the user drags one of the selected items, all selected items will be included in the drag operation. If the user drags a non-selected item, only that item will be dragged. The editor also supports both *drag-move* and *drag-copy* semantics. A *drag-move* operation means that the dragged items will be sent to the target and removed from the list data. A *drag-copy* operation means that the dragged items will be sent to the target, but will *not* be deleted from the **Item** data. Note that in a *drag-copy* operation, if you do not want the target to receive the same data contained in the list, then you must return a copy or clone of the data when the editor requests the drag data from the adapter. You can prevent *drag-move* operations by making sure that the **TabularEditor** *drag_move* trait is set to **False** (the default). Note that the default operation when a user begins a drag operation is *drag_move*. A *drag-copy* operation occurs when the user also holds the *Ctrl* key down during the drag operation (the mouse pointer changes to indicate the change in drag semantics). If *drag_move* operations are disabled by setting the **TabularEditor** *drag_move* trait to **False**, any *drag-move* operation is automatically treated as a *drag_copy*. The tabular editor only allows the user to edit the first column of data in the table (a restriction imposed by the underlying OS widget). If the *'edit'* operation is enabled, the user can begin editing the first column either by clicking on the row twice, or by selecting the row and pressing the **Enter** or **Escape** key. Finally, the user can resize columns in the table by dragging the column title dividers left or right with the mouse. Once resized in this manner, the column remains that size until the user resizes the column again. This is true even if you assigned a dynamic width to the column (see the **TabularAdapter** section for more information about what this means). If the user wants to allow a previously user-sized column to be restored to its original developer specified size again, they must right-click on the column title to *release* its user specified size and restore its original size. If you enable *persistence* for the editor by specifying a non-empty *id* trait for the editor's **Item** and **View** objects, any user specified column widths will be saved across application sessions. The TabularAdapter Class ------------------------ The power and flexibility of the tabular editor is mostly a result of the **TabularAdapter** class, which is the base class from which all tabular editor adapters must be derived. The **TabularEditor** object interfaces between the underlying toolkit widget and your program, while the **TabularAdapter** object associated with the editor interfaces between the editor and your data. The design of the **TabularAdapter** base class is such that it tries to make simple cases simple and complex cases possible. How it accomplishes this is what we'll be discussing in the following sections. The TabularAdapter *columns* Trait ---------------------------------- First up is the **TabularAdapter** *columns* trait, which is a list of values which define, in presentation order, the set of columns to be displayed by the associated **TabularEditor**. Each entry in the *columns* list can have one of two forms: - string - ( string, any ) where *string* is the user interface name of the column (which will appear in the table column header) and *any* is any value that you want to use to identify that column to your adapter. Normally this value is either a trait name or an integer index value, but it can be any value you want. If only *string* is specified, then *any* is the index of the *string* within *columns*. For example, say you want to display a table containing a list of tuples, each of which has three values: a name, an age, and a weight. You could then use the following value for the *columns* trait:: columns = [ 'Name', 'Age', 'Weight' ] By default, the *any* values (also referred to in later sections as the *column ids*) for the columns will be the corresponding tuple index values. Say instead that you have a list of **Person** objects, with *name*, *age* and *weight* traits that you want to display in the table. Then you could use the following *columns* value instead:: columns = [ ( 'Name', 'name' ), ( 'Age', 'age' ), ( 'Weight', 'weight' ) ] In this case, the *column ids* are the names of the traits you want to display in each column. Note that it is possible to dynamically modify the contents of the *columns* trait while the **TabularEditor** is active. The **TabularEditor** will automatically modify the table to show the new set of defined columns. The Core TabularAdapter Interface --------------------------------- In this section, we'll describe the core interface to the **TabularAdapter** class. This is the actual interface used by the **TabularEditor** to access your data and display attributes. In the most complex data representation cases, these are the methods that you must override in order to have the greatest control over what the editor sees and does. However, the base **TabularAdapter** class provides default implementations for all of these methods. In subsequent sections, we'll look at how these default implementations provide simple means of customizing the adapter to your needs. But for now, let's start by covering the details of the core interface itself. To reduce the amount of repetition, we'll use the following definitions in all of the method argument lists that follow in this section: object The object whose trait is being edited by the **TabularEditor**. trait The name of the trait the **TabularEditor** is editing. row The row index (starting with 0) of a table item. column The column index (starting with 0) of a table column. The adapter interface consists of a number of methods which can be divided into two main categories: those which are sensitive to the type of a particular table item, and those which are not. We'll begin with the methods that are sensitive to an item's type: get_alignment ( object, trait, column ) Returns the alignment style to use for a specified column. The possible values that can be returned are: *'left'*, *'center'* or *'right'*. All table items share the same alignment for a specified column. get_width ( object, trait, column ) Returns the width to use for a specified column. The result can either be a float or integer value. If the value is <= 0, the column will have a *default* width, which is the same as specifying a width of *0.1*. If the value is > 1.0, it is converted to an integer and the result is the width of the column in pixels. This is referred to as a *fixed width* column. If the value is a float such that 0.0 < value <= 1.0, it is treated as the *unnormalized fraction of the available space* that is to be assigned to the column. What this means requires a little explanation. To arrive at the size in pixels of the column at any given time, the editor adds together all of the *unnormalized fraction* values returned for all columns in the table to arrive at a total value. Each *unnormalized fraction* is then divided by the total to create a *normalized fraction*. Each column is then assigned an amount of space in pixels equal to the maximum of 30 or its *normalized fraction* multiplied by the *available space*. The *available space* is defined as the actual width of the table minus the width of all *fixed width* columns. Note that this calculation is performed each time the table is resized in the user interface, thus allowing columns of this type to increase or decrease their width dynamically, while leaving *fixed width* columns unchanged. get_can_edit ( object, trait, row ) Returns a boolean value indicating whether the user can edit a specified *object.trait[row]* item. A **True** result indicates that the value can be edited, while a **False** result indicates that it cannot. get_drag ( object, trait, row ) Returns the value to be *dragged* for a specified *object.trait[row]* item. A result of **None** means that the item cannot be dragged. Note that the value returned does not have to be the actual row item. It can be any value that you want to drag in its place. In particular, if you want the drag target to receive a copy of the row item, you should return a copy or clone of the item in its place. Also note that if multiple items are being dragged, and this method returns **None** for any item in the set, no drag operation is performed. get_can_drop ( object, trait, row, value ) Returns whether the specified *value* can be dropped on the specified *object.trait[row]* item. A value of **True** means the *value* can be dropped; and a value of **False** indicates that it cannot be dropped. The result is used to provide the user positive or negative drag feedback while dragging items over the table. *Value* will always be a single value, even if multiple items are being dragged. The editor handles multiple drag items by making a separate call to *get_can_drop* for each item being dragged. get_dropped ( object, trait, row, value ) Returns how to handle a specified *value* being dropped on a specified *object.trait[row]* item. The possible return values are: - **'before'**: Insert the specified *value* before the dropped on item. - **'after'**: Insert the specified *value* after the dropped on item. Note there is no result indicating *do not drop* since you will have already indicated that the *object* can be dropped by the result returned from a previous call to *get_can_drop*. get_font ( object, trait, row ) Returns the font to use for displaying a specified *object.trait[row]* item. A result of **None** means use the default font; otherwise a **wx.Font** object should be returned. Note that all columns for the specified table row will use the font value returned. get_text_color ( object, trait, row ) Returns the text color to use for a specified *object.trait[row]* item. A result of **None** means use the default text color; otherwise a **wx.Colour** object should be returned. Note that all columns for the specified table row will use the text color value returned. get_bg_color ( object, trait, row ) Returns the background color to use for a specified *object.trait[row]* item. A result of **None** means use the default background color; otherwise a **wx.Colour** object should be returned. Note that all columns for the specified table row will use the background color value returned. get_image ( object, trait, row, column ) Returns the image to display for a specified *object.trait[row].column* item. A result of **None** means no image will be displayed in the specified table cell. Otherwise the result should either be the name of the image, or an **ImageResource** object specifying the image to display. A name is allowed in the case where the image is specified in the **TabularEditor** *images* trait. In that case, the name should be the same as the string specified in the **ImageResource** constructor. get_format ( object, trait, row, column ) Returns the Python formatting string to apply to the specified *object.trait[row].column* item in order to display it in the table. The result can be any Python string containing exactly one Python formatting sequence, such as *'%.4f'* or *'(%5.2f)'*. get_text ( object, trait, row, column ) Returns a string containing the text to display for a specified *object.trait[row].column* item. If the underlying data representation for a specified item is not a string, then it is your responsibility to convert it to one before returning it as the result. set_text ( object, trait, row, text ): Sets the value for the specified *object.trait[row].column* item to the string specified by *text*. If the underlying data does not store the value as text, it is your responsibility to convert *text* to the correct representation used. This method is called when the user completes an editing operation on a table cell. get_tooltip ( object, trait, row, column ) Returns a string containing the tooltip to display for a specified *object.trait[row].column* item. You should return the empty string if you do not wish to display a tooltip. The following are the remaining adapter methods, which are not sensitive to the type of item or column data: get_item ( object, trait, row ) Returns the specified *object.trait[row]* item. The value returned should be the value that exists (or *logically* exists) at the specified *row* in your data. If your data is not really a list or array, then you can just use *row* as an integer *key* or *token* that can be used to retrieve a corresponding item. The value of *row* will always be in the range: 0 <= row < *len( object, trait )* (i.e. the result returned by the adapter *len* method). len ( object, trait ) Returns the number of row items in the specified *object.trait* list. The result should be an integer greater than or equal to 0. delete ( object, trait, row ) Deletes the specified *object.trait[row]* item. This method is only called if the *delete* operation is specified in the **TabularEditor** *operation* trait, and the user requests that the item be deleted from the table. The adapter can still choose not to delete the specified item if desired, although that may prove confusing to the user. insert ( object, trait, row, value ) Inserts *value* at the specified *object.trait[row]* index. The specified *value* can be: - An item being moved from one location in the data to another. - A new item created by a previous call to *get_default_value*. - An item the adapter previously approved via a call to *get_can_drop*. The adapter can still choose not to insert the item into the data, although that may prove confusing to the user. get_default_value ( object, trait ) Returns a new default value for the specified *object.trait* list. This method is called when *insert* or *append* operations are allowed and the user requests that a new item be added to the table. The result should be a new instance of whatever underlying representation is being used for table items. Creating a Custom TabularAdapter -------------------------------- Having just taken a look at the core **TabularAdapter** interface, you might now be thinking that there are an awful lot of methods that need to be specified to get an adapter up and running. But as we mentioned earlier, **TabularAdapter** is not an abstract base class. It is a concrete base class with implementations for each of the methods in its interface. And the implementations are written in such a way that you will hopefully hardly ever need to override them. In this section, we'll explain the general implementation style used by these methods, and how you can take advantage of them in creating your own adapters. One of the things you probably noticed as you read through the core adapter interface section is that most of the methods have names of the form: *get_xxx* or *set_xxx*, which is similar to the familiar *getter/setter* pattern used when defining trait properties. The adapter interface is purposely defined this way so that it can expose and leverage a simple set of design rules. The design rules are followed consistently in the implementations of all of the adapter methods described in the first section of the core adapter interface, so that once you understand how they work, you can easily apply the design pattern to all items in that section. Then, only in the case where the design rules will not work for your application will you ever have to override any of those **TabularAdapter** base class method implementations. So the first thing to understand is that if an adapter method name has the form: *get_xxx* or *set_xxx* it really is dealing with some kind of trait called *xxx*, or which contains *xxx* in its name. For example, the *get_alignment* method retrieves the value of some *alignment* trait defined on the adapter. In the following discussion we'll simply refer to an attribute name generically as *attribute*, but you will need to replace it by an actual attribute name (e.g. *alignment*) in your adapter. The next thing to keep in mind is that the adapter interface is designed to easily deal with items that are not all of the same type. As we just said, the design rules apply to all adapter methods in the first group, which were defined as methods which are sensitive to an item's type. Item type sensitivity plays an important part in the design rules, as we will see shortly. With this in mind, we now describe the simple design rules used by the first group of methods in the **TabularAdapter** class: - When getting or setting an adapter attribute, the method first retrieves the underlying item for the specified data row. The item, and type (i.e. class) of the item, are then used in the next rule. - The method gets or sets the first trait it finds on the adapter that matches one of the following names: - *classname_columnid_attribute* - *classsname_attribute* - *columnid_attribute* - *attribute* where: - *classname* is the name of the class of the item found in the first step, or one of its base class names, searched in the order defined by the *mro* (**method resolution order**) for the item's class. - *columnid* is the column id specified by the developer in the adapter's *column* trait for the specified table column. - *attribute* is the attribute name as described previously (e.g. *alignment*). Note that this last rule always finds a matching trait, since the **TabularAdapter** base class provides traits that match the simple *attribute* form for all attributes these rules apply to. Some of these are simple traits, while others are properties. We'll describe the behavior of all these *default* traits shortly. The basic idea is that rather than override the first group of core adapter methods, you simply define one or more simple traits or trait properties on your **TabularAdapter** subclass that provide or accept the specified information. All of the adapter methods in the first group provide a number of arguments, such as *object*, *trait*, *row* and *column*. In order to define a trait property, which cannot be passed this information directly, the adapter always stores the arguments and values it computes in the following adapter traits, where they can be easily accessed by a trait getter or setter method: - *row*: The table row being accessed. - *column*: The column id of the table column being accessed (not its index). - *item*: The data item for the specified table row (i.e. the item determined in the first step described above). - *value*: In the case of a *set_xxx* method, the value to be set; otherwise it is **None**. As mentioned previously, the **TabularAdapter** class provides trait definitions for all of the attributes these rules apply to. You can either use the default values as they are, override the default, set a new value, or completely replace the trait definition in a subclass. A description of the default trait implementation for each attribute is as follows: default_value = Any( '' ) The default value for a new row. The default value is the empty string, but you will normally need to assign a different (default) value. format = Str( '%s' ) The default Python formatting string for a column item. The default value is *'%s'* which will simply convert the column item to a displayable string value. text = Property The text to display for the column item. The implementation of the property checks the type of the column's *column id*: - If it is an integer, it returns *format%item[column_id]*. - Otherwise, it returns *format%item.column_id*. Note that *format* refers to the value returned by a call to *get_format* for the current column item. text_color = Property The text color for a row item. The property implementation checks to see if the current table row is even or odd, and based on the result returns the value of the *even_text_color* or *odd_text_color* trait if the value is not **None**, and the value of the *default_text_color* trait if it is. The definition of these additional traits are as follows: - odd_text_color = Color( None ) - even_text_color = Color( None ) - default_text_color = Color( None ) Remember that a **None** value means use the default text color. bg_color = Property The background color for a row item. The property implementation checks to see if the current table row is even or odd, and based on the result returns the value of the *even_bg_color* or *odd_bg_color* trait if the value is not **None**, and the value of the *default_bg_color* trait if it is. The definition of these additional traits are as follows: - odd_bg_color = Color( None ) - even_bg_color = Color( None ) - default_bg_color = Color( None ) Remember that a **None** value means use the default background color. alignment = Enum( 'left', 'center', 'right' ) The alignment to use for a specified column. The default value is *'left'*. width = Float( -1 ) The width of a specified column. The default value is *-1*, which means a dynamically sized column with an *unnormalized fractional* value of *0.1*. can_edit = Bool( True ) Specifies whether the text value of the current item can be edited. The default value is **True**, which means that the user can edit the value. drag = Property A property which returns the value to be dragged for a specified row item. The property implementation simply returns the current row item. can_drop = Bool( False ) Specifies whether the specified value be dropped on the current item. The default value is **False**, meaning that the value cannot be dropped. dropped = Enum( 'after', 'before' ) Specifies where a dropped item should be placed in the table relative to the item it is dropped on. The default value is *'after'*. font = Font The font to use for the current item. The default value is the standard default Traits font value. image = Str( None ) The name of the default image to use for a column. The default value is **None**, which means that no image will be displayed for the column. # The text of a row/column item: text = Property tooltip = Str The tooltip information for a column item. The default value is the empty string, which means no tooltip information will be displayed for the column. The preceding discussion applies to all of the methods defined in the first group of **TabularAdapter** interface methods. However, the design rules do not apply to the remaining five adapter methods, although they all provide a useful default implementation: get_item ( object, trait, row ) Returns the value of the *object.trait[row]* item. The default implementation assumes the trait defined by *object.trait* is a *sequence* and attempts to return the value at index *row*. If an error occurs, it returns **None** instead. This definition should work correctly for lists, tuples and arrays, or any other object that is indexable, but will have to be overridden for all other cases. Note that this method is the one called in the first design rule described previously to retrieve the item at the current table row. len ( object, trait ) Returns the number of items in the specified *object.trait* list. Again, the default implementation assumes the trait defined by *object.trait* is a *sequence* and attempts to return the result of calling *len( object.trait )*. It will need to be overridden for any type of data which for which *len* will not work. delete ( object, trait, row ) Deletes the specified *object.trait[row]* item. The default implementation assumes the trait defined by *object.trait* is a mutable sequence and attempts to perform a *del object.trait[row]* operation. insert ( object, trait, row, value ) Inserts a new value at the specified *object.trait[row]* index. The default implementation assumes the trait defined by *object.trait* is a mutable sequence and attempts to perform an *object.trait[row:row]=[value]* operation. get_default_value ( object, trait ) Returns a new default value for the specified *object.trait* list. The default implementation simply returns the value of the adapter's *default_value* trait. A TabularAdapter Example ------------------------ Having now learned about the core adapter interface as well as the design rules supported by the default method implementations, you're probably wondering how you can use a **TabularAdapter** for creating a real user interface. So in this section we'll cover a simple example of creating a **TabularAdapter** subclass to try and show how all of the pieces fit together. In subsequent tutorials, we'll provide complete examples of creating user interfaces using both the **TabularEditor** and **TabularAdapter** in combination. For this example, let's assume we have the following two classes:: class Person ( HasTraits ): name = Str age = Int address = Str class MarriedPerson ( Person ): partner = Instance( Person ) where **Person** represents a single person, and **MarriedPerson** represents a married person and is derived from **Person** but adds the *partner* trait to reference the person they are married to. Now, assume we also have the following additional class:: class Report ( HasTraits ): people = List( Person ) which has a *people* trait which contains a list of both **Person** and **MarriedPerson** objects, and we want to create a tabular display showing the following information: - Name of the person - Age of the person - The person's address - The name of the person's spouse (if any) In addition: - We want to use a Courier 10 point font for each line in the table. - We want the age column to be right, instead of left, justified - If the person is a minor (age < 18) and married, we want to show a red flag image in the age column. - If the person is married, we want to make the background color for that row a light blue. Given this set of requirements, we can now define the following **TabularAdapter** subclass:: class ReportAdapter ( TabularAdapter ): columns = [ ( 'Name', 'name' ), ( 'Age', 'age' ), ( 'Address', 'address' ) ( 'Spouse', 'spouse' ) ] font = 'Courier 10' age_alignment = Constant( 'right' ) MarriedPerson_age_image = Property MarriedPerson_bg_color = Color( 0xE0E0FF ) MarriedPerson_spouse_text = Property Person_spouse_text = Constant( '' ) def _get_MarriedPerson_age_image ( self ): if self.item.age < 18: return 'red_flag' return None def _get_MarriedPerson_spouse_text ( self ): return self.item.partner.name Hopefully, this simple example conveys some of the power and flexibility that the **TabularAdapter** class provides you. But, just in case it doesn't, let's go over some of the more interesting details: - Note the values in the *columns* trait. The first three values define *column ids* which map directly to traits defined on our data objects, while the last one defines an arbitrary string which we define so that we can reference it in the *MarriedPerson_spouse_text* and *Person_spouse_text* trait definitions. - Since the font we want to use applies to all table rows, we just specify a new default value for the existing **TabularAdapter** *font* trait. - Since we only want to override the default left alignment for the age column, we simply define an *age_alignment* trait as a constant *'right'* value. We could have also used *age_alignment = Str('right')*, but *Constant* never requires storage to be used in an object. - We define the *MarriedPerson_age_image* property to handle putting the *red flag* image in the age column. By including the class name of the items it applies to, we only need to check the *age* value in determining what value to return. - Similary, we use the *MarriedPerson_bg_color* trait to ensure that each **MarriedPerson** object has the correct background color in the table. - Finally, we use the *MarriedPerson_spouse_text* and *Person_spouse_text* traits, one a property and the other a simple constant value, to determine what text to display in the *Spouse* column for the different object types. Note that even though a **MarriedPerson** is both a **Person** and a **MarriedPerson**, it will correctly use the *MarriedPerson_spouse_text* trait since the search for a matching trait is always made in *mro* order. Although this is completely subjective, some of the things that the author feels stand out about this approach are: - The class definition is short and sweet. Less code is good. - The bulk of the code is declarative. Less room for logic errors. - There is only one bit of logic in the class (the *if* statement in the *MarriedPerson_age_image* property implementation). Again, less logic usually translates into more reliable code). - The defined traits and even the property implementation method names read very descriptively. *_get_MarriedPerson_age_image* pretty much says what you would write in a comment or doc string. The implementation almost is the documentation. Look for a complete traits UI example based on this sample problem definition in the *Single and Married Person Example* tutorial in this section. Now, as the complexity of a tabular view increases, the definition of the **TabularAdapter** class could possibly start to get large and unwieldy. At this point we could begin refactoring our design to use the **ITabularAdapter** interface and **AnITabularAdapter** implementation class to create *sub-adapters* that can be added to our **TabularAdapter** subclass to extend its functionality even further. Creating sub-adapters and adding them via the **TabularAdapter** *adapters* trait is a topic covered in a follow-on tutorial. traitsui-4.1.0/examples/tutorials/traitsui_4.0/editors/animated_gif.py0000644000175100001440000000465011674463545027110 0ustar ischnellusers00000000000000#--(Animated GIF Editor)-------------------------------------------------------- """ Animated GIF Editor =================== In Traits 3.0, a new **AnimatedGIFEditor** has been added to the Traits UI package. The purpose of the editor is to allow inclusion of simple animated graphics into a traits UI via the use of animated GIF files. The traits supported by the **AnimatedGIFEditor** editor are as follows: playing A string that specifies the extended name of a trait that specifies whether the animated GIF file is playing or not. If not specified, the default is to play the animated GIF file endlessly. The value associated with **AnimatedGIFEditor** should be the name of the animated GIF image file to be displayed. No user editing of the value is provided by this editor, it is display only. """ #--[Imports]-------------------------------------------------------------------- from os.path \ import join, dirname from traits.api \ import HasTraits, File, Bool, Int from traitsui.api \ import View, VGroup, HGroup, Item, EnumEditor from traitsui.wx.animated_gif_editor \ import AnimatedGIFEditor #--[Setup]---------------------------------------------------------------------- # Some sample animated GIF files: import traitsui as ui base_path = join( dirname( ui.__file__ ), 'demo', 'Extras', 'images' ) # Get the names of the animated GIF files that can be displayed: files = [ join( base_path, 'logo_64x64.gif' ), join( base_path, 'logo_48x48.gif' ), join( base_path, 'logo_32x32.gif' ) ] #--[AnimatedGIFDemo Class]------------------------------------------------------ class AnimatedGIFDemo ( HasTraits ): # The animated GIF file to display: gif_file = File( files[0] ) # Is the animation playing or not? playing = Bool( True ) # The traits view: view = View( VGroup( HGroup( Item( 'gif_file', editor = AnimatedGIFEditor( playing = 'playing' ), show_label = False ), Item( 'playing' ), ), '_', Item( 'gif_file', label = 'GIF File', editor = EnumEditor( values = files ) ) ), title = 'Animated GIF Demo', resizable = True, buttons = [ 'OK' ] ) #--------------------------------------------------------------------- demo = AnimatedGIFDemo() traitsui-4.1.0/examples/tutorials/traitsui_4.0/tutorial.desc0000644000175100001440000000034011674463545025151 0ustar ischnellusers00000000000000Traits UI Changes and Enhancements deferred: Deferred UI Notifications buttons: View Default Button Changes model_view: ModelView and Controller Classes items: Extended Traits UI Item and Editor References editors traitsui-4.1.0/examples/tutorials/traitsui_4.0/model_view.py0000644000175100001440000001252611674463545025163 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. #--(ModelView and Controller Classes)------------------------------------------- """ ModelView and Controller Classes ================================ Traits 3.0 introduces two new **Handler** subclasses, **ModelView** and **Controller**, both of which are intended to help simplify the process of creating MVC (i.e. Model/View/Controller) based applications. Both **Controller** and **ModelView** classes add the following new traits to the **Handler** subclass:: # The model this handler defines a view and controller for: model = Instance( HasTraits ) # The UIInfo object associated with the controller: info = Instance( UIInfo ) The *model* trait provides simple access to the model object associated with either the **Controller** or **ModelView** class. Normally, the *model* trait is set in the constructor when a **Controller** or **ModelView** subclass is created. See the **Example** tab for an example of this. The *info* trait provides access to the **UIInfo** object associated with the active user interface view for the handler object. The *info* trait is set automatically when the handler's object view is created. So far, the **Controller** and **ModelView** classes are identical. The only difference between them is in the *context* dictionary each class defines when it creates it associated user interface. For a **Controller** subclass, the *context* dictionary contains: object The **Controller**'s *model* object. controller The **Controller** object itself. For a **ModelView** subclass, the *context* dictionary contains: object The **ModelView** object itself. model The **ModelView**'s *model* object. The **Controller** class is normally used when implementing a standard MVC-based design. In this case, the *model* object contains most, if not all, of the data being viewed, and can be easily referenced in the controller's **View** definition using unqualified trait names (e.g. *Item( 'name' )*). The **ModelView** class is useful when creating a variant of the standard MVC-based design the author likes to refer to as a *model-view*. In this pattern, the **ModelView** subclass typically reformulates a number of the traits on its associated *model* object as properties on the **ModelView** class, usually for the purpose of converting the model's data into a more user interface friendly format. So in this design, the **ModelView** class not only supplies the view and controller, but also, in effect, the model (as a set of properties wrapped around the original model). Because of this, the **ModelView** context dictionary specifies itself as the special *object* value, and assigns the original model as the *model* value. Again, the main purpose of this is to allow easy reference to the **ModelView**'s property traits within its **View** using unqualified trait names. Other than these somewhat subtle, although useful, distinctions, the **Controller** and **ModelView** classes are identical, and which class to use is really a personal preference as much as it is a design decision. Calling the Constructor ----------------------- Both the **ModelView** and **Controller** classes have the same constructor signature:: ModelView( model = None, **metadata ) Controller( model = None, **metadata ) So both of the following are valid examples of creating a controller for a model:: mv = MyModelView( my_model ) c = MyController( model = my_model ) An Example ---------- The code portion of this lesson provides a complete example of using a **ModelView** design. Refer to the lesson on *Delegation Fixes and Improvements* for an example of a related **Controller** based design. """ #---------------------------------------------------------------------- from traits.api import * from traitsui.api import * from traitsui.table_column import * #--[Parent Class]--------------------------------------------------------------- class Parent ( HasTraits ): first_name = Str last_name = Str #--[Child Class]---------------------------------------------------------------- class Child ( HasTraits ): mother = Instance( Parent ) father = Instance( Parent ) first_name = Str last_name = Delegate( 'father' ) #--[ChildModelView Class]------------------------------------------------------- class ChildModelView ( ModelView ): # Define the 'family' ModelView property that maps the child and its # parents into a list of objects that can be viewed as a table: family = Property( List ) # Define a view showing the family as a table: view = View( Item( 'family', show_label = False, editor = TableEditor( columns = [ ObjectColumn( name = 'first_name' ), ObjectColumn( name = 'last_name' ) ] ) ), resizable = True ) # Implementation of the 'family' property: def _get_family ( self ): return [ self.model.father, self.model.mother, self.model ] #--[Example*]------------------------------------------------------------------- # Create a sample family: mom = Parent( first_name = 'Julia', last_name = 'Wilson' ) dad = Parent( first_name = 'William', last_name = 'Chase' ) son = Child( mother = mom, father = dad, first_name = 'John' ) # Create the controller for the model: demo = ChildModelView( model = son ) traitsui-4.1.0/examples/tutorials/images/0000755000175100001440000000000011674463545021471 5ustar ischnellusers00000000000000traitsui-4.1.0/examples/tutorials/images/run.png0000644000175100001440000000202111674463545022776 0ustar ischnellusers00000000000000PNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDATxb?% XJK; f100+rrR8e55i+;x~GbIŮ55dcc>~|]RA##T%a* rrꊞ*< L >ccc)w X~Ġ1p -FF`^GG6>>N70^ׯ&߿4$$$W mãG}:ADAZZAHt!!aǏoܸ| @A @3,[wihY\#'' 6`ݺ_ϟg & ر**2.]:=a߾ˁ1.!!Y ӇoY޽{k/_]AFFMCC_'$$AO߿c^F ,-YLÇ>b>u7o^~5+_JIIs XZZ)(H1/2,Z(@xx?VPPa`aaPY hjwA\\AJJ(W _5W qq `%++.Gϟ89ف)ܹ8q`ӧ˯_?,X0@\moQAQQ 8gP`FP͛gW^jy X@ĭ[WWp缼ڥrr߿bsP>0a2<{f2@0 ܹss %(qrr1̜9=z/F=ã  ,-mqssCX=;&cg+IENDB`traitsui-4.1.0/examples/tutorials/images/reload.png0000644000175100001440000000215711674463545023452 0ustar ischnellusers00000000000000PNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDATxbdHg`` ~c ~_ fgaaf[?~209-8~MmNV6 e5S:w .`/O?3/2裟@@33(1a|!myKϧ3ps Fhn`TݙjQ )3s+Odad7w^?ytwǟ0sa`ef F(.H^scc}ʴݹ}ٖ8e`6b(sFŧPdee`//hf@ X H 0xet`IENDB`traitsui-4.1.0/examples/tutorials/images/previous.png0000644000175100001440000000162011674463545024052 0ustar ischnellusers00000000000000PNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<"IDATxb?% X@#c+3ï L-ĕfbx;#1gc1 ( "tN3N ! f!֕56rlSOմ1|}aѯ ~b&+;p0|AL ~D F۬1Tx1@囟 ?``fϿ1<~ #{W``hmg!K+8X2 @YiU0[1ܹlXV3B  _Ex̚u Ò 8baO |d>َEVAoIX8FtxDZ10Ϗ gC g2}c tI 1LPP` Z^{ O_|eY  \\ <  ϲ#ݖg@M ?2| , 1e@̌X|q10p3,Ÿ́^3Õ?޽F/_( fl#'y4 擯 A6bAV !v)O޾"Ő`|КJ@zlKfRed`w?8M gs22ԇI2J1t5` 000@1p2&DϿ{I?I QG]}6001<!@e`xC[sW 0\FOĂ' l!Oow3ݿ. \,HHiv0~#w^IENDB`traitsui-4.1.0/examples/tutorials/default.css0000644000175100001440000000011111674463545022353 0ustar ischnellusers00000000000000pre { border: 1px solid black; background-color: #E8E8E8; padding: 4px } traitsui-4.1.0/examples/tutorials/doc_examples/0000755000175100001440000000000011674463545022667 5ustar ischnellusers00000000000000traitsui-4.1.0/examples/tutorials/doc_examples/doc_examples.rst0000644000175100001440000000415611674463545026072 0ustar ischnellusers00000000000000Documentation Examples ====================== This tutorial is simply a collection of the various examples taken from the Traits documentation. They are presented as a tutorial so that interested users can see the results of actually executing the example code, as well as to promote further study and exploration of various Traits topics in an interactive environment that allows easy modification and testing of changes to the code. So please feel free to explore the examples as your time, fancy and interest dictate. Have fun! A brief description of each of the examples presented in this tutorial follows: Add Class Traits Defining mutually-referring classes using the *add_class_trait* method. All Traits Features Shows the five primary features of the Traits package. Bad Self Ref Shows the incorrect way of defining a self-referencing class. Cast Simple Shows use of some of the simple casting types. Circular Definition Shows the incorrect way of defining mutually-referring classes. Compound Shows the definition of a compound trait. Custom TraitHandler Example of a custom TraitHandler Use Custom TraitHandler Example of using a custom TraitHandler Delegate Example of trait delegation. Delegate Prefix Examples of the Delegate() 'prefix' parameter. Delegation Notification Example of notification with delegation. Event Shows the definition of a trait event List Notifiers Example of zero-parameter handlers for an object containing a list Metadata Example of accessing trait metadata attributes Minimal Minimal example of using Traits. Override Default Example of overriding a default value for a trait attribute in a subclass Static Notification Example of static attribute notification This Example of This predefined trait Trait Reuse Example of reusing trait definitions Temp Wildcard Example of using a wildcard with a trait attribute name. All Wildcard Shows the trait attribute wildcard rules. Wildcard rules Example of trait attribute wildcard rules traitsui-4.1.0/examples/tutorials/doc_examples/default.css0000644000175100001440000000150011674463545025021 0ustar ischnellusers00000000000000body { background-color: #FFFFFF; } h1 { font-family: Arial; font-size: 14pt; color: #303030; background-color: #FCD062; padding-top: 3px; padding-left:8px; padding-bottom: 3px; padding-right: 8px; } h2 { font-family: Arial; font-size: 12pt; color: #303030; background-color: #FCD062; padding-top: 3px; padding-left:8px; padding-bottom: 3px; padding-right: 8px; } pre { border: 1px solid #A0A0A0; background-color: #FDF7E7; padding: 4px; } dl { border: 1px solid #A0A0A0; background-color: #FDF7E7; padding-top: 4px; padding-bottom: 6px; padding-left: 8px; padding-right: 8px; } dl dl { border: 0px solid #A0A0A0; } dt { font-family: Arial; font-weight: bold; dd { padding-bottom: 10px; } traitsui-4.1.0/examples/tutorials/doc_examples/examples/0000755000175100001440000000000011674463545024505 5ustar ischnellusers00000000000000traitsui-4.1.0/examples/tutorials/doc_examples/examples/array_editor.py0000644000175100001440000000224011674463545027541 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. # array_editor.py -- Example of using array editors #--[Imports]-------------------------------------------------------------------- from numpy.numarray import Int, Float from traits.api import HasPrivateTraits, Array from traitsui.api import View, ArrayEditor, Item from traitsui.menu import NoButtons #--[Code]----------------------------------------------------------------------- class ArrayEditorTest ( HasPrivateTraits ): three = Array(Int, (3,3)) four = Array(Float, (4,4), editor = ArrayEditor(width = -50)) view = View( Item('three', label='3x3 Integer'), '_', Item('three', label='Integer Read-only', style='readonly'), '_', Item('four', label='4x4 Float'), '_', Item('four', label='Float Read-only', style='readonly'), buttons = NoButtons, resizable = True ) if __name__ == '__main__': ArrayEditorTest().configure_traits() traitsui-4.1.0/examples/tutorials/doc_examples/examples/include_extra.py0000644000175100001440000000117311674463545027707 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. # include_extra.py --- Example of Include object # provided for subclasses from traits.api import HasTraits, Int, Str, Trait from traitsui.api import Group, Include, View import traitsui class Person(HasTraits): name = Str age = Int person_view = View('name', Include('extra'), 'age', kind='livemodal') Person().configure_traits() class LocatedPerson(Person): street = Str city = Str state = Str zip = Str extra = Group('street', 'city', 'state', 'zip') LocatedPerson().configure_traits() traitsui-4.1.0/examples/tutorials/doc_examples/examples/mixed_styles.py0000644000175100001440000000220611674463545027570 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. # mixed_styles.py -- Example of using editor styles at various levels #--[Imports]-------------------------------------------------------------------- from traits.api import HasTraits, Str, Enum from traitsui.api import View, Group, Item #--[Code]----------------------------------------------------------------------- class MixedStyles(HasTraits): first_name = Str last_name = Str department = Enum("Business", "Research", "Admin") position_type = Enum("Full-Time", "Part-Time", "Contract") traits_view = View(Group(Item(name='first_name'), Item(name='last_name'), Group(Item(name='department'), Item(name= 'position_type', style='custom'), style='simple')), title='Mixed Styles', style='readonly') ms = MixedStyles(first_name='Sam', last_name='Smith') ms.configure_traits() traitsui-4.1.0/examples/tutorials/doc_examples/examples/multiple_views.py0000644000175100001440000000245311674463545030133 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. # multiple_views.py -- Sample code to demonstrate the use of multiple views #--[Imports]-------------------------------------------------------------------- from traits.api import HasTraits, Str, Int from traitsui.api import View, Item, Group import traitsui #--[Code]----------------------------------------------------------------------- class SimpleEmployee3(HasTraits): first_name = Str last_name = Str department = Str employee_number = Str salary = Int traits_view = View(Group(Item(name = 'first_name'), Item(name = 'last_name'), Item(name = 'department'), label = 'Personnel profile', show_border = True)) all_view = View(Group(Item(name = 'first_name'), Item(name = 'last_name'), Item(name = 'department'), Item(name = 'employee_number'), Item(name = 'salary'), label = 'Personnel database ' + 'entry', show_border = True)) sam = SimpleEmployee3() sam.configure_traits() sam.configure_traits(view='all_view') traitsui-4.1.0/examples/tutorials/doc_examples/examples/configure_traits_view_group.py0000644000175100001440000000150511674463545032675 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. # configure_traits_view_group.py -- Sample code to demonstrate configure_traits() #--[Imports]-------------------------------------------------------------------- from traits.api import HasTraits, Str, Int from traitsui.api import View, Item, Group import traitsui #--[Code]----------------------------------------------------------------------- class SimpleEmployee(HasTraits): first_name = Str last_name = Str department = Str employee_number = Str salary = Int view1 = View(Group(Item(name = 'first_name'), Item(name = 'last_name'), Item(name = 'department'), label = 'Personnel profile', show_border = True)) sam = SimpleEmployee() sam.configure_traits(view=view1) traitsui-4.1.0/examples/tutorials/doc_examples/examples/multi_object_view.py0000644000175100001440000000274511674463545030601 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. # multi_object_view.py -- Sample code to show multi-object view with context #--[Imports]-------------------------------------------------------------------- from traits.api import HasTraits, Str, Int, Bool from traitsui.api import View, Group, Item #--[Code]----------------------------------------------------------------------- # Sample class class House(HasTraits): address = Str bedrooms = Int pool = Bool price = Int # View object designed to display two objects of class 'House' comp_view = View( Group( Group( Item('h1.address', resizable=True), Item('h1.bedrooms'), Item('h1.pool'), Item('h1.price'), show_border=True ), Group( Item('h2.address', resizable=True), Item('h2.bedrooms'), Item('h2.pool'), Item('h2.price'), show_border=True ), orientation = 'horizontal' ), title = 'House Comparison' ) # A pair of houses to demonstrate the View house1 = House(address = '4743 Dudley Lane', bedrooms = 3, pool = False, price = 150000) house2 = House(address ='11604 Autumn Ridge', bedrooms = 3, pool = True, price = 200000) # ...And the actual display command house1.configure_traits(view=comp_view, context={'h1':house1, 'h2':house2}) traitsui-4.1.0/examples/tutorials/doc_examples/examples/instance_editor_selection.py0000644000175100001440000000367211674463545032306 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. # instance_editor_selection.py -- Example of an instance editor with # instance selection #--[Imports]-------------------------------------------------------------------- from traits.api \ import HasStrictTraits, Int, Instance, List, Regex, Str from traitsui.api \ import View, Item, InstanceEditor #--[Code]----------------------------------------------------------------------- class Person ( HasStrictTraits ): name = Str age = Int phone = Regex( value = '000-0000', regex = '\d\d\d[-]\d\d\d\d' ) traits_view = View( 'name', 'age', 'phone' ) people = [ Person( name = 'Dave', age = 39, phone = '555-1212' ), Person( name = 'Mike', age = 28, phone = '555-3526' ), Person( name = 'Joe', age = 34, phone = '555-6943' ), Person( name = 'Tom', age = 22, phone = '555-7586' ), Person( name = 'Dick', age = 63, phone = '555-3895' ), Person( name = 'Harry', age = 46, phone = '555-3285' ), Person( name = 'Sally', age = 43, phone = '555-8797' ), Person( name = 'Fields', age = 31, phone = '555-3547' ) ] class Team ( HasStrictTraits ): name = Str captain = Instance( Person ) roster = List( Person ) traits_view = View( Item('name'), Item('_'), Item( 'captain', label='Team Captain', editor = InstanceEditor( name = 'roster', editable = True), style = 'custom', ), buttons = ['OK']) #--[Example*]------------------------------------------------------------------- if __name__ == '__main__': Team( name = 'Vultures', captain = people[0], roster = people ).configure_traits() traitsui-4.1.0/examples/tutorials/doc_examples/examples/key_bindings.py0000644000175100001440000000404111674463545027523 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. # key_bindings.py -- Example of a code editor with a key bindings editor #--[Imports]-------------------------------------------------------------------- from traits.api \ import Button, Code, HasPrivateTraits, Str from traitsui.api \ import View, Item, Group, Handler, CodeEditor from traitsui.key_bindings \ import KeyBinding, KeyBindings #--[Code]----------------------------------------------------------------------- key_bindings = KeyBindings( KeyBinding( binding1 = 'Ctrl-s', description = 'Save to a file', method_name = 'save_file' ), KeyBinding( binding1 = 'Ctrl-r', description = 'Run script', method_name = 'run_script' ), KeyBinding( binding1 = 'Ctrl-k', description = 'Edit key bindings', method_name = 'edit_bindings' ) ) # Traits UI Handler class for bound methods class CodeHandler ( Handler ): def save_file ( self, info ): info.object.status = "save file" def run_script ( self, info ): info.object.status = "run script" def edit_bindings ( self, info ): info.object.status = "edit bindings" key_bindings.edit_traits() class KBCodeExample ( HasPrivateTraits ): code = Code status = Str kb = Button(label='Edit Key Bindings') view = View( Group ( Item( 'code', style = 'custom', resizable = True ), Item('status', style='readonly'), 'kb', orientation = 'vertical', show_labels = False, ), id = 'KBCodeExample', key_bindings = key_bindings, title = 'Code Editor With Key Bindings', resizable = True, handler = CodeHandler() ) def _kb_fired( self, event ): key_bindings.edit_traits() if __name__ == '__main__': KBCodeExample().configure_traits() traitsui-4.1.0/examples/tutorials/doc_examples/examples/override_editor.py0000644000175100001440000000060011674463545030240 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. # override_editor.py --- Example of overriding a trait # editor from traits.api import HasTraits, Trait import traitsui from traitsui.api import ColorEditor from wxPython import wx class Polygon(HasTraits): line_color = Trait(wx.wxColour(0, 0, 0), editor=ColorEditor()) traitsui-4.1.0/examples/tutorials/doc_examples/examples/default_traits_view.py0000644000175100001440000000155311674463545031127 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. # default_traits_view.py -- Sample code to demonstrate the use of 'traits_view' #--[Imports]-------------------------------------------------------------------- from traits.api import HasTraits, Str, Int from traitsui.api import View, Item, Group import traitsui #--[Code]----------------------------------------------------------------------- class SimpleEmployee2(HasTraits): first_name = Str last_name = Str department = Str employee_number = Str salary = Int traits_view = View(Group(Item(name = 'first_name'), Item(name = 'last_name'), Item(name = 'department'), label = 'Personnel profile', show_border = True)) sam = SimpleEmployee2() sam.configure_traits() traitsui-4.1.0/examples/tutorials/doc_examples/examples/view_standalone.py0000644000175100001440000000175511674463545030251 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. # view_standalone.py --- Example of a view as a # standalone object import wx from traits.api import HasTraits, Int, Str, Trait from traitsui.api import View import traitsui class Person(HasTraits): first_name = Str last_name = Str age = Int gender = Trait(None, 'M', 'F') name_view = View('first_name', 'last_name') # Note that person_view is a standalone object. person_view = View('first_name', 'last_name', 'age', 'gender') bill = Person() class TraitApp ( wx.App ): def __init__ ( self, object, view ): self.object = object self.view = view wx.InitAllImageHandlers() wx.App.__init__( self, 1, 'debug.log' ) self.MainLoop() def OnInit ( self ): # This is the call to the ui() method. ui = self.view.ui(self.object) self.SetTopWindow( ui.control ) return True # Main program: TraitApp( bill, person_view ) traitsui-4.1.0/examples/tutorials/doc_examples/examples/tree_editor.py0000644000175100001440000001353411674463545027372 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. # tree_editor.py -- Example of a tree editor #--[Imports]-------------------------------------------------------------------- from traits.api \ import HasTraits, Str, Regex, List, Instance from traitsui.api \ import TreeEditor, TreeNode, View, Item, VSplit, \ HGroup, Handler, Group from traitsui.menu \ import Menu, Action, Separator from traitsui.wx.tree_editor \ import NewAction, CopyAction, CutAction, \ PasteAction, DeleteAction, RenameAction #--[Code]----------------------------------------------------------------------- # DATA CLASSES class Employee ( HasTraits ): name = Str( '' ) title = Str phone = Regex( regex = r'\d\d\d-\d\d\d\d' ) def default_title ( self ): self.title = 'Senior Engineer' class Department ( HasTraits ): name = Str( '' ) employees = List( Employee ) class Company ( HasTraits ): name = Str( '' ) departments = List( Department ) employees = List( Employee ) class Owner ( HasTraits ): name = Str( '' ) company = Instance( Company ) # INSTANCES jason = Employee( name = 'Jason', title = 'Engineer', phone = '536-1057' ) mike = Employee( name = 'Mike', title = 'Sr. Marketing Analyst', phone = '536-1057' ) dave = Employee( name = 'Dave', title = 'Sr. Engineer', phone = '536-1057' ) susan = Employee( name = 'Susan', title = 'Engineer', phone = '536-1057' ) betty = Employee( name = 'Betty', title = 'Marketing Analyst' ) owner = Owner( name = 'wile', company = Company( name = 'Acme Labs, Inc.', departments = [ Department( name = 'Marketing', employees = [ mike, betty ] ), Department( name = 'Engineering', employees = [ dave, susan, jason ] ) ], employees = [ dave, susan, mike, betty, jason ] ) ) # View for objects that aren't edited no_view = View() # Actions used by tree editor context menu def_title_action = Action(name='Default title', action = 'object.default') dept_action = Action( name='Department', action='handler.employee_department(editor,object)') # View used by tree editor employee_view = View( VSplit( HGroup( '3', 'name' ), HGroup( '9', 'title' ), HGroup( 'phone' ), id = 'vsplit' ), id = 'traits.doc.example.treeeditor', dock = 'vertical' ) class TreeHandler ( Handler ): def employee_department ( self, editor, object ): dept = editor.get_parent( object ) print '%s works in the %s department.' %\ ( object.name, dept.name ) # Tree editor tree_editor = TreeEditor( nodes = [ TreeNode( node_for = [ Company ], auto_open = True, children = '', label = 'name', view = View( Group('name', orientation='vertical', show_left=True )) ), TreeNode( node_for = [ Company ], auto_open = True, children = 'departments', label = '=Departments', view = no_view, add = [ Department ] ), TreeNode( node_for = [ Company ], auto_open = True, children = 'employees', label = '=Employees', view = no_view, add = [ Employee ] ), TreeNode( node_for = [ Department ], auto_open = True, children = 'employees', label = 'name', menu = Menu( NewAction, Separator(), DeleteAction, Separator(), RenameAction, Separator(), CopyAction, CutAction, PasteAction ), view = View( Group ('name', orientation='vertical', show_left=True )), add = [ Employee ] ), TreeNode( node_for = [ Employee ], auto_open = True, label = 'name', menu=Menu( NewAction, Separator(), def_title_action, dept_action, Separator(), CopyAction, CutAction, PasteAction, Separator(), DeleteAction, Separator(), RenameAction ), view = employee_view ) ] ) # The main view view = View( Group( Item( name = 'company', id = 'company', editor = tree_editor, resizable = True ), orientation = 'vertical', show_labels = True, show_left = True, ), title = 'Company Structure', id = \ 'traitsui.tests.tree_editor_test', dock = 'horizontal', drop_class = HasTraits, handler = TreeHandler(), buttons = [ 'Undo', 'OK', 'Cancel' ], resizable = True, width = .3, height = .3 ) if __name__ == '__main__': owner.configure_traits( view = view ) traitsui-4.1.0/examples/tutorials/doc_examples/examples/handler_override.py0000644000175100001440000000200011674463545030363 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. # handler_override.py -- Example of a Handler that overrides setattr(), and # that has a user interface notification method #--[Imports]-------------------------------------------------------------------- from traits.api import HasTraits, Bool from traitsui.api import View, Handler #--[Code]----------------------------------------------------------------------- class TC_Handler(Handler): def setattr(self, info, object, name, value): Handler.setattr(self, info, object, name, value) info.object._updated = True def object__updated_changed(self, info): if info.initialized: info.ui.title += "*" class TestClass(HasTraits): b1 = Bool b2 = Bool b3 = Bool _updated = Bool(False) view1 = View('b1', 'b2', 'b3', title="Alter Title", handler=TC_Handler(), buttons = ['OK', 'Cancel']) tc = TestClass() tc.configure_traits(view=view1) traitsui-4.1.0/examples/tutorials/doc_examples/examples/configure_traits_view.py0000644000175100001440000000131511674463545031460 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. # configure_traits_view.py -- Sample code to demonstrate configure_traits() #--[Imports]-------------------------------------------------------------------- from traits.api import HasTraits, Str, Int from traitsui.api import View, Item import traitsui #--[Code]----------------------------------------------------------------------- class SimpleEmployee(HasTraits): first_name = Str last_name = Str department = Str employee_number = Str salary = Int view1 = View(Item(name = 'first_name'), Item(name = 'last_name'), Item(name = 'department')) sam = SimpleEmployee() sam.configure_traits(view=view1) traitsui-4.1.0/examples/tutorials/doc_examples/examples/view_attributes.py0000644000175100001440000000071311674463545030300 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. # view_attributes.py --- Example of a view as an # attribute of a class from traits.api import HasTraits, Int, Str, Trait from traitsui.api import View import traitsui class Person(HasTraits): first_name = Str last_name = Str age = Int gender = Trait(None, 'M', 'F') name_view = View('first_name', 'last_name') bill = Person() bill.configure_traits() traitsui-4.1.0/examples/tutorials/doc_examples/examples/default_trait_editors.py0000644000175100001440000000151511674463545031441 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. # default_trait_editors.py -- Example of using default trait editors #--[Imports]-------------------------------------------------------------------- from traits.api import HasTraits, Str, Range, Bool from traitsui.api import View, Item #--[Code]----------------------------------------------------------------------- class Adult(HasTraits): first_name = Str last_name = Str age = Range(21,99) registered_voter = Bool traits_view = View(Item(name='first_name'), Item(name='last_name'), Item(name='age'), Item(name='registered_voter')) alice = Adult(first_name='Alice', last_name='Smith', age=42, registered_voter=True) alice.configure_traits() traitsui-4.1.0/examples/tutorials/doc_examples/examples/enum_editor.py0000644000175100001440000000165511674463545027400 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. # enum_editor.py -- Example of using an enumeration editor #--[Imports]-------------------------------------------------------------------- from traits.api import HasTraits, Enum from traitsui.api import EnumEditor, View, Item #--[Code]----------------------------------------------------------------------- class EnumExample(HasTraits): priority = Enum('Medium', 'Highest', 'High', 'Medium', 'Low', 'Lowest') view = View( Item(name='priority', editor=EnumEditor(values={ 'Highest' : '1:Highest', 'High' : '2:High', 'Medium' : '3:Medium', 'Low' : '4:Low', 'Lowest' : '5:Lowest', }))) traitsui-4.1.0/examples/tutorials/doc_examples/examples/view_multi_object.py0000644000175100001440000000222311674463545030570 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. # view_multi_object.py --- Example of a view for # editing multiple objects import wx from traits.api import HasTraits, Int, Str, Trait from traitsui.api import View import traitsui class Person(HasTraits): first_name = Str last_name = Str class Company(HasTraits): company_name = Str # Standalone View object referencing objects in the UI context employee_view = View('e.first_name', 'e.last_name', 'c.company_name') bill = Person(first_name='Bill') acme = Company(company_name='Acme Products') class TraitApp ( wx.App ): def __init__ ( self, obj1, obj2, view ): self.obj1 = obj1 self.obj2 = obj2 self.view = view wx.InitAllImageHandlers() wx.App.__init__( self, 1, 'debug.log' ) self.MainLoop() def OnInit ( self ): # This is the call to the ui() method, which includes a # context dictionary ui = self.view.ui({'e':self.obj1, 'c':self.obj2}) self.SetTopWindow( ui.control ) return True # Main program: TraitApp( bill, acme, employee_view ) traitsui-4.1.0/examples/tutorials/doc_examples/examples/wizard.py0000644000175100001440000000054011674463545026356 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. # wizard.py ---Example of a traits-based wizard UI from traits.api import HasTraits, Int, Str, Trait import traitsui class Person(HasTraits): name = Str age = Int street = Str city = Str state = Str pcode = Str bill = Person() bill.configure_traits(kind='modal') traitsui-4.1.0/examples/tutorials/doc_examples/examples/lesson.desc0000644000175100001440000000153211674463545026651 0ustar ischnellusers00000000000000Examples from the Traits User Guide all_traits_features all_wildcard bad_self_ref circular_definition add_class_trait cast_simple compound custom_traithandler default_trait_ui delegate delegate_prefix disallow dynamic_notification enum_simple event explicit false graphic_example imageenumeditor include_extra instanceeditor instance_example keywords mapped map_simple minimal multiple_criteria object_trait_attrs override_default override_editor person_bmi range reuse_editor static_notification temp_wildcard this traitcasttype traitdict traitenum traitinstance traitlist traitmap traitprefixlist traitprefixmap traitrange traitstring traittuple traitype trait_reuse type_checked_methods type_simple user_custom_th use_custom_th validator view_attributes view_multi_object view_standalone widget wildcard wildcard_all wildcard_name wildcard_rules wizard traitsui-4.1.0/examples/tutorials/doc_examples/examples/configure_traits_view_buttons.py0000644000175100001440000000151511674463545033240 0ustar ischnellusers00000000000000# Copyright (c) 2007, Enthought, Inc. # License: BSD Style. # configure_traits_view_buttons.py -- Sample code to demonstrate # configure_traits() #--[Imports]-------------------------------------------------------------------- from traits.api import HasTraits, Str, Int from traitsui.api import View, Item from traitsui.menu import OKButton, CancelButton #--[Code]----------------------------------------------------------------------- class SimpleEmployee(HasTraits): first_name = Str last_name = Str department = Str employee_number = Str salary = Int view1 = View(Item(name = 'first_name'), Item(name = 'last_name'), Item(name = 'department'), buttons = [OKButton, CancelButton]) sam = SimpleEmployee() sam.configure_traits(view=view1) traitsui-4.1.0/examples/tutorials/doc_examples/lesson.desc0000644000175100001440000000006511674463545025033 0ustar ischnellusers00000000000000The Traits Documentation Examples Tutorial examples traitsui-4.1.0/image_LICENSE.txt0000644000175100001440000000760311674463545017353 0ustar ischnellusers00000000000000The icons are mostly derived work from other icons. As such they are licensed accordingly to the original license: Project License File ---------------------------------------------------------------------------- Eclipse Eclipse Public License image_LICENSE_Eclipse.txt Enthought BSD 3-Clause LICENSE.txt Nuvola LGPL image_LICENSE_Nuvola.txt Unless stated in this file, icons are the work of Enthought, and are released under a 3 clause BSD license. Files and original authors: ---------------------------------------------------------------------------- docs/source/tutorials/images: application1.png | Enthought application2.png | Enthought application3.png | Enthought code_block1.png | Enthought container.png | Enthought interactive.png | Enthought mpl_figure_editor.png | Enthought traits_thread.png | Enthought traitsui/image/library: std.zip | Enthought traitsui/images: array_node.png | Enthought bool_node.png | Enthought class_node.png | Eclipse complex_node.png | Enthought dialog_warning.png | Nuvola dict_node.png | Enthought float_node.png | Enthought folder-new.png | Nuvola function_node.png | Eclipse int_node.png | Enthought list_node.png | Enthought method_node.png | Eclipse none_node.png | Nuvola object_node.png | Eclipse other_node.png | Enthought set_node.png | Enthought std_horizontal_drag.png | Enthought std_horizontal_splitter.png | Enthought std_tab_active.png | Enthought std_tab_background.png | Enthought std_tab_hover.png | Enthought std_tab_inactive.png | Enthought std_tab.png | Enthought std_vertical_drag.png | Enthought std_vertical_splitter.png | Enthought string_node.png | Enthought traits_node.png | Eclipse tuple_node.png | Enthought examples/demo/: traits_ui_demo.jpg | Enthought examples/demo/Advanced/images: red_flag.png | Nuvola examples/demo/Applications/images: blue_ball.png | Nuvola GG5.png | Enthought header.png | Enthought notebook_close.png | Enthought notebook_open.png | Enthought red_ball.png | Enthought TFB.png | Enthought examples/demo/Extras/images: info.png | Enthought logo_32x32.gif | Enthought logo_48x48.gif | Enthought logo_64x64.gif | Enthought examples/demo/Standard_Editors/images: bottom_left_origin.gif | Enthought bottom_right_origin.gif | Enthought top_left_origin.gif | Enthought top_right_origin.gif | Enthought examples/demo/Standard_Editors/Popup_versions/images: bottom_left_origin.gif | Enthought bottom_right_origin.gif | Enthought top_left_origin.gif | Enthought top_right_origin.gif | Enthought examples/tutorials/images: next.png | Nuvola parent.png | Nuvola previous.png | Nuvola reload.png | Nuvola run.png | Nuvola traitsui-4.1.0/docs/0000755000175100001440000000000011674463545015310 5ustar ischnellusers00000000000000traitsui-4.1.0/docs/Traits UI User Guide.pdf0000644000175100001440000411644611674463545021504 0ustar ischnellusers00000000000000%PDF-1.4 %äüöß 2 0 obj <> stream xKk0 :J~)`hV0v֝^')I[hb8}i")PL9h<} ςBv>٘\rcZ:X&TWwoHEZt1`ĔKjws cpi_!WB~럋u_l7ObGgqȹ:7:%| Q^ZbȥLcֆ$؜5Ho% FԴiI+A[R+|95R7 J"Xp3GCl^Qs-zoL55L d,/-p$1xj ѲlaP̟Vߠ_4÷d endstream endobj 3 0 obj 350 endobj 4 0 obj <> stream xohW_g˥H)͂^}b{Kž@A\ikSQHaI]tnVl/B/uiVϺI )يiIզk5nkVX!!_$dfΙ3p̜yΙ3{? !B!B!B!B!B!B!B!B!B!B)+s GNvۺ{oS̝!B ;l~Am{6B)=/BH)Ux"Paa#B!޽wsݡ" #;37BHinsOŚ;G6B)(PIhe u ǧnB!@\>&TX'ۺ.#B!3w6aKyB7YmO"FFg9B!VAO2UXw89{^މ&B2gʘ܉LÆ[(B!Y1=sg щsBINd6rBHuVׇΝ4߶7BH|_rSݡ%U`ЕBFNd艀BHY{L5'3BQ27ޗz" RL,;im%D}@KoyE؏ީbF#-aEnDzB6\UXke7kk= ßMgW{7\H::fꬅ{JE}tw(JU/وN M1ٚblx($+%J$Uڟ/Rl 3~.a6HgQ:U$:~#U/Ɍl)GgۂG˪?DT m_alzRgd9fqA8vW.ʬN)lkϨ5Y lQA_{S! /8BgajfRg9`BmtvKo=#l.6Rg%*SRĤN5sZ]ζӳHiN:Ⱥr{ -F& Bau믧35,!3w,v*@,B}s_%>EHT_gg3-x M7)E#-)d}_mc~oR4oP,ΚV谫+fx2`B {PruSm+dRG9nd,7-Ls x=HsIlğU;|TO=\g۵E+ҦZl֑cWdE^'lUux@~ }[4uRg-P:;<:)z%Yk:iw)N[ՓyO-w YgZ*<%yS*L4O@IuV;e(VBp(vtc=_ oSg3\HJq-12Vg5t45Bʨou}hgKo]bO/|ra@S ķo}:]PbYkR ޱ3D:ffw%:krlƝvvSݡ+cӘ eE7VF7uSAgRIurVL+PuTEu u:;<:41PƁbS1_{{dgEu6`jvCCSUЙh*@-Ny鍷M8YOt}CcIMcƤtՏfAT*SgWxk,[XFg+XզZlv+&0 >ӷWM xP2S4`CwȜ>u+/ÊC,˷E_:[ѮYZ7d;m+ ^5l>89\ܸ2h~\] a@л`Z:+\t!w6 kRq>]\\<\"W >?yCT!zyh˚P7:ܢЎjq2SopaLJ,N@yuVxkNbէM}=Ykp<+K|*3 w0wj#ҡÆjtxop;"im@5MXF؟u6_gd'fQ٥\SLԣzsŏ?k<7@aXc#ZنǞ;`$u{i;fi-,Lx%]` AH~f[?-yjr9!B6{ByfU~OS& !byf$:k#'m]cBHyZRPgqyfXRPg-pmbDJ,!T7L|Fb:K! u6#Y-duBl>^LuЛ#/~o 7uĤ ~7̓oXeCSOnh ne̗xۤ%"|ѸE_$KCz>CKGpdm;B?RKiɡΦЕGrNggQUףQU23.4յ\O+㹁 Gj^TOG<+nQņL'ÎF4]WK@W_rK]vT]XeCSҜNTo8 _E Guda'?ů/ԒEuoJ0i~A͉_Pߵ ʞj}E]QJш&J溭Qb`zɚDgEYAs'ǥґ'NgUPgрw[BuV* 4%FkjE="RupwCS_G5wκN VUgD q *3uo)0zA9قR4}@HaUم !'ʴ"qޔ,t6jd$Zwm!(ѡ|n{\wenaBs' 0ItPp ,yPHb۸Q>.p4_FM )ꬌ=uVqȍ!޻&H{^3)ިȥHB'ݿ,&߈d$CύtOG!~XzGNg7FDiHn$sB?sDJVL8oN?tqa~ގ4_e9&:k:sY%bYg +%΢"_*K4SňCRZE~iP9)i'yQЖ^:[Yח"I[d< \3/B 2{Vԍ :e:[YܯLF;㮂hL%)o6)]kEYt1iqz)W"zc' ʨ^a5ASlĈPNxBe*ʃ~ޝNn(60̱MaM2' H~K_9^4keBNdtBѩ΢24 +*Yzfi%;ۣN #^˶'n>[d_g+KlCYYݵTPn(RzM3*k4&5OP@UPwM S*ЌoD+U4 p~TCRƈ:P%B3 m˕øpT9Z$QP _cLJ.0oOcdHd6* u}'o5ߧ$DžʀჩUdAN(Фzи"t22\[ B@v:+l?Ne|oB1$kSMLC%b￿wÙ#k,,!T7kMj;N _.s -ΎRg !dՍVε;^3ZD%>ŋ֤{jf龏OnYakqYpA!8ܾa䶼sJjO!26zl6]iZ޽X5?B T 6~_X8B v79ʌBoz{mm sO+aGNv M!A70rtS1te,-';Qî-%an'lJ-ʤԭt옇GCO&BɛAs-ENvL†5.!@ ȟM>16z=}ϝYs*BHl?oyArmBHviqF NvrY$SwdE!dmNt#\;!lo8~mb2\'XlSgvW؍;GlB!kᄏsoTή߶/ &B, g8K!8,vbT,!b2Lvk_';B!'#m{BŋٽMdG!ܾM_oOau}ofhBkWSFNQgɎBH5TtvGNvq*BHI|'][8K!;>n?:te,B!69;:˩XB!kɛ,=BYDIgkOO;}BH|]:_&B!XLM; ;a B e0^gɎB1A;^ӓ!x:qgcHޖB!da~~drή߶/o !wtSBH|uc}!B!B!B!B!B!B!B!B!B!B!B!B!B!$u$ endstream endobj 5 0 obj 8091 endobj 7 0 obj <> stream xZ[4~?"H)I*Rs"p$O"!}ٿxfl. SǗخ:?zzm9o_t>xu CޯoKeNC[ts糾.|Vng}+|nhz/d볲;Wxhfgm{6̡33ac_޾st'WiQb-baVqaFMK?͸̴@Cu2@>& R*(Ba)4 h2G'Ch̰q yi.Рyd! Gh1;Ω]<.>DS`+}g|Y-&ؑ N((%`'IFDceI`Ov vpÔo>YK Z Df[  p4(Ll֒d)=]M4Ld)(킊[r[&KoL@i'$MlhLS]0mOĕ좤5?} ;x}-:9qWLA UyC4πd<щlso}^z绳mq=\OSIKԞ&\ %EC/L) Gf'w F0,b~PҞ=,Op?FR-ӴM4H x\dݔ0ϊPmgo"h;Bz/~6\E"9eR; &ͩaQ cGuga`t2Wٵ+%kKŀ}Y+n;rE*(Cf${oQ ܫ3銚N%St7p'[,(R#*B5Exbg]L)%px^OZl9jʲ&ߨ:(bEQ͊԰ ,qWU;C z" Iy؉b!as)P9DS`b<͡|Mx,nvN쒢2T8=0'+s<ȺL;nQ:/MCz]Rf4N{(\91V.~ٰdlͨddu(o]qg.Z#&ϥc9,`_d ZB(U>h, "scc=f7{3WQJ!1ָGhٜ*o >syO].X \#u&] .Q8KUc?m8瘿L{ ;=bRu( DrI SbYg,wg'${t#iѠل2xhG!a(9 Vaa$DԾ3((PBO0B #W6>7(a#Ypad uh&0vbǂinY!4‰2Ɉ䯣u !sE_dZ-Q9Ȟ6.Wy6Ju?]r[wt{*O$]"!5@"gVL ,qe-E.ekL"ZaN*!Ɯيp5%/<1r'Zi_\d ~Eg Lyt*@g?N9Y,bXLڅ$]IX߉jSQ-^Kʬ[0eZβ,h."IbM8i~7+l*8bzbC#̲~eU(6E';;7Gw$dYh+e6bN% Y.(sRV=4>";ΘC&[u0LH6%ΈLQl^cZCbOFشdĥ[ +o3;&kMq8k@8DmlN '~Ma?8|&g%^yW5o?v Js}(bDyWQ]٠RYHy4[t}p!Nԕ56'cmⶃ.,qm??]a=r`x Q_ YH%ZYߜ7bZ y5 U>qU\q,[E0PJp |9H_@UCh fQ OK+XV)sZۍ0WK9e,Z#@cQ`+-`h={ū9z׻K8Vrv[Nd~ xƢܥJ~`w_݋-0 V-2 &$qÆ*Wex`; endstream endobj 8 0 obj 2262 endobj 10 0 obj <> stream x][ ~_j@`2}}()Pt ߯(ɶ2dE3iRT(Z淇mf+; t?m 7iFw8%?RzJ/w?7xUi7߾m {qT wʽ0>Pd }=˷T ‰ ePyWV{i<_sy>.$h'd2DAo?Oͯt6)*vu˾|#Q?8n*g:0ٝb6_}4C_AQyoPZ )pQϑc"t0aUbFXCS8U _ 3Jf6 Vzߊў<2CW+cYS׌MiQMu-x0Dxd83,ڽMްvm:%vjGE@.]dq`QHoKaw/*-`M{Cuذ;utyd̀Ի̄ ^r(/2QFc/#2|d-.NS7vX7dhڤDZBrV-ZkOX~a>2F#권sJ+4޺_ qOTo@Sy>MhM MkYKd *a][w *tL7󋱃7e[oܽ \A<3B0~'ScKx[^1^TxEPXg+h0u2X-@4dY2ZxF8y( 7bk 2MNy_cI$tE=vfE> ^:Kg#Tҵ1լ)/ lf'EE,1htiI+dN#i͘`U3̟lS"E`=}2Tz+Zq{w}"D#S?*{B^vjdDV3Nu)<ֆ3q}93dzxøP1.@ !yϐiVe8C 5aÚ Zv-=ҁE19/i5[ lځk!!ZVN {]^TAEy>Xn\y)OT> `OĴ[ωO-1! ,J:z0L9uPH0\33-! B"^*{LdkX*D $ɜe ]v[S"+P8b/OW"J07r>˜ͥ-ӛb [bKf&a̛^Tq`&"qGzt3;'xMQi>I1S$E[9LE+c)c:xG~Օs>DGicʢHO"Au_ $),=Z1Ih[,I7BYRĖ]e6̪1V"SoPipV!Vg5 ^-$xGH4H_Qw,߄5&07mmjF=bM+i^Tg"baP:`2zDg`lSB"0g"gM0Spӯ #ofaFL;LHx#F1a:7&~-FE8mONtPFe0Wp?yVz g:9} &+\{*yPѶf>._-;q{;Il*RE4#TdGn מѬrJ? ceKQ𧀆/|V hJ#Tj׏.\B"| K:¿Q.KRHN[]rZk)6۞OvYT6p.hq=Z/uFqvf@CG-EXpr-[wEʋxMnno=˷.\vʟ$Ӓ9v @1ҶF'ǘ# jCQHyTn'*n+$& 9- |3q(p&C5uY֐`J(& S|Blx.8,2rgE/Ȼ瞓2vRysk^WiX@O ) h@I`Fr/.H|[z" ^>׊0-a){!p8;QT\8Cnj1RCp X}Z4%(or86,]c-/RBhѰ[PG"~gB@t Q1dr_ZД h^pbi {8;[71a3cGn)Ie/ W  Ɗ dVs _:@{5U6G!Z[^=RjN4-IWӾNh"GLUjVZ&LG22=n`{: Y$2J4q#_jfi&)78Miۀc8 S}ɣoEc5{XUMDݵ'dGy_aN%`?w z0Wü/-BT@X GjvxMpZR@kqn ' 87뼗~=r;:{uF,,)3Z/-<{ th 'qZ^?C=Qݽqk|3U:4p ah+@#X tG>֜Q\3s_nEg.d l"D't=ɞCA @l¶ʮx#pE0mB.2F]c6yWybd26#2B< FU:bQf@F\DMQs\i/7R-*XDu)] {|:@UBbY6 ŝƯe#W}/XȈi' 鉭U2zh\ѓWLcAO~@_6zyogV endstream endobj 11 0 obj 4072 endobj 13 0 obj <> stream xo+|^ Y);+۶-Pt[^/%|IlKy ~K̏!淇_6jzmk7n=hoS`$JG<JO~؍6?m;U1ުagꠞw:^/x ̋-{4YXx_ᇇ6'و^?ܳx65,A-JW6/ېB}G&_ 55Rbc:eb;{W.AuecO5Irzt{fg }^Y-P!uy.ғ\tz6Ct ݂7F/3ָx#wQsp- |;̓}\vu>vor`^uQSwBTmT~2YjS>#|t:qKz}&L~+<+g DrA8ﶦO8Yʧҥ!L> w-X>f<љ!8-66ljdq׹??|\_=Zӝ pV՝jJ^LzմwBB5EqUǐ*@Zs* jej5HO׾Q&3PC~ 6F``K>RGLr77KL7! 64m ؉-2QM 1qqEͅ.Ē@ǑEX8lh.=[18~l`V`: pXwke*i'xD^7Ǚc:lFG>LL 1 9ΰ8@ETa9 ZGW+8v桓eN#~Q9V-Ue] g/d`1%$uٛ .l^R6cľ34V$BV: Ѹq Fа{tz hWO;kXwEWL؝{,{ABf5u q=Hr)r$Ĥ4D&rYoԂ=tc[} 4fYՒ|=ur7GVB~+c@-JAH74CP)$q>X$֮R H[:fBڠqwjh*dtz۾xgX|Cket:з0%mtB;WrDsyJኟC+ Rul3+8]7slFèտ23ZZG9hX,L )5S6y$XMA%دek'*IxPW >:׭@cKjIX07J_6/bXhejB^kes972ѰN?H|z?(\k4_n3!=HZh^k\"4޼ rHFY +fEV0 mYavۗ<*"XF&LKNB)!MajB,˩,IEگ{\nkVK"KiX}!+[aL?%C і#H(K rŊ9Nc;IIb}^0iȰ)1{OAI:E$5x 8Etokx'qd ,$<<uhYC2)4oĉ%=to'4='3V|USEjYf'1TQa MF;A@KiDE핤0U* y׎''Y3W%=EVKD4=%F!ԉIF5 Y,Fm|l\<~G\>v`ٰ]ߕXVL{S-Ğ ;6?hNRv,Zeň Ta#INAuN/[w88TLixYfNBD5uwAL&`M2\ϧcCv)L1{Cη^j(} :G@i:$ qV'&]>pZ734pB2p EIjgRV6Ft˘eUD4 9Ua7BgUKaڋIf?릁ܴʖz8tdQ4C>%,ٰkbr@$(X6)ljAO`n1*R3NEab(Xydp 0z0l#B6"2u) &˸?AK̉ mzAɡJv".|? fp {2=\aq0iY`YG.m=ގ*r؝a]CsQ]z.CeY"[+NTƺrn.Sm~c.necK:F1aOVqx`Jiᰔ׿Tn,낥~K^(bɇGTJXIV%*pz۟>n+TbJ#]SKŸk9G+r!L?.q ${HN7#(8h:裻?[0%*oU?#v?nȸa5偽/$»wܙO[`n;S07/bXeٮCOswr;)𪞠|9:X;!X#mj >JkPkIaP[P'g=Z{grLuef$K'XyÖiy>l0A'SK߄ޡ9Z3YX [c,'t5Ҟ>BN="T2jʂ\+U˻zPu:eS9SNe[V-#;DŽ_E[KrWxi?eto ,,ebYa)U$K. 0 I`Ua@"^$hG}UppzhH"b֊8sS&Q@CI< %O5qRK =|&cC;po\g7u!JG% jRh&wl_$c@2 H_-$KeSަ8(6!V>cMZޢ-ީZn^}SLW3[g㜽E4c$` 0Sw&1Xcp@KCʗ;o?*גpu\v%ԯ+3+p`b+bGK6 %S‡)Ӱ0;cLbBy;yW‘ITB5,/׍uwL?E;hIg@%7JTK G(NOɤIOCaJYF)imBS'FuAŻ$! LɜOͨm6NXCws1$SeR1o*u$3>ڄ6dޜQyzXbGz˯"ONmkHi't\RI;QmYwݣS%Q6UjTedO6qQPvc}|#돛KvL;y/O endstream endobj 14 0 obj 4417 endobj 15 0 obj < ] /Mask 17 0 R >> stream xkSJ}%‡AKݪMY'鐀z*~I$\BO4<;[zBxV~|]g$^y{*\ ?bSiN)"TTU&۹\9nF1oZP<ϴ8{ǽIw4UE 5[#:"Tާ٩ne " 7tZmʧScHn&2P3nBi FMLop7vz4^ąxf0ѽRai~oNcBf[tTG::9FNm)jiiE]+sV110uw'I&/#=7JsLz ;'jdjK%L=2f" S%\)LL)oՈbD()&}:}q{nŞL~\qd Egd [o!S-pq7{.bxUT> NFŞTywL儁 Sj6T7V9}M\$'u&v{8,E0E\Ske/ D /j]WGt.?n4h&54]O&w8LO 4 hױԕ&T3LfZJsiԵV)1 fzwq4ۯCɣO B3A ŎN_bXDLU/jQ+\ ~šb)/ͯ7WӥgSoTht߯Ŏ[Ͳ6_I&[f-Pe*m)'Samz..~\}$cq^\fsy0]r&k\SJ(ޛ087N*JvHj#HM.v^p]-Dz7eU$*;juI?뫫AT;4AU{C6B;wnPK9+ꈄ t5T| endstream endobj 16 0 obj 1307 endobj 17 0 obj <> stream x}1N1YY) |i 8A%W"v$KXfv ORK3[/b.I9$pU8s,eA0إ#sHt.nMkM'y*_G%`¹vfG%$ ^6R[(eo%E$$9ɯdKO%Oc.#ʆ|c!AfWmB)JJ q*_gҗĸ:;?GA ʅp .!=qu&4+5z mpn#gAΚ0=ae !Cwe>e N`P2V}94Jqq/꧸yUZ91 endstream endobj 18 0 obj 379 endobj 20 0 obj <> stream xKo# :/`o= ,&HnCS $OVzt7]W2M[52Ov|)Ma 1Ը&6Kr?g\oRj1#4 (F o&?0yg EL1I35̊DNslYV߆LXfDS#2#uȮh@k̪ͣ,Ϊa+_4_[Dpŧ( Ly XRf"ψ" EԈ)m3}!J*ָ{bAu(>ɣW#&ܔƈDJ DbxsP9z3ӣOh=z4Ɂ[7rޥЩRj=o;£r}/vPw}׊,I]r)x< xTkU=HZIU"h-j;&] )W0­ MGFlob2^*{aubЩ@ 8ۊىw!#zYl?IB2 \*?ڵŧnZ>jҽ kxzF"(<_zzA mAtW~-rIXS2 Ք *$PmYXP%"ʧq8iì &1C󌁩O4>!T68Ozm䵯(븆4Kd" {)_Uq pQ4-YHVQUr.ш2Y9((Tc E9H!# 5y5lȩșH]CUؒ TkJN\ ю]@WWn$fTQ`ъ=ߵ@!OHm#L$HmEb[* T!KXAfȲ^w$`.`1ZVĐQvAu9NVYhtKhKh0~fԉnJиP>ѡ&m2 ߢi}IP5}=kUeQ.ދ4DZgXI̠YJW__`>3eŕ{֜L QP 9$lx$w63f* Km0sf9e4?Yнp4S9x9g Gh2o#%.uZ,9tӪsz#+Lŕ˖juy3*^h* z}NH+{QJFhd#ZGŪrQ;h '(BQۅOx^ܶDRV]9IC+mK4YE t^G4G(U]wh &4wa 댒pX4I~ޕ[e%ЩiQa`B{F=lq1$PUns ~$sFI%~>bSmɻVt%VӖD ۨTų5ķbC.C/2nSOwױu.F[n:6+ز.]<};Nߣdh͉f3 d+WlU>;|Rqƛ3M1P̣9OSiWu;,`" pͥN\A5O2d5t؎-nU(}g"L F8]uI /W65b4೸9X0J*{5dU`hY`_`A3 h[lk-N4&{Tt0w pObL$`QJU]l{V'ų 4kua`Q<OQx&슷qINRr* 38|tXK~Z!Y@Vor!dx9q3=0`<ըx勥w]gW5uFֿ`R_/S,V_I:+WZB;/Rq1P71$r  yH8 K5 Q,VJ, TkuZ.Vơgl!Ӵ7^yRt}E^ P06[QNۓߡ30 j_,kJXkn#)K":(h=d'ZN54o8a>#uR.]JKF>VƐ;)C&y&η{yT'[+MES4cNCHO0' gPv> stream x]KyK~mrrJv;a(m>m[,<#-XT}*)7=QGl G/6 EISy7fo[٭jvvz٪z=EgP];мh2Gچ×/QN{Onp=:یgcce jQ>~7l^!Pk=9BQ/fЋ~6VuF9vMP郮 IM}Pզ#GRH_2>c:Cd:OdNo'ˌil ,3_QP/jc誦kogtlR/U+ձkTцNnw.IdDȐ,"2:4IB_QǍs0]GU~v$T95of$C6:rS'0_@LAAk-H{ƽȸ1ϸ pCF]:n<0BH茫y07|t) #p2ثC4F4kUԦ1PeШa{Δ9_EE ӢC84 %WǃsqnIq93sb6]@EўإĔl#hnO/!-s?U RB%+rwvCHW& n3C"5P^(9 `pa?!E]`(t 2(1 "b +EwTO@k、z0k%c7tg'}=+I \UFpմ$in+,ih3ݜqI߫yR;c2ζ _䐉QlO6# ZܯvMd]f) : !G~Yϸ`][1'Vr5=%LeF^^SnE-dE QHI Uj ;9GڊWoڪ7}m\>H2eCwC( n3'O~0`>HPDF97Gxz`DNx3`g&2\A38ԬZ6cuClIY{BCÇiX2\oB6qJ3R3Z%;#{tc qB7hi rBd &sv`J2}HvPԽVd|W_}>upċNJ ؠQ tTD}MtP_ Kl@՚"j] \b$؟IU nbUHr LA{F!qdZoъU/<.7Uv9qJc -&]bYH4ՇR~ pz›z,{-# p ͍O5и~FwFT%I\C'a2 4X~pa1_Ɛd^.S*o:ɣE͈yù瓔gg/8?(j3rQFB#qp~S(+ptRENAGFy@#/Yɂ8`{bXҺd+W8J]˦֏J *@LkZX Q@CR!G oN,V˵W hs i@hju0S8wϜ')WĄvi93W)IƮ܏t,- H .sC<QV0 "wFN6m 3 U]ʩ`9 6{2s8bibQ_GƶL}tmYRvxb}v 꽸l0DJ-u$ 2h9%Po863Xب \]^\WQx|pQ}00[ʨn%h%/0DH ŃeW25EZn=ǜMk8T fO0I Ukxe/$MƒoL+옼 %5 ef?Ԗ8/VQ݌}Dz9[5@Ş )=a@ZݔC ;mp#A.vx žk -hQqyy?nC@7TvQ0n$5ݹo> \d [M:پ/'=H(3q*\#+mČdpgΣ4&.3œd>@.rJuǰҾ`(C(3u(묐NfA-kiVO-\E7i4=ux_KAF2+V02y]78AΌH2W *prZ/gM!;nK7ƅ=L,144<5. Q 9% %KER&ge`D#UH%M W\ 3n:B%BƶVJ|c"V{Ltp; {"Ǚ QX:95\#:9#}1ΰ^#]0*Fw:Fl`@eb#RpiZN +\PM ,U fоlh['݉egO6&:BPb*(U4>lWePv}1G\'Ke n+_qYn4 \Ge,m}..iFN Br]tvޒZ~ا~Ȓ[0,N[HWTj.Ȍ?\E"U b&OBNE?O.`i,LW Pj-)r 9eŗC\lw 96/(3u`JJ:T<->+7[= 5hR^%E{u4I%.l]/p_Q,ÐJe]MH}EgmWε+uBֺ #2$IJE'2$p'Kkʍr6=8.mUxʮtlp ԛ۔?t/E/=}'Ogȧq8QR6NρdǶwj"b*eƝ~4=^wj2-*XuZl2>(,#"VIJ*]浊4a# +-U)?>V Z#e D)sE%^q3QX+r)<*JJ1S{H"Pgν2;(3F%|Q2> stream xZK#7ϯy^cp{Cn 9ܒ ^S*IԲg!2-T_}T>A ;j˗o?|a2 <_?peqᧇ>wvv8TgzVEY zwn[; cmkO#-bEV#hgag4ZO͌Ot+G.ܡ '|cXw\@UkC;\o%.Mٿ%- f\^Ý6e[e Z' DzL$:I%WC<!ME66oI[b<♐҈hؠ+8uNKӮl28=K~7S\WTV,Nx?~h4V&mN=[$La{üXfXvu`JK!Dz njw‚2ͣK*ILKxuvI o*Þ\ڮ2Ti}"QXY[e&2՛_w;~1!WW1| 5Mspo,]XIxev(1r9W4ߚWh dϪU"Ϯϡ 餖Xеȃk˛7/FzKpeLBh{*s9 9u[0\8#jXU_|3\rC[0E]w[ *wK7䦽fw`2; dkV\/Ct BQVef+S+]dL#fry:E67_E~ s7Ry/b\sD Y[L5\m9=0jŸѭM^qRCE`,K;s}؉hwXA;Wh *2ƛ^t39UEEݹK1'\LQ?XU3YAUT1)d|Eڶ$HYiR^?dJZ*:s2Ymc3` W(wq8mg5H &_ߋnZpD׫z 20nɋVn4: Dqu#[yzc'p> '}Lbɠtۤ z†CfY?tqN>Q$"heFNW{ ̳VH,i^whRp&B67ȼ6 +aTL rƖdA+͆jlŊb%5ULxkBgl>&9S7+TM|GEN5I޴SMt+!3d5FR*ĸm~R|gBE:qbZRBv9q,0+pv,ڊ<~U4{bwb\Θ-dRk%ж*# D`[^!ŝ$eMd'/PM2ڌY$؈k~W]s\D*PkF}>Jr5a{,' Z;d*!*juJ+Wݔ iW)2sW4bq\0dMկ,Oh9qbՐD~7\-ԩvW?C#dQ*t,C}]Ja,U`4Ge=YzG n377zu9N`&p>ba[3RUq 2ҍtC4H)Wf1UWe>%>өDY.RK1vQ6{5vvNc[Td,vjiM1bN%cwLY` [C%r=Ma $ixm(S+>D3MF5O[FU됍A8iETn endstream endobj 27 0 obj 2324 endobj 29 0 obj <> stream x[Iׯй!kb 'm0o&eԴ${/T]}mPE6pW/߆~V`'O Q7?~&Nᗧ>fj.puu3Wvpx ܱV|hMv1Y[x?=>߾}:"%,x;Ʒ߸??NxZJR媵z_85{ fkU|ofVYU^o3fED.4덺 ʢPb |n例W5qأ]yQ{;33h@p4 g jn C=:P(M5r+5717嬣 {pT?aڻmF^Ť6I]X{Q9 M8%A, Fb$ p_r_L~2w; Ѥ;eعtf9 $]n-51` u8t=/PIJ]尗JB B)$x`{KS|M|ņd0[&l䬁^yU\n33=`82Z~Jfn|*3$s?Je%G$6Fފw|['£/܍cBkq20 :О,FLZ[Iopg;m mg"6GУF@^![ڧXBr5X3&4۶Wx-A}LoGQEh3Nkӯ=k.^|{YȌz *9e ()AFm,wͳ =DO(%_؅iuMx_l> $fT ⍐Ub9aoDgl ]sу_P@99$= O rsMA%ū(As0gbqKm-/ʎʢl0(dOs 2IֲAwOEމ,M*ryLNSh]7&T4sbgY>پ_+ ?: Crl^I_ʙƕZshY4YBf(~k zL)j<Ta,EfDF3(}{4fUtVn6WX[_u:ix82W3v2<1^!ȫ[aS&*jmЗ BT.-S YyjaS$Que,DhV<8 r tOaj~阳kQf'^ʹ uۉ%>i3/$`Y݃!k52еM>%jF|d -\]B)dnyJUD~ όjp? I w ~XȉZN=~&gC3y덲UUO f@9ZOKS>Zn cPw?4^,ψe8&uC/16\=$\;wEOw<pZ"7e218tց7$1t G-׺'63+[Ͳ"Gh,C,qj[B!Tݕ,.l꒾s1KDƻ vϨUuVr48)w$$Z0^qtl-h ;kr}iLዧ|D7TmamH\hxJ G ajdq㦅bgIk|7".ys*;g;(I} U#7z:|g8f,"1[Kġ~~+> G?P8 endstream endobj 30 0 obj 2679 endobj 32 0 obj <> stream x[ˮ#5+z=R_mwKQtn`7p%0H }.?mݹЅLN;# x5}wß>ؿ;p?6F&~R}g瞧?<|G>/ au~r#0 ye!.?"lU]qf ]>on!gpQ`g.^=_WaJلq3LmL:.bL;er|h.bq|fv 'q FV*XW:[`pNvI?\a4cQ߳dmX$ v_oDr1i(%{Z:gK'}S/fI&[ѽZ v@~F\4xnb4e_F2dƨҨ^|藬51p5]a/=憯 T%0+jqg~o#Tk/\f{fX/㗙Y&uW~LF'4aW~!ƙ$)k|`!+hS؞>{%kY C:xXPCթ88ʿ.<;e'U7vT9htPwS/ + >(FoQ%@ ›G9%Om˜zJ߉45(Ť-,(0`3`%] GBcyLИg|  N9`Fނ]C˔V齰W0o{!zQvE~vPwU*NyT!\-a &F\eu]ߞIZL-L6 %]S.%HbefZl1LWf)qkˉ[Mv5Jq&m5 ɾh0\U1N l%7rp`Dp[6Ոzg)ʍH\P7Qm=b֏F4 DJT 613\ΎՆ&H}K솜Lgv*_2[`%*ˋFdhaK-+]dkSZ `ʫ0mΥFaP |c*lrb{ b~j7 UH"o>Y`iܞmHȞc_ yx*=m[]UVϘK&8D:ƤDM->G\rg[w+|PEaHy1Bw,tdPM|_| G{-p/-}UuJ⑥lf@Bi ?✞!Ε▦s T|!RSN\P{C[4(T iO OQ4bc`e$bK"D yF*BoM;me 8hP9sqJzc `ى֝ *)J$ztK2iEAwdlxȠRtiPv [-fh*+ 8*"[}˺ κblJ|1IsUXz`'_޺uSoΕH)ɍM*].4M>-Je0漞R^XےUMyW=9 |;{pyjYr8(VƦt)5r OZQ.\MY8>#EkI:m/zM{[7yĚw'hMc 0CPڎ"[ZPTz#lҶVGoK`{Sm'ј%-{<.mP$HLSF6})Fd%eIbz}V@*8Iv]㿹Cl]}9?)p!K @B֐J:EpݞfUu<+fQy)N#ìG~'B0KB656]$qYϧ44dU'(|cwt\ Jcky^ȳ3mW;C%A &l0V]*)gTLbO#V}x'-sMͼޞqmG_qmrS~O!@-|[6D#HC>sOGW endstream endobj 33 0 obj 2529 endobj 35 0 obj <> stream xYKFW< oWwF`ylHn96@`v/G-2ԯztYQMk?>s~u56 ZNj[J8Zos߼|ytl.[3\4Zmn^՝ˍ&sy1vzkfYζ ?.:e Ƚ~;}t ZС 5/y^ێia'qoF,qsg?A_UKKL;Σ3@(Z,zv'VCN Ԛ0+x'egu`y,- vdVL$^EO(1&7pxch4յV֚AuJ`?]^$T싇t#ȽBçW}U=ft"Rib)Y1 V<38`VXMdbc'dtMEx6?9/;jx ̀T!3W7\^76>##룄 &+SO% a,'q[xU. fVdžC$KT ,DdsxUB0 lQ=ðu9 Xќ-b9hG Sɑ]=p% DߧPMJ#)O ^ PF±%GDy{D#x;Z/xH_W$j*hH@VTИJ++Ԅ]HbGy.aV)xkى"_-TQYr vZ9 LKtUtQ#؂ N[ZqtnjVR;,yPSʧ 2z" :>DqJj0κeL!Z[2 'mTȹ&USYwI̞t+J D DWl)w`J 'y5/vnguCPDBN,q`5!zU\񌜿fɲg2%pP&3cKW!ષ UpJYU_E7P0'VN BH_%x)II}Nsy'OJX]Aٱ5'½WtH6w!BbF_#n :wMHμd:[iRjacj!Xj&|BTS♻ޫ [HS &"u|6522"ʀ?٫Ϡ" gz DVx Am֕) ƿӊƻ}F|5jvšڊIW> stream xZKy;"EJa-@An Ceփ/Y=[W_=XisϷfzf?? fhxY?4|24|{  ߞocs?o_Lu%[^d,TE͎bEq]iFU'KXEK,^Ĕ`gOy2P^OI82;Jn\n#zb4x~la޼3V1hZk~&qӵ!<(yGroϙ3CYO"W}܈{gO6G,J, t*gOvd >{~5ڱ\0m~M*-d|E(N{eBM"P^_!ty&+"cp๟ǟu- :<(W=JT#J(9~m}\OvT ~1Y:r!b_9>!ߞ _(_kX m,TμZ[%ipT^W{@r :m*7ŵcTe-u\T݋^a%ʳ$X ]j[w(3Pp-u;Ό>L1V}r<_K͆\FV{ϊK;0rpwp%qP D8.ymg׻M#-nyKa!.{8 џfЉns %WA]Z@]֬E)67 lZA+H2aEi%a7Blwljv.{!%wn6꼊N@8:EGhL&9GW*x4aNJX{/^rǥv 񵊤U|n6ۨ]S0 2.gEX7Myoqœ kYw::& Etfwm,{ vC>4]@C8s>y9'2]T^@%>SPVFڜB.;Tv9 b!K \xGf`fv{='<2}t^DG5u !8 y}ӁoDLCA 2^* S:su;)Osul))bMW%~G&.Tu.)AJRF 1\!1T \D\[@ *EHVKڲ5y> stream xYK6 W@fEJ% i)P`[^KRO[E[)Gq 5Z@N_~0}?_||px}.g}RHWsg,X)w^qTLq 4F@LQu6e Ja@h ۸ YE$&S,eq n"Ȗ3ddK,(Cnr^iQ$aYCe$J.w2,3[8glW̹ET)cJS]Jl)m?4#ȿ n~jQa4#|۬JUerH-pFe!I#˰_PF-9j/jš悿_s팣橅Öx>LŎXjw l:RJj 1Y,I X31}>S蓃!lsXX<)hLڌfw8}FH4cK] nP@qםh jrqFܭχKyf:-2)&fs[ϐ2wԝ|@tlsYi>U>"|]]l ΑJ56иh]l 44 pDзr]FFeB2  !|쾆N ꆐw\Ҵ,-Oq-mGeuy>pљDR;|&WZV]uJ"Hz(HcN95FmȳN5G?p5ŵ93F=H5%1P JWZi%MH\iV3"ww,Q,[q=@CCk Z(6svPSaQfd}<\D'&ҝL40ψ)zj6fICJm~T*G9 "6c ajDuA[} if댨{ `d^jKw‹W/j3ggϷa{LJczՆȮ4ɔHQꗣ,+5&7!~xpSMwl> stream x xE;ǃD@ ᐄ@sC !$"" ⇊귮 Q\982$_tҙL$~laDď^琈KX[SAW Dz-!Ҫ"RZVf.#%ke$v-Y[,-FhL)vM1UD LJ/4[1%~ kav6k+%N  \CbfkM K!T9 ̈ouIFuɯﱪ d0ݎHM9Z wiT超P.#EHĂ"A#fQze"h!޺]n#ꈕ]K02t^܄A:%+&&wW.f{bд]C-1[R(&E1H U쟈mEH,&4ʨyC¼Y>.Qf=#kI-l~ U-BBs$4PL̻06{;QX-2Ì!E61psjOQ4mց:յ; ByvR-nIUY{Uu乊n3~$!z%0?Y cX\~- ;qAcNCTT5g=9k +kliL~2Oq~ӡNpb*hnW^ݱtMq:/J5Gdrir4 $EX1Q/wBֶh?I =rĜ&; iAۮAL.v`ͫoWj,<`yѐېaNCCTV*)jrj2pnpJ՘69NLrRk͍ûow]klΩޘU!Cnv]vu$I]ʙL^x.lcT5Zt uߓĻ?t mc,~,[e6ucAcKc % Qq[2jv)9P7|qCaP^8iezcͷ;xQRzs,aVmivU(N\:2yyÏ};A2QP/0x`?vl3c[_15.{ސxƐ@ۀ;>L)я/33srQU ]7kU?L6M2YS.UDr3}zUʔq"M胝bCM@Gܦna'gߎ>^ܱ۷3g||ӧ.;vB/T]iKc6;/cFM#g9zͱBB VEd@R3J`Q\rtnRU |Nl2vn+}nj&•g IxEܨq0Fc13~# a: COmIvk ?os) bbDFFҌW(m0vO-x !P_ [Gb#cv-2j:jj2Pl99"M"sȑ: e/r͝d1Uf}.,S[ƤW.L Z0 aؑ?EܿGYc c*±˱+.k:t2%h~3,1o%`¬ܼb΍+ 6rM-ѣ'>ܗH, _O\KNYE+!Gy#Ԡ/W痡U;ANQ*" RF&EѬTS>>*򑪨A<i}i$f 6@yb zn37nHSVW{__(c0Y".τYiXLYf $ko%ibqa ܶ3eb>v35+ m6㗨OP3QAUjh5ɣ||3ԽZ0f 8AGNQ&ƒ'j b%Ax0gjHUPU U@U"\NҔv{c jnZ6^w˪㞿ƫx*ϸ?ʖ77oF#f,X0%\7y-#EYŒ^YD^Vv \xLB%=mHb@OQ9OR6PSSRPCW| T<}%^sN;i :vb6@UnfE8I"=f-M8T竎_bX텝U`_b|3Y't-]aiځ^]wx+WnZ ۞^^^[B!bU2MIb,bY9f2EgNAL BFdC֒)F*0g#5{#\F@ZoZj]eWlSh蓧X3&x]'(IM$||rizy4KS.mC+34_mL?MT>f~?ɌJ˘^Č]X =3XmTkO?0K{ț;-ٶmݻ9+3oјѤ1MOe)&̒,6 0G5< ND eh^bluGJ }Wzsj 9͜$z3 HHMHMh`l'H(PWʞΏVĴ3K9U\YW[]>Nfj EcAÌFr+3z3aiP{vyȑw\[s׋/;^}U܎FH^˰H-Fb,bY\'1Xe0P?k 9 ' ~K@gdMg̋r20 HDm#Zl'z$:P`2c*{.svuN&{fY6c|Mڨ6=y)#c''3< !/ѿSU9[ug͝J>|W<=zʕ+ʻDd6*a1˜i"7;+%+pOօqߚ[&\D\}Fg38dq@w/wKt~3&։$}2Oe誔)3P:s:szY&c6=:ſ&y7|rz}w_ú`'70cjؖRg/N3k<$t:O] y4oϛ٥e~l&]5Xfa,'HP@:Lj?M."WQAkȉdZjZ_goB9n.j`#SBBߧ>ʄEiʴ UdUDujfH|QFLr2ű]jcb>0ƌ^[D6q1%+[kc97._ (Ѝ.h)j[ӣGzC7(1Op1,xo9JcWVWPP4Z诌S"xfTNQ1Lj $cJKƐ>6R;%&{1/fNݎM7O~W}*R*V IMS LS[ꝦNU߷Hu^ "'OtB3?LaZ!gΆ=6\aBY/9yΏڟxg1ыc0cwMZI#5|k]kLZ?<雞?~ ^=zW)Ͻþ?˞g ꮐo3^ӿ!>u븓4cY_sIƌ4Œ` *`Xrc֘։iĜs، tc=ԌA_s#cq5+^ @O`,d&5w1&E_11cR11cR0 cA6[n!<ɀ1k0v0FĴĀCH:c +1s Y0.V@Ɯh`'c Ƥ6'^0&0]dc⍗8cjV־`5^`};Nݷv_˃N1 {SX1ݵ]Ervv`.kw; c$`HԼPc0Y1f,\I׎<50fD 0&xZs֕pokv75}cN41.)`Lc\:11cR@`L,cn_jCn!<ɀ1k0Z c. ${kc=E<ǀ1}e,0fc~+ wƀ1 cR0Im0&Ɋ1 Y1sA`&Jk:ebf쳜XK)@20&++]!%ܼ#&7ƄyksD2fmem4 c61eL!)qiN۬0`E c0&ccR0 cn_-wd5@R I-` $1{";˜W_qV@cR0Im0&c&7Nߎ Ƥ63fm?ko\'gmguH`you(.Ij?cD6[G%&|9cp"K F)`Ly(cH81+b2d՗$Sd_iXMny11cR%c1`cR0 cn_-wd5@Rt` $1z}U_6= Ƥ6` ڀ1`LjT5^ƘnrĘ͵1f`2K~'sulƸKY3 XaK@!u(\1XGb kkxㅁg1n$Idlc1+݅50h__>Ya̹L 1` ڀ1G1` 8߻cc=BX“ FHjc EsA1u$?1w?u4$[ dH:c ssV\W&}D:f0#ܽ.cn6{꼳s}wcV^`u._eWy]kw+:wJyy/;SŻ GRչ貁1T`H$)v٬fMC v(oeYsQ FLgTni3f;3N)/XŘS}u.cDl<;^^.+;$cUH.;ȘXGgӼWrEcNY`%*/0:leϕn0V]]X0:l\_睭2aeN\Y^90.:yyc 3o-` $1@Ra{a+NEssA6z0tRJ81DGٮYFX'YZ/ rl0 fWLT endstream endobj 44 0 obj 6599 endobj 46 0 obj <> stream xZM6ygU,Y43ݐrXrJ&^S/,M nm[RUW 1~5 :ӻ h=(`ޝ> y̓&x8 Ź1 뵿|>3_\j7? KדrS] O/bgWw׋{L4׳ A_<^O6v4dO.ah+&)Fw)7#ZqƍA 'ތxلG$^I-0)՚|`UZW&lGBHګFq 1P[g>%h4 <rvxak~N@Suϴ0|8c6ϟa\p/%,>'fF: 1PzR,G |Qo8:,BpR8JcsĠ%L(hi]sFi؀!!93%0e-ש8 /47#h\ ܿ i'iHs0[w&9dƹB'8odobjL|Y.%樏'Y A ;&ɑRoˤ^H36Gxs<[n[ 2՚'qjmvM*,̫Vz SsAUW꩙SY"%߄7C"!!CyHqfU)pN캮IzX9kܰbqQSe{ N"4thÛѨS4:; EIᾫ=?މXo;֖~#j8w09F1u>ea0)%oA̗r{ӳf$]V𐴀z-*zQ&x,p̯dlilRi;[Wt =h-ĬfSa}H"O2~eHB0 +*wpp*qÄp+K5Z ;n"񈦯UE?u X[9Ѣw ev'[8/n/]\{ŶӐ M~vڲ7jv @kdj4%rkd.b+1R,cg>`Ô#t͔ĺ2vv5^ע- TРr-jo쟴E%s=L<ߥ0ܚ_aSjC@.=E].= M/(Lq;)>>h< Co\V@ejisAdÊzzaHWn"+g]嘽 xOVDu5#~%!9GSޤ Y rM[]XUj=Zy?*V~7@HBV1HzB}a mRn&/"*Σoe}zwI/l"?*Gl&>ۇT endstream endobj 47 0 obj 2231 endobj 48 0 obj <> stream x Xm~ZQRD ʎ.(D7E ZkE-.jjmݶ.WjB6 $P=0L&y3ϙ3缓{Ι9 7 |o -P+ V0ܚx5 1S13ꍪh_?mŪP]U5#@|ZlѕFb0,Y><ٗ͢&oqWHno -:Sd#Kyz#Amu 5YA2Z 'm C2k;]4چv4lL2AfiB2h7ȓڤZ$6MMl4DZ8B])]uN|Z1RZuG9j*v߱w bCQH9=p"vE"jACfј" s~`pnECBTY{ B2IIZutԂ}vRgnz5B_=vZ1;hNJ P '(J:Xw[ؖwDK2XDp<$YrCv*9-'jQ/\WRu$fs8'B(L-UǸ*mo{[] sn. &vge)'<6<xe4Q8 kQe'>mrQe!e>ER"a"nW~ND,)ǝecb 2DtO?nY[Sjj $$xHQV0e ~Qe%_;kD!qʜʴ5{*àK$/4R… ΝΟ?$0Bp%C_"6,<1y2bvEV"p3ᓏ.yYЂr c!>A0! lN2t $_0(.rrřa”@A{Jy)~0A\& 'sy7+hVMowb_l>8>׿ /~uHr|}]V2үkG@!:ar%[o>8`3rT|F*>3UfZn't!vdս"UX n1t3μYWC /8Գ;pp]~~;O~-&*$4* M{yx|6JUf ~GНtI'D-n(Qϣ Vy bݪt4lWb5|K5_҈!Bhb񕲟.,α/!nC)oLRE7H/@1mŇMdS<1a7)V^THn$.9s|F:nOI'%6)W 3y'pƃ ^ خ[) B S67GNfW(?\m ljamVgx߬mۧɲ4y< PiQFErTՂ\9a `TDqus.nO'ϥRpTMhwLwzQj̿5z>IĆX9ÄA/.&X6:IUl-d85d;x0U7УEJ™ND}[Һ>kϰ wpĻ@!q;R P `h2t4x;s![ ݊(n&7:>ML$&ViuZuh N`W8tM!z83D\墬PT*ٗj r{aTa$aDa?OfAN\P%u;r !16}Eq$AےI%owwOس{Ɯ]%%%GE!A͔虆2JOBgѵ&6cd3Ë |)TL?-~di¯.&ܷl e: q{"?j C:([.^*I]˛хҧD^#o>qz0D_iq2t#v嚸J"+Ǐ:tx˯Zn)輊VЍ$ZEqgت0$￀Q(]M0OTcW=_%\؍969m@<̫EO'y`5qT*0fu5<$Q 2SW>kj-]|R$OG6$snpuz||n>ߨWXmPU<|"Ea/&2sSM IL3.xp<7A*b+%mj­ zBf~}֐Oy<8xx UdY]bՠ&{+lW!FF clfnfmUvӸLE!+c|'T;ꖧwB_1rsececUL~ Fl% 'z,^9o1$ !<& 48Li h%[UIfa9HHS<lyw-qz&jjl唘<5?'ZĊF>%[,y_ ⡏NH~_b{qŅ˽}m}L;׼_s}5Q?vm.;`}7i<0rHkfRFb n#TgU?K7m#˧gG{'}qGxc.-s*ly=w'Io$I_eO}8C?t]dqc'O;tqniۡO3x VIxx S&U Jjh_"#[,;6̓i 2Ԃ}ur|?$zDښThL5~`Z^RGZK_AB)/96Z+w-)Vqr&Hg\%Bc hKh@< $**)r3KC&l6hJh 7_Cpt0ȧB2u6z r›ŝ"s`Ҽ k HZră Vɍ&3S~#yj~1昴Jk*8 Za711]4E'<}p!`0CNNT<`Aa0ܱap88[y4"x0o<(Ae*Mv8 1 <v6>oJmXYpG==65u ^Aj}gzLAjэy,nա1<{À_pz>Ӏ'xSO5y0\u 9qϣ 1zo>rx0t0` S_88gt =Z؋7ֿJz/`1zx`= +E8zj~m*q<bZ<_p< ca=RS_ݘϫ0XmP`<a@wޣdjSSq> stream xZKW<|IÀ5 dԋdQ-kg CXd=*V4sg:O_ldM߿) .CwY}|oj~^tsW3֛y`==|Ŏ܆Df-rcb_>pz|uO?h/$v_)P"z{?m߽ jmS/@ҊKZAW7fė$WT՜{m3JWwoi$$΁x89eGf 5HD}3qآٝ4< .qyzM9Fİfؼq2thV0Mx6QauLMxΪ*"cm4"X!,~Pܜ b'EX4`d`^' 6gs^Zb]ǥH.. bk Ilxܲ3,w Xl+_tʃQQ?b]zdғA&s(*看dgAR.\v, (Be{ DS0Π5HAΝTHrv یNLu?ȩ m۴RĕwVnSְYK`[$+,RW~6*߰;JIs $N[dԡ@QfgliZ4| ^ 9X !XP<ԸvJ [ f^2!qI[(^N`RHv ӔVa z :5K [%I0>%m*ݒ8_~)Sn;K l |C)I;ao to*S𗲛02{/nמix-pq>- m@Qnb}^w]4d ~p̂bb@m‘u{ -#I-Y{ {]J!X_ :6,wʂY{?LFKOiy䎟''!'!QD}hPDgŜ0G2~Yzq'd4(D!N(ָD2s`i3f6S+pDBl&"f,wփ@h$S3ρ!;2 GMd9,l&"6s"+D)xdt"i„jeC(-Rن{JCLv*HLsv%٦fJlԽnUl8*U1Evn2ěx;ZM](pfȍ~>`OQ9V8$6eldpc$*yB96\緍aǯ<}H7DqkHb"Ro$&?vhi𛔌t0xؐlW%qpگ>hRLBYW jH0 kyOd\q'KvQo'>*'K_n6 5rn{tLRoJ&T(Fk\qfH76W {<`_'mZKT- ^a2Q]LUxOKSאpm%ܹUW B6S=W}3&]{g+lsȒ-/Ӻ/m3GCejyw{KsQ3>+vtI%M.Uz=5k1pٕ -YCj#\*UwfVWa{uDB2eyAkx<`vP)r<1 I}Ugf7LVxfLnY?M?uÛ{Jo;zG~?%e endstream endobj 52 0 obj 2536 endobj 54 0 obj <> stream x[K ׯy6P($ aSI^#DYl0d_"?Inu/5 q_6߯h5Fo_._h5 A}w>K|*Kؿ|^~q]9' $Y>.vOvfM=%nnjQ?_t콪7sg=0ͫ鑹$6.o3>IN3ir%NɦאZ >iqY䁟 $E$y"a id/Rј$\j#0ϩW#ĕȠ%""yAe"Lhm8:f1d2dƁEP0&L.86m^ɀ+qۮXd1cҳ+&BLkm8b2pe2n,&`LVzvDib9]^ɀ+qۮXd1cҳ+&$&h6mW8L\z"Di{)yHBZ 嚑 ń=RZ֬188vd Y brw TFH;, K9:a9 a|8i;MJ1b~sG0~%`$-ڥ131yv:ɋ&5ѭ%Z5J2N3F ً^(Ɏ/ K_ حh2n1tT$nZj,N;-@M$a|U!FLٝҨ@'q*'xӔU,SOug9+m\qh$H Eh͙^i[?k+zpcKbgl%sq%+CE0V9XrZ,()ܸCiӂ]ig(thhu Dwf8qtBH-,#8Q`իMfHFC3f6Òb})uAlu9Qc1"i"Vߺ,'@.ׄ&~IiBg-eZC=w(>t) -0*,(ecZ$_ T"/  r4 U*sȞ~@L+~L4K}LD oTOb t);Ύ`2"ՅPXj ~GqF}gJ7U2~qSt*kHys }dQHGD w]mٲPΛ&D5^SJ'BMYRGyJtd*E{sDה3u C1[9'++)(ka5@H.z^<*O$<8<ú6M>?x؅;8&'Y}, Nf AvjE[k:Ն6>kl17[9SA U̿HLmkkg8Su]$p[*胶1t !*p%ф2pDNF!nԹeVvdEj{x@dxX7~uX VnphqՎ+8_{ګ-ބB!W@艪+6Bwnšhlc/nfS~ʮx)дYN!bғ8DPLDG%P>ŸǯC?2Sx %up! -Ϥ݄xZ) ҝ{!eٮ,G .HO2\MxW$F#|B*}v=b.o  K^YQ^lwhwߐGeTgK`yvV_:INzt7H 1V*q'Qr>Arsk4M-(rp;ju\ݨхejX~/W-UFL 7QTc` '*o];}+unm/ (jeQA_4X/,mSNKO5*Ko endstream endobj 55 0 obj 2942 endobj 57 0 obj <> stream xZK6йP"%0`,CS(ͥ )R$'-h9yQ^s柷Ӝ :@_~m~ | LXGLRzήy0ybnW{1D 3\bFs~{'>ś;Osuq@zB] &i{^60%xڥbߺ-|}_ oZt\H՞p@g&}]-Y\u始 Zތ5^nx3`;{#wLH Z2=s;}$4#^8#[H Fԟ* kǨ7#`hl8۵.EZU,)kJZPf$Ҳr-yj^F;rED-`ukWgTզc%~$>5P{tyOг^_$?svəQLbi\8jד:#Uxц/m۞*g Z_'f0gdA >b,UXF"89Ж6QKߒ( .33,Db#v羂! ~ ڌ(,2/E&E| x4>W0ڋ/?e2Bg[ o!5+3RB+dQs+9/{|R2:˵=h5ިx50%<˦20\#$/Z!E HK GGF8P*)M|#jP.M(m'A[7㭫"{omoV\ӍyؘvsO 4fO9_ #OJ54AYYˊFQjLEەwuscں,Ez+hֱRJTMwpAr̩gY ldpK8sJ$-J$YPfCOI^U>[Oa(H_j = 'm} nM跈2X=kʟk*vӜ4lƾ6>Yt]yȀ]GH47e_VHIAь!s٤Oms>ÇBiUZv2fY INɨryPG{ c`:AľS[9dZT3ꕄ?5扈t|{QPх֗jT*RdvCd(g E/[tª3zR DҢͭHlO3k1FG;T`'02J&'n )4 bV"atqG6ɸZjEnK9nTd:*ysT@ ޭ24P x UtùZ٪5wh.8PdPqф;+'r57J_]UX'yC1:ȮXXE+|PF?`'̂$5Qi0Lyjm~c"iM+bQjɁպyv)`RlS4m]0Su}y)!(m'F5j>"л0)ۮEN?Rr31 g8HYvnF T Vּ,@M:vϢpQ ă]脸Y\rɧP_D jK/q8F`S ak'9">6(\ endstream endobj 58 0 obj 2173 endobj 60 0 obj <> stream xYK#7Wy^`@!$l%?Z]ztQ*}UUI6'9|t;| `;O_x߹MOn]8.w0 }}>dcr軗W\ꡞ,& ż}l\Fw6xo? =\#ۋ=?\i 19/dǣJ04z|&Yk 7ܭ'=jq.۟mae3q{ JAiXsnkZ{Aty]u~<GQ;!m#GGUh@#hY(w|"Kg_7(V{X+k)CވekcR;${ؖnQ%/}h>mZnGު[EnD5;5l3*S0 Fi 0V@@flCj[WH*bX]` -:CK\A<t*FB;bmu6nX<.ѫ 4#Z^+R;&|&K(cZ M"ǰ*֐۰1ܾR="NX0>y4 EK6#Y)wcZs f8p<qpjwQ,Z L !w :sfr3V^؋D0' Z,zO\:B `YL:Wqj^v(˅ka*,7ӏʳƳ]e!ysMl^to.~c6f7U9TN [)֜)S uJyAѢ C\<ĭ2i.V-$2G1[mfߪdz:NQel1,? WO&9Xkw+e.=sW gm+h>l#s-/j0PV`?EN[^XciSx|QL 3ԞhjO虅O zZTJ+- >*xIk~+|<Cߦ/WiyupP_`\҅+-L܀2T E 1[LӊF&dʬ,>W8BS}TX\P`Cغ˼ߓ_.| r[_fL~2nr{J)N$gyVb &_<]AA7;1IιX\)8,`r:Ka;Rt%xҋ 7/5)I"ʛDZv~4϶Lm4}:QW_uJ# Y`c3/ ri^T=#g1n-+Xz/)=oiQi endstream endobj 61 0 obj 1832 endobj 62 0 obj <> stream x T}J/O#JPQhqEXEvAaD}\Pb@c1.%%|&1<͢I%T0 t`X[C3Ӭ#>U~sZZU%{iQVeDX9TDjE!$JJiUTEUc1E,&h{OBh_I5 W>"$H])"^i1a4$9M6y-ϼ4f[-.Z\ڋC&E8>Xw롺pȡٚjܶF'CTV*6CIH̄BZX-];݈ SnhFt냬@DT= 2_`!v*D$ݣ$g=~5MsZ@tL&3f7ChK5Y7[JۂU~ HbX.S6'F9BND Pxy(;N08fh!rL(Z)GZQ K5@h%AkЂ)eVĢR4Re߈a!T\GGZ0UB'&3*%U0h@xH.hjhʠ1Z0DV$lPH@OM̓LˆEʁ䈞 }XKMkv"^)Pp\}X_jJ*%*d3忉\ u+f(N+*}OK ![}ײVJA ]- dɋP7"fVYەiÐ-{~` I^*z@ .;w>;<-EЗo7CW6U*' tMW)'9NjF|ȘRVZY7*?hiF89PG|~ŲY3 Sa959vEK [gA_A3rV品 J|7|*Aʐ%SgxFia}~Qn-[\ JaZwA4جT|sy9 閡tN!'R+چ6,-l'ȶz{fk!05TnL0tIW hc 94 @|ǝ̅3ez`k1Q!pױv4-h"BKcö22J o|wZ|60VNx]-ءZUO-Hy#=i )c9>tJ&SN"ۀoMNvJ8F)O Xi:T B:iKmb CK^)?bkq>8/s .br~vMKX9^4`6`2[wnhF}в0Pm|7PגIL41DN$ϭg8]'pDY^ f@]L*ce7๏g@NQ4n+Қo,?'YۦO/EJ_o`ҬuiWu%V` JaO7֒n9s9>J=BN&R_pGN+ DlXHiA" /Z<"ي-rdp--txq:hlf_9O\3%%֞H>ԁ˷?}V?az*TO L9C I/UauV~~m7[ez2d dB[5)\m-CˢFgP(T>>^2taZ.8v %z4#DD%P.ɗi)gq8qhq(q0BOENf /[lv%Z^`J=ڑM{wȷ/_ZFՁe*"F4^3*m94_u'iJT˪*n^lfQnqkT*,6MUڮ ;:qҢ"rGN4Z ! wKWK#e#`$Ilik҈qP{I$ж" AN-c]!D "Z7sT{_;4sߍW -8a9Y˧ )j*D(A=J5M@9$[4_]?J0Q̢'%^n?~z@AA/EC t5icLQ/Ǐ?t֗_9xɓ'ܹbK*Uĺ!4B E~ G]Y%YŸd}HD\##]?)Y9+[ 8-Nc#sOQNW?R9 RoyFIB1μa!` 9OI|*i YkeSUXW}uoxޣ7 ~ȉo-eFzF퉄hnT MQH B- zM+әavi7V.|YwGgf+=֒k)u\uA含[z2Sxj@_C3'1 HܞtF.f"X0S,.u.s-q nqǀS}2JK 'D3 -LtK 3ub5w'4Ew.u\yS\.IY vY36J>-O Y.qoyp݈)eK"\"]#' #Da`;qpshuٌ~'N!z BDmi!kFzuFd.| ?$kwmq~!|\lؘ1@8J \8l(f2LGޮv}n" -O{ sSM.68N OZ /ާIx Hҭj,&v--hq}\,Z]J:@sjչ j2ZG0{R%g2/-p0-Xi/L hyӂeZZZ [,´`:O ,H!(`=S`Z:l4u´1L aZ0--N>E˜> nYaZ<`uX,´` -rο}hh2L aZ0- ӂioL >Zڵ,1-=oL IZL-ea ǂ^C'gĴt,[.^fb*qZL 1ZLaܵ8r8bYaZinܮD]bnpSnxDNiu-K>i7saZ ӂio|hXŮ^!L}ô`uX,j61-X´`Wou-Z,n/t_W3lw0-fn50-yZnO?>ff5'|1bZֵM5 o5T7<>ƇPFi1 8!ȐS{S0cZ:`ha}M2ܴ` LKh('9 ֵp#M zbw |bsg1ʘu]_!xaZ0- Oioh1?k0-%[Ů^!iolo3)B_´`0n(´`0-X`ch!0CB43֋Eau*2c4A:֚0cmeH(\t2)#M{3s:Pl[f8Jx a^S endstream endobj 63 0 obj 5837 endobj 65 0 obj <> stream xZK4ynLiRggmHV!>p<:!4Nzns?:ӝ {9'߿It3DK{wuo_>??x=3\Llal^p*Кk/4+w=;&>SWpDwi,1jDO_}ncgZm.5El='Kֹ7c燋_adoR|~r l{#y D b)#ȸADC= ^y>3s#-gJ+ȴ SQd; *z>'7B(Lذ!º eK[6,@Z)8}hc'(L|&1PbaH=E@Lb-2 +WˌlקX`Ld,2S q+[YX*a<+l\kș0s΄e6cfBV!,5sܖx1'"NK*Z&!/T3V`PˤzJxϳ/ʈWI훜IS-Ri6kT 4i]UWբyU|i6SB,fzy!V3k~+05cAtYl O!fiβ3,yxJ;bqSMf-Bclf[2-#Hlz  Ö35<^`QX[`up"Dd6u~0c4lk)V0X}m TcHƅTPI4aD`Ukf 2/l1ƀ+`LS3a;#27%}P0xDȢh2-A}ݕmJqg$#x Ce0Rje'Eh>& ̟גn3CxwmFI-iถ6*)[m?\l@na3"[ܵ`asTH+; J LlN\5U/ͼ331 Jh3ܶ_4[O(d;Q`R0ODmGXEJQIr$?bK_R<.+ ;v=.;A\Lgc d}90>r0U$C8>sȯʯF=gC([$/d[ę(f`&JyM!te}f!)ÞnOɬ)m2+wx0EuDܵGe8"?CEQ"!80*^y!YّFs0,Ezߔm `*^ aم 6˹I]ty9ć[Hc:k+C@G N꾃oK_E8[~U.oP@H;=;~׵;?,r>[7 aI+AP8Zyh2V UxmXМ&; 2£8*EMC1  ն~]r.MG9CtT:2Ot!Pne+]ң ᱫluqҗWXgWZp[+ۍ߾r(?qn1 $oVx\_}f{]ܾ|k_n endstream endobj 66 0 obj 2005 endobj 68 0 obj <> stream xˎ_=S"A 1AN7AbȢHJN0 Qb )^ILgg_L$iQr:U=̓/f>Soq8_ßNߦa]:G (Y?NڻBû>U\/U9|^*.gF7q;=D).3ܤXo9?NDEE:U|qN?2Re8)a|SzBaf?O6qbɀ9MD2qK9MD@ MTx5f.=32q"= F"Y:ѳ `YqD+d"i$`MedT\F" L*qDkd##;iP1 OedTl"|F#g.zgW^kAzDyiT,Uύif'1rd:uQE.3zn[3Wӕ͈'("U䢁p}U,l/n3bJ6K46k[>D!},¼,DD$L+jtJN*)Gh}ĥ.*֋^6ZBK=Z"f~'XYl7X3;Mk(ZC/1&QنEW£ZeĐD.u!!$#g *afqO-W ˩W s ȌI/>à8% (PP({4eĔ9êaA3Xp0w]_IEYCӇHh"NRML8pe[9^PE|%;P5 jth3vH "\&jIQyy+!{!چHaÂr1Q: sQ]@~4&4ɢ$C$ kH[6* I%/=^A]Q GbZ CqPp, A6]#/51mA5x˕мF3Q!α1c/eԃmpDnq̺Y.Yuw Ah6 Tƴh86-// sY20/cg8UtsG+/x IVy&u2;SK<Μ c~6*_]86Ex՝le*!$╖ݓi=GdHXK1R7Ncz3)olfA#Y֧Bɶ 3C] nۨjӐώjSאc]ȯSduAtQaLIS:VOAfA-ys[I] C86{&=]_R]3·A բPCseH'2>2QcW?=A>\ظ?cC[ZuOXFh2 Ҳ&RJ 'T c=Z5VPkՉCw|XG9vs /܇& 1 t~X#tx\_g;Pkm.8B$}aCÑpю]U_pT_$MXfjT=kckJan|(X'$ﲒ!KBMIN\QlGeCngӆ޵smȂOmg:`JZCT$渁B UhBueBp&Sj5%DI`[$XvϨG c 8<9گіRZyR)aвoJӗ*2_ً.V{YT" {L ):i1'<3QW^M{`u0_O%畲 ijlXj0|^풳Fekq!e@5[Hٸԓ, E8 >(!^xcn,ޢ߅@f磹x=7%[0\DV G dIO;]`1EY yWQ]SSk[8sj 8GȻL*q $`@鏓_J45t7 #dQ^+d!;8 8aOe$TltckըIcd'. 8dV#%afI{1Vͯ4b3TgUylkTu3tw WPO}Ѻ~w=ȯK:Yim+  l2_ atJtbV AY{gIO;)[ U#Y`-ԚXL^/?pl)鎕YOqh$]͑ ܷ{XYۊO#@A5%y[ ]?-ᶫ[5.Qz7a R')#K2޽ԵB5J[/ ߾ķ6vsjSO endstream endobj 69 0 obj 2453 endobj 71 0 obj <> stream xZKo6W@Y%;E{j-3Rđ(%NS8pD37QVV\:ۯO_;Yo;)J;U>IO8{t/Շ|ڋA=mr/ڋx:Fgq5^'A(3*؅d#[ͪRq) "˽"ce7E--ñRPDD6-%Lni^uq`@N*5#l' $j< )xAAs8ӳHP?PvV=Ë[T`MU(O}:aәDy">o0XZ4ac%a"I6$D\j )?~fSZ5K/nuA(gԐyh\Vq(DYPE>)K>(B >u׀6SM.:s&DtPv6*:v:KPSV˥:7S c9O\#j/0[Mp"yZtb%p"J`a6ԍ%MTT>:)Tv|aZX3sYa(K>(>T`^ #eq{ E ֤'21 ׂ$veFF/DЈPx..&! RP" m7J;HVc l>4OV"* eX$-) m@gɱskUuo  fDޫN^_ХMʭE\+3H(h79nި2s(:`9q✁Hɚ~rȆnS畚洡ew+6\4WAc GrE*h E=K%-"Tm۶52&d47+iҺRIX]%<+Xbic\呩v~zD-:^Q-9"K`/zVR޷97^)5'9 'eV '$p3_6Z ߗz|c//Cgf endstream endobj 72 0 obj 1804 endobj 74 0 obj <> stream xVK0WR3~%HMඨ XNWˢVǞx՟@@Sƪp~@kUiIM+w^ո EMܰ'.A'sqN' uE<#Oi]rsBN[wו4[h:BDcX(K+u0FCNS`zJpj`vfPS pTrz.4zTqNIq$E(}/L\sJ0Σԍ!`QuF Ow 8$ `< d8H3'd$͜aXI98k-wcWN8<91VX3**dW6CxqjSƎj~jەꐓI|mӞ#5­PK1$BSV ˎN6ko[> \ӏ+]Mqp!0@A+lZ$r2 VE%_[,^|军LU2"Ip1vX^zt%U~k4٩ڲn4jJFr,%g- Ʈi !ߞ/-qmQSt;eN7KX*c}l8kjia,IY>+-wࡢM``ZO^F>RUǧaZtC endstream endobj 75 0 obj 826 endobj 77 0 obj <> stream xZˎ6 +@Rq&Ytw]ݵS~)(K)2mI!yIwTwTuٿ[AwσVSgSh? _?NS;Yݖ_};mgu]|]YqgrzFeըpR]"8LV46q0/GO>u`ڛ\ayNyPiQ@f&€p=΢n!Wz_OҦ JR"?a~$ՇJef~5alzޤd|#%礪_HI8%sHAdE>0mjWHf]=_vz*~52-eu [+JUVj:72sf!&/ 8 BE*2uP牘NP>![a`ɶkf^+ѿ_qܚ dQ,Fԩ"ܦls"I`;}sU= کt"P6D&;gR+yS:R佔3$7vQ%kA0-Ċ|]0d +$ia\cI&lRXj?j`sŅ 'xU E;R.#ܴFتhf=]T霉T֨x1x9!a 4=Vfz*О[\[Ax)qEU T8~lPhҮydNN.ׅf\]UlS,yD՟UDT^d= }짰.ָ]Е^7GD\Xn ,vn/LJ͵1cYy5c7/b kg(՛2 -LaW]Ĉ$:8 p0op/ 5طQ-i"1- M EBsI%&L6e$9W%f&}'0 K@ܸYJ&qN{ F_L}mw[> stream xɎܺ_M 4rw9 rJAOH7i~OnJ\j_i^~jxQsꟿmӗ=?a6mȾvzEAI??i?>ˏ/uOAyH]װ__vfxnj]֫Ԯ^_4㫟u kZ+s}1X[?\ooT-P<` 7_ݦ,T7plf#lw|]-Mspֈ[u҂:{pyN|[-Nc">e#WnKEPʷ0`!$rsb. OOډgFl6pμEB! %uwD2~6DPtfZ O2ħ,+إ4yR`u@; HzMC.DI87!b[ɵQ@ N< ZhBˈX{"Z$?KA<]~׵)GRIPh!&n\j4h 9Oh4-Rf LveJ)rFD M31ֱ{aa V`K2nبI;$ )'FVDeu\+\Kd2y=yr/Iڨ s 1t\yJ|[xe^{ tSF`ʿ`r2uudAwHbM\.rwX?M;PhC UcX!+]w )9qU(He`o` xzͻeB]Z.-Vp8Tcf:i̍U 9Hr$R3I;Ay?2X{,`.Y,\lE3{p rH).E>~M?S=hY &r97wgb8RF 7!li5;>zLWx}3$:/Mj?ͽ5nczr|v*pS0Eū~f!Lym[s̃a&(G)䌎|=1Q:cȩ=zTHhw"u珋^MkH#GqɦHM\F ?@4Vt23ycQ< ǜ8xq38hzU<| @k1󲅒M.w-G\,PF4=V_7Mec9ɼH^oB<Ǥ(8i Ďcc9S=A* ނX6NSOC6-ސgmMO."b, ."S0Yqe4*8Q.7akjŠRRȱ$mCʼ*TلnLݱR^'+N,00ggn]Ab> .RPqxO|& ]Qp&Q5&MGPβ X[2YUʓ[)DO;kO?WrdBspgd+<;sR "?=D*rS~g哘x5Z&㑱{_ݨ h¸cH)F5S@ d @[Pt5?v\ j T.RV.YkIb o6!KK8P~X&o&$U\-uTwijd̢@+ߞ 4M k;צVS\[5JdOjݵi‘7G4Re:ckt^C݀ēcQMNkGp5<a~_UEجvi\=FaұXҫI) Kr L~pHi"C d9RNwiHQMk^7]놆HS;M ,MRUzBa{|3_: ټgMhHwx OEֹ5Lv3F_Dʨ"]N٪k]x!X31a2?=kfm ;fQ_ +t&ùt2qnK5UaSm=0Iޮ GDŠ 硛;̉4QcQ'z )"[9&ecJpG6 :%m%oڴ6n 9JzqkٞhKA3l8@hLJhJGz5aBm2aAqhr.JAT> stream xZKޟ_@QIlC$ Y%@`f6%[rΌےJU_=U f8 `:-t_~0g^J8~Zg1t맿f/p6Şjn௻ygD0,Ƿ!f^%( ?~0!jM\@F&T, ÌX`٦?ӈ@ٙ+{FDDY19B.Ԏ" Q (sa(笱nf 80~N,)/qGDZ/IR uDf.I|@%C`GAa۟ ]4} [[M|J%~\c 1D啭(Q=US͵)*ca ڻ02o ʡc; [Lπ :aj{;heAotXl)!mr\i';4WQ*R*И1ظͫaU2uhqZs:agf L7b :k Ź;e ^HG,2笶> QEc _R+v~k>9 %ݘW[^8-oٺuV2VoDԪtNiƝK‮t'H|[^b=l+Vy~( R}#ſtG48 weKNIM vq#s{72( hG " Zb"k$l\_нV)x.Mä7y+)Ĵu(oS98Os C%.v?j"P{7xl[yJGVe$ejTW]A6n-` c kVМ3ib#(@R҈,pM]{[~Bn9AKv\8,v#[v뿣Hx?ξ]geQmgY9WEo1QۀeF[}b_Mm=]Ck]ML׏[!|, a sZʶ E!vEZ]{1qOH{P<#Bn-aF,ٷbRN`pĂ 8fiwf7C ̉H"ZqhařQs"N7|nf>[^KwL-;[DHI^ي#'^gF'n1* MŤaIX> stream xˎ^_+R-$Y4ENI&A0`HIU31DK|SD{ݷu{G:;s݈|}/C%t0C}뚹%d?A]}&V(8S|d^t`׃;==n:=.q8W {d4׿n39cI:p$'%'iUvr&({BQqjyVT1Q^x΢7e\04$8g͗U[9˯aWJY6x_U@ޙi}M6R0Gq=sӮh#)u@_JΟ7:L.CؒI12X*4֥Tg|(y~Ar@B(4֥,G*GESX!?#c9:_9.urTrT4塈32#F,e,Ky\9fph##VXTiKil8*T9*P Ȧ.XؗXPhB~Fpa iؐ| i(蚓Gj 9)ke AsRYۺBR7AIoH6Bu,r`[Z.f rݷ`-dm%KR YImBsƶ]ֶ\CvZƊ3]|ֶ FsGZR cwс/۞Q:Q&z) ! `S]rB=$z;(U˜86;*r8"U 8yQ+Vh9xLrv\rK7e_j$ؒ~|*a4~8%$S),֦I+Yl$V8XJ|-loUFb/f/Ms8-~چazCTy̴w^NJ-DX\M%dM6odc07bɭL:uo+.MVoZe a~wosOivs~LsEZ23@oz7ˆz1Ćm^si]jۀzλiCZaZPN?))C8`ȽIJ9c8UiYL}5̝xI# \'`hzQUj3S ]vhN=XN{^3n۹ > b-GspA+~/1{܊|솵#J0[G$:N}{?NW2kE)܍+ߒTpeʿENp_>7sJoi65Ȃj' و- endstream endobj 87 0 obj 2260 endobj 88 0 obj <> stream x TǺj7ħq!(%"**ˆ(, J h1%DĘg5,$715 l0L }5=4== = (S>ULUjhi1"w "*Ҽr+JbHÒBPM, (ЪZ[U/-~-1:K5&*"@t*E5Ĭ-FƠwO~ca3/!2zG-w!y4kQ ,ߧ+ b`ƄOWЬ hY> =Yu}V5CJ H@Ř6ؑX]'ZSY,L }J7%#}A}r@D\=Q>B"CJ-HM C̽+z淀0H:@GkNٍleJW8]۴2Hi虮RDBqN1IwJ#hEWm<N,&$$WlFWbRZ*GZR 9Ah.'Ak M ~ W8 @sBf0L{tx 2mb"n4lmj+@_.hl>f ImmJS-e*z>` @O Fx`a@zA/1Qn}7M+b^BBro-9s%W,%hBu)gZ N֠Q>"u~m+_HH2CũA%sDKDg@؉HQ*B]o;[~1u-L"NJ#yh66jb:F(~_kK>iiիswRKT;UTR𗨹YI U eԉ'k)wtkwْS18z}lb:lu4?V.N+JUq>`ė5 ZB${F t}xrDL)Q[5?~ZS:j%;TP"ʷp]\t)`VS}l*ݖ_9zc(~a Q*^) -rq뱉O#'_y@SVR+kߩ*ȦF8?FXsQ xCuu*4+藨 Tzrzzz3Kᶤj`l,r\lUpo׾W)exin$;B,NFYU +b=/Nxx6Y雐?/*ðϗorٳgO>g9sN 6|ZzaԎiIзoVEmB_ H\hAG}rBFdАoP+r 뤕in|:(&?^%N- -Z4*~*}\~+j¥ǧEN&_o!^*# BJ|hmoT]˓ <&M zw ]<@_0ܯ/z `,f grr r\9>C1vX۔I+0ݒS Eg XO&^9VKz<15k*hbg^uj3gM=}oGW%E £69TnXIR/4]˺V4_Qco9|R86}8wV9C [!\dk0X \W[faET`!鳖'撣Գt%C, 'p$B8h&f(0NEEGT<[:ry.L"N"I(h15~>{Ի'>uyOig_oE޷L!y`Щ֧  V<' a~vN<0d,-aJ2b#`3 (uW鹊OʥgSÖSNsfsd\NԄuM!~4;B@ HtW*-i QaP'aΟLLCE@MZy]?(Kjwz|kўOUGޡ߾~sS}jT"(DvkZ;g#>YtIȧ+\"}YI+ TЋԜԌBs-5n 5j9O5$M TY"tF'-1'pDhqFtE4/V"]ƌF:K†HBT 0_#'^WP<8]$o bߕzB}@󂘵^Jo}p[K7l;o-n-//G<,@9B ш',~y?cR~kɰb 1jMQTLSEԤԸBը*<LҿPNM8\'@?FO< HFIr"0Hd,Y>X:P4o9>u;r2!1݈8E<@{ɥ٧#9vm|јWlRRRrQHi`*~J',:( [(\Rj1d֫FS?[R5 W嘡|"Q Fm7PԜbjF15X8\'1u TT iA0Ivx s)3dmA@YOr##m<@GxAb7'e÷%?ztkbon۶СCHGAː*<;O#Y:cհzXTYC}4Ë*BT?ꛪ|<^,Yɼ"UP_LlICuA0adQq\%42/Y6$=){cz#'4f+R4I[KQM׫˪_6Verȑlz};v͛Drȼ"R8BCpQaak0;'%'YMrD$'ǧ+)mzdzh~YG*{J{:ᡑqī8oܜ=2b<,- / F+I,&O%yT'ďxWg?zurETs39* y>pą.w4RKFZ=/tbeñ5+/hsW-C.kCET>N䍩%u+B5;=Zjmz;k oѺz4e#)v HgR{"!wё !p!QvI9ļzڰ ؠm-BU{P@e\q$ȻU3iOg?k[@y-CjiitcraV]]`-;{3<<> mll<`cAkti7a<":v/\t LK?XJa%</8n`)2o0 E`lfσaR8TD]axsrx)fG:u01hS>ㅱo}a0f<毺<l{x2W,0Xla<=Ev2>`܃nll<`c0Ƈ{VRgyx鍈yx0\.FӰwZXi<0|ou.ݞco׏5ziWb5y/> :y0P)Xt[gkYx>iI/$SXiDYsx_VO>`kAuXv!awZ|&H[t%#id:n~XGF$ۭql̕@2un/~;e9B<> stream xˎ_f% 4 Mwmr0|JL O$vlw]$9 o_5(A8_e 00jB$f=U^tѯjQo@noq!8Wz//vEN"{"0Ww֕/5r??Npy Zm.h@V1⢞/D ݣ~pW5E7jX4 Lxv1cvaMO36V'Lq&g ߲0~JTAk-dٵVj}#, \t2{t-ZP}{8]?3*ɡ%0ɋzv;{3u巽ht ($#fņSp'4 ݙ[t7j#`Pyp;Mam 9VoS+,vƄ_@|6Ǖ+Znp׀A#-5i|㐮zA\*>B#XJ-[#dE[\>:d2e0%ȴ=)98fsH KeFpL?~9Tz K:D)dۼ%h(uL%%_έ7Y(K+t+*7`6ʲQnGGJ9 r>e~[Ȇ1DW+K )۲xSN%ẈVIv͈i 6%ƽM/;ba%PlL1\Q@#"blt;GAt٦Iԕ1Nx by}k'L8Zb5 TZ;+k.K1zn"= #D"(v#ZMNH{K#MS dy~,z>vSg}wewyא)wDkm3SS;GS[\"WE0Ǻ,s]䌗|1*:B먧v{ ,)3it#ً'+( }~$m m>Ҧ#|ƻL^5zui,vrC+C?9DlG Zgۨmuɜa?Tb"c;d%M(^Eqط_nڀ#;6~(Nj އt`ّiv0M,罌T(0540W..}\3ax3^ 3|BBWZeMS ci=r)G|M[E8%ԚXC8{4,資^2$2dTO*RG(<1Qb[p}Mbhc=İbT>2pWt5 Q4E#eMJ{z QG`Ӿs1giA`l V _T>g`| JĒqsϼ6Κwp0dy>YԴVŨ\gf80$0qJjU" Ow0F-\9}|@nԻMts' ]}A{.&JAP<4dGy'i4 y<72|7?r* FJ[= f:tY FYF^ ?;;1o2V?/xySO~,afR<BO]_M endstream endobj 92 0 obj 2173 endobj 94 0 obj <> stream x[Kܸ̊Q0h5 9 #dAI流")lޕI5*V}H{6E4<:]q8z߿~|gգjm~ߨo_?gPo5Y/f߇_̠xq>^Ӹ\Ӹo\xƆj:yQ*M}j*MSӢMOl*@[E+528eZlkD㏋Qf4&i}4&~p˲e->*cYIB' q:*e,:+H5kjSkBMY8TѕPIIN5Ut%ԶAȲT㱬Mm YzgaQ+6 ,5jw%6W4y2ׄ$H L05feIJm&Hɣt[,)Ÿ&T%A셪`j)F\BLP)SqrVQPODމ严 }GBj4!)4A8Q7t0~ZB 4L ~WYT2,rgA)xYY8)9j i}V.#dw5٘E%]-sl |VΜXIs"Ғ'EZ5Lpl\UeKY9sLjbH9n)j` pKkA"p( 7|Qܥnd p y 3NOӌO,V%%kZ  sA3!hN $oљH~2>(~B;5|؆'e¼vf485xH(۬4Mj .rvJ$T"?BPOPj+0곡$҄<(qkg. =yw2D\ns"lV$t$,sۅ$&Hᬙpc@)5M sP[VG{3ڛ{Wlaxqm)d^(W8|uƒH-&Rծq 6Xy夎u4Cre$|kHx:,Զ-!K%,J9-/ӣoi~aA% i]dޓzF9vZ_DQ\Ȕ*3=-7~pK+,؎XA; ?:ڇ% x̆'`S66X늾=GU`2Y%d%#ې-HbbuIDl005jܰ'L$^PFԿ|+4"&ZrX!!JVc4>X R).Pn%h8ܓ] s~7R$p!ӉƜdBbGBd;I2X?K[IJ˝$I+IM NG+!˫UgUh 9 ˝jnQR%XHBqnQQi@&hYse,#WbJK]GUq09JMy[m 6q-@rL)FF b1tśs}t0Hsɰ+~ӕķ}o+R_/U^)_W;yb !wƁ3no|$R宑.zSI =n=7h3prs:_7E>Bbw\zSv%!Q.IvՇgܸHM]mVXL;^ 6ݛ'inkؐĈwi)cHA2KhRI"5]<'momS bxT\T>THn wPN,~lmTѼkk;p@Ff!Ȥ\_f*xR6:/K],1sv4SsKUew~-Xp\*s4bi֝{..%cAՈHtFBKBh(u l[Mzہz3(.9vM P`1Pihў.9Z=zW^M`&wWڴ)ewmDX­KG+^2u d]BBlS0UZ4~#&[uSVP v9 H}&BGkRr+XcQvS+-AmpF T SGT*{#ynJY_/M+wm\l:OY0jBc:{73~Y*5Өrm?"2{X-]C$ҿu dozoQx-x_I;eFJG<+yR-KCr&J7Q ³0lqy$[y3?]S)Ν}`JegSoZbۦN`)h 3v~pZSk#v8тj[2Zyь50|R8;Wbn%%H}xZ5咲Pf)=5x$##=V [fC6'U&ۭ>) gz endstream endobj 95 0 obj 2703 endobj 97 0 obj <> stream xZK#7ϯy^{- rK6C {OIURZR^.fnK_WV}ퟓ:9j?q7}|#W(ۗۧﲸ|Ӈ>wv5fu,^]^[U]ߵWդ.WMwkݰ Ao?W#eDI mVd`3WK?,ktxx9 Fç2h 7x_aN~%8{ςZ t:5L^P/}>w^"fWn0f)l2 ` -a8ԋ'{#.c2ȹ75,NZlh«{ dA-']aoo ƂWi>33nnT:jkoمߖ$a\tHxr3_ÍFf^ƀkkֲ;;!gDff܆h[rHCE6!legRO島YxmģL(0L]+jh++4_X䙺偾SL YJ^-?9M.l'7}&䬅uָdJ Rya%v`WJ F32<"U͞L'';(P.c y )yPo^bGŀ]G0B(}e4ja Otk8f6pj+:4t={cSk5Rʁd(;!q!>G4RǸ[)[@c-Wk#ZN>R!D$rQUQZN}LLSzzjUV!-/HPΉg}Mgf ]ueɁ).$xD]U%P Lܐq+E uKn+r"ݢbu긆9]B|h^ %=eإ$M(|Aj-VM1 :B8(h P+ :uLgufkdS|d%*XV5 ˳DSΘ*fZXZLQѮEC;s-)XȻA^pcRC,eHCR1nvVQu mvfrPNFw6d~/mXUI;v>KKRjw@){mP7Q+Rherɑg_xOՉE"(1˩v+)t׶ÑDU߯tY*vJjthlƷXVyE}?x }Ix@{'8W&h(Ҍ V@Ŕ>/ Z}!l& ^8(ճdqtƇ{pa3SHR猪t<#Lc wբ+l rّtr :6޹^Ջ.MxHhǪ,+ [!3fyٷ'JmZ 5creQNXڸI(.!*Ŗ4oS _jH}CA Fr2^B+ej &-d <4 MӮtIvA3> stream xZ͎6)t`3H0X 6 ̐(SNdI$ƫN{xmTsTtk<_ ycmj*Y;mOdt ^X;a_6?'jPPdx9hߝߛn/j#]Mg{0RtĬp6Wʕ0 Ba'9yZ>hɅ119$6 \okU-=` ixku O i;le2Dzq!G/q! 1dcgm!~Oqt óWXcqp FUXo` #2AМ72 Ǽe= 6C8Y< BU+6 8[GvSCm vߝgz !\#TC2Й*̊Mǂ->)-+GE1GD|S ?G:Lq^Xazz~庁qoa(!k`dpC\iObš5ի$8Vr[ѭF hq;%} c4ic+(EcaޅU2qptpDC$1F%s4pVnGp5TYH0U] %VTҁSJѓ{z"Y55Rt`aKB:Pp#5 0YT([o0CQVi%afޘ>.Em ~y@i{1}^wdVVC.“+cp&D4D# _ԃ[%빰ev#&ӅRmTU)HU(,Ed]J'Ӛόtőߛl$%P={l'T97Z"[6tp'ɻ  Mzem3TCJbyRv$fY+[O%"G%&"?Fs"]Bئ8b3^З@>2箜wȭodZҾt99VYmE^l8=vp)JlLJPZsޕ42uT\&>mlR\&cUY~t{r͉0<&ַܢ)s+-tv̐J߲n@]caq<,3u٪&3{UK&G_+}%Q&L3wdujaĪ\ Z&( ECb,gUm)x!|ta> stream x T}j/O#JPQKqETdUQMpA1Ơh4hf4&^S+ #0334H{Ouuܪꩆ6Fn D@Z\UP)ZF,)ZQI*eR"%[YeQU[LQ2}ޓ`ZbjbMv59~儷 hW+WZL $堜&뼖g^Be®-N[Ar{iA XJP]8ЍlM 5n[A !*b*~鵃6CIH"ZX-];݈ SnhFte5:Ud_ !z* D$ݧ$g5?Ě9- : [&NЙ!4%қ-%tsmA*_B}deZ8U4 Uk-G[ va +'<nuN, N+hrZBG#1JŲVʑVTz aFJZ`D iPUmbm4Re߈!TGGЛZ0UB'&3>*%U0h@xP.hjhʠZ0D'lJ,pPH@OMA&ha"@zrDO`>UMkv_)îbYT}yzQI{qklSn^sI5,Lh_s)M95vRh791;.e;iE"߳QoɉfDEG͂O ÝN8ԜQɌ+ZZ`< 5Ÿ.vV Ͻ]Y~/V-u>w5J whު``P Ì՚SfK-TH 4rr 9%E1iXƜVmϬzm5DQ@E C& r5:-@3+ė}\80i?Vw( vggOӂ&_+<6|+#i˷x {#  hՂ[UA⍔:-|>B:$IdrR1^dI߉YZNZi'x(u@ \S^CV9CJacifhiyR,WN|`'mn>87s… Y>5?;F/`0u 0DػD74|w>hvf7Q>(l%S99tH!%cI$ds+E#ش0N` e;ѣE'l.f1x(EJ8a}is#%iy[*J_66~kω3oV$ mimh[4(a]rU'/>7G @RS>yrZ%ENH'ǦRϦPcI}dwv9Qr¯!3F,PqZ 불'-<`Lk?9BK ^ ZY%j++aS&W|L{5>-yO ogo?J!nb@pganXߢ_bzn1|h B-݆Pmx}#K%'P㳨146K [Ԇ}'@hh),$({$3=KaZJt8t8h8`8Vhw}'Ӈ!'sІ-օmh5ATTS;{""dT[c߲TՈZPEDV뷂ݫ3yYS-.9M"xYU͔M^b' ؔ\״ȉk)eu[+mDK8廒s5n+> 0{^~hgÅwܼ썛Ѳ_3!6͏F|,Үُa^uD2&JCCoQP[>5}59O5>WeV52[5ixViY 3 SE/iyQe5'3TGI_0,'UW徙r--N(I{^3D IKIU镂:`?)|"' ?):*'Tӭk2_;v࡭/rA'Nܽ{ŖT$ĺ!4B E~ G]Y%YŸd}HD\##U7%Y9'[08-ԣrOQIW?R9 BoyFID1eS` 9Id4~,ι"ڱ2j䫾:Z;D3kB?ħ2=DBj7ŨB$IrBSQ&LSF0lybfiv,OEǣGnkI:rzrf.鼁Ae]z2Sxj@_M3' HܙtFeaNgnX7U,-̔8KO-nqۀ}2JK 'D3 -LtK 3ub5w'4EwC,qXj]kN)Y uYu#2֩J>[s] P%3p7{J;F8EL;BEAbb_k`ѼA]~81@N0@  :A9ik`6Q`PLs)"nrܳ^rod=eB1 vhpdx@l#\hoa@!u6+N:io}Y,+/_=vWF_ym >kvyGsmٴ Zzq/B\0lfrhHL7hc;Rn:D8xOz~;맼CS jiiahy'=F﹩&h'-jqb<ta$VZ^5\`{Utwl>.-J:@sjչ j2ZG0{R%g2/-p0-Xi/L hyӂeZZZ ([,´`ZD &0a.3fآOTh15"2hh´tҁ-|ha1ÓbV>oNԍ9yZpO%fAZA93LataZX`0L uӸ ǸhwO[eV9+O1s-X0-Xi>H-£\9~o=Zz~6ڻ ӂioL ô`Zߺv-@yLKzS qY/t± 1-6y%kqEb8ki1-|h1as-ficquqr+wSQVOag:}.aZ̽Oi3L ePߠ/v aZ´`W+-w܎i -(obw~qΠ[rg0-i7s0-titUx13x<糎װEnzMdXFktYr1>p2JaA$Z޳3.l5E kn͖ŬSx`Z:`G G>Y0-nZpOƇAp`(я0G9h1z-ii[g`)aZDfܿ0-| \_2KK_/63N˼X `uX,b-XVbuX,´`tX2QZzAb -ĈbfhffВJ}X}]ﴴ  `&Lh[.9ʴ8;8>Q|`}e(ܺ3|:#B> stream xZK6ygU,n@KNI&؄K~JOےw!xcRO-^YgoO?OQJA>P:J]h2/yd"v8Yp /bpp1QG cn$tA_<ͯOOMSu4S@ib"n{/6".̸rR,^p+ٌlMq2 U D﬒MW -[}:" LXOe [ 5 {6cK]%nn6P5DCxǒЄ^*/AǝG0P+=!n6+X(-;.ϠtK7v7ҏ*!TPˑe7D}i ><zK0 bXy59KŸ8c-u؆p3z,, 앁q@;8!ϼZ jK%X=KU*(Q} 5%:qSϊ˺ RƗsGEϾ LNWa%<|#:]%MHrvnK9) Bm(ӀpB g"{ZЏD' X z+)>k2cq(S ܽut:E,)]Ғ'Vb7ZM`IkNL*=Nׄt{FIHL. KKW,P-ZnjQŸ8Et-g&&0;VSh }FJ_)tE,#hBX#ɻAc,k`CކA,]B("l=Ae1^b񥼈 1Myݍԭ;[LlNp>y;zL~m 9/'ZgHeVWnDfv~j%W|@:((71}?AǞd8LwT~8I/ T'XCUg׏ZqZQ$_H}jZQ endstream endobj 106 0 obj 1997 endobj 108 0 obj <> stream x[K$7@! *o {Y0!Wfm̔E([o.N94^AO_ 3*{맗Cv4,jX6dx-W]O? 3-u(77/z]^4~xp媶vOsZoxUz]~_샠nS.<4O/υ+)@c@4RiѺzk(@WV\WD|FPloל5aZ[mw}M\{m?qeG-vݖ/^)]%!ipx{(I3 OC"[gYC?x9 [Ivh5C̦RS[Y+zI1OO -sYeU(Swr9fÕލԶY<~c XajFOL~pWKSeA!-VgD,Qѣdr4`} 6ɧ-=WΛ{v;{'^ȯN){k%B4S;Jvt&ZϜ\) G}c*N&ɇSh>xj8e#k{vNUlT)X۷ qE d_rwCZ1M%ɀ 1vuW\ɴUb8D|%ǚ| @ [WUs |6IOy~Ŗ4gZ%s8d V"_wo B|"FݏO1u$OpU^<}܍ŽB q;r%iDb!E"Oс:S@c8lp;~DFv[+3ҵrujs.m1=-X u#^qy=Y/h{nyO8Tx)՘“&m&iq-8%[9v.3VjÑIdT!\msqF#׀m]B `Est oˍoZ OhXh) R+Z:p䱪`'[LQ!KvRSΎE/[#sFDwCx\&sX8: 7u7uvmdx9kK U;vԔ{pVĦI #=Ed$i9iɣr_О*kw4aYzIq&Bf$xOx(\aBmT#4G} N癩bJ[l2c/EUuڶK+Zd>N(äjFO/eE6{)AGE[ -U% 8ի=S^Ip=sj> t*mwUg/Lgh56ev8`jNG@FR皫lU.^DTB!GU% ?Z,#NuIJ0:^ʔ-.s&Frtw9A[[OT%="wd6]SӨ(+3(P0gL)߻h5%XrYԊ{R}T9AdiYgM]vLNͼ. *NbVʎ缨FYЎ Oa'oe{:pJ볎L۸ڟU>Y"kY+]NTsqXYk7BXZ"u]t볩)0>ߝfI3´9ZסW̲UE=tZ\ DYˆd>|9^@Qy>%Qe8"?5M|,({Pu-d!;іck[(gݹq9b^ j\::͵mug/&<,}pqPS&[܇&S3)(D(Y-߰&ZjUq]ӓZdxaU{ʽt?VF-￶tҥ+w$NOUU혿'>+)טcBvg¢I\M⵩ymfxi`yJ`ƺt6d9?Mባ+hn,[8#h! f37g1%ž:h{Dͽ[ט*w[Al"*Hy4'O5Hөƽ0#ғoC5ga2R꺕3!<*[dY'>TTF\߯/0byܛ ޺xH.ݶ@lw6Ζ*F)7Vgd!T~Tha{NyS !}0%K%KxC&u>Pz̅sgή9\b-XHJ:pXZE `qNlT =0ID|3{ /zLem(%Ӭ3h(! (66ѿr- s=+7~om*5&)B\#Jsu.BfS Zm#"8.BєnmAUfwJj:GhF|L4j/.<z8 endstream endobj 109 0 obj 2746 endobj 111 0 obj <> stream xZI7ϯZkka SN/y֒`3SRIO۾꬇j8)u>?>aIOZ̓&pzS}; ^]E-WsQz4#鑹 -ӧ!igܞ z n5(+'_<}nZP1 "@k/f"FbfDg´`6ȫ8~ = 1j8uauZ\gH8]4طL (<~::Mҳ{EgJ604^"Fs6^lg4bJ.rp c1$yd|F;' nǯU)"gSt+nuheQ eZQ3Vcoܠ wR򨴩,VO -Oc6C/HʋC[b0;XM/ 3X[6MG|̟`g@q=4rk=]&+AZ⼢ ~|uB9McB|WPH #D~uꔃıU94Gw_`zCeکJ(OOar4LRڽrg%00Wg{|Pf~] =.`nsvGMYmJ#i1~ZrmMU:b]yPYʘVKObÝKkixda$)LZryV1Z;%=<5 =/o M$P~gܘ09sH,^EsIQ]4B,; bOY@dž @A7Tp-DeȒH$ޕIpH&VmjgPy^71E"sMM.5;D[mMjJ 1JY9e Hs3#"Fq$]N'HwO7m@z4L>=AaRr ӪNE 1k$uҚ2.Jkt UۢgBfbUU|CmM[g1&kl Ȝk̚3yߥqK0NzD(_ά*ʝއ\a+#v{?o)@E*HCϗtxb߭jp˥h~p}uZWӹEfs}Un4P<<|Atcx:3Su=|gf}'G_)(=D훨@mWB#Zn[;{'W4XV7L}':Xls!}gvJz(esy"ˠ1tnM1Sԝ&/,7M F^i˰Ѱ}]6jaސhE]M-5]5)1.aQ4nȊWV~4Iwr&۪ yP c Eit 06f}،80ASzq--_f}6Tm*ߚNk9%%iJ9X^$ >;&<^Ң]dOwm&+PGRjwgk= t .l'G2Qq@gD0#PIL{Ri+)cD%DkJXFq9i4,o@Q1F[DE#Ȉ /C6(H2RРQэϣLk T׊<Ke=8Uo>LX֯h$T*J\ M8YK_'TŹbO}ɟC endstream endobj 112 0 obj 2264 endobj 114 0 obj <> stream xZIׯй!sbPR* |h| csߟoEMMkRR,}o!u^~t(9hч럿uEw_s?ՍF߿|C7봇 7A4VtTdy~2~y6o6WY*?W|pPk0Py9/&k `&P4\k:^=o~ws&rW4:;uFn􁣰8;XHgCzChl>m^>ƛ) S Xѥ 0h}p-Z8^㮸(Mx`X`1*U v̎٠j/|ZS Hιjᑹ\&F5#2uP % n>G?h?} JtDY, \܍ڸ8ngyqЏJv-˸`1^,=wf];n p@o pfl@m0+q0f_*ql0g̋H/7J6u!xŎ2m'pIP'.m06ņ`8Zfîancc[+#!a LPeHz7~N2(SL&%yNr*-> k_XN>!&fhy.MCUESef3 ٵ$djbX*v`ߚJ>L.S!LIZأ2Y@;;3֟u=ZL)Fv8W AVVY TqZRv{S؍c9~o.J5rq^Zt\N$$PnʄEtZp tO)~&.`V׮(4@IM1gFZ%K:Cg\TNnr27UУk`~&%Vx'$.SmJ]2k ,,ɜO;,%u|Jay1٭{jS9 k[\o[qR}ʀpM#F)[3lw 65p>P[y_<]lX>%\S& qdđavӓڙ4R;brz-vo0mDA!q~zu6cȓ7Ȼhe.8*qLJmg{c塉aݞyrH;&ͻ*2S9<:@wCQ~{֊EΗR> V r< ZybRih3=O, ?sޒ&W%i3h\CvN2}bd×a'؏xHh9;V >:-ĘxWԀr{$prqW9 5XiXG/&Վ[`.*G}TWT4>e;>H;5#wyzzT)R' ӀL8vCK$gԐy+(mKM'MD-c碵u2*Ϟkq7NԜJuM kZd|c~^2Ͼ$yѺ}i\0mh>diE:=(q9OR,d}b o|SH]݃n MSn %0iӉ˚˟LajZ yvdextTCj~*i( !_9{e8t ~xHh&fI8i3.r'3r36o.\e6Mr=J Fw / °33?T\X3~D9H]XB`~inNԟ'9-ut*4w Pq}nsyEO`P#8 0p endstream endobj 115 0 obj 2507 endobj 117 0 obj <> stream xZK6WIQ`[z(zj ErdHspoߵ h>%ʰ% Y3)k/t'c1r=u,v{ pf\fC!|Xb̴9dЄ-{T(Q$ȳ D8hs+E!IrJ$Nc6N[W/NTPqׅvMJ ˿{-Kߘ#.%MB{u+1؏!r`06};&ktwaL)J>"+vC M)H87]4Ee3/W\tBB4ffrFk~P㷔C?&%#͘yUV/2Nl/2U]ZZi%ܪek?\+8՝ $)7SjJѺjm n7<ΡgJYutFx- a/.'`K^Aj<ދk-gI% d3{+~*B !=[MRtbӒu=t &5VK w16O-)g`ds>oZ֢5DMo:Bh栶0Ozt1tm.BuYrqΆk<"Ia˰ |u!)&m4 0Gfe&[* $1M|^0V$hx1iS07!6^S욲ޤ&9?xR/idl\S̽!z/Cm0wj#oږѰ}OjIhÈLKqRlr{ݒØo *@Ɩ$Ii>c'=OiכdA dٲ1M eF>+p9 6O,gM,[pكRP 0C+;S09GH@%-{%|]`=+V֔5g qbG'l$l^ Icaf6 r}(A6bnI1cMԪW !:4ja~{ϳEzJil;e٢[/ӸY4U=/\,bn5l9ͽ-<@lW+TEL[J0An6\"|Awg1/Μ<*p(e1jTZQ^y`KƱQlVj܀$rqU"W(iRwk}MpH)VU1nmmlx_ x#B|0+L8\V5ܒwB' !iA8Zҳv;$6l)}mEXFc zpy!ʚFc܋nq]0(cDcڒm^ח3(3Y {hS-*YLh]$B>J KȠЌ2 1KPiD2Dl5AcS-uq; Ua,=29Mᑌ&"\IzVT_#mLzb'1HnR 4C30U<AgY33 =e{ß&p뉍nX!LVܹOmm3F̞~Ool1W?H:Q%j,.%ؔ%>jқ0@iiifaɔ}8]~fx MX~`/^l endstream endobj 118 0 obj 2141 endobj 120 0 obj <> stream xZIFW< OWu#@rxC)撿ZzeILzZiZC_= =ϯ7?}h:@ßzg p{돾Aͬ}"]H{@\n>M=eÚLocZ6O<ړƖn #d.c v57~/fi@plQ'_~<A d4w!& FH7ߌƙ;"Ƥp\ƇkC5Y]y;d+rz.97M K /KBy7 Zr.ouh[ݜ )J-}~{VAhlUuY3dgX+yXe#H[j#mwG8o$donbωާgݭa?&ֱfԆ{i48`֡_ Zdᤶ)Ag )QhΐFgǶe"r R}:+ $8b])eRR@:==rWÉ9gUXw%\Q䭔==)l'ÅogHO>ļ )\$y {5]ks=̵,2.\㐅MD[Iˀ bդ6=t2$NMu;sȏA۫;Gu3LucquR؏hsy)\!wdąM/_-?BVF DEhhJ5i/,fa-8ա:KXlyIGM*jAsuR;$]xJ}MbUT.`G z][ `!wN7!Oܮ\/$1+Xd+!i8qG.kJV ..'+;j&N;wCWkoiJci/+6L.m؊fT,P"i3MO={)P%XբȟMp2MaZ1y-ƹ(1)GL;Rִ-pT_ z=>cэEPr< /cf$ŁuS#?dUƟ FNj\|6qWwux04?1ۮ 31چ6omv`B̺4dh1Ge{>2ڡJx,G wBqjILU"ti="D"{,|*)#B_Dڗ-J!F!a,s 8xgwњOkidM97)%Ĵ_$9w$,Ztas~0 P%%q%' qt4e6G0v+b'?3nxI<[L*kK0Oyg㪣ˎrS>S``ѯZX޵16āk_"hPz -ĵ!(ixM9htN.,/qC1D*ZOT5-BR k!<Ě,J\!:4bVݗ/>/DIlPb)6 chX0ֳ_*qu$QCR/.[R/wi }BT1T2D*Wn,IdD$^sɰU.Fw/,S ^TX*U # '/%`>NUn+(Ml)d8cH[ս´o6,DyHwic7J/HQ( WVT9r܊rX?U9uis|e/U_Υ|jsz?@ endstream endobj 121 0 obj 2188 endobj 122 0 obj <> stream x tU+0Q<%`X$a_š%Y!$@V ! MDMPeA77P8Ψ"d-I$nܤR+NW/[UVuw"!0sJ*b˨**EKUQ)|-T IM$T2X!QXQ-s,Əaچ6ԄUP* *Z\ZEM` "Ι.,nj2a&e̔i$v ds"IG1pn ;/DA|WDJjdD\1dw3Hv%J)t^T~J:8.y*<*bJFPsn#oP+;XJR ڂײ4d/nH +v[ kRZj~Z&z#IzjOUP "#ta?P6*1+"hkPz̢jEU&h0FP'ĖaJ^9H$R`E~"KK+ɮm̼a N%~tJeԫ'h)l(Ns+2UJ;M +ikXc\f v9wq~!sNStD=kqjc䕘 9K >7Fe^-kFWQ{.WXYt6?^ΘZ4]8Xp2"i"|HL҈C|ŎQr!cU*blGٖ2I6ʁ?`F}d4>FV8mTնܪMY2*ק.ԭM=-ɍRgVN)<[w gy~},BmHm:C'oo?vkC/>nN EL/1["zFqlnBڧ&KTnHC]g]+7eґ(*^+L֭JŨsUg%0g𱑏F%~˷dd͆_*;we(6(mHxF]{[_53/yє:stF:lqz| /1S%HX)tnu /Wmɩ|fnMve6/NӧOc {(_1鵯ƽ;s9l5n#C V'~m\fXj]34M'37zH%y1=k#E $jǪ"TKBU U,P8}z<>j#72B%cK< 2osX۩PˡU?dJy_ʷfNԴ1bBlQ|\h":yE myzhBYHO-@0Zn0,048,8X8!8*0lqpq@_/xVU¸`AO%AS,[[W-1ZHЬa#Jo]"lrtրKTxYz۵_;e'S~=ֿYS ,'T5lqf+T Hpq*Wgu38lDpf@nR!q)y;,g3N[c8848hX6/]뗦;a؍F"* TH[?X-HŪFr[=Hd*"=KIl q%ף(N}}3'KqD歔W}7싿sZm9D`NZ4|cg9$ vRlkx6 eN=B66+=l_4=m-=8jqh=0ɡ}s|4gT4 H]+[͟ɍ߭ʜtL؁~ꈾHߋ}72Kxhaj}=_vWGۋ\`Qe̋ڡ7D]ْ榵~lƖHAP Ipj]i`m+3b5:jK as5o1l#6ҳ'G4zѽӽs i:P#<AS4VaqڼͲNkjc|55+{_ p#K%_c d Telxl/Jj>q6UuƯm{ruƝ]%%%h|csn7H $evݳi-e۸1#"bk\\tԆd#7ШknQd*G3 ,42751t_38CAO%ASDDBٓCT5K#yh&ApXEFPqizZE12#{%Sl*ti?Ï\Mx\{/={߱oxw{n۶mw>z(#mT+%f)$6Z ۼ1ZPp{_K 5YO#74pBSϕy&lÃɺO)H&:l#=s=}=i=fiM6_@0 u,ͲH(fYӵti͟qTFԅwW.aF騉͖@ l*޿F (;<_맊QTV誚ܥt\OPS:, d r|)26;>] h%AQ:%ک}h\~j&H*RR7Buw{4xES!?DD!P_ay?`߳3x6tχ^SHw8.8?+I>\Kx`[<Y\ĢȹuEA="?R@k }s:㇂?!;Cr澐/ 355 SgKeHƟ_nŁ xĈa|bpy;*S߳j,QX5q g@{)wO[{ڎRhٶ6j]E&r]:4ӓ%8hGdo7ߞ}s 66]yGc$5$zL4Z$Qh*Axmh|$T H,HKYJYK%7?K6Zݹ$ޚ95z !M-NpL0ؖ^a9LM-_lX;I;&k ,Upfu;-0K8C&@unK(e g,@񖀐 X% H`  yߗpCKXE:7 <bRv  LpKK6flFtf{ X %1>  } 2sv=-?8?IIZrx%N` K@o wz !'$[beΩܐ` ZB !H8 CN} b wXK9s`'h  XB&[ʙrrƙawK@&hGO?L$ =8a3׍KP-Cѷ97ĒrÆX2uhl, }%X %1,p̀% X %1A%τo 3ia K8[NlK(-J%` a,A> stream xZK6ϯy{U v ma %$l%?ҫdIvOvfi۲ꫧZ\K'H[ӻ'ߟ@LF)OUϗW;ľнڽT{Yf,zgaf,q/W/b[rACxn"ˠϯ?>O>tqj˻MLp=S{JD_>?3_]*. "*RZTqϠ _a]17X *Ila&co-4!]{v_̗/:5[{q[UoTHbGO%(j@x`u&B}f%D%;HhwӃ a^ZZiڀ{fݼFh;8#I@##'4$+0Lݚ u*>Uȸ7FXs =x`!=)ρ"݁ݦjv!9h}g ~6%jCƥZZji(̆=Sy|zomOU Cn6!#yJ*`0B{[]K}->7ĊaD#{c$Dl[fi9XλΜ;&OFm#V8pl#*{JAFzt%ЧCxSE2 M+46P:FX͜r"B)=9rCuޔ)7xH1-K)qiܣNхZ:w|H~."A +桕-y5rFz5pc띄,r3 s P*$u#^ҁNjdOVD%j EOz+QhV 1c=z58ȡ冓%;kѻAES[ 9̑kʕ֪_東.|3~džC}pB9UV;5Jܲ}FC*>Msr*z @2a֍wm(: 7qG޼1geԤnZ(x'2b,suJ:ʤ#n4|Af`1)ZR+}Wv. 0vqb ƻA^2^ð> %g*-:ί10q'WrV.-HXpҒScHo)ӆ-{,Qk%+KpO!JiKP{]wBɖM# !滻t{ Rj0L}07|÷4W8Ќ|eJC9K:ksp"H~@&"yUOEBTf]HzuO(P|q.+fUW;z| sؙ?V#,VJ=q!S3Ydff1I9ٓSȇ nG!RBF)1rϑ a6N=)e2svso M|NTځH5'Þί|,tuxG<,1꙲6X tTVQ<})Κ9!VڅSSՈZ|a VJuϾ~3D&{J W5AZC5l5+gRA gҔFZ,dW[GeQ,7jx*JfEAsv"#Guw܆Nt.\ ԮN{UuoZ#jHOR/6ߏY̡5C?֍v@ۜ(1BEYQL=jxw&ntrSq6BĆNgaJ ?1'^(jʶhr GjRjɾ@l0p-+!AjBRZ=6@V[_N}!X1=`MVAfki] u# '{taEm=\E{YC{bO5}ͬ!*b<`b }GLh@"FmR(ٟ͍JاwtTq endstream endobj 126 0 obj 2143 endobj 128 0 obj <> stream xUK0 WYIv`Hm Ci-eҿ_rL-<,K>2-nL PC:Y֗irEPOgNQD$=X\W88A un>вhωݪA5u`Jev|Huu[ .DYj.z`gv1NpvC 9_x:oCqS/sdDžKV2!؃-)'v  SQ>ȄVW+)u1%3PND6EI3- aJ+zen\<Y{;oCk`UչS8tꢞ+*i*]3,Wnv%mDH^&"틂#shqp}(TrLzs3r9$fZe1RU^e@s'F/HjwFznx`Xvr9lȵZrdmEfpJ%3@L\pwoy[1ָMd>^|5j^ endstream endobj 129 0 obj 662 endobj 131 0 obj <> stream xZI6ϯ9m^9!r$,yu-UY.pq u׿~~fMޤX=?1J?}tY/÷rPf!^oG([CVzU֛~Qtk0A1q59|nxXP{RKCٍ C֟>Ih|k{&u7=VW xG7SOwEӨA*Ʈ6>zncn)@oH2 fNfVzZF!8o6G}Jgi&8"N{2Qct wrSx:w]fh锔d)`Mhنp~0Je#8EF.U后:  xԼNAa8M`'H堳)XDW, O9: SSU(!՛OESxEUG>c"͐rN$b7fldg M}nW ,U}"ahϴG@'_ {u.J mgk<16f^O13m9BĂjOrU W {sT$8B/ۤz 0^J !ܤC1^e> Ѩ iSbKdt1>w,=tr +p`l7bMdpS /CeWx WiQV-%|d&i.zE t5x%]I Al4YYdDaTttZ3.f;FuȳJ ki\Br `oy5:wڌNȷgYN!W.\Qn8S핎( c5ld4R`F/u[ۮnpۮa8h1H2O~ƯOa o/|"Ry.65IiSW60ķY+ԓ YrlL~`̆$Nxn{fgGV073d{ViJ{*Ѷtin&ΖQ1{U6֦Y*NĺWY .EX{[Y]d)SR:B Q]š(;s S9#~LBn l[f%Sh2v:"ِh[hݹs!=6rV@:=cYѐ>?W%FW,St-4 "B u/Ě1*^~,`@ C,5dl:9F˵E^*1ECST%]U2ϟK.rUņesJK--詊iW  bVfNiy66g> stream xZK#G|W4maƧݝ/Wt#|D|Lq_Ob: I?>//r?"b߾|vg7-l&}*7Ny~ߥv+d{r˼{MORM~y׋~r"_zQbI_wo Jqqq]J|.'E}kEg( Q+l)ńgjoԽ JꪮN^"WֲWZXa/ bK;.~Sɸ;2n-Z 8AO@Fx[~xǭ&9@H(})T`e# D9,aՀËbF 6펚C녡qD14$ &.YͨI&4B>&%dPnE9J+6qEDeHabßi:=]D"(=#t C|]YQr[n ,1GF_PE'"Gf:~m*O)vGY7*lg뀨gPJMN#ޅ݈,A/\-N`<ෂk'20#` F FNi7:ek(|o*|mL思CZ~F+=-`CF2ZwY;/j#\ت՝> Q^kcymmeH; 1Ea iL>wUVIU?&[uY5aʞI3EB3u, Ͽ:?+ i:bDG2iVVhUb:$::I?3z;w-B؏R7$×0ru[W{XDhk= n=X `F#UXz2ƤК4XzSfОr}"rkv N5>$V6S>P38C .b̔>Y4F} YYOM 9l'H5yUe;ȠeT51k<OvN5]Y=U8A/O!&ѝd/Cm^rHet%09iVH#X{BWS#-5ZWI.|re_5\kJքv8ȍjYP~SxW])PF`|+0wF9IV,8-bN;m4Đڏ_Sߎ E?‘eYn'i-G5E |]H~dtpE=p/!靟VW^LS=ZG-9.VhdţZg#uJ%D1A6rZL&x&zp'q)>Iw=P,2mmr-#׿Py?ͪjf|^TH I.BsBm#5n P0[4䯫wJTvLjCWgAq wݪ$ytxwC}X?T2> stream xZKykEAi @Ok6}#LI=nUR"R=A eϛzj0׿x ⇏ ?竺Uwt7}U\ժ5|{'~?Z|\К~2wË۷!ig|< 1Q1]%e.׷|.jM\OD~}7kY9ʟzLJ&ed'r򢾫D^>YY]7܃eKĆjjUO2oUnvQ]Ͻ1~4`ZmYw{'^*/!kDta]WPˎc Q{`R-YH}8ݢc d܆71 .ʤ 2ϬibB\=B\ ,}Ci K\f4Y@Hr\ u0r5ֈ5If43dt*G Tإܩ8&mc_V#zh_|`ITDU""z'"zٚzͤ0R0ɲ?/uyU=ȭkIW72(i[9հ5A3萓ZdRԥ:;9pE'9 7#UZC5rйj gaT#dT kՃ\u A gbCW)D$~@p8pY1)nIm(2JE/{?66I ABpiymtU\gƍWW",}p[]?213PG?x(|vY6k6ۉ+A'w[uOO$e 㶕Q{٣- uJxh@959..%Zl\nۈn%?9OBt纜;D @p aL 2y;]S 2bŵa$/^4$%:Gѝ^R^~)QG5ćFX PK~6$E/G9ҧiؽl{w9։pZxz_~4cN]C:0T{mdz) CIgȱ[MyOOⰷsN#Ⱦ Uxw>zni ʉTlc-L~-Vq> stream x[K#7WyN ݆0C)0{OI%j{f/a֣W8[b?m>: n`t%NIvL5zwNF~Oڔ͎F xüp_^r/П) 1fSg&?#N`gVvbҗ GQ.pXb]TC{GIHs4XM8j"%,YF64`_a;I6p&1-w#|4P4솒` jޭJ`[Qg&pPq&72}8*x4b " e}zVU&G^ CdJPr &iF{)$ ;PVu4JzfXff+{(O%iMADz~"zU+ M(Gƚx AWl"hSD!Yb!5]z%huw͡}=>,ԉT.I y!;@ =XIC{HE&w938F| Nv]h@vgUmkw1ƻ5HiZfwzfKubh9)zkGoܳ)hH|+y:Fi3pi.2k%ZLfT0QVrĪbp%11m0Cri1%QVɆ]7m2@o2bw1ɂ&nOx&DZsj4{T R\ÙVsO`(zvXY d9ȁ[/Ȳ;'\b.BD.1z>ztH ?LUJk`+/[~)m-ʝ=j0yaI wm!v/9xbK#(cԗ}i xq&ƂD^'HC(wR^s?ͲH ɑM3Ivm/Ht1=frS-@¾H#]nRao xbr_?yxz1lJy͜)#NfĎ(0T:w.f]r+L0 x75>:{ {vqCy,_?V ,/Q^5֘a5X3J< bwWTZzWN Am_쫑)1qq e}#A%U0@)av|Tr,^<k04GoK(QةK@fTDR_xP*DQg{`j.•ʠ޹L$o e fMeX0ZWF2o~o伇 ppoAF *}8UtN`>2\&CP\ #q/UY Z [@T/ac"Y94]LcѦm*vݩͱІ694+-MG,Klh,uGJ N?zyK)t:Vyױmrd^TB c|(DǴQ>!XŊ[w%q\1U\䨞z'5 U=R/lժي:M}iFPʈB2] rTQQ~!se;oFnpǙՀ7Θ 8~НoS&ɳh;1Xgb7 9!UYa '7nOSNVDe*fƽP"psak<2ƄɁ^PgíE#s$C?Uڗ+!1=ԑp#1m} xEb;I[ć똸 86 Xr%<7+z QU<97MBB Gnˈ(~&$Q^ΫT[D۸ 7sXo vijgZ /fO; )cیŨ=h噁b(#%w\P( V_>UȏYKV_~׹Q@ԭ zBgY*HXR;ac[#M6o t_6Oime5~&k endstream endobj 141 0 obj 2254 endobj 143 0 obj <> stream xZI,7*k ̮*443o`e#ZB[Ц2SRؾ~=Y?GwZ˛I |틝|!8_w}퇫V}z_ʫXVux_nw(:97)-M׷ $,/$fOnW;?t _xZТb>?x5/zZ3L7m󀘞i5="ko^PjXg ٬ HN~pNFZaYkA5.%"؄wVc%y =8% sFhjBw9V}~G]K☸@{0ƐeE4P#s(1V5 񢴠9ew6cJ"v"m5Igska5X<U̴ܲ|42,ss 1/ sQW)wٙF @+~}kjN^ZZJ AF#q3[Tn[ړ#\TN4$Nɤ֬P Q%",DCgh IØ y vϫyF*vA6MKܙeТ-m7g>Ą0BRdpܑQ7p)& 4@Lz+\;T*wDsA"6)6Oi _ϿE2WZA=<7ܐ^Ck0VgPR&79MbwqA˔o%$V E6~1fT͉4"s"Ւq-HcQT/,+3t۵{rH'4R?U7J2%19bL4A Q# 1$ ]؅\VBչcX#IE#(ԅ+d|"5D,ݶɹf`-#r\~|YQ&\` -a*ɿLHptBfe@%]MLTKYb-=$6V$1;%ܞvpt@n|&6΄P ¶esS~ !/ST-ddX@_U엉@8(t޴VGc~`F|+Ѥ/@";NYWhd xc;/famJg(e& H7]|Vs_`9c ~¡5eI/ݭ&ETKl{OeyS<56eqFuM醱H&-δd QSyoʭBzWO:V;f|!ޜjk;AS]i՟߂cT qVdk;[5`@{D.}̣G4 ܄axN0:ԛL(|O$L@b?[gK͢O]TNdikaF[^ 3JsMB[z֟iI 7^j]9?(B3?ْElc9\H͑n՜ w}~Zv7y,9uT&7<-VKzz\%AV!gPP3UAcn "_SѾ<>v~FGL1 9emy+!JCWd'&I'5'\u}s'ފuxN$*לjB*gvv;TBΥKzq Tk:@Wm\xVՎO\՞w ]?V3c,b*",FpAx%Dƌnê$ S)Bc(!ScYAIR $7B=woG?@%.*iS.C9)iUPq`ᇻ]Aߨ~b-z~m endstream endobj 144 0 obj 2215 endobj 146 0 obj <> stream x[KW<@{Y$EIaۋ6A9 rd-($9E hFa 7$~Noß? >`~ 0Iae~9a`}~on4_>>`R8;"YOjρ_j9z \E pt;~v" 4wI"K7cPȀB.и ɭ4]E(J43.+G5#7?v10njJ&GHvqc5}Ws,lx&c%ӑ=BrٗYT!i+.wA‰V&_+_'%7D#A9Жi-hI#*I%(TxqgG=g\"=3I}^βԧR至kы4Т"ZDiyLt.hRn2/X3Η:nL{,MdQ_sVܫJN/iKxD+*xǐ\H}\d*l9&(tOxA:[ |<-լ`lQjٖ5&embwQϴ4):]+EvuC6rlL_ݡ ԟwjew%t-*ҵ6Q%G+p[vb[46B g(bS9pI S,I?kyQEOlI-K$ 45gl=3729l M7Mly&S>䖇0('vr/]-E}sjջRR}W:O@m(ᄱ<$)%*|hb+ϤBfBu a)d0D( f[uȌnGA0٤JuYRvA^RJug{fc_y@<^Ey7=3%ٱlv'X xfbwSՉhoEъeY0 \W=ӌWŊ,)ѸtJ%u2[K]ھSv1) c/k`E`*7cbS~?BW6wΞ6#FWémorS[F ׿7|<ٕG˻V)-m2az=nѰALNPF=Z(1 Xp9 &r4-hxdB{o)`U6Do_w/vϸ!So\ *{..5ձl G|[l+Oa~0[p3 =QpxE쮃)rN3!ګw(p_ѱ|ξGɞG;~w.ձec=ldku(VA5ldoE[Dϯr rW|SrY9[6^π|Y)΄3 , zyoy O=v H2i5 x1 LdvjnA;h0҃ҌX7nB_Dj0<ە!pO:.!i}{wM5;w-o]7݉AʓU\\dحh$ϡ?Ա};z endstream endobj 147 0 obj 2595 endobj 149 0 obj <> stream x[K# W<@JUl$ aSI^CzP% 聧)^/Gu|Qx@;8߯?Z?u߾xRwBƽ_?='u9/ipRYU/7u#^h"4o+}~L 1iZXaŏ(#O#-H[7ziRP叿;$2ƫ㠭 :k\oQF8\L" aj;[ډ' ajѭkn]Kb2dxlĂ@ )& %(5 FR@x8%+)n B8%+!b(E#Ď#!v$f8LJYHGb6޻]Gq-q$Ď=Tؑ6T|͞};^sP"vp+}d" c(jX}HGZ(Jar(bmG!ͨث7ͨ+9Gd\q]!!l"vBPیX:یr\fkyb v)'mF>H=Ӓ'D-?JVucQUK +}% %?=iFC| gxz[;}ß^YbJx~b1wRw XwaWV]ᮖ?AђjQj:F=u{D"cϖ𚱨0TF>>fL=Vpғ'}atE%dv=MpԿ+mXQIehV%g5pJQRz}inhC 㥻5O PDO軿OKrdIafp#e>/5`) 2yՐUⱬ1TprդS4b qBcSݵ~T0gH`N;ѝ '|w?>K8Vi؞kIA ]KH)@T(w Zs0o(R<  LB_Ӕ>a*7Jy mLT YA]XimCjBkw1+Oh.7ȁ`+Tl SspTg_ 1icϨpaTm*B(u '~;4^3b!m}Gy.?M5˔wdzaz9.]?*|W8 _ޜCEc ۓwrt qYH3"w\"{aXd(]Ue(8yz[,CiVoQs9"&vgd\6\KdJi` "NX%ń D$d:HEmݐB٭rVxJFɒQi]0> >S~6(,F= V0OR gl%s`GR)ズ( 65t]A:SRK3k7= zGMQdT68D*qN(-ؼ@ OVֈAbIPRU}2]#zš`D1K{H9˓!b-IV6ϬK] XELV/[zXb%:y9u @}z4+;bkKڦCcۯsaǯ>t`7И&פ dMc ure%b18BT٤fC@1B'i/^֟pB*Վ~3Jη_Q5q$k:pɊǃ&F@|rc&/dEWsFmck }4d&AM_䥳^S()lW3Sj+YaEZc~ͧOꔥ/4+,O6ish oa-$mlGFavͶ zPF\U+^›ٸUʔG84 l#5;҈GxN4O>\yU&6 Iޘ|Lo <јKӮ-Pp (:hDSY͡]̣ Hn=أdqD73z.h$J X+s!Y۷vEN^k|[yU-rJ% #dg<}mPۦbʃa}fjZ9 ~߅0:K4f7?\vmޢj+z ꬽfRS+JoѳO]lK) ؞kEG3휂6`vGk'ؔ]ӯV(yBo0u S0S9/Vک+yd(aqD~?q;0aXfUUtըY0џ`'&MӋQ#mKGGi-IۃNCu{a^ǘ N-d_内Ft eȉ p6*ӷo__ endstream endobj 150 0 obj 2910 endobj 152 0 obj <> stream xZKyjR @O`]f/G>J{SCRF;*qÿ߾bR_71?ߤ1O N |סz˫ClLwOE:;Q'd>҃Tobk&E< wx+^&v[򥞴D +1 2.ev4O͕&"5p#raUMiO(jhh5fÊAdƛ,L-9=S#jzcQo}j׸uaEbWkNL- Ɏ ͯ!ycA xy_*,xnw=Z`N:I,4Qߴh(F& wW_84m^usΩy/X2JU[\XM黺DB&SU 4@I1boTZ41עv%Pvr[͞Zl=$TX40KJۅqce7>`I ͧÏuJukF^۲EG!3hpQAru*2# 8pfn ܎dJ ك1$EqaFnC&\:nkف#ey!HWQhLςF"Fj~y1X=s}s?K'˴-1P/0O`&a3S;鷣{,'$BT0eB J6RL7M6ZeKHlpZnIBOf Xԙ!k7;DUtJңK},p'5xf)#p=gD(1&mpjwWyBF6|i9AЯ 6r{ҳnw?,M(\P'ꇝ8uvRn ]VY*'"`(>"kŲBgVh/td>#*(+)w4秀۹T~><4[#uj{j ;g4ʐ)v N8:2JK2jEs, ͱQJ%žr>A5GWy҂k M>ovo']3,fG6I }yKZO_QFZ<,9]CAMFiB& 4tfbJ `!!&H ^/a)E>aTo*NLZ cl5]YXp:=M矝#VtN8OkF}U8 9x6O&9= gK]ЇAc]i PW>ʋ@Wp^5=.RYyF(}NӾÏΒgݓ%цǧK{ۄ0.jc7qG Hdy]f%Uی Âu%$$˵WQf#$3A{&QyT1<8UY4nv2.P\ 6`>'8{MCsEU0< XŒ^NEa4eGhj᱊R 'Lj U:GhFgR<,U7lZ; o^~* 8 < m):l5y{GZiHױ&X.[-Ow^x$!=1xO$:j0 PSauAXyO0$ T¢ip (ڟ4z TYm.A(#@RCV~?Zq'P)G6bj1mt<rJv/Y@ hBq0I\}K'mi_}>=j8m)^~ UԾgl endstream endobj 153 0 obj 2399 endobj 155 0 obj <> stream xXɎ6Wl,%@Cn  '' ؗ~^I-m@vתW K2/T{ZjЬGˇ |B.?Sxkdnݫ,\Td׷_omf_̈́LgJ .GnLS=jfbztT8DM/ ig_9Wr*B%ƿHKU-7SLJjC-sv0 QMdy1:Zk?ƍ3ݱxgZK_ U(`O`@V;S?QSI]V4@"w8[ͭv2Ȃ 1k SA!gԹ] ZL5 ]@.8kADKPHEYسb ;> 0923:.p]&͸pz1Ax L\rt?TYZmX /JL(ÌI/A zĢv$ cq!!Q!!^!`f0:\jL\_Rh Lx1h08 @ƷNE9z"[X=g:m2\?]o[_-q [xp$:ޔx㽄J.`W4#5CeQ/ZU%r^A$2fPsS*yHSާ% G>'AR%&=jc@HX}HJϔguӾG*N&z}ChA|G^76 $x X:D(Bȵ:8KuY'v㎇oNnӎdyqm] * T3(TY,FWZ\#k%eN8Jнr2NK?r+]U![ɽVY9wK&wDYSRx:1Izol(-L6Y0o ǍU#:03HԁAOe4TZ%Es!}2֥}͵NѦ5ߠ:68"^]|W9y|5[lʕvUnG N)( r< e!v1 cU"<̣g/11Ĩ˳tf~#:OO͵4%9gf-jOQ#  ] >> stream xܿr8pfFztdn&s0[fLr65R@^W TtrTPAeec&;!;YI!Ȏ@B0$"A@=\ٞF &>7fN2#0Qvp<ǥĵexM_Koה w\,{-acBay}yZK^px̩7WחWJחܻ̽߱^Yv<ߔ7GsoEyQȲS 4%05X{`Q֎*V^'5Ys/?z.^Gz1#-Wxo䟜q {zEw11@l[{ѽWx) ץ{yC^`h5;ڋvzU9KtIͽwy, Ι#M% Hz+lrKPz>2/;܍4Ez *3E^wZV w!:?:!8a'̽@i KW=_4oz゗j@`/I"WxooFDf45^s<F"zu(ʚWbu2ɽuޞߞƳtaGn*}y"\%M(-YPoȽ!irr~;D;^ EXl\lyb(P ҋw:f0(XET^$MjˋZYYXyB%5_^_ljŗ&VSAoEy I}}"4>UW+O N',^`O4Aחa#M]eB7AHao,Kcڝ ojL%h$%3g\U}H%së~7vwiūzzB'Ǹz{=Ƶϫ-*˸xyZf#B/b-[ ꀬuifsdv~8? 6{RB+9p##gv{ \x`{+/>#>.l/>v~a6l*~ c4+@ٴ^qJ0bgxlůMuCdd{zc{^e|:Zko۵7zn7Sܝ^bJ^/y+Ӻ˺VBFƃ~L+^kJoLf7mZoqqoc"#+{bd{=l"3?7S? endstream endobj 159 0 obj 1366 endobj 157 0 obj < ] >> stream xܿr8pfFztdn&s0[fLr65R@^W TtrTzFM;kوBv,'pBЎ("'D{Cz)l{b0==ܿY?8fKMizS|?oxr@ /N{ooFXf,5^Fe{i7C^V̼KIᅰ|0e,;p/N/K /.'UoJox#.'_xC/\DbP?~ G륣b;C_^7^ $AGRJ,x!?6^^*e~f W1{i:g H:l+5v80 ,y5I/$E노IW?% R.l/L;0v~a6_86prļș9>[if㺷#96ކxz֫> stream xZK$7 BZ]h m` !$l%?d*W{&-'߻F5{E- ]]sitKC徿ڽ4N`">웍xiOm慆%(uļ|y};Өʎ{j2 pܣtM~qw{ݽ8MU/Zhq4 5GO>oG44rw>mGՍ) NWzv٩e+08ےvKD, ܻGL~F,XVu޸WHDAeL-[m;m>"gyN#=MNwnYsPoMS-ΩxWA-j;tx'2w O]ϻL@-`Uwsz`bK0zdjN+y0 7GNDKJ)\$!.z''tffh jy;RCM<1C5_z&o$L]z9iͦ[v=?p"եk6jfYT|*Tߨ .QViu 39xj%Sn)j8ɎWTRisd۶on"Vq$l v͈Ԛ;,:w{B-ʅR}vc b7]kͼ`P1p*~$ʘƚ!cgcZo9p-A]̣<csX !7BS BB,@0JfL< 8D; pٳp.hu*jڄ|+k`7#Xߴ5)lHɒ:Q뫠/kX4̑ZΆy]Eo/Rbv9;LDOO.Gq z8"2im.dsnd3mJ5/RК/u"x'~]wƟ8_0,O\qe^/Wm*;\el{*۾Nb"Ϗ$HJkl3I_PaUfci|+N3ַ&CՓ^ڸF]hƲݯ#;t)҃d)UǠY~ّM\-}o,4wI#c :â,s / m5jyU -Nه;I"Q&9lq~)#UѠA \%?Myo-W/?̽ endstream endobj 163 0 obj 1942 endobj 165 0 obj <> stream xYK6y{Uz4 m` !M&؄K~!rKw afN_՜~lA{K  TߘUiE/<~z!4ߴy4t~U` g|&u΀ow9~@PCIg-`o?ok4=-/Jp x|Duz]ec џ>\swQE .c\f2L롻GHMɼ'q`[hzi&\Ma۫K'"u`'@.9g ZyR0_L<"SXfeϴ>gY$T,"9=oi\Q, p'Oh^[4fe (۟;.h]'h&6‡fyjG(gp8ZmqDz4H!PyEK$%D`^lt \LCr_AS arG,a38}:wO[lX)MЁE ^$?<2nr&&3uAYjYlSl3/2H |TzdmP @xچm$!=T톳V)X$y;_e9nZD}ZbȊh#na/R%PoGH*6_U[\|weN:/Q)e^iKT y x~W_-hAWi >%\RӐ@j?FVT8?Dڗ[-T*zgXE4f)4b"8ɥZ׬W)^ 8Cza\"L) fb@荭@y~[3S,J㟊*$Q}@6ÊU%xHYWXY>N44R9Ph\$g% LGL/wfr |p V*qH6 Gk[k{]=:ɭ}Tɖ=ڋ˵C(nVy$U+Ĵ IS(d:XջY*(;b_-?%txX[)=t}]DJ.a|˅EXkyϫKFۙ}NxZvHveÒBI#z&N]*G7.yc߳E^Nz+YN7 *:f. Gʭr]bvo!h R@_^uXڈ@A5F#+Hx$E@4R5FJ]p2X tps"7.ä[L'HAuzH%:2NF9uNJ^xV9p_Y endstream endobj 166 0 obj 1668 endobj 168 0 obj <> stream xWM0Wfe1v mٽwF#r,'m%K6H{FނyVZU~z@ |Uԏ (|ۀx*ǻ?4ߟ94v[uV[}s> stream x |Lu_m[ZWUUZ bMbT%$P-.A-A%$!b H2l$d5s3g֜g2yMy99sγ̙U5,L05lGRSP^BdR UL}/<тKOyET*a 0! `NO *@*DJojP(5&ټaõnkd6zo@v :34z96?69ˈ U/`YuZ/@e/ye/*o6dXkp(BiHLp^żVƐ^Ō0ͩS+{MŰ52}ɴR0{_@ y I 8/A9Mfhd\̨yiZ~7(+ *OTn2 )%>'SzM{ K#a 6Ca#t xZ91zJ&JF rAأ#7q͡ f~DYs]m=Y1=Bi& æ)\Ll 7*\&xR'3Plkr!M=L5kBr͠\"ʀ/ۻ LR ~>?1,lF5X2$PEEtuTQ[g=|soܯmPȦ4AX84<¹3\>C &}S0e@W|>༱")g`=e }Du@}@{ %6b3Fl/EXUqzS|U?FUo(N^'^# VIƮYmgVty PHD<߷鶕k, /YWԧ8hrb^E?}[0\:UPR-}"B%ЁD.W_hhjm^=e6-Bm 5Ձm`R5m=dZg*B2.2]t'+LVHpkiiЖ1ix`F}h'Y @Wc}g_ɑ|zy܌Mk<ƻx3>eP6VؼՊ歎z%H;;]G)GwO"h^]>Uᝠs@~ ʡA+Lq>Fo85a0L[_Z:ntddbI.s=E)hCqg?q'$chBMhi`Dzӊz1 &/tSIوFvu'SEc@s;#a;^dIr`F¿}ԏ]ƠYF#5kgTfik]y!Bn 1fd䵨8!TA${}<ъSC^$|_y$x ZD޴=WSԘtSʘrnttpX'*Rj'DV[M-.Yт#d*pwo xVrp9FCֽqY> xt~Y饣忺DNAS\ɧSP- u+"^'ݪ)'1اhhw3C?( 3hn?oqxSzh*J MW-B?RVc!B @>-[(Q7΃[,Pc<s$gK̔!i7–ߪ.V,Ҡ>v+7(';w0C`\# \\hwvG>k }WިA"\e5΋E\~huZw{oԶgTE|sŧ]BM,S͖15J 4:w wN&b}q2q _;{Q[һ[-4fZݮQJN!tre$Vyf.-{{\) e LѰ%1+$cYL2d ɗ$/| m7WzlI֓ rUomIH]?C1Ӈ #;wQ\Z4Q G.tm?AMTH\ZۨEޠ\rh3'Ul-BEmV=k7n hʲ5;. ]:;;6IF73O'Wrq 4hI'TNl .SY,_V f94SVkGU(B`t2/$VE%CUuCr2 cO_i}éG4`xR 1z Y.T%XY@ Kߝ+}_ QKo?'Ӡi)V `ʀ™#1хnJ1F+t}`;wiퟨk ވ@UZ t_>9tI=OM>k/6Y+U O|00$444""b߾}hqZ5f F|JQ Sެi߄UiL6^b=]3K P Fe^6 V#]4'GŸSl^v1@rS(J툲N)Lm e"(MhюP<4v9m85'W$L_ P*@rtEЍBF, [&TRɗK%=JB]BajT^.!F/&+gG*޲`p_9*_'O 4m\zW{X39V1Y>`薛k#6߷o5]v-[ãP~n2XMy*jr JA5N^ۛסXzrq/u:7 WV\^m+ {`Slkh7%ܬE۲S֧w< *)dMʞoI%ҎUmV_@ҏnt24X:$X2p2I4E!z!"0,<&o|ς|e^7PO8OJ>V6󏸏^AS5taB4ZK]˯%{\TqJ={6o޺◐ >CԢ@n2LMG]R(LTEMsVygLv>Q I.*rVY E:)ãSjERΈ U|;ǬXG3$>wЎJ cW&Yp~U~'=WBuz?꽅UoT6SDM _, BR/WEG-þw Q6~S]{M^ѹ>KODyMwz6×P!!z])l2"v 4 g|jWzڀvw6kv75[ߴݷ-n[]L|VlG4MP@s'f)-ӁϹ3lTN7~`FI=K *Jj/Ew&nϩ+~/܄Y 4Z.ukMd4yxlX-=elxxPn7Q_'ퟃn(=j_q +[~#,+`h4k nZ3 3Y:jn9ķ`ѳzk9[T{TT54""ˉ;h|>ٳYYY7ntl]ѠEFFrݻiӦp$p( yflAMͣuDD'iyR{@ #""ܴ8jKvi 47!""%hp6^ZDDnIQW{gr) i_,UbvMțƯhtd0;yH]N̪ѕڼn[pqW7p3)@;{,ܻw)jΚD+ vPӼX5|"&EhsӦMfEfKBZ2dY˘>[2ud/' ."\JpYK, m ݠJܤfR.4$jnp{_@@B"GV```PPŋg͜.11 dee1)A3s5u|AG߄}9s[.ȑqZ~œB! *jи L[)~A۷oAڹs]wӂ0As#41 SO?A'bp`;#k8x VLL ^\;^[h)~D|˖eЖeА=@ H,СC>r+[ڛc!U.T)A2l߾}p9.ѣG;pĉ;[=ՇjYlvzZpp0ˠmP519N#ˠHڲ'㉉@ٹs.Mߓ C@3Nח֭c3[W "SN%''_xKLXahI … ߸cǎa@۵૯첇rviԜ]tudA(:I'+OO+ #4n)hBF]]֢hЌ}O66ky\HTx([Aͦ^X4&e).@c?yNGQ .Y#'C  %Yv$4=:HuTb݈553[XaA*z/֠JCSϷAAAСCƧ?ɓ)))W^9-8 C@3Ndu_x1}Ç= .effg37ůƧv9u!2-cw7YVOV%-Q?|~z 4gKǏO rpbh@˗o߾-JoG8y8O/E.عsgLL 4gN:M`\=Fh0ey)C^7y}.bP,^y`o9"G4d)))0. ?UTWE^dvКu hPW X M-kֻ mj˝ț!*$МM큥A^O7),pUnؼQWdɁ@жqЖe!lXHdQ@۽{wIacC2D=Xѓg={ E54?(~0w#lR^375<--;hZ@Szoh@& )KВ$B,QFTW ,7 3Ȱ; W-pJYIn4&SRq)\u)]1?|ASl)39cJ:⾣AcEF@4P8?ץ¶qɛ0.eQ1.7r25G h~<s(UϹ(=dMʪ-wD>XciHqkd-)(xJV4)ud`!N GqϞ=O/\yИauu עiv2 m Q㖣{} pѦ.z޽{Z?>4gU[[yU[mN.8Le] rS1[Zc4X{/RXie@Y} =?I'lr,蟤՝O/nghrlW߲$v5Pha4gÁF!aTQ)zȩ';b#m[l}oWeg*߭TQ2'ez_SwNOO IKKMؠ;W9NɈܩF&YA4bD@#&YA598Vq"ddDQF\M4""+FDdЈ D@3Nd֑HFf-/B̔4n7'иp0ƶ&7Ьۚİ&6ŽMb[ú8Df6=m@alkSbXۼ6/u_7lڔ֖S2]TCA@s\'1-Mٔߦ |q %]n͹ ~@cX[B+&WTV>ɹpFsA@)f aM@#闝fǰV~Ш:*҃[ɧwDm5ZA3J$= ԙ4eZn:ra f0tuw诌ņZ+hFcK%55RP N(ZSbJKGb"\[cXkQAzOr VЌ(,Kl5SwqDplAqmM{kW7 ^i d\@u$#.VTq V]Gɗ5S;Qm͡A3,W}?vPz1f٠??~'CZGfa0b[A4ణ"EA݉O̫μkmwudmFA3 5=*6İ(h) o+e~A3d2@7H2HfJh]h MBY3>X4-Wc}GӔuu vx:>8=N@3$䙲^xL=]Up{|4u08#94!!U-?0@YPzab=NTAòr3d\|4""ߚ٭xy̤ E@#"hDDVh,U""' "'2H$31.eD2S\и gߜ@lC:͢=8ZtG4 f\|4fLtG">Ash&GoQ7}>AshG#9 ]ϭOϮ%=YNKzIB|,UzH(AshFG#9%/|PٵuNUV)hͺeG 7$>AmP_wa=KˮKU DA3'3#hʰM& F@sPAe/[שhE3hfh3DFA3 8m}bиGSgIc.eZEif:YeAZɌ:pbF-^O by@{|4x!! Bh((/)e9sh@5}&3 8Db>xT4 ?M4g!| nh)q&LJJHu@Y~HR['&&IZDDd68$"ddܢ2IZdNIIiS"DD 4fҁ$""hpQ{K?h IH06oެ.Mۓ&@޽{7mD:DDat8!M4O9 h;m2sS:GyȘgﲉnJ|>=h hDDDFFDd1Qko`ܚ}WijH911>>#a4ϏXh\{mP Z{NbΌQb xM3vYz|bw#ڊ^- r endstream endobj 172 0 obj 11982 endobj 170 0 obj <> stream x \=fq>V퐗#di*K\UDADP%RM-GOyR3vL"**eY@egvgn;;{vW3gsټ<-#<:xeHsX""D|:*%Bt,Gى*l];nj#)RzvB½ 6Ю 3L& |>5Wqq}W>AYk]64|8|3?Fo5(&%؈^DWpJ[{jA:, Cir݂ʎK &Ϫ:$MXmP#.S1@./ 9D״nlQF b:9ClHXr !AlB@aw~K5%:rZրQJH`4 d#IY`ow.19 ,beDYt@ J*+y P>$"!$rkA]c RAZuf00kN>0*vQ |^{ KN?3"JlWmP}Jy&œ㖑 Ezs48Z|?M G@W.|jqB|㲇?lzퟕm4)(HyBxɊВ!%HdJ- 7jW!D:hJ 'F j&_Y\zvf/f6f~$Qk(8rh9ecypWE_24ss/#'4}PQV*SQ! L`}}}]]|j[l5D ڸzmsPWO(Քg99P_@VaIDžZ3%Kwm|Ueǖ4dylD(x4S5uFϛ2$ӫ޷ 'APP2/g{k3gΤ>|Ӱ+^Z6/P+S'Bݬf3Uǔ{9v 9|rX t]tG~;6/p[&O-Ëp 3a_hv9VxhiIR`LZ}+$f_H/\h?Gy+aA@} ߠujPGY C*W084O1`eL̉IPup,).#ӔzJ *S2~XI>ec^9eر o^.0o6~t,&'zJxZ7^rV8|><:-ޯʺ 4* -,+d"]俛ږ}A[f%M`t4@JPiJRiDSћ;/&3D $dCk-N@aD;xVpr1 H0r0*}w곒'.'/%,&,"_[@6z5;O7)T'k u]Hx"gA=/ E>VZ{ Vj{}oL{`hWTR AYA$F g`HO!}sNy+jW@?lAXU< -W{CpӇq#ѓqJ!4hoE^{B/~6J3$cHVĘvE⩦=QQ&93*ğwqᤐ5,QU%:A&^s{!0YfuhcjgR=GYJXL[D9M9EW9w~W T5:iP%Ce JO-a~Oti@?RR^>N:x3r2[Biʫj6Sl*Ҿu+^J?~h{kfVa bzـ@Mgިy)xpSthԺF2s_p_5õtv[ITw8\UОFOP וN'}:Θ 睰G;sJXɁz[u#2p 5SU߽WS>%P#!˩˨~KTN _t!椑~` uB yeSJ-/^Sʂ}{w/7_DNF!P{g@I"Pr*W>;׸=ޟ鏛6j{g]슄rrr(zf:IHl9CMŔ>b%<$9^Oџbc3thIu ̗- eAී2RmdcB*(دF:y}.鑓\)K/\DrDfT-=#Z~bɁzYE]k(?`cդUUJj`_i[KKs<Р8]#NਮG E1~>#ܘ$Щķ̻K.7u>?ɘ|\_!PaZ k-L~x۰|uswgڸ{ވOLJJڴiݻѨ?aDrμʕx):$'<;NUsJ&9VO3/eA %vqXTjrIR5$\ޜou&JŁz@ hv&P?*}k$^D9Cg5]E60AooqKT:S>?q]p1幚XE[E\EJ;N9ϳoat> }5FE, ׌]K:ytbDTZUWQOߕh7nݻظay oׯ_cTFAsh2+$ªOP*4DCccer?֠G'B F[Itq*NA9P5R1rR,[np.B0p ^yI ` *=gV|CRԏT}=DBճʿJdO+CN&TMZIM\E]MXErNਮ %6OY0qҹg/(;V6gDI[!5N~x³7GO!'$*z{S? J.憬.D~9~غuۚOl |=TF#9D׀zP⟚OG79-qxQM= D!yy$^{ȉ98Sͩ&H-`k<ct*M=:&r͏9H-D#,y X*z?:"̠ UIՠ(X8qP'ī{ĩ_^~nSdFA5׉tH4T%oPap`<{B#G-& V*_*᪔]IIwg|^~?ͼC\OTԿ(oo/WWN7ݵɽ ī 2M6 42=cq1-zPO"j:Q-$iEsNtizA~3)p )R-T9Difs3L+K`O11O NP꯾|eX+OpJ/ݽOGkN{ޘƸc:p{.gnk' jBPW*3>BFW⺸VSm\sEeܮt{a'i'4D'O<3>=w}aĈS|<;'ɀ";oN]?8COtnk{G*uy<'Z,1j?V_52xO~!Pijj?Hi-u,G0ܢ0LIy])4}TPuمyQ5H_(@v,l-6d"2CtI' `#HI)Of#!dBT:0!D$~=\FhZ+nB] GKyv E/;8Ą[Hr؟a>KQPǧ#PiVy\ED@ څe9؉ZPQ!;GW<t\ek"F&~&:mbٲ0Xv! *] * ="=ƅAŲ aPB? ð5P{ [wMV1o DdRi2orW'-͈6 ;U>ZVU(CiNބ!Po#PC2 ZE3M(L*rT|Ћ)|9ec@΍mȎ@0bc`kSb5ʢ:CX=:1H*7ccŒtڀT, *]e bمxPƠbٰQD]T,.dGy ?7u-lh⠺%zbPِ=1D}Y^۵aP1vaAs!` PVV84MAm3*?n@ .nmD~*$A_s1f֨l,j+ӹ0 3jGW@eI̠46!NfS(\5f] kS3ĚtA ?oP5k̩46u][ں {b@dqP'TlOcPلaPم=bSXmYT,.AŲ aPBv4Dz\V?TBŲ\Y4ո~;Y8f0.tw{x}㝎mVUM%IEUCF~e\50. Xj_7M }ͽq̉;5U>fZ$=Hkj~qP/&,/i $K[VUgybaP JyS% ciʚ9%NTH P/&2xҀ`jBa+ʠe )so;egx 14]iTqP5Xrơۺֺe߂7m s@Q86-0L4!4:Z՜,oZYΝL5?4i[T,TEݡSN) 4#+,^L(mm(mlUPωek4{2zd@'iF X>&'r@rp(mlMPuY\l0ezrZ݇z[ʵ֧рJSƞNY =W=_VC ?7GR?掛[T,ִkå iQ碧kFaPmMTQaPmMTQY}IsLEy@z„AŲ aPBT,.DKP>j5;~‡5 . .LT7LaPۈaPمL$b"t "/ k lf:sH5ED:R4MfB,oL ĺ4VZaTL7y[P4&(*ݎ=NTjw>< 1wߛ*HBߓ[OoMӯ:!P=3~aӮU cLm,-ӡՙ)6h.[ETnS؞PTd(6bVWG3jVQ-]]*VrT, *]e bم,Ts_J²TEZMak 3*.Z^fNgA'T^Q\^"AGT/+s=[P_pz>"q;nէԂgם˪;gͱUTlV2KҜºkOы9uoԝBJOe PmĠbAԥWnbFӲZg*g[o>@C鵼^9F6Zj)CVJ5e*\}y*`K7-۾ߩS'G_;pCi]/SZĚQ`PWѯg3ѯQk v>b?Aֲc֢I9KGCw OSr^шAf%S>GeEűU`NŇ(UH5=FQel[^; endstream endobj 173 0 obj 8628 endobj 175 0 obj <> stream xXK#7W`V46$C!M6؄K~WƻK֣_*ٞ{x3-} ~~}ïFYӣd+h~z)@^Fwxlv/=x`ǐ\d#fp4qx=b^pzds]gt{$O_cXaD:gOhDY:*dO {'[ wn 2(V 0$ Bwψm+0R9T19\Ɇg@fḳ4%a2WƳYBNHE@2ŖX9-߃N; `wa;{-N{!^($κ'a8 *K\ =\nquVI.{Ɨ|S s1"-Ε (EFsyp7DSd掙&P4ygMy5BL5 +McdKuK3l1W}6)F:tg5ZK$ xmYIU Bvd&3PiO]OCliV,̤|;t,[u҆,5$bfiEU*Us($ [x:k3DkP/DsDF1虳4SCWR B$$@ȤKY_eY*x 7OsV*YSc(P$z7wkd9bIIħ!/\kz$=MxyGk\jU,_*8YnOga|S؄G4@me)SXeBLLLeiȿrBrqt}+!ęW)uv v)W,i jCSul&INSUIP7.3 WN5>E#*0 P3sf{r*l$XpYA+|l9~= [BiF1+Yxmsǟٕ"]ݚf{&7~]RDhoHHvm1+V 0{g S,pS;~51j endstream endobj 176 0 obj 1287 endobj 180 0 obj <> stream x=jQ *VBX!S$!Iiged\8y?iaRZ}5д8zVfU7j{Z [*-wOcWbŊXb*%VXJ+VRbŊXb*%VXJ+VRbŊXb*%VXJ+VRbŊXb*%VXJ+VRbŊXb*%VXJ+VRbŊXU1Vʓ:ZKֱ*G - endstream endobj 181 0 obj 271 endobj 182 0 obj <> stream x F[;5 endstream endobj 183 0 obj 34 endobj 179 0 obj <> stream x!Kqqcv ė$,/ajmXYҴ"@0#o~pE-knՖ̬Í/zQQ65*VկU\-6>槛>>hlДӡfA#M''mNގŖmbl&Ɩmbl&Ɩmbl&Ɩmbl&Ɩmbl&Ɩmbl&Ɩmbl&Ɩmbl&Ɩmbl&Ɩmbl&Ɩmbl&Ɩmbl&Ɩmbl&Ɩmbl&Ɩmbl&Ɩmbl&Ɩmbl&Ɩmbl&Ɩmbl&Ɩmbl&Ɩmbl&Ɩmb-ٖgՆmyPU ږT#lCl>{3:_QTXQ]?ߎm{Bzs endstream endobj 184 0 obj 394 endobj 185 0 obj <> stream xN@av^+vޜ&p-(FưG4ZJS# =X;'i?0C2?Iny!!\?B4V>(IaW:e<˲QŸ^̞(c\(/lumΦO(vp(JR?ntAux0}Po t>+2w-^#o= n }%;ku'[dRly\T0ny$HMEH^TLkqyw;49b&+&Izet']&Izet']&Izet']&Izet']&Izet']&$q&{M`R)k2O.ms _*6}2WțkR9wIyx Qƣn5 .n: ?Fi~a'IA Nf0 ET㮣XvL4m:ߠ\Ƽ_1Mb&ۙޝN 8(-U endstream endobj 186 0 obj 582 endobj 178 0 obj <> stream xMOPqw ~Aq!&Ȃ;E԰DI&in:yi=517M_U#y"NU Wxfv_l6t:!g-zoooUryqqQ 9k4m2PxXXQyA"g\iojݽX9[e~nooa^CYׇԭm0 Gn|Y+WWWyu1T:;;. soxin{oyQayN6[0kt:{*F%PY.//(A fk6Et^"(|jUt0: & 0:MaȚֳDatF)YSzV(4}"k [jQOdMaYm0: )l=MFGat>5g(NS'6Qi D& 0:MaȚֳDatF)YSzV(4}"k [jQOdMaYm0: )l=MFGat>5g(NS'6Qi D& 0:MaȚֳDatF)YSzV(4}"#) ~z\R TX_b^^^(A fdC~M8JТke2_*Eli\C֯ЧWݥN>a[Rgng KrqHgNnl61^NNNzknnnr6>$Rg۞kxl=DEsl4o 9kbZYT֖./op, y\%ہ> stream x]oVƓ}%cU%knO1)MVjzm}4ij/J16lpelM߰!;x\?oO󜗛眝CyO0+ȱ͡뺆Rn\\TEJR$+a؀bZBT3\[Ru.@}xsۚP`0JÀZdt#'zPdS2ZIa!E&ܔJ=J@N.S*5_gTD}&55hRc_I}&55hRc_I}&55hRc_I}&55hRc_I} H ./oyg4/2D=OVwo^S!B7ٺ+\e2:)( -A6 mX]Nd7AFr]2h幆}\ sgp@v6 Eve$M6`q!ȧn *8\qT%H>,՛m$}G_1gnG"Ss{-Kn $/UZ)/RGue-MH-z%v9O/SY 0þ zN"9"X3T;My,Fיl/uի%<&CesQr pB5hJJfZ!3]?M۵lqo۝7~> ^؆Wz2)PW)}2ggA9D{ á W1gX8RD:|u7U8Ee endstream endobj 189 0 obj 1238 endobj 177 0 obj <> stream JFIFC     C   '" /`{;b/%y'Ȼ,bji쿛JetRrSϭ ;G\tL7lҗKOk^4|vyrZ-2ƈr婵ׯBR9Xt6p¤h6ƃ6%qiW^glw3?R$ >=Tn>y,xE5`.{Wu(*Ы BX/}'>A YhUV VR5qw*:"B1$#u~{م7[,bHF$bHGd@}[ysWtm >ݪ,eD>{W.4s-5Xd"mpb&%LusWπ5F㊾>Yq[y1zϥc^ y;L؆fi&lIfךSޣM }K8qTѸ؞8O6JgLjz#WMj½jNld5qw㐡vr@ $;@ $;@ $2 >koPj{Vx۷ԋEƏjKJϏB,é"D+, +, o*=,aG㑹]DJL֨J"ޠN '."p8'"p8'pX.K-\V$/9K A A A A A HxmM^xK,DrZޚ֩>!egãaC<40 3C <40 3c FZ ^=ts}OƸ+Z> f_ 9WZ;>wwOx} |H7x}8Ŏy=[p˙.3[8>>r9>rO  Kx0p 7 x0p 7 x0p 7eh{-.350$ #%4!"@CwQhKa7AAAAAAAAAAAAAAAAAAAAIIIHԍkfR)[rV"[Б]~bKMWfKwT;6ZٚѸ=K&t tdf1|r~ mb([;dfDgbu~w.ئv]v,:)_{U{"4z $[JۣLuzn4dEhbZ#Zaڌ^YZ]6^SKۣnܡ\*fknYUSU>Z.Mh6h6ͳl#q4]* 7K,%;}7VS6isx'78Ǎ W/OJhl91N`-Ͱ[[g$Z1W,̄bd+;};-+VnV˓ӓ$:pϬ/?Z!zzWGf*aX0V +hG9pUrO#yG$9'k41~^?еz>B֭ͅR!-HP&5E>m{ۋ\y i2Cp+`26j4(@@@@!b7FJuA t}~OVkR>\\pysϗ9nD,7(E IGL3l|KZP>}Uj}=nQ>RDJ1111 8mV ۣ)JS`M6 l ۪TAϷGmV ۣ Fpg(ġ(snQ>UL @@ʈmV ۣ6UsTmDtn:x#6UsuU9D;DND;DN-XdQSUZn(rL@ @ @ @™J UZdȐdt}f'xf'xf'xf'xf'xf'ixf'ixf'ixf'ixf'ixf'ixf'ixf'ixf'ixf'ixf'ixf'xfk5= !5QSq1ARa "Bb2@C?-$yĕBRzͲyL̺΢&6/ <.9M'f .Zj/m\xP͏ۛ~=F)!I HRB'ЃSuwWQPD̿az,U"7'Ȧj$RQ3?RFm-C")2VT ~oXE~#WD~,M7ݍL{O UCywkpacA7\Cn,qY-5h4PBM1eFTZG'="jjNjYp/FF~IFf/^/azE="ISR>豳|-psF*1QTbFōosm-H3'qvvvvA F0DA[96ނzgA,/ HRpKIvӤV":ه6ob* BPT* 71lz &@eӔeC8pc71lA16Pdf)E"HR!0|-p+71lAAˣ")'!r躇Pt]C}u.DHQ ̄AQ6ob &+%hŠ_|ZhŠ_|Z9˲jDl!U0<,l šaǚ K浉5O(ŹbxF-k1nkX.QZr\'bֱ<\&5O(ɭbxF.Mk1rkX.QZr\'bֱ<\浉ꔖD?V1M13!2"AQq4BDar0b#Rt @Pe$5CEds?~)gMYZ& `eizH EVL\+". ȋdE²"YpVD\+". ɋd²bY1pVL\+&. ɋd²bY1pS#u Į|ծa)B8Z$mR5ғ-vI8M(˸W~kO9?B6{Psj6թYJRIU*[[( X8]vm> E(P\iՂ{k%K'NѨR-D8BۂMrQ:#tMakÜM5cбtk(z8ii|5X`|c K65 E6'Dbש[K ),a8{BL"h{2VFx=|OOR̃y[v~#Gm-7|ςۃy[po> n m-8ۃ-8ۃ-8ۃ-8ۃ-8ۃ,>,ς̳> 2ϼ* w^>Oql/HBM5cG Ql/XB_EIKuR>M?Є+$i((lw޶;z[clw޶;z[clw޶;z[[UBoWI.7FjX\\Xvk=)+f{Vd3UxKEW\Ii{7GgBSoRYB5:]i/涢26jN>j!b!b!b!k{UeRf_](dGк0a؜㉎vZU=Gޓl֛5ԛ+!.:,B,B,B*cwWbXV+bXV+bXV<>|Qֶl;rvaۗW#`gWJgmc &%ɉdIJbY1,LK&%ɉdIJbY1,LK&%ɉdƼ݈It}#UX]GG#Գ,iuҩc1p⃝#ZtnSjb^{u8T)͢|MKė1 tvi"H#tRn|J;cl1&2+]O'=,vw pBO@dž5ǥ{Tv .G]dfqKE:O6kDV]vOQAX]GG$r*ݾڧn^eڴwP+Cfm"En+Vun 7X t4bߐE3w% ]1}hue>@N!z3FGf7 ktI``u_=KdhkkҼ!&1ãSv_`f$u&ͺgO 8t2Py@Nm0Sԧ`{[ÒD}rs[+el`E: 9i[A+O~_W>+O~_W>+O~_W>+O~_!#ڶ,rX]GG`UzK^%/IzK^%/IzK^V>|QV+bXV+bXV+ǖ>9uV+Y5iyܳܳܳܳܳܳܳܳܳܳܳܳܳܳܳܳܳܳܳܳܳܳ߹y*k($M>tQvUE ݮ)OUy ۥ],pljܜ4VW:]@tmY՟mY՟#aX7PmtOcu3Gۍ>Ҥc.kMz:kE!nԒLZ@Zd.6R{YGⲏ;ew|]9zV>|Q'ܟT\C- e[+kQ_K0q{eD7]@?g#5ꮪGV{998)m 5Upp@SgJeʸqwQP cM;[!l9%$RŦlM.S6- Dl4lS)S΅5^ҽp .q /{e#o4&Ydڈo~#ݣ.h4sL)K }#S{ $qE:D:ֺ'y(9MW7(j)>u+Dki2u+Du::'v]Me-RU#ZQyO~'^j?/5+Mw^MM^}+k(Rz~5kY޳_fz~5kY޳_fz~5kYުqTV>|QZY}/eވ"rhm~KYyw/9n-ܼ廗r^r[yw/9n-ܼ廗r^r[yw/9n-ܼ廗rnW%UV>|PHt3C(-$4>haBow&Rdt55U_6ytϥipEuK*;? %#O+"G6M˷K+Q}!OΨiK&YJM=9>{r.j >\h)ҳ f}(,CI+<5|m{.xm,`v}}M[us iM|h{MP0Ǟ[@|6g鴚'KdzVIJ`19ִt7V )a0he@dsG7VׯRnGڜIR >[l\NM$F[-[-[-[-[-[-[-[-[-[-[-[-[-[-[-[-[-[-[-[-[-[-[-W7lV[+elV[+elVZ%}}UCCCCCCCCCCCCCCCCCCCCCCCs]y,}# grY3fw,ɩj)^kжxRGۋ-ςۋ-ςۋ-ςۋ-ςۋ-ςۋ-ςۋ-ςۋ-ςۋ*O|,?HҠWu,JM'ܧ|zk nEЋDH[$^pVװ&uν#+Z]Z֣G e%ěƺBSfkbΥ\Cq#BFFjuuөZ~"ﻓʓwI!ͽyXAtvz/ q8kGZdC/?H㓛sc=JoEKFp8twLsк=m3֒b9cw -.RțpRu.e"o?RuGBlHu6'H']jzQѥE jiԠv(:C%#wIˡė\V\"m6EITQ Kl w{ENCF,Մ9sF>z >90X, +E;qkY'r;IܲNw,d$Y'r;IܲNw,d$Y'r;IܲN*ۑ}# cwhsZvVkxoY 5f,[kxoY 5f,[kxoY 5f,[kxoY 5f,[kxoY PQ)!1aAQq 0@?! :r3:,3#83#83 8,ೂ 8,ೂ 8s7'@ A{c-Tv БRmhAآuւSZ ' 1YQXJ G`7}c2Q} jCR!%aD+l#T0 :b%?1қADk^)MU ~QU)V,*~nЂ`҆av, Q䭈r wGZtP9$B(d% &l.Q3_ ۻ@EZEH J0e6_0,@ь DZ Hтt;]T!`3][#q )bQ`d*ujWyPN1 7 " "dC%u 8pk T XYq;R2h(NwN;whD+U^ !.Y)S D#dNKF31BFUdB3MD>|ϟzׯ^z4h@ ''&6Dhj =d), R2'FWڤ5ԕDI$I$Iv>t F`k o7e,3I"'բ.ŠĄ5a[RjU@$^%,#ҰzE^XHZ֛Glpܙ3rfɛ -C@,KFנB]@@!Sb@, R/#rH*ڔK{"ϐ7&nLܙ3rcU=~lbLI1&$ĘbLI1&$ĘbLI0%ɲSd͓'d"CCE%%q¿&LBr'!9 NBr'!9 NBrS ~|}t`,kEȐ3+ \Jh ԗpCPYC]C`hB :nip  Ԉ ߩf[p!;"p!nTTuءc/yhʟQ,rĊ$!+E^$m Go7ғAl k(BkA0ԀDuu"U(,L`U@{3PqmiI 7+)>M&˜S ' EjGMdh9惚h9惚h9惚h9惚h9y$HZbeC푉ӛNm9ӛNm9ӛNm9ӛNm9ӛNm9\{V#p~w땨SF Ӻ8㓎N98㓎N98㓎N98㓎N98㓎N98*z1_/E%*[ʧHWQ'_&r|ܪln7 3e1  ?j: Fz(ڑƈ е\J #=\(mHTBfzt@b *~!N 8 |2L43L43L43L43L43L4~8(<4 `&MQ89H:wDs9s9s!B[@ޢR21A! FP*Q t5#)j`;:3n S2CRBF$5GF,E5j  +wr'@:aL==KkI !!tKd2 H8 @BЯ zLu* x{*O WAJd }Q T`X&ZFR6-aoL/h\(8N2q#qޮa%ʜt8N:qӎt8N:qӎt8BA@   4i14ƘcLi14ƘcLi14ƘE>| o x&M7o x&M7o x&B?|@ M7s{71#>=CIDGbCA P; (!FOORw) S^юU}Yp׈q= afJ/2IW*,(U#I :@vI)*SWV 4OTPX,x+Q`H3] t&Dk/Oly&zH,#*>$o] TuC Cu@wQ.QYh>^Wf }2n)IJq iH4 Ϸӊh ]Ro͂R[ACFa_D./ aL)0 ~A(hyp>p>p>p>pEUC"/uɱMlSbئ6)MlSbئ6)MlSbޥ fװ~&7_Mnu~&7_Mnu~&7_Mnu~&7_Mnu~&b;b P"IX<S0M&kl O<L[nN1[M4M4M6?WiUν}E;ΌP߾)L0B  ,r)!1AQaq 0@?401ƊB; “AX5g;}ӯ+@ s%O/yӾ}NΝ;D݈m&/w~0!|2,}2 ]d )$˾:![0&GXTΚz5=~5O_zMSjST˾6lKV!,aФ arDY. 05XQc>' %+''''''%TiESc.%t˾a$ $5&SRj~1[Fcz.pզ]ٗ$!CH$(0gqog|,ӨB^i[Dwߨ1HF6Qle(F6PMhī/<Fr!ABVj)ƍ4hѣB]״*x$ @Ԣoh(.8tPVqcZR2J[NgHyH5Av;glI'HI>iEuQ]y 0BN*U!/N\zM'40qʨ8sDrV@g(^ Wy< ©CN:¬J$:P8#zHA(]s(TiKU@DiN#0|Xdscx5a/0@$µq\Iu P3^I@Im-5t E`Kc*Y)JhN&BcTLۅV@U3uVNNNpԗ/_/yhA]*J:]ttޒESGW'Kx@++ ̣)vh5 pWij-źb~Bр(xBt칟32Qտ KC۷nݻv|(,nM*V*V:4TZw*ڹ+ 5*<8!깗ztW.ٿ6ĵF'"nO=<[inO=<[inO=<[inO=<[inO=<[inO=<( ̵gy3vÁF,}?  VVj#$ qQTE}"#J3 14e1Bvc_Q3(i 3E5-!0 ?+!]f±Zp x x~Qԅ|\{M7{J*VMDFtl 9B2𠡊:b +i3Tt!pp a]h^0PQAaaBUAND n"1s x@@&oI&,se5Sd-D0&7 Mnp&7 Mnp&7 M ( xQ.5 )#/~ԿDt4x(mjǰV`uf5ƔWaShͣ63hͣ63hͣ63hͣ63hͣ6V5ExDxsWìd?p"G"*9U]5ɕ*h kV 2SzL\.CzPNFxΤOwo9P1ps^\5Ȃj%ڂ4̭ g Bk4ݡ kE,Ћ1 QǴr.b*S'N/@q2C"-BJlOi'={˫|Q`R\[Ig8a8p I(-'îPTE`H1F)X-QAOCeƳrdĵD|ZۊDC?;O=bs)'O^#Y] pBV줻4 Ww$H"D$H"D8D4281"; R<(ɇHzBPA O&'|O<x>'|O<xcW% d?;pli,/TV"m]8rNGѷ(rWko5XaHu< XX _eaXQ ]hi;*, dN1^L1 QNƼ HI .(yQ J5?|8elFN?tWxQ2vhj CWDgC."Q8J/Z$"fBYrT'~4`=7 DH$S*K4U<s8(LQ r;O+/+/+/+#`p1E8M,LězW!V@7z)(ů Pqiv?{G_Xo,/^k׫ҭv# _`N37AȘ&Twy;1fgLpP&7qq5?l5(Uva3]톤kȗ!GrFxã2d̬9f;wrV>WHHDS'8*ѕE ٸ&n &n &n &n &n " 2P]Շ<(ѩj'G:9ΎtsG:9ΎtsG:9Ύts=z*bN:::NMj4萕hK٢ׁ ?ooooo,xHBji~Xhwak`SL<\Z+l%TfAELJ]M%a K#A)A d$ ۞t7Fv%o7DE|ЂKH dX!Bx"5Ӳp^cw*u)a8ĜVqO=yMƀp1Shah\Y]brZ.STrmXvVȦ3+J2㒚k1*C "QkoeJb]1V.1'Xݥ5|D*X&1s+d'D'L9uL="-q![s777777L(0e^!Uh,!'k=پ}f7oY}f7oY}fUO=pt:aa9 Koi}oi}oi}oi}oi}$2վa֩%|'ym[(CM(VG+,")i.*5lKl5-Wudou$t@&7=?#o?{D҇",r 2 74PJL2gb5A-Ja,+€6!Scw!Q`XBlU5!y 7VS0=4D\(n% o1J o`S|5m*ԢRF(kbv?{D&%NqEyMB`Uo9CS"`2,=^@ 49# HK.لIB1o`"9RV? jHN,{LkyTr3ŋv7]Sbpg[k{ @p0bڒgTk3*Z/]IjƱhwvNDez |O<x>'|O<x>'|O6!#6f0sFH'[-y:y:y:y:y:y:y:y:y:y:y:7Sx葮Mc[\r˗.\r˗.\r˗.\r˗.\Q+ptה endstream endobj 191 0 obj <> stream x[K8ׯsCeYĐΪ[C=n/, =#d=TeKr(/r&`[3 K\cy>Aa\bI,> Kބ!vxyCV3Lsm0,(X4lM| BmsO(Y*"IzC3ҳ.tq%1Gc'W2`JR&C\9M(-G⸜2+ 2ML |; j8zAKuev$I2ZwBݓ{}ѽ:fbuyR']~ˋ`Hےao$ h4$vIQ2m"DS">=3v0mš90`=%>@N!JcDE}!V_!EG΃~.guB Ϙ ![ gNMm)1pMXrFj׭,@uCCgy[No#-QAd&KsBL2cFL 2"nQ'PءE|Lbz<fޖ0qjd2<W-rHLoRqjzaڴVGhKuڊ>2 Y;qu5WA &ay!̃iVeRE1ź+>S6f)9-Kd j>4ܨ g͆ڐ KERJL IםQVRx'uimtcF*iI@rb\P7R[Lvw{BZr Vi ߒ!UCWud]R(J?'䖮?I}[;'\[h!uTDz8NZ6>\5gK 1BZȞr]V#*ƿ*B. bA7ΕX75QLFua{ haAv㥯0^vEA ݬ9W =4l +ROQNlDS'#x6V䢤D6UZOI8Кڹ޷W듃^M:.bgOl~#-ud^V B}G"ec6{*q8)L~bl}'|L ?3jG֏{C"VzhƁqdǕ2p(gX.cv^avNR!m*#;/s̖8vOǥwg8,Ul_= :{l0QcvUx)7kp=K8&Eu@3CC",POEv˒ŻuKȏTCS SGoI|a }Ҙto$!z!pk٧\G ce&Ykr穩E BgxE'Uxeɯe"~C ZkX@IOQs'Z~j@{x2>xiԝ!v&X.ٵ눀7&Uu3X{C97a#&i@>w`l'b+?>`w僂0"fUx(ZN{z|ww$r8Կׅ޴6$"zy!JBYA]BJqgizwq썦 US]-zeI2܋o l |I@^<8392 dFlgoq[$&kE"$`L:pA@OVwȇN2>nEH@#h(؅nॏ~w5|@wK%N =-B?jy 4NsD {heB07+t@FSvr_h1E˵'#q )%IPoʰcE 4 Ԓ%"Pjk jj k8N-6)]Ћ&4H.Y\_t.FXRo8* E<~Fz_Ԅ-rF*^;!$}R[9 \Iaz?qp\m endstream endobj 192 0 obj 2727 endobj 194 0 obj <> stream xY˪F+cdwBCVIn 0 3~NÖ%oB hWVU>Q6msfMu,~~CbqGM'o^_7nןgӰ4oߙ-5>펷v5H'}>ȴsdd?~:^V/> |%Yb>>~GYŅn/G^tedkm(*SAoўzG{ru;[61>Q3dHCH+EZc1QiXwxS蔂-˭)m' qBd,=l^5WkP"% Rt4$UY_o_EnH?"Ȍܦq2U AztR=>2!ҫ;)܊$$CH t 65.gUx<ǖ ~JR%5#^fWM;xΥ4ߕѝJϥbHv% O)=5|r9=䡁l~ 1eAJC8T ^.!2ڴ 7,$2;[]XfV+\;citGn1Hl.;fФMK],BEH݆V I[DTucJ=:Z~U@5Y3@uz_à@ ,h!L>E[=O1@x{ T뤂/@\˟d3՘ѥtrRc#;gC>H/lfV%f r9IжG/03|kHQwѝL(P%wz#a=4Fq/zq@TKa҆)ӅŽgMSrY2,>؞5YqTs۽خVI9hɫU&+[ey|]9QbZev k2.S+/P.I POd~(B 溺wRݗVtc^2Yn:wn'%l8DfdeR¦ϦsywsboȌ϶z~f;k 'M IK+LGS3*p93E*%.%CE g|hpU&: k_GԲe{F;ժQJ_@WZ/g8!j/R5-iiΔ[]j=\d@"kb%Y N" QX* XX2̌ K0V%-,}UYWSNRY[gC ΛEB.%LJ댉Q/(]v8VMr{s#Nf4|Vi*/ endstream endobj 195 0 obj 1508 endobj 197 0 obj <> stream xZM6ׯylK@>6@{dX &K%ےJT۲H>>R$N՜}wߚ}i8A itGGrtiч,=]+i/~whǟWwAyMƏvW5U3}\U~;PO+~n]|vFy4OB=qUvOTv7nչvo(ԄMU0oTvE_HExE[gfu35mTVit8&ek&0= z5x@i4u?*Rr[:rmrp0X`cHj`ZMDMRZe ]Uwa|Rtl>VpUX@^!&X|%9Ї~LjDiK~1bO=çmkp"Ӻ1RBc:uDLqDhhU`f{8V7lffA.sad3}} lŞ۰cv'iSqjre_w|vcy~!q/Oّ TA{x̽-YW 'a=",քf|Sר_U@ 4Mb,ﴹ[_nJ9.ԌoONǑ?lR;ZWڰ-08 Чuo@@TvvZJ#?"WhE7a"EUDZױKg2DU @F.je6zWxP9J^5ðsg&8o(lSBkA>XY)$!5(h2 13?t*tUg$yR@} Uۮu#9PCTn{ҽ c l9Zvo%nqcō<)DO/İ$5j%1&6R5N4R%cpWupd:-Kna?ǔr[pWXUs HAԎ1}I\W[)U>.m|s|Y2U7sAW̎!&o*5QkԋxJXwތsts8s'JVqN19.]ANay=:;QkN<:Mz&S"4%<.2a/~X0EVC;F̩%)͚u䢂ל'B0w* 2xR@=.k[8}r{S ËPTܞ8TL+0CZʮZI-5Krv)|(C)9eMQY:"Aꩼ3qS͋F{/NpһTS1n{HƔ`sfJKZ[$* /UY[B{ ]uc)vg '\'kҼ^c4nQMvq"CϜ^=G> stream xZˮ6߯:]DIaEw.E]]h6΃")97)nAg^g(}SI~ Mw7z(M??2ؽԝq-o3TEMW}z+'j.AW\dH_w*#sh\kQz9z|=A#MSφ%Nh_"V!p<^m]̈+ t($gG`ӯZ0D8(VBP0o`aÄ Ufxظ|)~lӀ2Zd.fYWDX`-׺D #!GՠITIVLVOUXB3yC: qfq%S1ꃄ>, C- *jQl𤴁u8Oi~0LsO4 E"C|fAA\ fe\ M-iI"" O;'Rn+>N?!u I[^7v6o "caA1AEwT4Z~MVT5\}Td- lݧHb.Ji$\l٣硂=JEs61`Y3^cQ$K-n~jt")a(ȒT(͝C1TCmJML@JM+UIO12o|%EYb9?PIXtȽ=K<Ť55}C ~r5X;-A %,*(%+w2M5Lv_*Rm1gr_41jj*y_vY8"I,*ldyJn+MWi @KS$"Vd ey}= })-'R&{5c7{d7U8M&!x.M)A07/#de[+"C0#,zf|(Ck e|Ҵ&voVdž:ZD$WCBL ]u,яMt[y%~0XJ1eEU-!Axdd琐2 f4\:ZU#Zm;bzHl+@BJw`Yx-dd̻fV/~ʻR(^IfO܏V'!{~W$U{g m_$F/MS;Q6eZt'97U=FC{ - 9B<)ۖڎoEJIqPqVz۩/Sl=)P6J=x{/ֽE;rc"9NSȹ{&iS{7hqCrɶͿj#veb=Uu vB!F2.c ,mlt=~*2> stream xYM6 W@R- ĉ(-f/Hɒ"˞t1m}|$)G֨ϟиFwO5dVwd"ޚl]XW߾~ Dm;(zC ۼp `HW3Y #դf|7W7؅57~e1hzxysz({DEzUPS {zD'N`aPJZwiZ_W]nhڼ믢uЅOLtUà zg청)b2v-0Vc4mXC2goEFq}Gw.''q[>}U7yvc}om7t޺:w*!QC# }Cs'oaNڅLf B򈓄Z"Fb?&*au3pWr?RqqϪMc-rOQI+!BUwwO0 *lj A\Ty[ j͊ԭ36h?ѐ9"fKx3 6a<5)y-$YaNMw^dD)/D9;٤Y^&41tꃉha:,pQDx& +ɬczɭܹC4qS$=gEc_l*↘& Eha¿T0(1GHSnOy]gA:9Vƕ[O16 ^jj w%.*ud8=2XoPp4pfUO&z=B0-{ g 0^UjqM SPq51Ek[Ih;a]ZCjضrXVl>XF/A gz#8-9uNcV1v/L9&|y> stream x XG]5ǣH (#xxq*GQN9Tc `4&Lb4Ys$f9$J0t`S]zzt:#t^ZQkPtW`"99uYۄUr,&RD$JV8WzŐi\`VހH@a~H΄8 R+p-=$Ԥ]t{uu~^Z|ؤCK4%2΁vaIwŁ-cqd4aY7HF R: 2 T& 3u\~" <2H68[=8% ֨Uj54(E '9@ XOXn.V]D7:HAFL.D) N txAydP R@}d Ys TW@1{l; /REoР0(G-*3\_CDJvSVSJv<$ŀĆR;ynȒ _7$~AV LH@J;Jhj""+2|&/JFJ3$kII,jH'ΆUy5BKN7 6$bq:G$7]T"VnyU[^v6Mf&9͚Q&"q$_٠0+7N"Do˭cշydWM vd7Vf6+Ql)6'ˋe咴u >B&}>KfbYHĈ'@k 0(G\0y eM.25?l;rΞmekh_QxF}g5ɻ؝DDX+Pyix0,(7Nh̸ᖓGnmrYsUqӮي FkMɲXind]`}K+>8w/lH+QO^Ӗ_<4q;ljR|i W_"Y퓧ޠ2=]2>3\NN*oS(Ph~ 'ّ!5KV5$'x_SS~㡓 \ )Sz\<죝;[bHS>>#J[g7x sF\Ǟ c-ɠ;QO߫] 5RbI1Wڠg樦BˉY.N}n5Pɚ% q//q=vO,.pr7P^<~)g#'$d: 3׊hVDW+"|n 3 {esT^qt'f`:BzT(QKJRvC5UU3HS xQ}Aq#.t?z2+;/)x8{;QpLx}6ßwOivjb$"aOʉeVbbJƽH3OU[+vN;p?2,e: q4'\1^^ؘ /EM0E.'1rȸ A.&]pr[U/+ו}Xu3W=U/v}m+̞ZZ ;0HRg I3$E[ѱn xYbK%ZIHeQ渝D J" 34SJ54c4 4sգz^0,e: M mD d18dNEﮈ+-Y1ʲQ{:YRјyr 0 hmw/N?ٜ q{/x3NOߙVZݻ?GehtPBK)$͐"mJiD1uQp8Lրuxv}6\3eRͨ͘BkT=ASvNV*J ,e:IhpQ4+L%ˏ"{C8qڵkȅrɽet0N eLU,gqƚy|2vR9 ,JG::ufگH r2R%yڻש$->\uB7d-kKFlHh_~rd4 _󯣍a#K2w?NBoA.7_ (1t,8+JJEEjpKE2hZ9סfI-É nYV8$z<6-Rg+1}ƣTE3Xsl͐48KQR8Ii?>R HD5T@*'KXQP+ ryUC5T[u,V^S*mR}c[n?}{߼qBU:F8k^O]ҷ..ѻ>q8K!vFJK ?؉It \(c.`':мvrv}luUb)uS'"x(5U6b$_e.Qb,'Q\ ɅFǏ=â5A55SjB&_t1R_l%_,w1psA\]iFnSPXYbogR߉ x&~=|}>2ώ :k1<=_5#^|eטnQgkjow Nry y6oy5|8^CO{p˻ ݚ~uN2@NC\XEQz$V-1E\saO=;߽aȸ q@6N.y".zƅ|ąc ˸ O# 0:vk6362l;nE?:u9gvkv֠2**M/g䰝Z>\ZA\ح(F$K . W`}+qail#.4\z%Ba i-ݶdx3yo qhЙ/vhc~' βB G7\ظ mS\pV7kvȅ)_'0+@0? (zCL~.":ąݛphp8~Lm dNlc q1 q@6 dlC\  H!?C\ ! -[ $$H#3Ͳ!.Em:tO1b?3{WF)P"{WB\ L䥡fl- .B:ąMm p!dv K#S,1>?a ^oMXFŅEs?u\*F\Mҗ9\SrF3 @.^D\XԎ٥$[5&L!.~?Ե.q'.sl('ޠͦPZuH,)3+Yn5qd… v217<an,/(.z{6#JȘą3TN#n6OR@Br>!.؂\G\ ! q612VJ1&$$b.F ;PGBtKʎ&ٻ!p5};ʔamт؇-!ҧWv &ƾxe8EBB24 endstream endobj 206 0 obj 6411 endobj 208 0 obj <> stream x\K6 ϯyd ē [ؽe[%Y-fa$,Q(H8柗h>vR_/oH14?GOݱkk>F'q9h@p WEU*bu+ye U ut2rJULU,*0ghFz fQ*2TX*K_GF QDFFzDXGJNSŒc3Vsd\x=>VHkaMt3@>{10*ɴԈ13F&5TJ!yZ˸2T|Mr b*Ah8$i=2Y{I0*cF 0J0u6FŔÈ%["xⓂF]`E :6"x9 C2iRzqCMOF~C_vV}K'J\, wR. S2V,,VG ^71.- I s|K]|!8k_pgi_/PT,춃3MKLntZ $&+@:PYzé> ?A]YH9]OPCkuܘz?ߗ~BQ)}kC1mvr^uU2ktZ2Ex6͋{|#7.A 32d[&JWh%.dPە+=0$Wf;FT8Ű/Օ3'zWz ye\tq[X a"B*f#Pͧ21(>,c. nUYA8S#JU8#5( 珰"* iRz! !0',Q""e XUV(Ƣ3F5V1*’J#]="$3r9h4;ou(琅Rw&|܍9aytw|=60uPr 0Ø1>fд#Nj}'9[p&8y}/X~k}x`}byk}*un77n9ϏYcܘί`ȲH=6x"J)ǐTQ EX4XFwAv w>LrXك,DYg׭%-\tfˏƋ}qo@&eXh ۇ/b׳KÐ׳rAnu ܙ"V>$ 0j$Du qMYzJc=>8hAԅ- P;%S*u4]kA˖v"r:A0.8fFF2Ǖ"lmټeC܅Y+^ˡ g\ɰQS"/Vϔe'l/sOuD{]*C<*&,WQ,ezh4zha:™^/$W0wNd5N _A\lYDe*A>s<%R*$m H+щ<n EkkOw?jt0 endstream endobj 209 0 obj 2529 endobj 211 0 obj <> stream xZK$@J! Ϊ.o >aw;znMUR /"eζt'_ 9翺}~}t#?~x|=_w\jWΟj )DY%53^ ^y]xd M +eVeɜaC}ƔKRZ·G7_ZwcV?6R/k5x w$k}Qh9<ю%uzKDV7|@UP52X-9ebG@Q 8yrzkӨo٢3~ojR5D(/Q(mqhZ(piȭmyCч+b7Y7a:}FRe* ey]!j}8TF(_YBh6g UPM4$/:n:u771Р@t QX1U=2v_6vvby aIIk~S { *|uC#'l'/')|u\O ׋kS҉`:BQF8:$hu/j8" a* k\km[+lX;mt17Gv2 ~Z%V"E5W}2qGT/V}ff^x;B'ygz+Dy`CՏ"UV/3'fA='$71ʚ ?%GWkJڳ {('#<4z2&q.$UiK%S b-ek_6y?SU *W|/:^X晔PCc@1fbSd+D!ڪ7tXfgϊ9]Q % vTo,6dl^&' -ib Df\XC%fE?gC0ݍ!W6 0ui1)D(Nf0`FzlXp6zG~0ʧs|P$6[/fپ6qGV(zQPO9&^7\!"c6Uex;JSFj"@oT ZɇFkZm鶖պ]tEGD/&t uD~ oiC˩]gٚFe%đ)[vl?l=#'<~;nF}e=5rHJ kgm<0ۤM۔-Vt .1PK @- [jF!~ԬS=ԖCV;@7*1E-bI3{C3U?+-bh6eU77r@6#ѯ<{k,=\ݼ^k̍8lW~rOW^.դRZJI[)= rX48Z*zs2tjON 6XjXjc |O?G0{3o|aLuME uS>>.c>0]t#Z_Rޮs$[g!bQK\{w %5*f:c@q  E)rn9mkWhTHP07vh [LƎm8/hRX+iZGGme 31c!"_ψ(M)巤 G a( 1%! /wX*]ScQ )? c{&,FCYH=uPQvpn<B ay.ĸX4QK_hA&!?q/Dn5`l\;݃ZX 2XH7AW+N֪V_RTz<kں6NT{vRR ;5MetK%3ޑ@1YKG`V+?]<+= '})6?UkML{u=m endstream endobj 212 0 obj 2455 endobj 214 0 obj < ] >> stream x[ ELX(^ {iC G@&Hi3@+g||#MռBKIŕ,Aq+E[7ϺM,Τ܅vz?cɣ}xNIɇDwj7M\h 4Ah B&M@ w endstream endobj 215 0 obj 189 endobj 213 0 obj < ] >> stream xa Pe%}RA~,>J)ܐ;`˽z>IYh?G,k}`@L=SFt Am) y5%@t> stream xZɎ6W@IB\|0|L`/ )7)$TEċRz˟N ~~_5iE_;jF/h*;vz?<7u975OӝZMz>i;^?/WysnZ-s>-<Ǘ&,Ĭ_ݠ-S<wD_qg$T|DE_a#Fw{>oi勲 p!H N #lo:ݷojF#[mG[x[ mh?;<||@YQD2ᢼOiks[=Z߀z߮m#e.ۚ%NQ@f,+ @}=p,T+Si)j5x3x;3[c4_n^,Shb*i5bA;B@ hf ,5͖%eѬՊ?Ci~<*|mwR} -3Q(xE5 ߬ƂVK'[QfZ1.ub`'>C?hp%{h )…ɥi"WJS.bkd=kx.ȰyЕaنEn-[=B) b[G׀$n9g][񔫘ҳeC@ zXUfdf,L \!@0dOH,!3^ssn2NȒ>1mb's#PF{<$=O JRl0!9dp%QsygQ#i 'pb FD]qrZeGo(t_<<&F̄R'\s75\6U[vyiDD%(#km킒W-f[qVƙ fKLd]*8lϺr)xw{~ ȪUO?kn&Ekb=I>)mE$&Ȇ]ED(\.bŐR,z]~+HcZl! E_-t1l, +`2ŤPH.yIE !|; N\Tor?{sWuͻ1 9"-2w'XL:v/7},l<`6%ѩYng :]6^77CZn)]Jx{exϴ cٗR&,.zDWr*t7ЉdQ4A[u-m](Q 'qe:7 t=;U:1/ұjPJvOWwisYB"TBG!f9¿t; q%; 'ت+ *Ӓ%Yɢ㱊~=`Ze7zh]9Gh d`2P7NMw틩'6m#u' z4}C 'yD˛~eS#eGĻly7o]ØCURG9 DYuHMiwu &L#^؄ɼ]K}PydvrOkE?vbry3mDj+BFC|~5̑DVC蝸>0QIGud&.Ey?>{5`Vf+ύ[³~'OXe/z<#D~ο={ Zjal8-/?oA*y'CGu2XiM/h x?\[ĶsfA?ԖkL!K YsLGi! )POTP4Z9o 5Qz T_@y3ccS"{(Vɾ !ॄ#Awgy-*n4q?Ԕn$X )yx#s3 nEY; [%StH#=.Mk zi7wӎG3*k(A+:b}@^/5~gڲ6 0fVnt)_&z13N`nZ-}D)1̽\[Z~Y(/E\{],D;Ym]}lYU0휼SBe3 G_˄%O%Wo"w?G^fY`3-o1R|x Iԧϑ~Ce)ۆVj:Sn42a>dGj_lZ\7_>]H?h endstream endobj 219 0 obj 2513 endobj 221 0 obj <> stream xZI#GׯsʱB,I5a==`eˋLۦܲ닷|oPzǠ69-~~{`GO Qס:~u^} EO}WGyO _a]:?h/v_2??<_guس|>bjUo_7uߏ ju㜛d.'ÓuC]ׅЃDYо;wVv2^]SΌ@jTNY}Zm9+)- 3IC5Lr*_I;Y DRVP=S.$| ۚQGFۺ ̦c ]5@W.%IR)S`m R\aHdF O q%B`tҞbNP 4x%\81Fr]Aɂ͚+_@8)`(L4 `-XHݦ[@\9n n WeMC31.<R_SYE|# x>=9ʿ$X$IC0CZA`0},H'pԞܬ2*i6|2!ٙÓ=F5#XB~Rl]uS4l E*P`q ni^p hI7(N JenALnǒ^cb)9zBX>bD+ˆV_,+)Gaw5}2!Z 3VhUJD!IZ"ژ.O[[r;I/h{ *V˄_|$mP( f< AJsi;39%2}dJ  4I cʶ)N`4X˦vL'/ +' 1VC9ن-3 =cQ/}- Z3E-bUĒ=ާd\s JcOgOfR fCഀoxBNoqL sƻ*ȟ2[<(- C9+R9S,5-yefG5o !"&"kr[k~)t"rODcQ;r㢸]]/^BN:DFdv'=*XΪy|([[A jrۊ\vQa]m BYI`[8Mar'1=Y|(0ϢP{Vg.ʂSqH.Sv(.6 Њu"b Rp*ܟOf2hw6,I^َ Sy>f摆i5쯉XQj(̡oro(L5@bD0WP4fD.Ҫ'R{vjQm,i0HțI6 f2[Y! . +ܒv3@Ⓖ3&/ ?yE|>\v7QYyLs]*[-Eu5!cL# 29FcpZQbimڵ'cUytN,B{C膝lIʗލmX¹ceOH]X &*ҽF͏xL%Zq'g;enP:a2 F^;!3cNe %{FtV^h8wX)](:#"pm :h~d2[Q'V_4vҙTz*=~2NǒS~SpGߺ4Wܺ/ݡka[ԌG|;p^+7jxl/SXO<O&2%4' }6jH;E6By.6<fan#o9"vFKNqm4rfWDPa5a)GK"aA'&~hp /zEfdZT<2]$Nm!NB'~b5n>enD Ў*:S. d35FjYv|Qd-=VyC)l:v: endstream endobj 222 0 obj 2419 endobj 224 0 obj <> stream JFIFC     C   \&" InҲ1l_jg[d}c`=4c8ьF34c8ьF34c8ьUhW?.Lsܽ_ժ^Ϸ7J5^ 3ԩFNB|@@@@@@@@@ v^Ǿ+{ܫ^|NQNQ/Toà=s~[+8J)Z)Z)Z)Z)Z)Z)Z)Z)Z)Z8wl=`@wۚ0滿@ 5Q|}5/t0kIJ[u*y&hSSU ]=ԩ)*'jj̺!sϪJփA]ySG;4@0,;:\)@ ϭh} x8<3ψs7>!8<3ψs7>!8<3ψs7>!8<3ψs7>!8<3ψs7>!8<3ψs%8BeTGd|>Q(쏔vG;#DEC4\b?B.uB׫)Sdi}ǜk#2 !:$RG"(;쮐%uMU[v} g3c1L&pLp8&8  g3c1L&pLp8&8  g3c1L&pLp8&JE_(^=2Vme\FD␲!>o.]ť)Zu,8PiBAjji[mP̬i.Ѵ(UflZڕ,Ҟb[$*פVWoza f XDT3.l4րlL\.*fnF LבEN;0oz &ˠpzKAT*QR;\f/[J_jlV4}e\qk$,R5$][,hedZS*Hne]ٸ&kT@eĥfK6,?Td[.T ٝ_Fڗba324;0[%[,rQ(Hl3B@֪iCkbF)bm7(/͉G%ջmALlRhws}vݞNҝ@QOymJZL+TY*5Vy0I$.RʨP񉩥/X]KH?{ozim4ˍlI]8`8hR &Hvyݠas+C)иzԯ5/?/o\nη _l^lioz9tH-2hJSQ6kOLtC3.Vːs56_њ)U %qzChњ)3KMaV._g8Y 5C yㅐ^xd0מ8Y 5C yㅐ^xd0מ8Y 5C yㅐ^xd0מ8Y 5C yㅐ^xd0מ8Y 5C yㅐ^xd0מ8Y 5C yㅐ^xp%.>('eK&?%!1AQP@a0q?!(N:tӧN:tӧN:tӧJ2br&4a۶ޅ@4fIᰞ',udu! 8Va""Z:"K}jn,2XvJ a.ĮU hxv0~{bwWHvQĶUJ6ɓ :p$^% _؊* b>\A;k"*:}_j<(UUނn*P: [0\rJeWh*ƳCJd=f?Ux•{SJ 3( OBϡcFhEbNqX`I M 5k1q3|gu={_3|gu={_3|gu={E\P&w)!dt- 8"qS{H'UUmj~:wmf7lB]qAǤFb_]GHeZKfS+yVKN@6FvYI!/l kE*W! [S? ƚ9Fx@gg ۬bSh!9Tф4ϸBh6KFHF:*m6`[>RW5x> BitkMRMZb#u(a3()&wA[PRr:)-Τc%Ǜ~]]VZjիVZjիVZj&'1 | }}}ߴx<,,G8 0 0 7<<<<<<<<<jRS$|(Q䣻Gw%J;wy(Q䣻Gwy!6$ASsU󒉎f%.֗#25so<o<o</^/ <|$RsXJ(;죻(;죻(;Wn%!1Aq0@PQa ?BO~Ç8pÇ8pÇ8pP "BeѺa%E,UwG V?0&HStv cnDBJ]OW;]xh}. "xWҕ|&+]`b\#M4 s6>(#!&r}UcMpX ,dX\ɉM'8 ep-#̦B8t>b-ZjիVZjիVZjիmrH 0 0wN|Edq,0GC1!}C=я> stream JFIFC     C   !&" HZ7PbBWUE Ϸm*N5 *CJPҬ45 *CJPҬ4ef^?,;~\y3c޽Ǩ_*^\|Kƙmju?zN4zzzzzzzz|su,z=6c$026@P}($m6DF#hH$m6DF#hH$m6DF#hRף܅kJ'%}ЊJ| 4e)s|1nJlӈ"b)W\:K;߭m)*9F&黈EEm!O5z2kCIewm=[Jm58s8s8s8s8s8s8s8s8s8s-nEW]i0~N sn`0[- sn`0[- sn`0[- sܢS_%Q 1@AB?PbUT\ʁvSyO;)e<짝i03Mƭ?(C|O‚3Jf(!PC4iA ҂ȻuؙJCc Nm -X~imK&qpv]< @a6 ׮y~ɡ2rz°ĉm6LLխ ո$X5`BeD-.;+H^!M%7TIfHC??v$DČ=?ZR.!4)>s0ͨ}QI?>q])4ȝ4zZucl2MHi8xOmge;0*iMUr.%aFwgQ FΧ]л` n_Lwν}[]um)9ȬϷuwVcjTI1A yhr/aF,ܐS}=%\ SIJѬ6tqKL}a)8DsN"9'ⓈqIG8#Rq)8DsN"9'ⓈqIG8#Rq)8DsN"9'}[I5_Ixu*iJJڙ!-3gR/\SE;YSE;YSE;YSE;YSE;YSE;YSE;YSE;YSE;YSE;YSE;YSE;YSE;YSE$%>%!1QA0@aPq?! g&hO9r쑶ǣ6ع\.{=bsع3)ϸohXD'#a!A1@Q?I?v5)ciS W|_ u2 S*rN\˕9r.TʜĭEd$L-jW #6|qj3gTΩS:uLꙌYPTc^'!1 0@AP?ٷ߿~߿~߿~/΀$H@̽hdx,].^ R8 !l#^ˣ`d:ˑwN`vPƊA諭?wpz0iv 2zR%v P9K?BNDhc\ G!dˎVni_"my`G>0AKt@]u]u]u]u]uTvtq 'e2ϟ>|ϟ>|ϟ>|>0 endstream endobj 226 0 obj <> stream xZK#ޟ_=zu=! "ddI8OJҫ۞@{VK*}JG96 $| ~~m9࿯Ha=0+㟿sS q^> I||$G3>Gah=o_8\pMԚP|`>F '|$ ~R#9pIx}ep@8hchOqaHi#m) &ٓ(In:Jkat%*!6AMzT2-Tt: Cm@r"֍S[,J9HtB[`jWciD~Ϙ#Cy( /^ڧhkHq,"XYҵC"]{)X&x@8!DdX|rid2 $BP-1( "Z' l#uAgZKGX|"Ǖ6Un.g&d8i=eT nU-I!X=PABaٚ{*h&%'$ Z)UErB1f)J/N }z/T9'dp"1w6{Cw".O>#}WMX$cq;JuB{[Jj=]M=KzԄwDּm뙽ּE 1~K+^D[x .Žrs ?oX'I;b לclZk{.0nRw mrzw|o&6|h<>~Fx 2<}/qX3$>UZ6 A"TdF^+뜑ZF&6Ou CREU ڭA]׸]m @*FTӳ >xHLm]>}fjX+Ζw3 B]Qe5|8: ``o\ [kէWQe7LhZ?ސmaqQoE?Ƙ6y/BH1Uji^:n@Px 0UZNCI*E=l4qblc'91R$(tc򞊗x* ߝ}Ղ_}iդ %>`J=X rq#ŠѭY/Oc-.M^_,U@Dċr 28X%&1?S) <1? 0q endstream endobj 227 0 obj 2177 endobj 229 0 obj <> stream JFIFC     C   !&" IhRtCEzM ոˈv6 gbqF'bqF'bqF'bqF'bqF&_(3](+یi{*yCX.?uIuIĘIĘIĘIĘIĘ{&g`#026@P|?{H{H]狑KKKKKKKKKKKKKKKKKKKKKJ̻x!Q7II[ٸڇ,v6Vq6Czh1t8Oo0a"zeNLz^z^z'nGFP!HR!HR!HQ;|O&Q1!2@A?*q-[եt5+}51ȮV2d}4^zRPk޿ 5&ԚRjMI5&Mi= !341A"BQ2Raq0@s#Pct?ˎQi2f7BlQҤH#ь6y0枘gzc i6y0枘gzc i6y0枘gzc i6y0枘gzc i6y0枘gzc i6y0枘H#x([uebf&O~٥4hmUMWU:lC}Tj[Krj*Y;uouQZd>ȫUיJCG@q(Ua%% .nQ{ lDxl:5T/yu*$Mc|]i5]Vn )3GQ:J̰5mI Lwn(q(i*JCORYw`Et?G_j*йiqU?@Ϭ4Mv[`pI!WH~<#g]mT6(XԋwXtqF]S=TJh亮ΚAq+ 3?1H-nqUY8]2` jWLWƽ{]uնԧ "?>)CL-48fK>q@Qء, qͣ7Jl8bm!kP +vd6)Oy9LPu;;(j9 OW>Yv˵F]2hk@Ze#.ցv˵F]2hk@Ze#.ցv˵F]2hk@Ze#.ցv˵F]*!)~#!1AQa@P0?!f/&pè1?5A:tӧN:tӧN:tӧI7aT(ܿ vx6"rAN.k.0.DABť.  8cKi(+lD@)%З =NHe,*D$9ȶ ODiJ46 $~_U$6!@#DJP< ,L!"(dܬ:Mx@Ex0Sۊ"P mu`C@P(CMX=ܫ$$SFd&l?#?qbbb_:C:C:C:C:C:C:C:C:C:C:C:C:C:V?f =}}ߴh@<,,<<<<<q!1Q@?I$F-t^cf_ AjJr dXD 1aq!AQ@?{:}2@X=e=.) >_f = 9;VrvYڳg'jN՜9;Vrv1BrzrymX(/SD7gVg:GVhY4uf՚:GVhz" !1@PQ0Aq?}|}^w(QoÇ8pÇ8pÇ8Xf^4nXn X^%ހY1m#~BPw}ܭ~ t`L쐧QYr;(: |R=s3^#bO=|^4]nAe rV2T$d3Sl9qþ\*ӱ[.Ls/>|ϟ>|ϟ>|ϟ>|! endstream endobj 228 0 obj <> stream JFIFC     C   .&" <} HZf~kz v|ݻ?ը`Sj\jj|jݐ(Rӳ OQdg,evS&?zuGx@-?==JҸGي;v*LM[:Ms]>g{;B %'-I=pf" @Pq[d3#sYYƸlMz{)Z {1d05Uv'7RA{H-u\V6Y<],p[^[ʹmV/^ZQ+M\Ժֵ:V"=X$SZW.#Z2 ʷ./?Ff*6Q0Y&LweG+xQC(EkjFo3E (uw5`οe:Ȧu,[(46S+꠆<9tꕶ1cbXwWb5cٶz۫L]/ew&akN6_1rq?s('0aW 01!"Q?|rV^z-a/ޙOD+J/މxFQ[0+OW! 01?қZTA5B\ RQ F*I=1k1'&~YjK]d~~=!"1AQa#2BRq b$03@C4Pcr?.ZcOG[zy9#Л5+Xxfy^HԪ-]fo"jJ 03$gW0ez%0l\_E} IaszxmlDW#,yiCQ3KǙ[/+:⪰BgЍRDK3xmyN!I rl7>u0ϔh%톞Io(1yeӕxxyb*hLcv}a(tcl-NW<7&5~۫rN!3g8M3[xzIe2f;q }H{er+kRq/~|5QY㍲;жr?=Gvz9ښ'Osˌ卩t<&\͹܁jdǩ4vP/xąߖ+=%LqHD\.w-$Lтo6l>2K&h 2(w4#n}..DSiY6̷G~;4}6h2xt Q8X.D .(ɖY0>PN{6刣T: WNG0HaU%rݜ7O&&;[fߌQV@n]F"2٠XclTWEiiqGeC=!*AE-jek\qBVSH)qXߑNڡ')O4_{q)C͙Z/GzRm|7]fk{ >^ȑC(0FxGmኺZH)Kǣ\>] k|얒ۺ1Vc$H#^=S~GN#;q1?#!1AQa q0@P?!5]đTFY)WOu-yRl;C3zus:}b{ٕB:#Jx*uR*"*jHL)ѨpvP PCB[ sWCK i711YWHWmrv"+qn,jŠE0utjMUE~CHPsNU / N|[p*J~c ,D:=#Zxv O0$TG-/}UWz RJpў0Xne+es-z:zh@@s/ROOO[l[}#PTكÊ::_гudtPj|'#3oaÕ1,!XҋxW%J)g83 ZBHg9Bmpq> stream xZK6y{U%!h60ÐS 6aJ/a,nK*UIeqk'6/u?}Ag:9?э(Ln>0tT.[N/w }w{V|d~I=<_wvϟ^|GџtU'8 }£u7.#\+<ݞwOé \\hj)^/td33AoUf ̠gp?'3V̯wsw3854u[V Gi{Y !GE /ؼJaDL7䪴 r5}A\V# (U9"#!]{*ʬ4ٌOYFa| r3F(hہ,P#ԛbjq=N؉kǭT;IRm.M}"^R'_ҾnÉn|e[!տވ \;Qa 44m[; n8X8vMm#v.MmKO9H-0.Qe+c~K!͡yUvIC pU`HU Ѷr֘ }Pk;* zxUCpFi+sܜ&ɇ,9Q@ҟ`j6xIVA5BWe;'6r :6s?R[gcHwT:V}c=g6x.vMkxҒU\qȊJi\ZxUVxavb&%ŋR}X.e0KMrB[U:c CPb%UU_>f)nso0{v62g-~F6'6^S;uڈf ZB0e*}'Uh&K+ vPr?Vs"mηIVNLq/VVY A4S5b*omRνv+aG㾜tt?55,MXkk>tOonD7y4ۓVN=V֒nXgSO*0;6`qLAx[QyXOMPYaK"?Zp 6ZFz787SM`^F$:K-F!u^z"f"eAjra%B:_H*W%eAAԮ>ܟ&3Ӓ֤N f)N )_ȑg)[,p4.o]R̋١&dHWfIjBX&o8/tqr5{jfniUclkZ sX{ @U.% ]Rr|v5lfYZnVCTQ. %> stream JFIFC     C   !&" Ou_YV̡cJ|A(xس-+@J5@prs}t=2[ LB\4d'G][`-Mv|k+a'p\oY~g azM&rc4SP?gP?2B !0!1AQ"#2B3a 4@p?NU.~/,ed8V(@8 aIQռK~E[m,-U $fAt^r?tV@~"ƞ` uhЍt#4 bbAݮ~ ]$ ue`k۴g (G e=G:&zX{}Yj$K`Rc8/6dLȬ%4g/(^.O|]jڒ*vo['wRd{ш[>[R` F)Z>j2;=7gQ^DEXSڞz` >zz9s: !A1Q @p?!eYO:ܢ G"Īt>? d V Ѳ@PŲss`u9au-2QȥdF7GA%$f 8ԗ)>"Xޮ\J)FQI0͚Qpڡf"#\P#d >mpujcXVat94$2CT [u|<<<<<<<<<<<<P?Ο1!Pa?EYu# !@Ap?:'vĦO1"3/; /=?y 1ӶƤf[I[}ʣn~9TjeV;? b"Ib[oNȰ]/ZV endstream endobj 235 0 obj <> stream xZK6 W@$(-v/Cd&[dx,$տo /hn}S*|sW៪wԅwp盩@Wo_=O{'8pGթiE][8SGP'\> ^v/Uo^pJNZ뾕'MFЌ~?}SUqA-xK0˜/GcO#n"=&mՍ:ؑ.Q־Q +஺(8Þ@qO0} E4icS>xGdETf'+NT~6Q,#zCkkKNؠ#wjGjjd2P\@%Ŷ l/eg"B[D(S J͂ߊpEI i0K4XS'rcS{MMKT:1&Ct-5ZRRXBc~P82V@OhLXR ;! 8<"LPS L"O9תY]Dd@33^Bs30qyP<\43Cw =sIaޟ`V@$f;L y'4n9Qy8swdor\՚9־uƥ'zHxo-+hGJ2,zKܛ|vv2%YL k;nbl['~Pgsw'ʕy3CxɄ۹XUv,a(Y6COnl7gS"+Kh?r[|iĵGXtKN_f74bF_s=[! ;yO⮹ăU~x줮JKTp^xWGT,fQ$&3%v]]2Ï*7RA]ZqbG+^ٸtΘdڸ^|Ui8ufq0&meC}*P\h&.AD(P:Kx`@XpS:5Jk-WIb/3hRN Oj'5u)PR}yiH:/"*%Þqy\x_%Ix8{%$Q.2jm>bw%h9Dtr%heo~0Li 3ۮ%yRXե8E3E6m A %N 5aηKd3* R׃@>(m8pn<>@߯Vx]5͙Xiq4< @.CV%<%CMG$SPzf(?HD]8`"0Pk}^w}RS0k1Fᄟe6nKw͇}^ םY Cf8ֱKϰ` *5-wie%b2 )*Z5Zm7i+Q9ivPXS=(a1<]| {4MO2v<72L4Ir{ys p󬜦Χ!:(~@A8ӻt<*)#>pˎ80$C8yh6ܺTJqc/8j~n$R 郎Z/KO\E(vA68*FF2FUeUABC=QjaENP0 2sc4\\l΃i( ZG Wyn 4)?cIAJש|L:> `ʛe1O⒫{asP_q1gz+ohnQ_*9q $5jYh&3X c)% }ڡHOO~͸V+Q$_( { @ endstream endobj 236 0 obj 1991 endobj 238 0 obj <> stream xKk0 :J kv+v;m`Ѝ?np^$X [KeEÇ"c@!Ԍbݩ-쵶GQdfjq%W=U~6uOPHޕC  *Q@ .q -3lVH%s0hպSSJK& ޖ4'\,G1!UKZ0XL$NL'k1c}^ti;CЖͬJ\aNzFv!L/CUהP8 HW:x2j3Krq5j=S<񕉶 u endstream endobj 239 0 obj 374 endobj 240 0 obj <> stream x \}j^I\%\ETEe]P@DYe\P34-_Vl3۴^U^Jer7w^LΝa;r~g̙̙sf.ͭ&"G"2fAR"X"*"X%+Lb w5ݜ]7[7F?Cy-SB* E-N"f]lhzg6nh~)mͣv7{j<}/%̬78 w|%y3b`Z4A kzFTSgu(, ҍ]Ԟi؋&tB7{^`}AoD##CDѿU#4ȵyd[8bUcf=>DzN]Є?:'uqie0zi\oHkiVBKEuhђRc!Q?QJle`R1ܟ+VB~$].R+iאe45ZtH iX,vYZr|o!^U[@Da"J.aWW= kĀw\>_ȯ_-c,UgI̸T+Y~P~[؄B۶;HuDJ*U^$~r!ng()27[HyzM+UL)OSaԼ 䜵d:r*ofB1>tcbFж _"Jjo]޹mA&;L>OtjYjLDE/y._|g 7"RuK>:v@g~|3gТptMPˌzZiaE^S m3FožHU|vLjHU yG/m~~zH._mn:3L!8ϱq]2̍o/ bVu=?})GJNYgԀybJ>oy~{kA0)N'AVL˥N'ui1q6\EB$910~alaL96U7fڢP~qޞWJs1rFrMdˣ^S/B~{1Hg^yzgL=k¿^)KLO JL`}Ki= .L"}ri!j!h=.i/wn5FS Ssא~<«4rOa^' VW)x_fr[_̛rjZ; g̊= gr: )pvtd HW ȉy+H,rD9, ͬ{tjP/&ZrmHmLşkbՖU!9*M=E $=,]7k~cϮ/yڲͻ^+Xq;JJJ_K)~xnOSZdRy;?ǪVְHy_3<: D!)RH-y(bjFj"j)=$ʉwE0`ɔ~;PϫQ]PpbiwiwYܸX/U*M:P=U=jfҩ=.l߬ȼs>f̿wFPN#Fk_{}QGbȤeÓݓˇ&ZvMܷX}wO1r"'OK}?Luas=<4| A89/vKyҟ.wڋxg/םl@~ѷ,b \ irzMIp ZMY?E =q>zr|ػNz>Q. p}B~2~џ_bMm+C7yj^mmoW{-5_Sk#v^Y8~_&YvؿygSou8N?&\3v_O,x#H哞aIZ[_XRs.{bv B iLtuAH1^#Zeqv t fjC4>M~=2+X&gmOT7'~>|_gE |%&\w_88Ư/P|3d8 ]޿_,8 W_DNV~ NmЩ/v/ƬtpCO<0t;e\9ER y%f@q1)6{1Gg-;i_L*_)}EsG8J%gX6eLJm(]J9l.HƇ f^! ~`=~C/p8/a~€_8J멀2Jz~C/{[[#b)h3̯-(^~I<'V/ҧpRA(\ɣNA4@)󋳊XN ҏ n+}T|Š((B|Ygd y?J"EhlK/R~W4`_NB8BG+8 .vl?̀_8/p87h37Jp 8_p ~q_8/p8 ^ ~/ũQ~~5d w?@/2ҍ 90~ը/ ~)~I&3/ZwzY~).bRW+IPί߉!m(by؟h3Xn~ $:>)EMS9P)+>޼~M]KL.G٩/6He3P]D6NO˜r9˯_޾K^%6XK)~);>dR mPlH%Ѩ`I&1cJ%A+3H%qSY-b?"ЙQܯ>}Y8Yߗ_8:_ ]oV_`IbRJ߉!i~r"L|5~q߯!_8/p; 0/p_%POp 1tzu@qYq̿_öOy왡#s$Mֳ/Wm,} G `ѵ~rIiɴg@q"ݦ8_}K%"31*Bp&h&Ѳ_mw=őNċ숢[=G+Ysb ? )ҋ6ATt% +wJ8rڤo+[6td js Ŵ/Ðk}SfK.Z;IH,EI (9f҆JYs.]; 1KQ{!}M)%lgLӜO2*p!"VjEƇ~IF(XFő %Ρ .8E6Eo˯NBۊ&MnȬ>óv9őY"o #l l~o*Ph%0t^ص)"CŎpvX*%hty,~~S@h PN3_@K. ǁ~Cq0~!Ei<^ŇW \\c]|!92#Balo.xTsaa8-G%(Y>X D٨PS"3z L~ endstream endobj 241 0 obj 6506 endobj 243 0 obj <> stream xZI#_Qir J'm0߱efdUf՛nh5=Rj֙b࿃u9?|f;oL:?nB[\pwκYf>|w7bӼ{Zs➧4Ǜ~k^DL:;_3>˟~}OVeub\lrsǿ7Wwف`YCLQ7׀h<<1Zoa_x%U@‡YVxK7_"HZ4 'c>/=j ;'':38½"р^RhP'17!f4FrH;{Zx)].l'F j`Ron*/:4t ܢH6ibû" #~4 L8$>н2J\,aId8#v(ugAas0rdp 2 c)LtެQ(]1rDžeu%D᫲68e#7EUf64*\5rt/!UQЂ΀9#K^R*O!,NI/fB$U4jtJ!/ZE3Z[Bߧͥ$k)^OLLSdžq4r1xb䞸}8L%]u7U?O8_QviIBm7T'rSQ7~"\(ATinjlz1&<mhiioF7 ig4ǜǪ=_7||N|1*BǞ)L'D $QPdGspL0D/!(|*p(wDI᪈f O?hiHrz=e%o?Z?{#BY;Aemgg.Ȯar L/@A%MAu>';Kne A!a:ԍDHg\cj0<^O?#΄soU!%Cb\@09(lŰf+DN[$ѱ0t1wTm4oT%B:b0{,X$e?d~ͬ{$b{]A-^#xB_K~z=:txyl6)ꕳ[U`B_N%bN%)ɅurCH9+ZK\6jbV]@UgH-%HsZa !M1kjӶ=g)HA5ˆ\JEE*հHNN@zk 9<$M劂eJn,ݫ.8Ib 3 $} 1iѐ+9ǎ]l97.kE +h&JkRo,~r[q$.)4T!NĀ⃼3-j{Ch3f@168 G4%'!ʱfko@7?@{#x*1MrwU"֝4e3tc[Vt_m`?gvEoҳ}]d(03"il5i R_AT~ٶ1OU4I%ư&`rE NqJoP3Hm ^[fMOc]ut Ne:TBu)M{~:svWn-kMCu7*!ß ܥ  8|0x=KNO̺osi=r[._w0%x%H]p0wGh'ld@ʓڸGl#f)qEDO[t]s(.;]*}tP> stream xWM6Wx]HH%;N]tQj rߦgFGؗǖF3gd:qὢHxYpo޿V]+~`F*WSUG;U>U䓯8Fa.Lsf=.erWS8M)~p)F5_O7WT?kݙB{ݷ|ʙzG@W}djqlC%/f? Q3 Q8 {X>S3EV{j  ڭ'*X1:`2(Ԭ'n6cAiYMo/ftdL$~r 0~zY(2&ixCڔs FaNK*-(fWr(-$&o.h[>99c2'0([h=M lr[ BauG4gZbdE 0ql 3rϴ6ܒaN!nSArK>'4A_[VSbt܀?% t;<6 H9_SZ IRDɉMz)٪($;fVfwico$+9K]i[Z3|Kn.w$0Z,;`a.͇"kGjO%^|aɑĂJ<-=jUDU.;aڟb=BhUAKb>7lKeLL/UEdׄx *5Ů+H u/L l~4C 炷bWVR$8,5$vTfƕ8RMB#=ĸ4쵸0G eK=-Q֨zVnTt cCH.'~&$"WH' P\0..F 6b0Fn_aQ˾VbÙ?+s ٷY$5N#jGQuT%\ZE S"4 6bՒ>Ht ]\)_\cp ] >> stream x]vJY~qrגdh;7B)\uN8EJc~gөp6|c|(AP*x⡺F|#~=V75;Y*cԫ]M)/^_n}PpynzbJo/럓6}T5!ziݭ2^_fӾor:N' ɗxUk__i)Q]@uubT׉ P]G`(BP%dR1NLHIxQ|J2F)ŧ$cqbBJ2Ɖ )G@+>7#/vb"ޯaė2ka"ҳ˥ѕn"\sk߈w5/rUNOr?\K՞ݢx/agZg<_+WC81!%ĄdBR1OI(>%dR1ZMI(>%dS1OI81!%ĄdP)ŧ$cQ|J2F)'&$cq!xC(BP%ĄdR12P%〦dr!^@A(Bo= ,/_LԕqBofQ|i7*v6Ufwv5,ǟ: v5}/WYj_N^)]Äe7k=^l?we,&S;^êٚk'HrU^ !ဦdS1OI(>%dS1hJI8)'!xC(BPNI(>%dS1OI8)%〦dPPN> |ANϓ EV endstream endobj 249 0 obj 2260 endobj 251 0 obj <> stream xZ[6 ~?" 3kɷd.о-ҧ[(lK~%NILf)$EҧO3Ϳo:@4|h~?|6TZ_>PP{]xvG׼|yΝ>)j:8I|sᎠ:\vAS?>}j=u-M8jV1[o_>lsaMq C5j?n=M_.W;)TZDjKw76g>S`hR켪VZ6Y;i%9>=Ýt'/u C jz6x#p,`t [aFX~k lmX}`^s&r|gN ͌QGlU&Gi͂q#},CUwM^,xS#ˍRow|5@޸ LjAͯJ7q*0ٸB؃GOEhNӥ9_+Q )}uÐa۲^wC-,[ˢ "=+ pl#, z-I!-➦>V5Azab;: s6,ddfJ){@}=)1tz-Hk_K$S3p* ޓcl|JRHǧ>ӆz}xgKZԑsY8U![…wzhVB9Zd1^b%nc=I! sxhgә'Vd Uu_~U~K);eHR:SC<,ΰb|*a/Cr0.̰4m*v ߩE"Xz+P$sT0ӑٳaj#-.2T2MEGL9BK;7st^ WHb,HdEa}7d-yT;r%*^Q} KtO,IBW8b$m,ش*^kYUE^1R"kvr@Yf'Y;XdYP $oҕj괬`mGC E]4> stream xYY7~Iflo }}jB!-7/=Yd;)XٗOݿNuGus۟tgꜷS7:'A8Cb{]+r?}}BV|g $&S"{q6/?*\YMz9~;}tť;7^җ`p׷ç IHŞy"oP|9zEfӗ@"{Rΰ|~ƓLb⥊$nb?TW*&>%%" f" -(.(<0#*lFV[RW3zku'gWtLaF`)lX ǹqW[P%X\0k&)>:6>\5{}8' 09frS:!/|䈕(V)AU1:&9:bܣOQzQ0OkȃI]-3xVFݵ6Af5jU h\Uk jʁc6P@Ѫ+jC-1lp1%'dc$˨}&nU՞gjrG[5a? x91.he;;srXƪ9<7Lx2Vu7,W YѺŧUΪDe%Fg-GlE8A$tZ'Y f#jB,SL/ FL`(v(s&lֺ^jʥbݝSIklSeF }e_hkу7k"T++%dE6_:"ӽ'Nޟ:g!B>0ZӹCإ@S4!@C L UF +e LQ T1#< }kS=]Ռ޽ĎIR!Hy[ +m@;yҶ@;q l4͹+#a:"'1hG&ܠpZ>F H ҋc3v<_CN-% B*+8xĎ  wF tijSqwk6ZSńfGieCrvƊASpUu5MNPeMT#=_g$4z/ aCo\=8ԜFF}*F P. ;V%TAA7.RčX!; NٕiU[`hA,]W{将h&w}aM?b<=QG)M,6]* Xj8J!Ipu$ChV U90bЮţq%V}MT9⳨ ~֠( 6f~ l+VZH9D[6_ GYPPzĭ^`7x2}vi;yi>]<(H i7'EbO}I(ZQJ1~C?{> stream xA0@k]:WK/Pc<6o'bŸ0ϿY:2CbːLtՖEli)p>4}} -,2LmfI"ϐϞ|eeu#V['Y§$[V=bU oev$[U .be tA)[#Q=[GkUlɶ_O}S[©Gml"(Y%?k}3'i+W: $8bj<2} Pllm/-[@ߥ±- _MT7і$^&]j$GD!r>[Y[bߕʝE[G{I{Wش?p#3S5fuhuL[gG/9d'1s`e>"|7Q$"AE-I?ڏ"MQ9=)eE'kT zݖXMB G[2 WlQ9ddm+GFr6w؂9ш-uFsITr6l!nf[[{` al!1-BY]^uk,u̷xuI *>goYU Ozlllm1uؖdMw0T[\r+-W:19xϤ n[I{|׾qɖXEW-zl˂(电EOq?J;[a-|R6ԷsJ٢cslly}=h-I+ÓG:-b/1[[a[` `Ksb}a[?=ܻVˮ\ endstream endobj 257 0 obj 952 endobj 259 0 obj <> stream xZK#9ׯs= Rcp0sk(ò酅WfJަ#[is/_3 }`3?> 4;7$[w^џ^3^Op1^b^'yG \}s!{=Y Hz!LLpvfv̳"Wx?^~_u`D5y IypʃBiJ4Bk .(F#D#aG v EM \3.df,֐aǻrU/sIp V2.P!'e&&pbʀbof$t 0eA_-'#6lBFf!ِm6dSdRW+Šs A \=xt{xf|zX:c;IdA'HbDq&FX23'y"꒹=Qe:("Ȅ(ACG.<Ҍg^:;& CDޔ oAK $aTpZR'I?zVNw{ Yd y'AY{9 +cKrʵȪ8١3vaVQ#[Y^qmZTj%췪 Vi ʜ2p::ف7:M2I\;BBŽX=\6SUFhk%4vd;@ rlDlmi1%- JKPT\e^d-4SUVZ 4{61wui,02jNZ;*j]XmK*ier=vz۸V.TfP[Y^88=6-i+t1!,5>-`wH*)U?C_Vhoͪ<_*9inP3|9Gnl#=oصZY?jj' M\#4[V(m LMP]?*E?{RZq$%@MXE*EJUhV-+-*U&2Lf.* ̨~sID a =C~5L!\9ñ(D*ӥj")/lb銍(壘 "``U+,lȷkxeopڽH^;LkgD5Xw }Q}H7y&#`9j~5yo\5[Oޱs'ܹ]e\Jk%խŹjV|dY]ŀodOzzerJm(UYrZMe9FAUMulTݚn0-z _M>,OGo 鏿 m#/MѩE֣(G؁"2@F "ơ^B m$ q^FBeǜ]<(%iWφ2£rkp&Yz̋^[ EbF"S> 16"E٢TC|ͬVH>[ `gøS&L~0gl9JPlFdM/^p}($4A1=k xlO+Ԇw[^ESjNāS sO}޳M1vn̾* nn+E2@'B% ;J8a>ꂆDlo(8&?X OrٴZy`0T endstream endobj 260 0 obj 2204 endobj 261 0 obj < ] >> stream x휍 F\o( I 7 dZu9?w,~vy,L9hA i,UT7ԙt*:P83*۹s+FJgǶ?.T*6q5]hGg09m0zhsXp0&Ic[I=-<5Im8Ffzϥv2g ,"Ѳ 87J8ϊsfǑy,Of!GBW7ly`xQfv,9˄%\yT$f8MՁ/u^ots>ʚQ0RC+l3\ J&8y/gurQQr'xw&](CzYƁpQ4:D9w봛sZ!w~!mmǞ`8G_y~vv%9q*?H}1~ΗT]i6a[SChA$J7l};>oX3iT3ySW栥sW8[xZ%#m"&uv߶Bx*\fY pZois Eh#G:꧂;> stream xZKFϯy~Ij1Xk@!$l%?U~IMؒWyypu >}~}׋߷?^1â=a8Vfz{Szzׯ/*ڕ wNEv ۼ6||Agq賘.'4yE&>]N~~/܃R\&%^RR_^||.e’*H ,TtGr1gah/ntyv?Ԃ'G<\>Z@pJ {>MO-qM*D  ʹӦB&MCs:ʍTSkJ 4 nj$X;Ruu%SϾUZR{QWA;yhڠ#H5 uoB== F0u4Gw1+\i{69;%x_Eti*f-~k[/==pFЮ,~H[F^&_q& O;4FB/!9P !gL"%*c0<0VcFN.OV,f4+LUIeb)\St3zngq!A~7 ?Vz#1J{T9HCRDs!E |a܄rI'"БvyOnڙϢ\Fͼp.Ք.d;CF!5>;lO$g dWg!}Y~>*؊&Ǡ̓,!m%˽;k۳: C2InQa$uOӓx_b!{ ԯEdM 3ԝ%5֑䑲_PTW `6{,&w2 s͠ W@x.B0Nw|Qn*Qzw(dLx&gbnZAXMNzxjg^mn}"%i4vЫ'nzem^R@kK鉨L~kn!?aW͙ 5$>߭jt^ ӮVw6;AXn^)sB`8NBN^fg7|Ȧ8\&Wy*TA-.C ;]h.uQ+$LބSb:B7n([Hx@_fFP(ՁCᇷ'_dfIHNQwq5+I9!k*Nxw._7cY0P#SSm[ٲ2^8<<5.t#Z ϩXoze1f QSQUWD/ >;hvQ6U 'ٔUOowF'1 It9xdPǷyZeS/boñ\wCYC݉k@QZw; ,oIus}Tmk[q9(^M0uddm^$?b.ސ?_#aoJN VS'HOY9 lѭ5V[lTY Cnu#q{%f_wvg-O4%A֗xx,. endstream endobj 265 0 obj 2073 endobj 266 0 obj < ] >> stream x흋v />v]P=sSHpG@:8gh |l?ZOjPiAfAXE6 xK]Y KE6߅1ZBOea C}4_0ƠebBZ[zǦ^"9bAX t8-j8!h 1[G.l7Iy}_9Օ2hB4d|N b'Zg:z+KН~-MY]P~I]":}$SBY-Hԧ[ID'B[Q;KG䲕cA׈NdBѥ2 >˙-51e-(ŵk!Lda-$&U@a:~Hw,W -,C4zŷy oAbi1+ BIB iO,8I-\V3y0ikNcaF$ )oc45 juǺ~(DIӧ< 9:>]0e9 z=+0, Frtibrz?B~56)شnU^ba=ϽjD5WhXvtCT҅8V'8Q!Κt'Kҳ`q7 a|NFز0zuen-Hx11Z&^&T1yBع˾na|+;>, `a5zFXg3 h]讑J(ڏ/dg3R2T k ދ%22d'B:i;J21> 2oBgީE ٿO;ь,Ϊo,[XּJv0fe3 %5 ф:f.|Fvk+Z0> stream xXˊ+7+z=`_J'$,BVI& s7KjC3=GN|q=o7?4|ßo v/2?~!<C׼|cy{N#];FtGwvq=}@.͹z/M0A'{_~v&ĞW? ͽr'r_w_~w>dm"PX] G-JKefֆ@.,:t,w -HWcUvqg[+H8 '/yb~ q0CxnKLW4h{ߕ+38 ~eȷ?ƫݺv RzO:`>=ɪlV3gc>L)fMtQb9sMlv4f,^5ð"1*ħnQ},QIYanVfƲ$SEd2-\}4!6$DЇ|~<7%[Zq.^ږnHlf˶]Q͉ߥGқ R$q\RzE{\dJu#ÄSNhf ҵo)\>[4s}H3m#4c&x[bPitkeEH ztWU3}@knIqO\x| R4ȨU 5}vKZ",ZR/ݧҩX4V3xS*0lPtK+-Tǔ\5"CuҔYgFaf\u-+-$>$c[SQXɺ S{?Z8ֆL:dB s 7td;,4+U$C.0,nY涐bo X#McB_( Najpʉqz!n -Ҍ<oUJ64tpqwݝtֻ͙r7J''v5i Ih:;`^&UQuDWM} z(U\W3`g #$~ 'NpZippz$1s6SS'Ud-75Iw+ hm lx2ݝ/̎1(V2^jMt?I_Vwu.REnEد͸q| "Ne]|\t|NrҤt7 [8 /W-[kqUdOJQ5:ʄdizoP՚ak(z!ٷ_{EaղwYs:]ܴɵ)-BW-u.ҧͼDמNo/El~m3 endstream endobj 270 0 obj 1423 endobj 271 0 obj <> stream x=wZF}o-oi{SLҒ6% ]s<#%XS &=;/'!1G/BȧBl!Blk2%u]c/!d\lp\?uMȺ 2^YBP,!`LWiA&+K4`:&afk沪(Y{DX6P 6 # fqB%LeWX_yo68#dl`l@kkh:N;w ''6X zmUz{O l@G,#:ρoJ 6. b c1O{ ϝBQ)YCHA&c7 6Ȅze dBH 2Q l .,l .,l0l0Eal+69T ``*FA`X#` LAO`X# څ 2]X1 څ 2]X1 څ 2]X1 څ 2]X1 څ ƿvb{,3Gn7mH; ./E"6[w6m "aA|CbK-L; f!fwpl hMg7I7{=݋l0\OrqV8d$l"$:v '2\R1^:* m wW!Y[ljz,o+bMr=./=~˝cٝ J`96H0O, O=eC,+Aa l7`  dE6(N`Q{(}n;6|HtG 66Ȅva,LdBbA& dBbA& dBbA& dBbA& dBbA& dBbA& dBbA& dBbA& dBbA& dBbA& dBbA& dBbA& <\.)R^#0#jP ~/uuOX]Mg6x=78ة9:vg|xF4B60GMs@['d&?95nU_܇IOE9?G :p:[{Ъ1U$76 6o"m`. *i Ay,l6u80 4Ul"m`veGTp?*,po2mp& ' Jj^ƜmGP ?=<.R)) ڳ6B6؛PyF6{68leL#hWNRmpw Ji x=BUN68T~Fxy[ 5B68Շ'MZOp|ZԹflU`0 \A qk0zOǏIg5Oi#i+v~L>}mXei~d?k F(J;x[gEF4By60hvͼ;9+vs 3c݆cu6N?V꿥N-F(f!R 2]q|e؀2o!Bl!Bl!Bl|v n'!+J ? ű@ 6 `B 6 `B 6 `Bzm B֞b>ok."!d\JKheSׄ+ %Dl " 6Ȅze dBH l6l&o.ʋL%a`2"`'m`[ۘ1T[&UEf3Ol6N ĺ;v؋spb~`_~Yw 70(/xzPLl0N/HH_6N` 0&ON)lry5dBZ?|C`LWiA&+K4 ooY.,l .,l S~ JSTR,`(lC6ȡlkP65 fQ  65 2]X1 څ 2]X1 څ 2]X1 څ 2]X1 څ 2]X1` kk'2qv6@"RZnOl/bu|`)*/"6:t!rl`IoS`b6p~ ؤvgm@xx۽/ٜ1,gCN+ANcpb Å/\O襣J 8)}0Kz~Bz{Ŧ7l0 C dž\``MM=i| }w/ ķFL#K `٠l{x{k6Hg@ަ6pf53sb@ }r`v i A,+Aa l77)t6X "&'ڠ;E'g_>} .,l .,l .,l .,l .,l .,l .,l .,l .,l .,l .,l .,l .,l )/!dDʳԇ|.(fD#iK]ӹ>VW陽;^ύο"vsGÇ$ίYd P 0ce6jf>ɏENͤl=1st9fm~*|xF4B60{ju‡A8"uL3ɮs r`}#H"+î l}os;{sP<zr}}bMFxvAUH:o }kpfl ox/LAcF1}~#mvmO<¾Tgl@Jk,pP Tޥѫ N3@)U#Tp?56q!m;^`Pջ- U8_,^CP NjV 6un%ƤY>~#tU7B6ػ?L49W{s{ctRYD͓AE{_.0Sg_#VEyEߦ'u~Ϛ'@ʳN;0|@P L']3o;Lj~fXͭ쏕or #BȸcLW\E6 l@l@l@`tIȊyOCDql9%!3 !6؀b !6؀b !6؀b^r욿H`,,l_/iɺeP \kD>C&b/o] oK 6pK)^h 64T {` 7rmp=]w'$8A|c;>d#Oclc>%ؠ-?'fHcLIT:'=ÈWL< \spL:E'I íbx 1[ʟ_FbUf98kEn*6t5F"A;) /Ի Wj<`,Q9WԲݵy5|dQ6ؼN=Θ7\ wN^a ^_spgǃ~;X[l} tQeSv6Hdx96gٶb"?}K``)fw!S Pe؀2o!Bl!Bl!Bl|o!0nIȊyOCDql9%!3 !6؀b !6؀b !6؀b^r욿Hq5! 6Ȅze dBH 2^YBP,!`l6 6ɛ˪d=`I@%؀6 Aؖ6fw3_Ubټtc䳁MN]$868:`i6굁_VB>a. 6޲!$!l4S,>W S(5`86=3I`SĠ?E}$?w EdbD-\g -!bď.>* %Dl " 6ě[tA& dBbA& dBbBRl0 P65 r9T ``YTs(l0?u ``Lh@ 6Ȅva`Lh@ 6Ȅva`Lh@ 6Ȅva`Lh@ 6Ȅva`Lh@ 6ډ-lvl"3<TlۋlG8` C-X36 epF:ñz66{'y޼?^v/6gLp=1ŶYlSp68?p!Kz騬6NJ_? :ߒm_gmMm60{u_8% 0x,ym#ep)AzM,tkb=z7Ft4tOYl0dme)m aR#=E_ ĖJg~ &)m0Im6=EL_6shb}46sxS!6cHβA^Oj똸{l H |`̖X* w'xۊؽFlzFlKm*' e A!bEwg},o>ȣ8odWlXp6H\0 $ r#,6r=0A6X 3) 3em aHmp!6& 6eEr 2]X1˷`)`Lh@ 6Ȅva`Lh@ 6Ȅva`Lh@ 6Ȅva`Lh@ 6Ȅva`Lh@ 6Ȅva`Lh@ 6Ȅva`Lh@ 6Ȅva`Lh@ 6Ȅva`Lh@ 6Ȅva`Lh@ 6Ȅva`Lh@ 6Ȅva`Lh@ 6ȄvaĔg2"@Ksf{\ B3葉\xFv;9#C|]~2ψF(`iHcudr53"fm9:^??@><#H=5GhC Nv{kwZ:d׹D9F0]оP EaW6;9(E ^=sܾf~&~#

    58367BP NU A]_ QK#ؘӾʶAUga_E36 %ŵA{zBF({s*{miI] {B@8QA6A0B*~/oF(DIqOX:cҬs @*T&`==nF 1:,I m"mpueS/dz"<"oӓ:g͓AX ~'qwwol>ȈF(ͮw?gsnnߝc&}5zlpibJ E!d\A+. B 6 `B 6 Xv߄ON], endstream endobj 272 0 obj 6584 endobj 274 0 obj <> stream xYˊF+`~I#6$,BV7@&S]~ImO9Ub'>{pdq |>f1ȉ Vߗi4?S1dx'pi?}pgx6@ zѧ`]\ o￞eg6.GYęe9rve7>؁-Sx9$ps {p{;~bL;/DBvUM?/ewp9EdVa`飲qxUh vx[h4Y';nEĊ%/v 9SB,2'F{ &$'&!a+Exgb)Vzxh8ՏddkXxGp^ L+-nU!4wwqll޺fM?=-{_ٕœ.D-eIg 9*v0DR b>`$d0wDp[v8EP^br; TT . g@QV)9˶(3ҬIyF+e&%LqήIhtª٘lE)E uD D,qNLyǰbȊZziIz$k7)+!y䣟%;ʞ7֋ _U8e* Ѐ3L:N,G»vPf #B^c̊`4[ц"~%qEq;*1W{%mֽSMmOѐ c#HzVϠͥ3ck^AjJ.0zn]O]CMcq^O<.Mʈيav"-Ql[JĤzT UZM&BZH:)!F1*WySq tq%{ c0-O.fEf4|)b Ō!>)[ēD`Z'6RClh6^y^giIsL=?]SEkO% hiV &[CG%7hsT&Z|-HF0+?!p!-~)AnC,Lh?QKrN;ȭ v~Q]WC{E\^+TٹXv8*OPbeFyt/=!, 5EO3|,eᘮj/K(-+غwŻHKhwC!JT\R}ŧR9h4D$/=dtOכ5)MzG1k%a`%#;T'ͪ9,7הno拉xZYTt*7Ctxϱ =Zqb1BNHs@֘6gG7ee1}UrnI򛝜(i{ڍu*ݍܤEP.ȶY7(0t G݁y8VZC諳>$=xW;* w*ܽMazC&ݦLKe>>I6 O-XLL"p > stream xݭfaý .[8з m \8tڮ>Hu|ZGq;jK?aS >pt˿q巻H'D@]~أ/q] ! }e?Ã`][+5_}Zm-AKC|b!j$t;O#|x]fdd '!zZ놨>/j#ջNGhmiS!jhRG"XWVi?ˇ(}#u7,uO Q4EG"I !~1; 糯Mլz͌4;K/V׫787-R4D]G` GC2I[h / "Ht ;G QeYnaBH'D@:! Nt!J\ȇeoqEGF Qñ,kz"5 NtB" H)k/Zٸ~2Ì7252u{MJSrMS;o@&#-#zTAT_u)nATTL}Sr *O|[P9 Q   m\;D[X&DB$D녨JPm-!EB$DBV i}=OoAHD25D!EB$DB5Ϡ5e# ؾHH G"!3/: ;DIs# B|p!"!ڞ"D#-4$B#!""DB$DBD8D3LjW]0ST ,KNj~gԂSBt*!zLaJNm D+ebugy:|չ|UNUAԷKP9u *b*z |'|U$D'$DB$DBNH(  Q:!"!tB$DB$DHH  "!"!J'DB$DBNH( ѱCԼ_p!"!C4*B$DB$D 7)͍S?β &DCtLajvjKk/h]ouC4`ѼUO=SZ-D$! ۶g Sχ#Wu _^'1WgoTTLE?u|+#UAԷKP9u *b*D#^/aU-TsQB$DB$D3BNH(  Q:!"!tB$DB$DHH  "!"!J'DB$DBNH(  Q:!"!tB$DB$Dhv۾w3L ѩtCt;5\dzψǟzL-8%D2t(޸`RSBt*o!.[inTSO!*SNE? _/W˩b*ԗSѧ.!:!!"!tB$DB$DHH  "!"!J'DB$DBNH(  Q:!"!tB$DB$DHH  "!WmNg S QVyfߚ p B" H'D@:!h{z3f'P7 VeYItB" H'D@](MY,{x(>7: VeYItB" H'D@](lB" :!x֥"ص!j~"!MT"!zфNev'6#[>7vRoovM1 PF)Dp41t3/D#BG?#-{F$DpG)噣4P`&UKӽ[arE~)";!m> stream xY˪6Wx==zٖ1owCE*0z,pgթS%Y]렆IӇᯓ'0Njh*ACp.im?_mW5gue5Wo8PusZSYφ'k xz>> INq{rzK~ѿ~9}nu@Dܬ/`rqbZ܊qOkb/Lٍ~K5c%@5aڭlsū^lǎƫItSmF{ oIh 4|&MОZڲ;b9gzCw¢ltȰHԶb4dЖ'' }=޺!/$M:Ն]Ձjhx6jMfl6o0za @UyMglhҼ{ a;tXwӅI˒Xly0v -(]mƣب{2t-ތ̀;ΌEu-V/ m)dވ0-D g^O\h{DJl^KfOeUn8dL &d!KJt'Qe^0Ħ!:d e\Ds٩K.f :B귌b:{9|ha'="S)(%n N e;*uP2gk";ʵ3]Iѝ y4-j2Z"w=&5GUȡ!ǘUT+;zA;$7@]gPģ6/[y0dv B.4Z9/@x0ɡ 8u+csLd [:c*/tW@GkX|38c^wKV_KY!$qpg!Ʋj{|H!l]+{Q)- 37Y$3 $"1ܼuPMl(-=_O]1b(9Tٹ␋a f ?4TǏn>K3|+ )R[PɃXy U< =y轨Y}B6ph6WGޑE^nWšeԤG$ʌ\L<U.φvE[u0Cm=Gzl#\ۀ>77?:$,У -6~D4jD>sfxC8&/?DUn).?Y4h٘6pr`tȌGV8$ @E ),xySW.W<:iy-(ww[~| Fw~MC8S@ 3r+Qg%.&bZth4 R endstream endobj 280 0 obj 1775 endobj 281 0 obj <> stream JFIFC     C   K"  cm{Ol(= = = = = = = = = = = = = = = fbJ}Z$*ekD>gz.om/zSsSX\zI^Yl|uG@zE&<6uF[L *‹t;TU[up/oXY ]lS639͐GNj7RtFW/3x6O5oۣ~BUF[ hlV[wlwPz2dyӏRrP0 T'W.8R5m+Φxc'qyvǴ6D97DCә7ru>+KuoL|Z=j 9b5mBXnK?0K}I˵{ID-'˔Cc[]"ۧf Bm ,ZOY޻ss['+wSOsbܶ*UMB4\t?g|US*K,OGE?prW5irUG\0\ꡰ-f5fF"q=͕,j ˙@]#r FE@ܵr}e{O6VQ?؎h\lz5} ڹt3g7{2Vk8P|N_R: 3lEUa?yb6>neJ] ϵ{4RY= -$pZL_is8X7Sp2y9>! i INڍm5=pF,ңNJ˥3T9d/A3U-j6܆ƾ\>MC<^vXy u[YZ.5z|?6~t]oo5T}'ݏ0ؿ b^gizzex "NʥGRBsg^Jg >t>futa՟#9CK_w][ ?@z-5XX V <*L `uRҼ,D|<'fvDR49׭o7~j~Yel+,KɱN.wCsf݈U3[G*Fԃ{ByQPv쒪c:i/&kٶ]|wg<,;)d$73+Y\ \QFelܮT*%%nEE2#8 v<輰G 6Z{H&2bw#Yэ`Z#*ەArTdGxT,z2^4b 7F)" h7hAf☮F;DbPK@^X KpHm1g1ŏuJ*1tgE]2#ϭoSؕRUQ=R+;G` ʩI`$ϼF`G`Fh`+ 9678%H !O}^F*U!hBvRl&O6͜j@z-fVrI+ߔS:8˧/v48m-D]Ɛ7@ܗ`xH.{5=5s!Эc@N]IWzx8Hv4ncKi=όu#i݇ wa`wa`wa`wa`wa`wa`waxw)wa`wa`wcϳ25q?445126 A!"3@#$0%BPīO;"( ((((((((((((((((((((((((((((((((( @UW3Ÿz+j凳*hA_C))<\DzUtT4q$u[u?{*Li !4CHi !4CHi !4CHi !4CHi !4CHi !4A"%V tT>&Pgm\<{*ʘVcJ*6$ؒbJ*6$ؒbJ*6$ؒbJ*6$ؒbJ(6raʍ*6raʍ*6raʍ*6raʍ*6raʍ*6raʍ*6raʍ*6rk]46*oM8 kLGd_vJ4+U)E<(39Iap_d:H] #:].5Nv@Prkv"TD5&NiE=|C_VX*P:uzA }/Wf/bRHB e&CX3!kG/jۥT- K1uցeEx+IE&-}"$YȬ wkըkPT*+(r<^*#`a1~Wݒe^-HuQQ6ܱ\XIGG bL-Hy#eq5\؊hR1]̏*v#Y}+`ըmT*+r~S@D~ !;wҊFb/$DQ%e 2K\;~13Jr2mYCT eӜNɚ8GH(nb>M)!#4,VK ]'9deLi>&Sz 0`cigQJAgJ;QB5 p?q( @A!KT#Ml^_vL/~apab.WOf}`ɆS|c1nc[}*A H~h(( 𨨆KA],-R281~Wݐʑߤ 3!~H(b_/1j[BjQ-/VR@ar&HVpH H$ ?4 B₂xTTCu왜s% ~e۵8˱B*~s]x?ܹXnuq#Ҝ_`vN]Df/]E zekUwҤ BPz~KQ چb/&%dVɚXB]r O1zZ' t>h("sO>kq gF]A JNI}9C.p1O1VRcJL&5APz~!wf/J6K>N9 %٬n!C'"Dح n&>@3wGbv70i6H6yri€ޥ!wa^_vL""~r{guB;.2ڇȂ})AӃzKQ3y}1V >a6=\Fd_6T*5ILJSgP$> >ŠeHCFX$E+?v@JMgі vPFX Kc%pYL:GdoVPϙ˘4u~3:4k 욭f=Sf//%< ]O 7ÏX}8 K]p?x? ?f/h܍p .Eto!jQRR9Фd9RS r  :x;~՚F5%|$vF4(%ެf2 OCb6 8M|Uf/mK.ŊcCSclo,N7Q7(5r݉ Cg,clo%T[qn-Ÿ[qn-Ÿ[qn-Ÿ',~Ww>s"JQq>2Uk8=ߕrV`Va_do2[L)E~2DYu:7psIVps^1!URUpIQï<t6YȗïBQ/z'U2,I)s R<0ҺOvE%YLbc!,U5yWu>H, jh_dLJ?ZhPLMC#AJZD_45iT ZU֊$Sj%pApApApApAp@OOdz32m3-Y%P!Q#cSP>FDdbS !VnXbLf/) GZZXkK iq.5Ƽwn].\pˎq08f ]^6}z 2\pˎq.8e 2\p08f 3`p08f d)+ o)!쓾!|=W-^H>Ƽܩү»UJ_nCq b5*@%< WNHhʈk%'^s,Y:q!8fb/#71G=bd d\q6hX= ^93yZ#vhx(~PU}}|H鲘vÒ'UӍnHģxm l@cń[ U(=1 =_1~Wݑ{WQFE9`QFE)N9j0r(ȣ"0r(ȣ)O+u9`QFE9`QFE9`QFE9`QFE9`QFE9`QFE9`M2"bREʢQrT\.U E¢QpT\.*EʢQrT\.U*E¢QrT\.U*EʢQrT\.U*EʢQrT\.U EʢQrT\.U=M_D !1Rq2Qb"3Aa 0Br#5Dd@S?qtBI@+꺮꺮꺮꺮******(2\,SSb6&n{]v@>s(Q\S"neUUUUUUUUUMjkUdZ Y֪&VA5 UMjkUdZ Y֪&VA5ƀZj9VQgM6;^Bڃ 仪Av`;J k̖DcқՑ+ U8yrԙԧ?ֈ9(]("݀.q.NnFڥ'E)8 R fSz3gQٲlXlBs;v*ApڢO>Q^WfmVYLkVU{Ed7if4KYqqMm 9ሁSc*t`詣f=̧ #31HH R.\Zk8T#V;O \C-ҢNt m}H^M[>Zc[2{@⬫*N{,}Qd9s 4 Υ,ihOܠ1`0Cm3,|Hy4ӡPl8:2h*B #s1I5I AI;MrIh[7)sX,>;Obl_CVdiHСũ- fwf hΣ88,cW(mmH>2nB,GL*r4Xp:R1K4#1/1~#hZjXi[R1"B0ttѱ6T Μ('R*MjkI bحoRfϰpN>Zi*͒4iÕ{D5iMDc]֬سOpNEk<⃓\hTZiPd>l8+KRq#CvM]*esB Μ*(4)5*55ˤYt1>5{wXTHm؝;O)!]WPj"j2E cRX`aa-#bg~}tOa_M_M_MRxqKVt3$4'uJમ મ WU7BwXxq6wkN{?9ܱw!3M ಊw,psc*:?eN*vYS~ʝ'K9,pscXr;?9ܱw,pscXr~ I@!"124QScqAr 3BRa0b#5?CPAd Y@,d Y@,d Y@*d X#-%鏄ۇ/En)+ZhyBJB4(Zf Lti-3A҅h:P҅p-3i? L0Zg8L`p-3i? L(ZgB8JP+.?ĬZZlJ&kOo̴.g qRvfkbv/|*n>-kr sH*V[( c5e*)[f FZ DTNNzڕAEawjz ׈Kڲ[ZWSK[ ۧ6ɰ.﬋,l0YĂH՗ZkT!B*7'9=d凛f)ʗ,[U|9RC=cAEġ3踔`).vbՓZ QaMrsӜNTfٔry<^|Ź|ڲsVDSJkd\K[-ZֲVeecem*ʀA],觨*,W/jL6 f 8 B|EHD:M՛}k-|?:χGYT-iֲF[qd ʗ,[^!/jZ pd `VY9֋+ Ecϟܩwu;Q by<^|Ź|1@VbQ$]f+1WY?S+Rgac31T/Ub^>|ʣvK[&?7m|G[DV/7rGYeD"HԮ;腵;腵;腵;腵覵[7#-D-D&[7'by<^|iv!P~[o}sK[_;WWWRqg>rsK[V *j8z- מhn|a3  w̴/^{ez- מhtǻZ>|@ho-Λ|`MoǻZ=2нyw̴/^{ez- מhn|CuZ=2нyw̴7^{dp@ẉj߀ S !13A"24Qqrs#5Ba0Rt @Cb$DPScEd?[Q2'rc2ެfZԌZkV3 jaX5c0֬fՌZkV3 jaX5c0֬fՌZkR3 jFaH5#0֤fԌZkR3 jFaH5#0֤fԌZkR3-jFeH̵#2֤fZԌZkR3-jFeH̵#2֤/B7KZ.{>ϒ7čt CJK񴋁ߐn|Fݒu * WR!6K&Ej- &rW.mKɦfmjcQkG{ [i7%ZDOyvBg܄=&eK5RBT+oQ/ ǥThMOPԘ׹ @bYnæH*QTUocXq&|',g5vS]_,ge5vSY_,ge5vSY_,ge5vSY_,ge5vSY_,ge5vSY_,ge5vSY_,ge5vSY_,ge5vSY_,ge5zS]_,g5zS]_,g5zS]_,g5zS]_,g5zS]_,g5zS]_,g5zS]_,g5zS]_,g5zSY_,g5zSY_,g5zSY_,g5zSY_,g5zSY_,g5zSY_,g5zSY_,g5¬?%E S##RBE"] =PLĉJJ]^bz>=u=!:R[J ׊9q0RJf:FDӧυlw ,!;'e-XUΑKZ.gsINffwN8Ḅ*7Uޑ9ToIToGD]*HLoW:DoWzD3.%ՄV ^["kZӂksbu nyR#)!,x9SdR.9 [)mEڬ-gRBAyV1]݈8эf6[5?ܽٺf?Wь[+wXqwKl/Y o[ٯ}bqN*u(,!|ZԜXnB-MRQҖQB7>QlXEhU>xB/~!!Q $v9ҞQzuA#c<޴g֊3Fyh]+X75I#<޴g֊ACE ~gփaaT(Lg֊!iW$R|3ETpV5G?- 8Mq#!wLIE3HՆ [H7HJRL`lz!Ia$^l]Q7Cdjİ-픀|c՟F!! ڤR&x!ҕQ8̷6w" HPĝ7!e(JN,SB7٪<Gh`{ 5Ď9q1+A]|F`iFİm%E/Gc!MtUdC`x="Jl!)Se*?73,TڕqoC8xZH}4J R1+JBvO=0-S`{#j?+xMq#!wL%s*#:z!vT XQڊ޳~R%n!\ܣ-#33Lff} "r81) &@U2 Ъ-~yjK٭r=u5G`VPJH E/eӅAi47FzXO \[u5CФ%B7NjiE@Z50Vg6? rX&;&._ķ"s Fui(.=86=4䉮VwĿ#½ ܅} #0=Vq~x&;&<0kjcƒn.LU+u8ah7aį7c7bd*2\wIꄧ f}HS Xu%$V>֤6c̘bC&,2ҧaT{<r3fquxDz c٦[d5P=?߱x< =XQL]0Vg$?!XMq#!wL6[Z47zaLJQ9|Հi U*3 km"҂j @[c0I=&Jkw2zc{'%}9nݕ&U?Hy62]d /Y\0[«Zֽk+%@Jێ)DQl$RiXmaLK\tD|bM%,iZ㉖Myң@QFO48;>1QFDzl:Ժ"a6<8<}3o0ݻH4HY"V4 >cJm]e<P۲R%4&G L6KI-pqĸ/x<1QCbZTm*>L/r>n ׮%hG`C︘KJŶ|h߉ܬq2$kbW5! Vd 0nQMHdԏCn@X+$QXKҰx&uϡ0 NF&iZG1[V-)Fjs]QdK7um:H!_H{J\Hs=A|=9ŅoSr OD>}p#f??Wi?!_Is{|J\HsSDmط x5Hk`jڥcCa{+b2cuXXq ;E;z/z? kPZbXf[])/Y!vkE,qտ;,~ŚW.kg_4F\/r>n %ľ5Ď9q?=W\=*2ďj5Ď9q?=W\=*2D\HsiT*l . ^+kC䄸SjE] z[[nn8UF֪>U`5c+E+M6["A.06R-[P iv(t $*Tm8 @&ZfJT4 imJ Q6XF(St#[PԒRT\oW\=+q/5Ď9q10Y0ݴ͵Y ڛT$ehxOhKBէUGuun=.)KNR RiRt33(ra l$!-oc,3+n{P3:1 ĸ R(+m,Jf$JZ-Ւd 7\vETI(kD%aAXW4EІJ*55D]P8KY>.,Rу  ܅}oĶ-7zFJ颔(} E7zFO]Z)y q!bV4n$c)r@yJ$ijƜ_tXV^H藰Ӆ/Ğ{4[DؖKh$#/#q'(̆SuؒO-,I-*#M?8In$/r i粅$Җw%)q*P4eP,l+M°㘥S3NRiྵ$*ZXţ[G'I㍍u$.uu-7y#dZDDnˢe/)Je (ݎ+[kfvm,㭶i +5 )ι8{JZ]ܔĩCDRjVU5hcQZN2 l4X $⌾K*LK6ֈNc)s&&[u5Ď9q1|?5bs <=Z8vCJ'^+>[c1xմۥkS\ٰkf?޿я_Ǎ[JV5ɂksaT*f11 4pU +cL(E! !4B+4 6@ƜX.گcN]H۹KF#LR;ŊDi xTzU+2\ɲ Z r AƉe[*B(T &1g8G]v^vakrh 'sj ´vMZmJPPR*ڨfuͮm7N)H.RR:g\El ;Uh/spMq#!wL.o56TǍc1j+KvTr7|)X Tp0b1e>uEW. V{ !TP)1wˆn5=,(SS”r) xڦJb^|Dp KqdoY.K/KqdoY.K/KqdoY.K/Kqoi.K/Kqoi.K/Kqoi.K/Kp\oKŭ @r\Hs,?巅DN&,4XJ YYX?pt%cv+\ \Q86[CM TUKhRкWbbYX[SUJtjиS) [SAr d8m!Md*nNO((LL#&=@`_f?1k?Nabh˯/yM%,.츲F۵pO$K)L-5KPEPHRh<!6'+P۳N5-+F.ݶX!1 SiZ6(WyI%wc8U0*8KjU=3,SN8bUbnT{^rCCNn.&# _ď7\Hs)p7U+G7#7d)Z 6+MUXj\7SKeE9k]M />[o%/E$l5QQU<|#u8Ī^6i4 KBԌ0*re2ĺM!N%aFkE`͉Y\nK6dqb LQyiX7]V(Y).-ݷ T}f7QhnTP]_KIF7Q:9lQhIxbʳ,R RAB ^M970][o GFa;{[ZM) xL8n\Y+)ۊqTm<% 8h 8a.8P\dE"î\RĹMV;Z^rnaYi2PJ6iTuד|Vneś EZ,~Xjiٷf[XPq6~[tEKAAvRn4nuFɭ7S7"ks`Vf)U:c}]lWG<'t|#}]lWG<' bUdƶNlWG<'t|#}]lWG<'t| @ˎ8Ke$lWG<'t|#}]lWG<'t|#}]lWG<'t|#}]lWG<'t|#}]lWG<'t|#}]lWG<'t|#}]lWGhKm"R(Mq#"qTX+38*38+38*3c8*3c8*38+38+38*38*38*38*38*38*3X*!1AQaq񁡱 0@P?![t 1[s Q D@HО34NDy'DtN:'DtNѱ:TSuN:TSuNr5p($ VҡI57c(9"nc-S?̓o\ ,Xbŋ,XbŽ @ @ 0` 0`Ga A̖R˝v-4j(801Ψ*d,(jaTAPBۚke{*M.n%j.`q.5J"-w} .%S˘)o^ 8μk{kьro#+^ygc}P}&WEp(x;&TE5c-S2%*Xq]Ի| Do908]ր%A-^@Gb:1?1q="j9Tڑ5FnX$9[g8!Ϭ9:GGH a];;juAsbF U-Cd<x,D-b'\ Yఉ4 c<x,ʢ,b*"3a] ~"J$X(ZGKpEэO4* :?3K ~b1c]56|Sjt>awpq3rctttPvhs׶_ŽpZ54LLc, 'v"0%FPJʜxL K$[@<җz[E b<f/Ay`@IȲX cGSa^|-:H3N طhr/GR!PM_ؼ.nx)~-$O$F<ܨA&FC5dٕT4~XJ֎; \4%x2y?{A gv980`W(*Ǧ"ǤZH,O|cgza>dAŻG[ŝ7w/2 ]w\.l0\Y|Zۭm  Y2ȋ3,1c Z uaWw :BVnwWK~D\*tp|Y`,5spaW/mGI5?|M/C:~@AnQ߿=̽gޣpfחwp |b]Uu'x;==80`gW-="(b2:jzC z59#fݣ:"~u,mqUv,ٖq*ݮg@Imiz粬^lyp.Q`\aUZ~ gXC*C1[O9AX\ x{éSRZYTƊ֍ݼ6 :?3QGG3-}ca^ɡzf8  v sQԇH]+Y-md3ӹl!VAfFM¡rӄ\< BS{]Kω7yxEE̠VVsy4W*] UF jo=ˬ$FDZkohA1Nȴ􎃧-#޿ɥ:a;$:Aq_U(͞ngxޣ6v =lg}s?=&XgtZf,kQE84zC;1P3s82 0H#x3w*\Zp2&6p`TI@oK.iUE]=b cW X|usĿ#9iʫ|QG "5WDebmq5zŧEzFb":j= m5MΛwghr 0-8FaYoT4Kfpܶj|y 5R&9 _4(U|g~sF`%"|,jthRZ)tax^hhsprh|*;f7Wp`Ǥ,Eum4C6w2;ݝ/iL*0JBɄm{{.glޣܾvw 6{igl)o3pfIQEL4C)wgh-iU69o"Dr#m_ZTkWEWtxkufho=[ejUmmapHү=!t\7qMͦ5]z5&`wkﱻ:gN[{G zM^^.ТϬ^Ӭ,0M83*:S"gxG7HyW8T" qWܟܟPb)-gVդj ;nyK*bwVho8 m كI[i9aW 'd` 80Q5zU^aYÖ/V!wvv *: GR AuM*7;8!;% m{{Kcȁ-]ʍ.lK1fr`2D/vl]̆jv֊/`$ԧ&MmMh׌,yԋYfB& GEpa҇fڪ[t+VpV LͷRohk›)y>@ AL/!j*Vd!$VrZ3_ S]=#u CZFX-ZqVۣo ; Y7hS&B 4["`*ErV3qt&IK'G#S|9v{f{zóG퇥6xlY_ohn [a4kz~_8J)oѭQw.+A ^x[}K)ODM9QHGR˺n->iUE\NRAi[}J<e~Sy{QYE->}+ח8q4 Ư[}K:VSܦFJ~~Բp鷴p(r|*PȰֺ>ZJ d_" tB(K#Ts臠L9qRg "j R)Yf Zb]w@ @Sc|3(‹4jH05 K tB(K}OESIh-Hz=A`(XGJ"G^ C+n R+ E0=n`j$Ixu,3 էZĂRbD @kѕ—Wr ӐG>dUض R]-T[T>u*(d àGd,Uf?$%EA@h"2R?uȡ wcN;v?'cN;v?'cN;v?%AF$lPY v b\-XiHÊƛ}YҨ Rj0a! fŅI-8u u5ʶhIW2A%M@O777J `^u~YRd2r[J¬ ިrJ3aPҸ<6cW%D ww|kt-Vo;Hx5kƜ*I-3pC   [oi5 g;<>]uӝ뢱nd,"ӽ0dhx9>,tv]P  55wMRt$XяiՎx,B8ld{nq(B\Q7`Zӳ@V(@^]SzQtD\cr(&EVozՂ;j`EI)jL.+Ub#yOż՗$xVQE( rnZK\7q^o Y+IMq 0hZ|/-UBMsELXij14A6,& Cς[.VOŽ@;wIkꝯv`+mE X൒ -E۷#@kÍŔWCfk`‚Yۍl3$aq %HUmfu[^!"Ao0!"Ao1iѠimfkM l;_T}SN;_T_c as`A,eI_Hs]s$f7۪5NusNz;XAZWfF]SuN: >$#YqQHI-!P"G RԠSPn(LqTW):ȣ SoƬz 82.HkPEN$"* K%IVu1I`BN JRA_TSuKqGWkDZ&xx,4v@[ K) ux49Rg)D:"PKG&!Sv=iN@@RI@WλSʩBX [\]`)?bހ#INrs`wK27MI `T;)\)\t7b" /Aj &!SvlkA+XRKOc,VwN eMSpf݂,jAahDi:T.JX'99Nrq1+OMuhE*@6@$(p @ @ R 6cK @ @ @%NAeFǼO9 5g>O4NtaXǃUE4_1">ك< 8u 5WuO q3hxqup(!1aAQq 0?Nn~s3g39fs3g39fsg;9I9K uELG Vyo &WjM_5~&_kM5&_kM4]wt1PqX1o=! f߉s-&C2x2˗"%\\[׺,|&=.q f+S\IUGS$fPE-* @hwj/J\sr")0BqF ѺKsQޠ~BHP rSa{//~VYxcvYr` P~ϫ3_`) [G.BЍx|D &Z]π#@pJt%VdLh+Lnj8|[1*̤U]- Z(橷M1-հGGR?3  8[O . *@ZB).9RډL z *L0 8` aLS rL.Lwh\lȪ19/PrS_06Q6@ n=zAM{DPaEoB΅kSC4>ssbm_uhT ]JaL.ǯ_09gQnSP@KD# C X:c]! Ɔ0}-4yE;FpV(+*90f-;QgLf+SRS4ξ|ί%cڳqL q+ܲ}J>$} y22WwcRTӎ7+:iWͪ,e1٥gEEU+YӯNL>0l|ǂ9Tn{G弆M`ָŎV#QDlrۖtU*tgĞ:Sd63`K{;G[2ۘ0J`:Nt9žcAdf(ReFcv[UQ :]Jxx;l7.\rʳ7oLab_Bz)b\ e1#p‛?&|R:n]WWEh޳ʕhzag'7ؽR 3qBK ~OUAce3%r?RLS)e2LSLQ ))2Xl:++°CI $܆ OXhhhb)؊b)\`uQoWs(!1QaAq𑡱 0?4Pyy؛blM6&؛blM6&؛blM6 7hR%Qa0)* bγVT=#**Gvsyi=syi=Cyi=Cyi=݇GU&X^ʌ Ѭ9Yu!$AcWꅧTJkT^V5~;H*́EHIOX"Žer8*V_%LFnxY N%ATaP&}`1s@ϙ&a&4SR.(5'}=n ;F!ϤumGL &hQ; \F.F):L-RIf^=c.KrR&+ Hx'vUitG>G$Ǵ![~߉|КGȭ%[^jyŘ!*/e,B+NAYžO3Ծf`;~?pWUܾ JM%^X7`Z0;Vۼ Cyx8cD3`\ 0l߇+y(I0Tw=<nZr_90r*d+̧}F+z$a(J)OG+"XCK( Ϥ$۟_\dR`SK.=_Gu| pIoD/Z]EQ_Z`- k{Cl7- 5tun8[W‚_s^)BL(̹AWs״DK ӯ5\lD.3+grtk2Jְ +-jX8Xr+I ,{FUM &Mz\eG| #(f$_ iI \iෞ5',)𐦙~Vy薮pJ`@rv LX'71N"L$Žf Ki", 0`,4rOiカ%6e2[Hc2 ,%9M#&2S]Gs{dWT4EĄMBv0@PãWw{KAh-%jT;ak\u: .#&a\$(,H@XO&^W"%෯iE}GJk&l߁d)`2qL˭9*ϙ8{E>o~x*7|%J4i0aI%J4i QS +a-j t4e{᡻-_}] fxhnT@gM56l ˨,=Nh;ͣ׺mbK2>gOyt7? OZm1|16WἵP*?vűNmbm%%%'~˥K%d-O:SE?4WF΢FDo՛>&)))+VF_SUUUToˉ%5'{D""7R_ ŋ,Xbŋ,Xa$H"D$H"A 0` 0ʾ٠ z@yzGɡb;:7X2};G-5˝u0uW(H|) #-`/U)J?çhd5U.$7٢3.bGa.HvR,nA5!&>?}ç.08l[!0РwX֒S 85 f o&Pn4eB@ܛXj.AFg9Qy 9y,nwy Cw9^A6} 4-K.[52sfX9-2@]d&T8µYn096S`.P!1qq`J)'q`p!#+P3N^<+5l p .nM&וImB\{ϭ<-0/(5pJ6Qx3izXG\߾Az.6#\g&"5G,V+9]Ta^Wljdcs+ovw❗_tje!BD(?338 TX(R_j7 9mˉlb`8ĪߣX{3 fꂰ8:5{ڭ s;\@A>psbuώ8 =@ۂL @|XES_"Y]7½ L\woEހ׹]&oTPlJ;qz .2/^l|46@`.90F]`խ(C fݵa7Jdh8 !gW#%+!ڭIJڄTK1UfKmn )" Z .! T 8&|nUIEw  l ~l#lHrHd/5 @EnmVnoFjƚb+^j\vi@-] PHHH@@H{$/Z@t]swYKkxZ}22!N*NΔ|YfVdt!=%]߀QM'io kTt9֫3X|\[vw (r BXh=46\14Sbk Z*#"ݧ6ၱ4C"6dZ1MrImz_[C"P~-gk^T;!u9ϟ>ioYN>jgӛ4jXDwqzB<\0 :)$@pt!&̈́mU}Da P<ߟ-yOmWwR/SA/&bbԲĘ=X^ۘ8pK}B}vQU֨5i mDǶhRJ&ӇOiCD[0CRmi/xpTw\oaYu@k0a::E>|Z(_ 1? Rufk0 /oԩV{>8Mj}օsʇs7P"޸jxmIR/ai&!" &ͣqpD``` 4tB `'NE#"?HkOdB1 +\i@v-c GP¥<@L>?e25˖7^c55tB^ŭ]{&H&}Dƿ8k|ʅ^An6 |c/HSo6Z_G 6v wPt1kP[{{~֪cLQ{Zr1S =ʹTY$ 5RYBSMA j0ܣ(mvqXaI+kŋ @Nf95 26*-LՕJh3'Lh(Fzz+,]F=C#\&Cȑ4[`C6p pЀoH'-2s@Q7r7R$FtX |%g'$ݷr$Y:TD14-tdoY[{}uSXuPYr;܀* 5o X"E",`u=_>|"@ $ޏg~#3yϟ>|ϟH"D$H 8kzh%r;tJN'&aB-$|*Q*;Zw@:h3 qxORU~(i~M޶ ]o} >Kpŏ2\{nhh,. n|V/5]B͵?ϯjpPS 䰷 ,nj6-%qcIP^)iYX'_ފ H+\j""#tq2F^#1XAoI vqcI/u7T~i> stream xY[6~ϯdu$ٖ $m`KBa[f_{.,[V<;,a<$K߹_wxmTp؁g淇4mzݘN5pxj;vmf֦5U+ç_B\m8_EHy4t΃9vxħOjTUj;WãϿnχ$*'@f9q5I7'ፓF8w3pCXYmi?:9&Q8",|t'kE$1ћz$!%fcأܮcWp;r G,N]w+ ,3{' iYb".D13S]a<^۵p4knCYD3guO4m4*IXn'aۡUQ*d!Bi3 dxA*+C 4 776jl6H\ $597Pmh0bK<JV_Z>/E,O!AZ ER6u ň#;Q4[2jx'rye ;Wc4ȘNuI3V^n#s$eOn1IVʏSr?{| }F7QpTx_ӆ#5X&DS3{mcz}Dp, T#S2tW%<ѩvND]I>_Ѻ (wcEL33b`.+ ietbuO.Rȝ3[12Q:ېppgTv-&ěĭ`3gsy ]Dγ^"uLzgU7@P$ EG4n3wq4QoᬔX5Ӈ):(x^G 9e^Mjkw+Ӿ'իV=S^rtWTLFψ U;tL1bVyUgpF=;x\9'hi%жp/#mHyݥz8BD)F>*6E:CvQ5rm+:74Gwp]9zeRb}H[$QVSᡂB;uJDwR;L4k}phu3hpq#Ǒ)BhL:ڐqUq< Mki"PhDY|@U t[Jp sYb) 4&tRk(ADy\kxV|=J^y>yJ[.uFY^m-fe%ڊ[2,2 mIFx?l١}V,HUm7خ`. [*6K0oÔW,PMq,;}TҎ{kX3<,ˢ5*|[2K#Ebv[5dhb!OD6]Gԫ12]Y E` ɕOJ[H*T&+&c̋lϬb,pluxa`.miw˼sឿ߱on|h_7SGbxХ&;ufg)ZgYsϥaOE_#o_`]ِ9}uLUB_.4?^~ k ptΏ5&=~\=(Eq /&/ ] >> stream xv g&m&ۤIW/|Ȑ3³ yzxߍxy~{|~[S)_a&f(ǵ-ClvU.:TU.YlLftf Œ0Yh6]6 ~͢.7\Xt]5il\1=WYONyRY-V;Ř {}fi[fj,z,ffYQXH=Y0Q#A٠sE5ҌgEjfDg$%#!OFJJFd,Yʈ>aaRV'0`&Ԍhf6ի3 ͦ: fQ,me`?̎n-Jf<`&ɣv/S C<`&f<`&Ƀ_lvQ{%&լ+_v_KI7wo x'cܛTꍾHJ{Ta`Fe޵kl赙Lm)b I6k6Ly;*<&I=엿boea]b0#3yLȃXC$s *&",'mLiĬݟGZg U,AqEDA"b"F fDhOyQ<ȄL%sb`mԭ.DY.Q"df4xvM fLUcvt7$m4 <7fo|vy@so"$ᆱsEd3Z~*Z|g18#v7|O5>ŮI7V3yL0> stream xZK6 W<@z! 0$@{ @EOm")[%YNv1@fbIH#NQ?;goo/׃l?)WD ?^p)S`N]stӍT,>(Ž,&:&6 y͛HGEv=\{؞4Ҟv~p"|g/mm`MԲ85xtG4jCw~4pJ HH-"qܨ`d'2`Ohbsdu| co sV+[EjDPOq<'Jh~%JPr! U]ޡAu Ӕ0_Cw Ѕm4'xJ^\.Paqz:Ll.Ys~ChܕH|ˇSFuI;F$)b; u]ۆBό f*aLŤ:$ln3\RԳ8}xB5e+*i & npD1kY׃MQV/x4{-ԫA<XօL-SDQ wu4^5NXQ@AGaGi=.D9Xh IGf͢RƤeS!6C\\Mcy'$n)7K9g ]&mu~>ŏfK{=#&!άk7J9ACp@VwԖʛȤ}<ɫb73"8bY[7 *9 KJD8^BF'H{Rlԕ7SK=T/p 5-1X!ĩ hOX$z~)5?PCXeoz?: bޝJ+v%:,ҭSuQed.apǪX Uip'Y䬼nq2vWZƟU&w_٥|F%WWyo0Kxeπ]u(mRJ.y :fܧy̅^ UTln]\vO:G }d>L]HggW5m;vqs^YMMM{u6mO`:|zykei͋P.)KŮ^>z%̵/ [~.Hs.ꦔ"@ ȼѽ^.җUSU0q͂_AVe}#p'+bڵʁRCD0 ?&1x{?H)j endstream endobj 289 0 obj 1705 endobj 290 0 obj < ] >> stream x흉EKgPTHB\(*$GTcЀ]D7+A!"(-zx?飪^UuTTM}dfmWuu9Ӟ>s;ig"3|POzҶmHOքD[ <"x4YxN 3U ¢&ւEu;bjBߜ%!ԔLm(RXhfBqbG6)UͤMn[ǖJň1 k[?a`ھ7!p/"'HdyErnI&o`LrZ}< `a jNO5Wfiw:,H>CńU78!'xD,X#bG,qf $  <"xD,X#bG4_М0ZB7ڷ%I%/5y.yL 6ò0 5࿿o_w=/RaAڴ{]w~}Gbjff|'+FV;*d=Fjo?w|+B]FdJY̜:U(K6N>T.3YrFO)L#;js]}¡bVXdam+CXՀ_]/߿ Y00w b>@frKL^ ,~?A2~(MuЗ>}qߎ:(HxA,ixǯڷoUvo=>(QvPz|K|Cg!n_Eϻ`3wعss^n/6}衇O<N[W"O e`%[zru/[/4XD VO__O<2Z"}b_ QBc!9  `"_h! >}A,Z  b1i0XH|>_~a_lW06wG _IeݝWGbC~!E~G,|M`jz'THթ S,1Lv6 $JXK"&daK  $D|쌚zsϾ[M`p;GH:n;Q}d E)_Ψ#. X{ _xXMנN01|՛naqI 1Օ奥/|0I"nG?ε'hOkFze&m~Bhp .xƎ\zng%U/n.tt1~!T7flwW/EDn HF}> _/p_ń"~?~A,|_^t =NM@G@)ڱ0~B(P5I6/<$^6C~5)~4.|twy5c G"UY5ۺrfΌ<5(1{-;@/R %+++CssЎpŊ/%K&>5qЎp񋼭gcE2e$"/1՚.OMBXD]C;/O*Mkh @ VŢș9*ڱ(~Q9ˉ/kо; "ԁB) <"xD,XŬ # _49{`R,HD,X#bG#Qx7)1`sX,J%V 4bn%Ĭ`,ЮuVɛi`pmrb%&e1`Fچ7'R~aB:k#$&L\F!끚X?ac9 >Îox2?$nEQV$8> stream xZK#7Wy^I~$L lILVKG8{'_h/_wßݨ:D7L}ٽt}C7Ƀ9E]vw^/]kww{Ԫﴃ@IyzNQOpio?I9崗w 8 tI`{YaAI$5d8K)vz$iW>VT@|+}jK 4M9L֏plYmE U<[`M!W[/NvwW7#fist} |VLt"Vz;p07nC/vꭌ3+QʞqC{R]6wmO):U#pCь-؊f_ϽSY0ґl Afū[*d+o2"U.2+X&jDߚ಄c E CA37pwA\evkM3\K9]ŖϤͽXY%|5Cb%RM`miV%Vl% 5mD  HD1"&H KnL*"O%.s1Zp2TZ}KaYIzik#Rarj;'X ]>0JrMY6wynkm: EfLc*BFb $>3p_5ԃ}:dӈ~p,VqNCuC}yV%9%JFJNƟL)"xъVߓ}}`3M͘ļO!$5XV.6AlsC5i`4Uq,+>sãFқY>R݅j%IAci[WwFI/m}biYl )܈q5{^(Kҥ+rbDK^tF6]U6Gi%sf{adcP +k|푎^3VZ{wl2E; ] >> stream xb0 ;`sJs8,;u7U}?zШ7Oo&/ˏo_p"QT>[+ NE\9yvo?ezgLW8"g`x]U`9(ٓ fH]ٌ/:uVWj&IЌ9 r=. OjUS&xګMet <_4L=i6+~8ICiꗭ\qvGK9pYD)WUbiu$pH1WǸ7Zaٕ nfLWZ,j.a կ䃮mF90WKM\Ţ8)&2i)iFlJսv3j2_jV)+@qWtֺҖ~n;g8 F\tyS vo 4zzr-q-x^XSh! #ߔD]e2QW:LfA8@]e2QWɮҹ {0U]ObKN+%|:$?\}]kՎܵm/9k\ȌS+2]׳k]um{)+Y7njoRWu1ף\)uD]esC/z/Q-*uD]e8kd 9pLy50ɲҮyU@]ɖgv4lȾ!UB\[|/,L+_̽D b>9]D]j cD'Yxn)͌6\+`}SLU&ztntwG endstream endobj 296 0 obj 1123 endobj 298 0 obj <> stream xYK6 W@Re q(-v/C< A~HJl.P{VlkϟOP'0jT>8Iꇇ/\M٫3]]Wvx5ugx Χ9#4awF }t9}>}&6z*h/3Uo=t[$߾~+O Y \5^8o@3ĕ"ؽ;%4  a2#FJ_rR,VDaCƩ9F DC˶xU|Y0 N=c7hS8` @cq4>Ј# dZj,B fq0wc!EHhnD%" tG'UQ#;P8Kz4O2Ɖe qݱP;RdQCBѻL5xsC4C 7= pfO6[K#u?X1'Mp}r_72u=<(etxvV PP{Ud4VՇprƋ m:B< 64ΐ^ťHm){|R5'j֦9!K:ug(|!wzJ)蜟S)e]w~*sT*tqsgຘ`j2y6i..[F1AJ&"D ā鬄,ڹiH0M@'fЅh!~?5P*.1:J՝bwX/4o"ȘWT)0~l\uDRexᔭsN|a#tN>!UaaΤ1aYaUmHF>#¯L"'d9ml2'3L V'AVkhV!O z(+cI:Ruf:sa)*)=9aYK IfF&5 #a;ٌO=a|tB#ݵ+@|80ƪA6";-{H@{ڈV1֒1dЍݜ(s= ΁♒#]:cЩXM+aO>bH7htB;x.wa`+'1j~q:qS-~ YE+404){f+d=qM诧X9p::лmb~u2c%?Sr=m9X,L7[쎙jݍa E RMa*igUˑZ5 WENT,DZ*۷)+R} VUYjGM:n]eZo'{nX+2:v%89Dj/;O7h-ڠznjQܤ ӓ8h\qhuJf'ԫ7VW tNn36qW 1O䕚Nۣ/NCoi_F`>R,6]\Ir\ endstream endobj 299 0 obj 1697 endobj 301 0 obj <> stream xZKk+7W:`_fF3qlhw@ڦP-H9iZ=#i;yćo N\loOß>\a0i_C~_NinNaې=7o|QrJѧp˯×^^"l\~ffgr]-BΖ)y^Q\_~<\_NLTA$aA餉x %s\+ =5 81ח;QPa#2[ugS≠=7 $Ks=!zٟR- fAhBxd+ 1ivFܬ&\L}cc] _ kC¢b%$H#JzV/S5B1Y_V2(b5ǰGLZO vkPcl`B95{jX''o0gG$aZrst|䝴7z@ţ2$PmgkBU]$2,Fc XD tw^s!n;Ԩ}#"ۆeӳ#Mlk{!vMjW ;Y$ `/`luq<]-ѵ.*".uW>bHEݔ,@*zuq\Pr~V7=OF#o >S"4t5sO&Ë gdXˮ܆?8G,^+XY=VlAͼ.k۝+~ {{jp-Md&'9DS ] >> stream x}G]G)i/ ' ѣmZ"M!VFj_&ƄƐ#9 1Ԙ`i=W#Q.Zbi-"^ڐgwgvev߳7Kgv3+ 󊮁eGc<´M(;eqaYtB,xYDk,Xd7E:E6(1씌r3p>1[ND"r3Dc̀Y` ire­\ |3DN,dϒh$f&i>1EPDXm`,p{OBĢ(p!/!ʘrwFvU±h;yd,&9sg86(x„qXЃ5GȂ6Y~$VM3W_  " qܵ`ٰ֫${RD^Hg!;m."*+.(IrBL"Zc]y Iba!!|ҙR!'Y*,BmST:Q^/rfG˲Hb0+YpdY"t, "1t,>";ea+, 8,Ȳ#, 8Xdt,xxaQx1VdYeGYpdYeGfۋ Ͳl<ˆz]c{%5e9E^:-]cY'i;p7=vr3B\a3Z,PXF?E dgR-TKlZYΥI3[9P3C܌&Ompϻa91fiA%cd9/&,G@onJ+6$q$5`O`:/UYX2%sZITN+ pfsTļ`4qYCYdM_$4UK&(z&vG f+ ,m@:±Er;V@ lXYsXcZZilȳ.Pf@|p3 pߍ|ҙL!@;,|ٟsE|K+ $]B3`]{47s1FQ,^kYHR;,rЬb6E բLlp°Np[pdYeGYpteFcCf,r߁Ĉ , 8,Ȳ#, 82Ƣ)2hv)i,-3 )@ BS0VM_w?/nQ?eG5W>p}'O܁l~388xY~<+_Ŀ}q(8&wj8pv_,DQ=pmݎB"dćj:mxv+w rSL3&:ڲmx7=hbqgxC}&&:AU#; ddXQI DvbD 릍gZCؾյ@YIe}E#cc_?2t0\;=ov?}?kT-a00AS_7>ۿ_QR[N?&ďܺ}ǎ׭ӛn|Vg}gE i4O/ªK~fK.|Ž_SO?/+zٳ/9ҲmTpXԢ-E~!rx~AE`G?Bb[q}k}y0CY{>ʈ_`o#YG:[pX(Z0Nz0xt/! ZC`4oaYЯG]`1N  K @|!Ӗ/d-{C9>VFyxر=s *9FcrrbllzHn}hUQOpXZjg ȰVsǏ=22yn0gEIe? UVz-&wY֪yU/t噌JK nA;kF` :gB^#0Z^̝SS׈iKIX( Eʹ]^$_4U@ZUS,UzXSWRg1#F$u qesT~~Н?2҅*uzH΂nԪrF:JO |;*sPzEqx½s9,+Mzq*z͛ᜧggT$odgQImkݭWHUE=>AP$%k%Ge{߷?3miUQO{9<7 :Ѹ=J:k7)7Aujpqt_,.h9T-N2=Ir/dQ:B~bpX'&x [J@#irG?xq5>=lXqpW|\< TK >VXbaE?pTSt">A\r޼υ֜¶>K/~|tYR/F(E-seIn鑑FXlmz51EF(E-3/}E;r411`APxUq6t@V :gnY{bWQ{Vu~Iu,܆;!i8dJGP-[o%VɢNm7KH" ~6 2i:o8yӰͱڤ(HEt ߈/?+IiydAعqڨ(HEtz_vGod8oԨ{Bf4-PJ/]S:}RP&GodipeQ cdU, 8,Ȳ#, 8,c&OysGsENj>E , 8,Ȳ#, 827g!VX*$g,Bp/z%B<~388xY) ~>rX ^CP<*|^WH iItdB̂M"@ya)0rPӛ],_K(R$*B:b^m,gGXw͟=}[OXpY"XQI Dvbsbph~ ^`x(>1:Y۷,_ ~ja!]@]Yq8 d/ 2K8$g7o 5`}w18ҬC,(d}r"GZ  Zt%x0/[/H Qҭ8^t~葑3* cmFw, B޻HSj^%)@BG9"wt;dA\iL^HfA;kz8EA98uŪzr;}J) .t"x)/zkz}2wNN]#Ͳ cwĂ,fFFS~1``rnWŢ$`ҠۼZUS2NEakEEWRgZa0˂@X8P+]2P,F*)I=]XñJ{w2u/hJUŭ=CςRx۴˽=}zpSrs07سgFぜ;Vu^w*#V~+uO>'|&^ڒ#eiHz {Prx.) ȰN4AC{Pv)7Aujp{Pz(;sof' D~lP;B!qJ:-U]Eڋu_Lz ,J1E#hd ҲH5,b܃N ?"])J 77HhH܃ cDN2=hИl*~T $IE`܃2Ed E I"8AGdD,P %sTp,ԅg1|t U4xt0j%l0$kk6(7E2C+4 2u/j%4&d5b5(HEtL݊W=#Ii8d0JGZ ӲJo$":e㋟D^mІ` fUU2~xEy$(f7^x󒼆Mpd4 ɣjRQ'W{? ٍ[h hj4 '3x2LxKSZm,Ѭ-^o|#c^TP ٍ[H˒###.V_ ̳pp;7:6"k4VcP ٍ[fd;^$whbb:zq2ς##(ee$l-̳ (*AC'-kO*1zO"ivٽ.p $ 7r2ς T etmjx#Y)&|I҆,,ʧ Mò6jx#Y)3|#$?$< 2⏠GwܸKXmTo$":ev=TX /s8oԨ{Bf4Q Ai>kJOJ u*\fYsea+, 8,Ȳ#, 8XS\w/򿏱zb, Ȳ#жeGYpdn^*Tv-8,ȲBYNEJ#jEh=*~rD:jI5SwGYP*qcf,|@TZ;Yd\ .PB . ,͉Ek\cH}9`Y 7K |LE)R2Ģ12QXk.HB|{|bmcH,=G/‚" }m&5UĊ҆#) g$CjOF~I*vv/sfWU2YD!\T>"Y"IohRZ[Fsc_gk /T:)N ['ZQ"".70{ں;IdYeGY==̲(.,beYeGYpdYeGs'!>E c1beYeGYpdYeGe"ymAaF^t&S('fxa-yZ,rP9ҙTK"ՒRa^C)Ybf,hjGWCYl_qQD_-#~:M,)L041OS]ٴ,C?8ػhRdN}/s Ldrqm]z;YpMwhck=pRsl[wb}"/YCYdM͂jXQn݅m%:` C$6Snp,25]v.l*U[N`WUwxiPȮX>|D)Mz[Dȯ1m 46LQX %?"_dt&S(w N}7y;d$, 8,5Ȝ~eϽ endstream endobj 304 0 obj 6363 endobj 306 0 obj <> stream xZIWW BI 98p}O-o_^^WU_իq?ϓ>:u^/orŸ/XYMډ-|C^q >MMozjz,}rWsg^Ylr&>B).._令^p{Vb'3ԭxOEt=_OnOSԺ ((P2_Y,_vË́.g@:6(N$ejI'L´A$g<>U.19hι ]TTcCa.-m 0ֺ~V]ιW$0n;;ʶДÒ>{xU;J`tã8"_ f47hť]5.Uz\h/1f͞PzM v|)) n q\pbjM|(~]X٠QV(e5޻r ʣY]r!dCpg%[&1ܣ}:B7F&V,=2 a׼~hrLQcs اV+@86E<_8,vy@PJ-6r 2 H9* >y.ʬlt(]LB9vCgTql:H(--or7OZ D OE^O؆A)T/kfm6 JC귘E!RZ$ڌ 2,4LT^/S) 8ʅ=\s#ilFnSrYS~-v[(EeLFS~4I^M3yYhS,?TdxVqʐ\6z[M\~D$=jV0}E DЈPf!wZ09l\u%O5yJ/muDgM5dk&dps;gjJhgxzZ WYˌp Je+YOnRv24KW: ~#\ ߿wT$45sV?XVyz]g!QcZEX*YyܤȝGN~΃viM(K8C \["98 Qgw4ubUvi2iÍO-",=lԺ8l8UG\X:)[6(tՌ[!ie6F*b^I8(ׅss'O Sx8?X&.j˧Zj> ^ʑ{c8 yw ] >> stream x 3Mk?M FN1ʎ/z{{^70`GG|X  bA,I bDlOx)A Lźů*.u͹3C}r_*@)5^zbvUboĽ m/…Jj{gX=ڭpgX7 /bA*Xo6Xl_sId.7 -ydu/6LU3[Pbl/%* kc' B bBnE04CełX&boDc vƱQ%U(łX 'bX^̮YObgLK̡X bX bA,6 ĮSEx3łXLGa)HCLG<ӑ0bUW [tH[l;HHNG SUpKs*k&E=A`:ҫ[ah& bAT 书3S<ĮGIb]zr azƱQjV& "Ո$5K{Y3/C hϦ\Fӈ.ص֣;9=Ģj>X]ĎPbA5#n^ŊVjF El0{bM-sev1܍[ry̓eHRlZ<*ƑD5۪.\7l&vz/MD.lXYX{\#vӡ@z=@ bYbk>hC3-^Fl#ܨmXRbAP,A (ł؆plCI,1bAP,A (łXx08kصOr6łX TxLRל1b9h`W9-)堑-v][FNR;fbՀfiAa$6cblӉ"fyb ņ*^b(P1_ bΫ8hg&łX|$ A LĢzvصFY.TX bAP,A 3VԴ/D{]AHa]\$,A(@a.x(łXvr M[ endstream endobj 309 0 obj 1386 endobj 311 0 obj <> stream xXK6Wx=$C.(]´<$[$wyjѨ>/_пڦ׍qq[7u6ڴYu_!e_]syë'(dLm:Gu2 IsRpį OjTU)BPK{<`pχ b smݷδ&TFIZY֋茧Ea3$QUBYE͉}(xR`]";a= U4?\iPѴg9hP15: GOn8vq$ДIP-2}ȅqr㆚0q]ϺkbA%'|R`idb n*0 GVhsd^{/aq_io.s @V#ɩσ_/,^EvYEf%hQ^nQY?LnkCĔ A$ ;2YQl>_c%DžzZL+CYlmN6H<0sndN##8,7&BYsVjuO{)bLJ$37VOō?< q-a6sa撜(?aQ PfLDڠXU\z'?vѭuR/YW̦C0WU0 ھzע'|f_pV(XF$N ŧ1j{X<* ,gj8E3R s}1Mm稘E|)ap#و/0[qs}Aճ-{C? KRFM` 'lHeID'3+]n25f=z cRk-tq/ &D,52Ak(AԨ%-67lN ;cIkG $S5H$aT"^:~Z T1gcH\ʐmt| y*D>jXe3=b\*E(Jygk2D4K{&{L^ <ݱnq=Tue\M*mA֨F);Hh4#_m醹nGyZBDKUfdqVγ؞2ob/;]y]])AbJHK7]miw}Ţfd"> stream JFIFC     C   _"  _^s{uZXM!Y4HQ4HQ4HQ4HQ4HQ4HQ4_!&i &i &i &x=^;Ir6/a[4z挏痱nx^,1^,1^,1^,1^,1^|v5WKWKWKWKWKWKs|~]bks:2xz^ͬ0N8'os  +έ;@^@oW_aB"':SFgcd6AcdscȀH&|gf3DᖯEd(\Yq i< S3}D2We0/O=*5cȐYݑtlq6hA6tWW'v6f<_cF1dcF1VbA!A@:þ,F/c#21c#21>h\뫅$$тM$тM$тM?5E?t<ѼCwśYYF:þ,r7~fkM;g?@<=z@ ?@(=>yzǠyzǠP@<=s102564 13"@P!#%O;"(͐gJ3ҌFt:Q(ΔgJ3ҌFt:Q(Δg3Fx=yTE?oYR˾0X#B'kJ $cκeOȦ-6ڋq=G2Ca !0Ca !0Ca !0Ca !0Ca !0CaF#cZPAshaଫVTThIQ%FThIQ%FThIQ%FThIQ%FTh9QFTh9QFTh9QFTh9QFTh9QFTh9QFTh9QFTh9PL^jBͷӵV2J'w}'\(U ڦ*'#d{FDO5Y 7ee.EȱwiRZ&i w}$[=UiFr͞n3y7w}vHv:\E)洏^UWOfQj޳q/BK$yHͬvbihFNSTZ$ihŢ2^ ^/q!EqQfr\ Sfn iy_t$0U\;Q#h| a6畁nRF&}P^/y(5*5ƒXPk aA(5ƒXP4>qUJ /*ƒXPk aA(5ƒXPk a@e 5%XXPk a@UܒYs<2$O7&nZhF*yr3mFM]xG%\dC%EVGؤ_`HON)Ɣ̡PsCG&[GdPTt;W9/ZpEGTpEGPpEPr9^G;g4Y,Md#XR3cђeCO}= yvyIècY$Y>"V-2e|RKRJ2M~M'-J~]xES.ņņņņņņņņņņņņņņņŅcP<I4I= $u>IXlXlX(֧ #mޥ]xOo}Qf͝Q+ru ܼ_kJt4b ]š8äPԔܠܠܠܠܠܠܠܠܠܠܠҒJ庵}'ÉXhSk 7 Ӽ_k~'7xw2Q $` kDcem*M),$>:HϷcY.?'w\(ÅpaŒ8Q 0F(ÅpaŒ8Q 0F(Åߞ]xCʢw1dP*J=etlJ՗oUKȆRٔh㱹N~zww}ںln?I[%r iᤋ[gܽx?xb;ϵN~zww}9QDlݜHZ7fI 6r2Kfxɼ#oڒDE.ΆQ;TU2'4vv)CWSߞ]xCnWhvuEtbٶsV-*Ų⍑(hŴz}ZVPlAe (6PlAe (6Pl?q=;N ,t,Jt?n]xCJμR/˥Teeeeeeeeeeeeeeeeeeee- Լ_k~GmfmMuh0C..QF:TpQê8uARW~ Z'ӖjRUi{~L#Y7FUI5K҂?6[\FMo7o*Y;h]r_١ ɝkj8G5Fq#QjSD j'̮F\'C t0 'C t0 'C t0 'C t0)\xwOC#YN\{`Uˮ K ((((((((((((((((('"juUcSRs2AZ"qE-h8AZ"q7Y#:xw[/V}'w}?ռ_k8jlwC.}$Ơigt#5 mVOAVVl,Fq;F eL2TʙSS*eL2P3@2U ?- >3NcVon ":X<2Yxچϓu03YS|HV+bBԎ bXKe0];x=Uj.j{ v#VOAڻi :zlty UN&bv6 נX(nb!J-*?PUWv7kejCRZyΌ$~ jCu8z[.!* TQQ藶ێLX"&PAjReh6P-`)Qy=ӳs}U: - nI(x3, e[wVS8ZCb]$($aTktbf]ݴe"ˍ.nAj22iƶ b^&d -k5QhG!q!q!q!q!q!q!q!q!q!q!q!q!q!q!qy0p)%C0˻ qhq|Ï54-.պ1ԿZZTT,UN:+jd!fe}/2E%TM~h+^JPɮeYmLrRָָָָָָָ$>Eo\ !y@4"qUN&mlև]Rl V%>q]q”ALpppYC\A^L2X#(2,2;~:V'njL%7hރCTujK`mtZh& yjtFJJK4K)^|M*ZM7ĩI d7, LK Upí_J[E/ZQ\X#<DEiP nҒ?k@>u"]*e]r򋶻i4/uehejIUƦOYe|(En6,ָeˆXm(*Z4_rde|(B$-$"E՛K[Q<|\s[t yQU8*![6A4EiZiiEh_اؚfUhy6J\2a enKܪ7hܥ)iNFJ6GTmw5FƘ,mBK y8aP:MpaVVm<zC쬪o 4z#Hk*%̹nU&u nUܑ2n>HFrGW3=hg${Ex"$lWI[ AO$2;~:VXAE;d,L HoF'^[1PVT hZ)^1fmtw%i '0%3S4'*6}F.)&rmQi2ׅ0[p2 #kP+F-ڻ0$M%\"\B JLmJ%MS|5XQy'o8*@"7RWpw7|0;SVۨ\MM9.ګ[B>)0җNM(spjH`k<)Ȱ9Uӿѻ):hULI˹i!\>Idw9 t6܏y2*$Ll+qo.^qk%N2I.3sJeTިWRiM0Tqe[\u <ѲRm}gҭlyRdjp;H1 Y+f9mRFDiamכeR5{\Mhd.)hE#}CHC,QXq@J!I0ZT8jm!Kc 0q(qR޹KeZR4DS/OM8^l%jm mV@8SPh2ۻ!mf IeDt9wQ*K6JE}MvY4f nҔNrڔJS$&nJ9p 'glDI5̎:_0^{km'D)&[4ݔ9wGܗa %- L̤yPvpU_>̈pT+BRY%gYp6mJ 4lʹp*BۊSe;]ĺDe \} E!,Kԧ27;L(US q(K TZ =GZZҁPh?Svx MqI`( SR =ۓ,VWXk z]>ʲ8ڭ$amM@QMq'%1zkdEܔ;&FBrRqԙJ\k8ѡsPBҎn2.7@m=q!.[!4Š8S_"qIďzHAwǒI/teZnR=k*ain7Lh*+nq&M&ҷruPi>tb@1Zrrm_5d)L} RBH9R h>2SZ6+8q*49O6NXL"fYTYpۻP EA+8+&8lpyړ5S-)1.ӳvsp*z-5YsTm{[d]/wE%SӅkӗKt XKQES\8%6]J4+d^}”bviVkˁsɖrV$R*+ybjfG:6]J MeŻwTO^^32<190i=5fnj@kju-d.nØarn<ؗǺ?vԼǟm?˺K%\Ӫnl,)k-OMK>/myo7*˸1/HlbZK.HPucH QAMREF55oiIm&(1YT(*[m8m{cm h6p?Q1اky.RjUC6%$SM?s.T4,Vw™}O(q FEvN|X㾦"e?I5̎:o0fkllLlS.0TKjJ07 %Kk&MtT+ d}˻fqƔˆ?a枚as  t:^NoYqu`S^fM)qy][:TԴhr)ohye 8ywXQJUiB(rIn_GpC/GJ|FVj]%&ۚyi-h(bi tF)Tl)N5Kt7QK&KKN2;_, M9J-*1LKN%i-wUJs}Q8S,Yy֩ZR+X=/яtJIz_#<SO1eT Ҏb -58)y.іWt[8;)$IMs#!ΗL#o!鹧.hUJ0ӆu 0 -'sm3gj[{b,6VӫiZ1@Te۷qMJv'8(Kp&͵G J0&] #͔)ZSQ MjIؼ @BJEr 'c֖e&+)R!58,k 7-ae2rr  NJ.p8=XUlˊ,%˒Rڔm۱JS lVP_l)璛EPTר6Kc}ޗ$sa*q-]QeU16y2qn[RYB6\2xXO7oyJ㼧*&?h*щj_礚GpC/GJ|FŢNINK59c')U[#8HصS-%JvQՠ]8+K*@ɦ%Z1.a Si )*aEG@8PaG>m`,)g&4r\CfťMlPe&MA35|F̲޶S-]ݜ3E&aLQTdmk!$[شԽrm.a[ 6cbfa /K2 w9bIۚD$d֭ٛnR@(x 2H*IJ6{\+/2Ts)v$^qɹ"%CdD-ٻEc67W1jqֲÉ@w Z?o4,Xi6w7! b"_G|y6=oL3.BA\2iB䌴[vrQpY]`pTFYr!;I{BsMs#!ΗLR8TrG wn#-ޤxcԏ pzR<1G8[H wn#-ޤxcԏ pzR<1G8SH'~na(,PBR,R<1G8[H wn#-ޤxcԏ pzR<1G8[H ws(TQ:=D.Y#-ޤxcԏ pz-,~~;08 ~Ms#!ΗO2;~LʥbZ4A&HBj(G_fAR}`SIeե$!n$ ('GOM?ktcIT]x)ViD?3 U*@X`\nUZQ˅d"ȕ+lBѨ=XZ*#O\i=q4ƞzO\i=q0${` $LV^Kl+i5JFs\xck pq9<15dž8|>s\xck pq9<15dž8|#Ms#!ΗL{DN4ش㌭)VM㉉˹.h5$!=7|. mU9A;e&KLJXKMp: 6EWy(4L^a)Xϛe+)ywIlZp*a )RE<މ<Оh_p[*$&2_k]_&ծ*qV*4[Emkro䧓k]_&ծ*qsIdw9 hpmT#y3+ZQx Ky!<Оh_p*ML%Qp4hx)q /2e0̸uqmU F6aWm+Sٹ77Zv-9߲(ha8R4ͪKlqʶ֏xI6^qPt6˼/U^R5]jokz"eO7$4[w)aMnC\s!/ yr6=/y>n4JF8)S'XB&ݘSqpYc)ѓm:Աm C-CwL!ǚarٖ*nTOJrD>!I 셯-qz$Byc}mHPVbv7)XvŻw)kq6o>[LЗ EbQpmҊP*U\w qmi5J Rd =I5̎:_1 K(6yc k̾'2i-y4jmtĕ G|p{uEQj|Co%4`,1b74(8-/12ջS~\s!8 za7p/=D!R0ʗlV>rG{|ソ>q^8~OpW'8+ߓ {|JxT"ͳڟ fO3l{S=mc6j|1g>ͳڟ fO*Pj|1k]^@)nUy=$2;~Ǵ~ƞhij ne`Y4e$e)s*qet/Qɍu|Ydst0UkTylrR]Hm:m%X754-[)&p8PAZ@& .ߖ6;fݭ­R5SP䲥N޵FМR&m`Z$2;~77î7î7î7î7î7î7î7î7î7î7î7î7î7î7î7î2 Y-ۈ.S(D.`>yhJܡ60eB &Vo7oS"Ŧib!NI*N A[kӍ-K*RҺZ'݅- B{&;8S=h#3L8S=h#3L8S=h#3L8S=L2HUs-^3QoSqDI5̎:_?\s5̎:o?\s5̎:_?\2MOUg@Wkǫ}1vLz]Wmǫ}1vLz]Wmǫ}1vLz]Wmǫ}1vLz]Wmǫ}1vLz]Wmǫ}1vLz]Wmǫ}1vLz]Wmǫ}1vLz]Wmǫ}1vLz]Wmǫ}1vLz]Wmǫ}1vLz]WmǫU}1vLz]Wmǫ}1vLz]Wmó7V,!1AQaq0 @P`?![ I|atbbls9{g=ls9{g=dg3F{#=dg3F?F{[=kgl{[=kg>sBtl5KC * >&WR#.ZhȢF kyF@ل:U R8z DrQS* W%9(bҩFQ|T13Y"iȨCtI aӣb蓻zzf*ITԌV$C?8bu*9(4\N"ެƀX"('TatBhI$]p-%lЈ3u& F3 c=!H~s=!H~s=!H~s=!`W! Mr$)(qI &.4K9Fe-eF6[HhAW=!H~s=!®+:@( ::T8@2:SF"zC?8=+g>>>>t~y:|D.ߣ(nS md\Tz9fuJ)(l9}c5kQ ˓]hRHБ'Vd8x,啎*D64~qʡ]r<{h'oatYS' xD(wGITƎ ׎+nKSPAhrH`㘿̢UA;;x- Xb!`&&@CEѪ(o!7}'V$!Z MHW1`zsAx N{3W&u*UMho:Q^U6Fqs1$b HlXW)m(_K ZEvxUpt|H9u?z48|g&Lv~ݟf I8v:h?5P@ ýlMƱgǀ upOG^xM1"gknLȱt)Q9<4 ݜ]$]M"L=j+JRnbأD0 |M2,MB7q|xp^{>(@x.Ea;5y ۥc#[^ h&G^LLƦe D#XaYDFQ,6 p`3 PU 0\D;~Q(Wnȓ FVJF 1KI(Zpy>=S>25 `csy,puG1 ^ik^>-}[>\WOe _ς9l6EsD} UGl4 U%=F!qep] 0sk4몝l3 YIMrR E'v j ،2ٻ]a0a;; ?c d!P"Mɤ8&-FCof]ҕz`9vh"ZYlH@0k^m|A py>=H[ 6$h 1ӺKe03:`E U|[ jp"#"<4 * tiwJ" }xj{Wy6gO%4Zp:>7hTm1T2+tgC&Mح\i+J1uGTT cnrju)檒U4s?*<&UـB-A}}{3{>z$a7|t% |_2%z+rSYhi :#Q0^7ymf; s @G R mQ'RHfΤ#AL i-;CQ XՈPB) L`y+b3`$_i8<|ϞHB;x9k9(Mʌ<0枚(pW-fN@G(*bxf c_P: ? RDؔaZX uWڪ:cCK7Og|IXqJ"ꊍ5kn9׿?y rvzL{`8/=% %"h A0kbLO&X 6E4EwUQ 0kk=4x /y (:9D>l1z/O!][ʠh|gT?G=G='kp@La7<78J"Un,'?^Ѳ8Z|:9bD{.uxɳIDȃ{Ӟ-w^AWkRշ(e20Xa]Sq TH4`A*mMe FĆ\v`zL$TXBy>Vf۸\!([ v^PN"(é$Q@*9|`6pW{"|QtQmgX+===X0X 8DL9 ƭ-> UYɲO(8:'"r"D$H"D$X6;"5P0B`)`RH"D$H"BT'>H?"Dp/CY_#'C֎&"gp-A֑w1u6}U0!kID3A6|#uNT/j. gTI:^C}%hl4x :^;d"(1xn/U1+*BC߀u!(Z߇{~߇lGS2,?D:!6LFD6vSO r u'x3{v ;fNsi.#/-^ZQQ&Haj27?tq]Z/"ԁ?4O:P恳YyE [Y^XBU6XWX,`-ww|}w|}wEucᕍ-@8~}f*K@P]tӧN:tӧN:#|5bkoG^/Fa473NP"u1vX C̀3㱣h ڲ:mA7ͻӅl㎛j=|E {k=mgY{k=mgXvup,i.aT"&.m!, q(Z$5(M\Y: ƖRQI %h\BYOz?9Oz?9Oz?9O:"z$l)|Ǎ*9/s :ц4uq+p8}8`c{ؘ'q.8`c{'qqqq88{1 M4M4M4M4 0 <,0,,߁ KeV'kXkWrz mI[$9?Bs:Cm;x B!ULw2ys'̞w2yrn#s'̞w2ys'3Lm'g;w1.k=}YhYh 1!$BͤMDڔ?KFgˌl V[RN]4nyb6_JSwiOwKCDqd)j`F`F`F` vs /^&EC|Fs@I_DKFx\4R6Sm*irlldmNwnb6$غOV$.o'όlK.^IV 'u_>3KIJ  񘍉`Ox,d .3,IJ%Dc2! ~~~~~~~U[?'LK+nT+r\3r ^?.333EmY…g (VpY…g (VpY…g (VpY…g (VpY…g (VpY…g (VpY…g m[g)!1aAQq 0@?-,,30I.#6L)"hŘЦC* * * * * 6 hAa$'>AdM_" ZfLI@5BAC4[w`;.qs˜v\(e;.Arːv\,݃(1$3zPƈ@ B"UF` dSt S&nnA3 !X l-;~*?KM6~6~6~ BC6XlFMUG1ArsAIF3o8zl_~l_c '$#%FWl_~l_ `{c)2_ 3 (@7r &&Y\vIU 9 b]ȃFAd&ρ6#HzsBK\ )o S>-RzsB&68{E.>$|fJ|[1>,y=jrͪ$; ~1/ iZ`@w. X:a,aq!1C9pD"3:V"q 4d@h`Dd,k ,9dAb&9^P$, ˗ba^EPd4D7a4gЫSPjÒNNdAXfܜ3|*4rJ99Q]8qwtӋwN.j}|M5:'\ds]Wf~V#'}{qx'qx'qx NAyOlꎣtN]c13c13c13c1Lj zj}$.* * "]p0UUTVF_h^SBqU )ZLX* I(鮏\-dHS̯e Xbŋ,Xbŋ$H"D$H"D 0` 0`*fg# "~'PBXO9`^ (hީm=`=P:UXR;>UmJ=X roz[Gv߃>?qW_P,40ɖוFz&0 =@y^G%'Ea|ϟ>|ϙ7pp}ڂJ9݈`-lalEMՌaw>|B8mKB5#-6O$&!nE 0 Ё[8߱AE&a&L2M{b8GKU[-7Q!g%sBx+qN%v~꒕Hdɓ&L2Cb<yM݌ _Qnl ÊetP8 CPg۶|,G#I Pݸ*B{ PB*zތ (PB (7 PEgB.巘Čmr#";(?%*n* Y6gx74bHRwݻv۷nݻukb}o<@N9ol;pv۷nݻv۷h5 |/E9!i_a)vBnxaW f?<c; TRJ*TRJ*T8>j(u;0`\;| m3a Ґx\ }βa=G]%VI2/Q K_9=ug&;d絯@ ğr XbNSRVT+r ~j<[b -CQF'.O 3:Y2:.4P( @ @4f_r? T kADx,Jj㵊o@FUmj @yaK<<<<<ޱ_I_ks7VؤSU0!GgAQ @I9`1~Ǯ3_S*v _[7T21 DwhQ+Y?Ԥ p< $|el~,\3z*L^ã~WؾQ,X`)W.\r˗((`p<lX8pÇ8pÇg */qMBNf,(5/3' 6VJ7)qdkH7;q1ys#-=ЌA=<<<<}p`j&!諯!̝\ 5'+f諯PB (PBiR 6Vݩ"AP5 O9aκ뮺#u]u㮺D]u]u]u]uԎ뮺C+/ endstream endobj 315 0 obj <> stream xUK0 Wdَ!0@[(lz$-%$,dРU]3d}><:y^UٵQrӃn$&R=ȡwv0`{a?8i؋!=Dqٕ<)KxK"cv5m,Z{HkgI?v&PY񅕓AWbNz}f ( %7QIx4(Yv9lӖ[x?`sZ-Lh"V@~ 7c'1qPlg쳛k#3B g-8B3o6ђl@-:"l)6?}K9ut! ϼ yu# J_XGATkv>5wQjˑK9D⁏/NFdG.<&ZݹH=hhIFфX]G ybg8p8s+-ꄄy{g^\4cREb:bksY==m W-ܴ^ɲR'_3(v$8}#,YoRWS endstream endobj 316 0 obj 652 endobj 317 0 obj < ] >> stream x흽ܶqʚS=LrT'(c\jv7@RLtn=2G^Ev$E6I~ tHn?Mi$@jn7r 7>+tU+,77Wdzn{!U&X%} K *Y-7))>޾ێ8IrscKr{w{{Cۏˋɰ-uD믷}?x_{)1o޼}|~͖>o_ "Jw_?qsݧO_3%uLgD;ڇfX/~/=Tu[Xw?T[o>|QjZfg[|t莤^ԾGlr}Tc?k}lTM7jOۀfQ{$"KًgG? t>}gVf㞿>i‡v/:ZaWث*..|>>WYUTI3{#VۿVTI@nکyhKO+{>|_u}4UޏwǏ?|0>:Cmѵipcos;E1>ޛ]_mUc{Ǐb &c&hdTN*EpqSI0_Ƥ~|^ݽշ SUoUl:j*>nma{?^I_J×?|n{.Г>ov}ޘꈱv8|s!0>ۯBoBQMqV~ًgqS'h)Ns"o۬j/k޽'OyMSR72l.6 n޴&CT||ltTB>b|⿟Ta5W>bZ2˦sEvi 57ˬ,?]ꈷAG"};|TideI^!ȇ~yuM˻xr=Zv|o$ְ`_a%'kC|x|w],K,?nW}`AXH19.}`AXՠUVW]t0~WA2}(;ɀ>@XP}6.־D{S.Z,=>)o:1u/*X5ܛX('z"WQѧ()N1>z^EQ>tPh"_uB~#"7^_`C1 >, >, >,F(66 Y>XsqCu$7^}(lyQ^,UτUarUYgv h̵t(*X/vaK0%W_}!}6Vʴʆk˯dX幒y;^>UQ'E-8 ֗`AX}`AXǘ֐7{5&飣>ds=LOMS"ztj\E;j \7~rqFã t;Ȁƻ6o)݉v۝񑈳v~bISmNV C 4e!9kU:X_}`AX}`AX}`AX}`AX}`AX}`AX}`(1Zá (#V>o>cSi ˵mWP&D/htH0h\Z! &KoU:b5ћ_M!Hm,U2ʇy>tj .ٿY>ً N"+֗@X}`AX}`1 olB}`CՒLEeIR> Hf0GafWL,s\He,X_}`AX}`AX}`AXGg}+,>l9I7탮`0h3\g$G_?sMf~zEny,swsnX_}`AX}`AX}`AX̯Ode!ȨMϐ, }O0}ou"e~ʒ2dX!+ߑd,?S%X}`AX}`AX}`AX}`AX}`AX}`0?|XzoaCI&#|XyM}>lgs!zȯQ7;aaGAD C+FTmiC8mnV1>zA}#|'(eLЩut>N]!:?}*# >, >,>z] wFbV#,Jʟ$I}^od ̽M̯1чr?Y'̮J, >, >,FGyߦ.)Hq,e)},~W `u{!&H64k&Qå4㟇K:e߆)+K, >, >k=yik4yQ\))cˆ|+!>)CQؙaeP4}_2*Vv>U X_}`AX}`AX}`AX}`AX>}`AXŐWS_~=mU> 5VV={7qT<WiJGFxڤZX@GiWy3+], >,E >!{ >,I>&})Q_EѺ}',E‡bk@nu-/ÌI$b"){vLIu2ܭ$Lj쏿;n@S%_(p,˕?W_WfΤo{;w>To&NÛA~$֊|u>ڽ*C>Dh015}ឲ}Wc }>>`{I|Yn^gn׾e7Ar6l],AćVO1{V>QDz}`4}`| | >, >>;rȞ>&)cҽ+R>,CG0߇Vs8ۋG?q!üWH[.FɗW(>T{)Sծ`ZshDž}ʮʟhyJ|%R}U8"|سW.^XOp=&~O qDJW*ʥ H*}(:|D#:#Rp>_ +s,aFqD2+,w*a)̷%lKS_bYJ.wlyy۵G*f8&9rDW[PGXJ"y,x/>t߮3>, "wf"zŻKgpCF~|_$5c&] flg4ۑJ4ܼ҇} ҉YDC)ϕ$+m a(]yn2,&q~ >, >,öG\\\+zw÷']P=j/}{[ }"QT_+hESI\T0ד)bͯjMh+ Z$h71:}8ma&+S`8 PJί)z9RRk-f78.zŌe|\*dEhy1bo= RNRp{֒,#҄ixxc=kIrB>xФ $~%9B}G۳ŰG…#*ƽi=kIrwW^JGo&{{AOc)0ޒvC.uF;]I/ {5VONy1v_JDyb|27la_tHd+/Jy}c)P~hfqܾٔd<>`}`AX}`D{,KQ}L}")EN`Q> }`AX}`AX[Rj3 W{:#%?"S{ggap~`eo`eW ݣu%H&r<ۿ{A,4'f~*)WOPa?1]ɓ;+h;O<_JsPKt^dp"AvQ;=A9"KЁ%A Q| |.L⌼v7gʼn :(҇Ϸ|DDcJ~Օ>dxʇ%|ί0E'ISWfh`27vX.>G@? hq2ne %GCH;K, >,C7XɍA(Z2r-{<2L"N(ю@#(_1}x},?)8^yeA, >, >XCJGu=>)ŧ|@?خVHDwDyq@nF ַ^Dq ZfOޓ!T:[#%?3}(飗9?W^VIx;vvvdu{믰, >,N^+OaY5PϷkSk'^ڣZVx>vcB{R뭠vY6Izw( 7s=}sEvc#؋3>jwpX3+Dv%Ul|o:.q}`AXX>Zv sۣG 3ef{}?* =vI9nãuXC;X Wuԣ%LjQqQr.Xg?+þcHp#nίV4y(\v68v+޻,p|=}`AXEYf%ԠڙNF ne@xKo/o; 3ۇ5>hd4s3QQa!ZY~ef{mڣ}; 믰, >,Q$2QEڣH10:LXEڣH12G<Ă>, >, -o0P_'N_\P|u˸>l=J+ } M:W!졷S<6}\wڮ7ގU:~nG8\qRHnD?ܟ Ә|U+o|(U<gdn}p"B<#v,_ǟwvݧo;ڣdjHi*|#^;NѧFqO/!}D>FWL~Ď/({ٕt\q󫋶vC7zŸ:^ ?Pgz#rf~>RC2_AON~$2A#QQ;{}3MG=A, >, >{GCN=I'̍}z5?JTG/v;b8x`6(%ڥvD?tճ(C/v pGENGYǨѾn|H ý뢀Dg#T=Jۯ] >, y -}ۓ7=ʐQ=JV:lo0exW lܥG c=J;J`{TKvӇb.lJ1^1=ey] >, z 7GMO=jD}xK=Ա;}pQZz\QhyY.NSڣܟ6}eTMjb{mغ!7;cP~tG`.>^_O{yDr\nc7[_: Ǻ, >,Xj JG>hg:eۣ*H([n_o~-h0jGJє(#>hc<3ۣc %,X}`AX}`AX}`AX}`AX||"ˑ;ɋ qxN＀ gK>AT'}ܽ{'cuWaGlO>]xnGf}ŋ*}#}%w:yB}8qHLT54K 8$/6}4Ϊz|د~=>>zyI41Fuf]Q>CQs?خ/?ݞd0S>M^~`DQL/={ٳ3e7=qT>=µX&C,}`AXrMq" \n6 9 endstream endobj 318 0 obj 7194 endobj 320 0 obj <> stream xZK4yn\~ŖF-%n #q@EB,hߧ<^q&]sUى:ASS}_u`mx`w'8)7͞$珇սǡvi2L ,@wo~|Qټ(w>ўEų~Qz=.J׷|J A}s[| >~C ZY xŎZA^#'/&WtxRG|I=jjЃQD4V+!#̐+KcOX0^9Jt'%`4v-X=>EgX=[6 ȨE-h|o z|7F dKQ$ ]T sc^Sz^T` JBCB[Vk)l%~ߤL0rL&!YE+>\ẗ́p=9 l0It09b;e͜b,WG 8ޯ$B)~ bp,G ~`a;31TaV/B*֜,MP)@j''Ic1`2237ulB'6ɋA,kdƌFCNvOwH'h|SW_ieع#`P=vY΋M3y4֎A%K ]KTD5 C2Q'_ɑÛi?c{FB7DS\ϊgq Nu8H>HqA \v;ۅe d5&`DXLĹ-X+_ZO7lFGN\%Πf+ tk'dgl_y~5F Zm3xjs`l5$Zf<T$3%3iy&DLKzƭfFRFTcaT:Kxs'| /u#Au?(;D^A)ӿvY3sܨ<턁:9K&[/ZުlӤAocqlvfzF[Z3yrZTЃooVͱ%`Gൎӄ uQy*Ϣ2MڨRe6}2s(C 78O)/@$}P+qvii[sQBH֠_\쎰 _ x~7O%@-PV:S~O7-mv؟¦d~Aެ(znҮC .~EˁLw뾴7A!iDnG7.s`9|1"3Prk/.98eL[pXl 2(,Kis1oZi[WD p.IuyHf&6 A/dޭKY2MI`#F013qRz|2XSYezeVFm#~t1„SkF]aIe/r6Sځig֫W^6 Y_ U=)@2!%捍s!~Ʉ(v=m {x]\"5nKs)nMPy3Y,f1[0%#D n[Aav4<-!G]'lyX6ݺ-7N_ޗs:0[XD^xogۀ^/ZZ_9|Hd%%_ }xw?n endstream endobj 321 0 obj 2116 endobj 323 0 obj <> stream xZIG_1g^g!hfxɉ'ؗTUo3#?𰬙jjiyډ k/|~~]׋/Rݠ:݋ ~GKWuߺIս~x> {>9˓$fq=$<'JqÚJ-}C#tr:&r6_ ٟ鋴\ZU. @ R|d0 ȆS# WmObD>ୀJ(hNМV GR -NJq ]I4!I+|_mذ[ZB~E^zZRW8Rܔ4|91#NDciX~IՔrRCI*u:ez AVhT rFHB@ia vƹݐ0߸P}0,_㸒#2H,+ n [" q8 A'{0la#V4#磴+!o@"7ZUh-}4QG.fP~hě)I _h"-# K9T <{N̩rYr2Xmc:K5gVըB웊#m MT^]~HJAN6$uC93cHV|xcFJAέL!c饎 ePf H< y( [}f fF8A`fh : Ha:<בwbr3+=@PsS07DwdEmec)1J #|,D$=Vd !y4qBjE J(}w{ w>V3/O <~G=NQ9ӆ'J[))ŹiVl=: vgo ]9IC.O+<nnT),jW`)M9sBz]șFszR oJm 0IDS[6e{?:kll`i`٪3'tF)-VXuSe@v|:| |9+]n{j{l?k5[$ t]_I!ci05΁M90'(b_J]OI̸ oo:dK*q 9\t|U g /4;S 'y`NCl}a':f{& R-vo^΁f#.D膈 ԙDc3>vԬk ~;Lfkx}Aʔ6R=TVGOx74,UՍ[dDxw9e]VAuMꐴ9tTfEo-Q3;ܾQmg1 Z\\,K}.RfM;_!x]Ud+I:OY&( ΰJORĦa$ORc⍦SrZ]2 o})匩Hv;5UW{O*?.t6oAlϒhfm3b L ob?V9vݔ)n_m endstream endobj 324 0 obj 1948 endobj 325 0 obj <> stream JFIFC     C   h" >dŅqa\XWŅqa\XWuiy|>~.+ ¸,+ TSv,אEqis᝗J4yzP5QDDߟ _EA|P_A|P_A|P_A|P_@'|^ި}7i==KټO1| s~ S4>ƘO:hf=iC-1V:D>w34tS/ZXK7Kϫӟ=|*<_M<񫵋8krK>mvݥsRO._N jtL[GEQiTZW,~%bHZ''~GlZZ!qL^Q>j^$H^-#,QDtM%) 9[+T[ho ]`WXu]`WXu]`WXu]`WXUdgO? -[Y >C1Ế````````Wl[; a48~bz~YVUeYVUeYVUeYVUeYVP7G.~'#Lx=/QR#!a10"@PA?4hѣF04hѣFs$нrrX7QbRPjYy1#P,d(>(2FcxqXG_'ōE^~G/_e;)NvSe;)NvSq̘?ȔJ%DQ(J%DQ(J<_agiG?RF23!"14AQq 0a#@BRrs$CSb`Pct?xt+]7WMoxt+]7WMoxt+]7WMoxt+]7WMoxt+d^%4(=dG;}LU Щ}%*!eM9PwG"9/jrb $F˸R"/oGEC 6\9O~XXSGG4Re ΒfԪ[1^JXq6Z=#o*M2Lu!D4ڢQ6.&%JHFGOTB OU2ti$˰̵n]f%HGBgG2uzi]4{F_Z-d+B8t#}s j*DB{$iJiDF1DcDF1DcDF1DcDF1DcDF1DcDF1DcDF1DcDF1DcDF1DcDF1DcDF1DcDF1DcDF1DcDF1DcDF1DcDF1DcDF1DcDF1Dc "5*gJj*$1j0NWZ+-S EDceD-S Tyr9^aj0NWZ+-S Tyr9^aj0NWZ+-S Tyr9^aj0NWZ+-S Tyr9^aj0NWZ+-S TyrZSU;SU;SU;Sk#/OXaiHBK쨦!48RC*YDCešUo0g%3-YWʼ%iY6t[k~ZOdS/741YWʼQ_0D7cߙZ237b]DzhBI=JxcO_\\] &Fr`v24lBMn%3LzgL fC%k]I"oJeknѝ_gfIGaID AR~_JVl*h?GKUh] yֿ|zÅI!DM-DTC HPi2WRZ\uSw2-De q9.~W'ǯ%>DGd4EKu'uȁnI%NQM)"R)KdSY*%止IZ M56Zh^ s3z,GH$s?*288lȜING٢E-ԟF1!m!R#ݮlED})Pթ=jO[ZBfԋr~!&'GE:T9?8aGQIǯԟ>ГBoe$LtkvMjJwލjb$IѤ6E+oxb7QhtD)mb?+3?YVggv'XcuLI;%ckb+ը\Qn5ϫmiO1l!l!l!l!l!$+m)F------------------------------------& xwxwxc|cV;cV;cV;cV;cV;cV;cV;cV;cV;cV;cV;cV;cV;cV;cV;cV;cV;cV;Ƴ ȨgD?KU4)M(D]ZhNufґ+9d)*䝖g !i7[h[ֲA~l3ZGF!³Cg, Y+9d8VrpY!³Cg, Y+9d8VrpY!³Cg, Y+9d8VrpY!³Cg, Y+9d8Vrptm(NRWmqju)J fgDh}EвvgJ?rg$iC[Iҟm=SA};GvZzr>B*$o4V (~SA[3&{>fԈ?ZtSu45#iR#LRyef'AN]Ɖ{<p [m,YDCfG=t==9@2$$#D9\v^)Ti-{Y,>Q`iOX5| f(k4EY,>Q`iOX5| f(k4EY,>Q`iOX5| f(k4EY,>Q`iOX5| f(k4EY,>Q`iO-M$%S?wlQq*EV(3Z|XϔmP"BXϔUkc>QUg*EV(3Z|XϔUkc>QUg*EV(3Z|XϔUkc>QUg*EV(3Z|XϔUkc>QUg*EV(3Z|XϔUkc>QUg6NB3!:C@d 7Pd"ТKpJai1QL%Knd_P-tC%fmZz=^CQq1 4hܝ/kE=rVڵX-*$гQNU ǽbbi}8;f1"r3Q%3-Za=Kq 'b?Qթ3FuzHDĭ(f$Ⱦ^E2)(34ΙЪd"ܓ֧4eHDhDn([ʈeI]Gi*i#I*ZȏWVkllfes=3ʞo63-T\Kmjh6 zwo;Íɤeё2JJ#+%ISIIRD{bt|\3Υ0dᖮ.ψnIR?W*!1QAaq 0@P`?! -_UUUUUUUUUUUUUUUUUZ0VOԔd`7N]T0AcgKJt@[z8ukk<xJ ?s]ƊI\PR JSr*+-u"F:VU-q)v1)W֠E H廊M~ҥNoׯo%3!2!.Ӭ?gid j4oooooooooooooooooo\J}S/2/׆._|e_|e_|e_|e_|e_|e_|e_|e_|e(ܮŌyLfS2̦e3(rB5K碢,xwGP[F <Fǒ Jl `]Ü0]:ZW~.h%*됆!2% nӨy[<`XLAAR^Cd~MSNF?r VDԺjzN"mTKLfVabnJ"]Uլ/R z:ovH+ڧ(r* hMKI};ogX:ʀzNveh5.@ſ馅'N;N{hOX5v}=} 4;;̠l -G'|[%Uf][(uޢfnB-~t>iٻ*S1!@(H[Ҫ?ϡ{%;K~]m{?߹7_\-R|kK_ 5^=v(!|:+` : *i]|w31eDSmY؝#l{fs2HJfRtG}(٢L@SƀYs13[Jxf "+h H<^ʭGj ,f 0YRQڂ 0Y`,f 0Y`,f 0Y`,f 0Y`,f 0Yj/53)LfS26nLfS2̦e3)LfS2̦e3)LfS2̦e3)LfS2̦e3)LfS2FEhQEAt:x2֡UQ~"UtD`m)Z/b$Ytuv ZBRЭ)wThrOi=$rOi=$rOi=$rOi=$rOi=$rOi=$rOi=$rOi=$8]>a U^\૴+v ztj~/Ң(z2 %%e]ҵn]_QP"fEꢳ"Yy](hѣF4hѣF4hѣF4hѣF4hѣt` Gҗu]qSYGҗ[뮺뮺뮺뮺뮺뮺뮺뮺mUA^h. /څ-h5jV/+![H)ʲ B- T*rQ$ww #wMFuQJMʂvh̷FKYƛ ‹ hЭhJ6;wӤzoFjj&w7ѾMfPՊII5RD`-}:ŦT#䚠 yvz__W ==<<^Wez>^Wez>^Wez>^WЄ!B!B!O/mҲKWwP%Qa!10A qP?\9.K%ÒpHw+.K%Òpr=:(P Su d_2!B!B}R Pn|K3cM Dq"<"jx}Ϣ,.% tjӼN/^JW¼%y+^zW=+WWɬIod已r9m윶N[{'-od已r9m윶N[{'-od己NtN:)$o^ E5[QnE5[QnE5[QnE5[QnE5NxBrUKV9*%XcrUJV9*%XcrUJV9*#o趪4o xf›^ _PЉ) !1@0AQ`aqPp?J%DQ(J%DQ(J%DQ(J%DQ(J%摤4]Ѭ@1"yG:U@$Xx B{_L$suER)5@6o7?ס龻)jie ׸崁!<.zi"vC2ú7j*J*J*J*J*J*J*J*J+-yhÇ' 2G8pÇ8pÇ8pÇ8pÇ8pG$Bb?B 퀌LUв2̕ f\|OӀa ¯UݘvJb*[txJS;3Cfhl ]0|3C YRz r*omy<"mc{ #0 S4"Jۡ.;ZISdpq'N`WRo_]opvr7נ|ғ y= C'u'wbFr/B,Z VC;KIf|dM\7aH4̋^]5<+7qeMt2{, ?rĮo>&z,;'Z-hl}-^I@>Q%9RWf£x @ r%耑aZff} GNE-1Jh To+AB3kJg5$rQ  endstream endobj 327 0 obj <> stream x[I#ׯs4g&e [CO06=}%2EchJJE{۾xW9 ?T:_> z/ҘaTvbp>|]0ɫ|]}Ȟ>//?i_`M9 %Y>^<]i>>o___]䫘oU,"ݛxE)nn&%}nŃK!(rP,ūJlq1뫶(9_W2}]̫R7P@g'u;/pbP6RHC2-J, ;# og]jd○H;=Ubx*|/h'14&JoYjMk"[F|v1Z=uKě{Q#?]#"ZCcIY@S;̕ Ρը97ȈB=TBX>b'bAG{Tߗ*K&1m'!+\z,7_j,7+up];i&5&MC~|.4M+h!fJ=X/lNiZ ;\5)ڍ(~.lV(Hk [sEYmSJj'HW9'"bRmt`wI \3֗]C߃o|=ʧ|o;h)ROŘ"et5F:Lm۠\E{qO]T 5afp AFAhs.tX38"s:,s}9Ѭ7q9S7TYKIpXNkƱt-N΢|®iŤ9q\/e@ XL6l4̌%j(xaa*&:no:>y݊iUuvZB,I=xWr]:[Oh#8103B.ϰ96ΏR\dS8 :hM<*8љfO-SJ-Qy@ĔRJ~DkjQZE> stream xZK6 Wzٲd6=,zj; lK~)EYRL1ى,Dyc]ϑ g/_3??CP 7qJ~;IE?1t8|6f 8`Dgdlo̟ L%`=ٺa53.k#.>^o|CYbpZD]Jʥ;}rVݬ [Tu8g> FQm0Qk3 {H4pxڞ`l$f|'aݨۭxMlFT6P] 4'Txa>c.%?0kLB^t>@)` P/)럍ßcÍR V;pAiTe=΋ _;nA}D0dU 7 :7s+܆isg x^TN"r1&EY&.5 N REM/<<B 4UERZަ+h05!*v)>-RXIv=1;B7 ,ӫ%;ah!&vcx㢁YBmRrGEFGK^<&ZCzrwD,wۤ- LS5',0ЫV,Y2 PbmuC.U\]q(ڼRKyѹ@cNJm(P=P %9pJlQoóK1vnDJAp G;QH{ Dc5.Pp[b QDQiBE F(U"`Ц x!N>j /"4d{9U%)M..ѢJVc\< [{8%YjIBlWns-O96qx5];Y˂Bk5=g]2\d"Ģ}jMAH\}Î1"BJ dI3Zk*i'aԛ1憧UtoszO:r.Ѫe.!7R $%ދmIS~[Bg&H&MߏX}u-7zM ES5Lhqo&R(*j]#$N:"`K`񦏆$ t'a+uu|.$]R|>?Pǽ}g5Fw*XWܱUq(X5$OY~Q^cJsx|-pu(q#`LơNm;C]"V񾺻y$yD:Ifq5Jykh&8!V p˺sALR= MVRR/5I:خnO+88r(ևPK)&o\{,zR#(7cboo:6=q6@=P$}ZgR[4z[ۼh6'i9 z?F5-ٲi!YdѾr#h^ __ V,4]|O]J_ym 8gfnfhKnUX(xHZ&6/hR)CREQ,*T…R gDY;_ӯ)*ctvGPb|c0Ιܶ&Fᇸ=l9t컦/8:a1~# endstream endobj 331 0 obj 1887 endobj 332 0 obj <> stream x=mtK8 [%8:<ᄓN _=3iB _N͟qƧY%DJ@P"؍O0ػ^.oJ#(qPJ@P"6Ы%Qؖ|[ÊJ%rmquU[J>PS%*? l~]s=4:{iȆï˷xDxN 5ȫGDCo]v/.[0×df;ju ܚ~AlKC~r$? ))1 ήP)qS亰 ˽#jaRRJ,G Ov>bGTDR-ôbuCY%$Şw|/;uc*Q!QxBn*;'#"?\FJmLw3x8?ᯩwNYOrXJ;e+}scw#C=7#0KީɄ}b'sD>b3SSb\=X_%ĥ8-OשP&&%-J\( P"8s@?Vb{v ;V" ^K%@hJ@P"D4*qDgͳ**S挱H[gke%^D4%( @hJ@P"D4%m9(qp@>@(q `AGJiPрux46V⯯ϯ_^AG(UE}4ܦ[{ݥ 0nP>ȔkOSq?PAhOs+%nI+*˯i6u)ɎT__H0(Qnͩv?.EڭonnnBS5nQb+.N6[ґ\H6}n_Nvk=A0xD#R/_R^LJX%R);le%w?XOJ J@O{E>J$TadwPl5;#m.^_α1(z6K cNi 1(QDJ{@sXPbaTxnĉ4b$Td͈ ֩ٻzjAsaPрux4D% (QAGJiPh^t(PlJjP"D4%(ql顸#JEj J\Ԡ OYUKH#%Jz),U4GF'DX. F~^BtDG~? WAGM]RT=^sb6F J@I(ܝjHCGR˭#'Әlmlpw JQR8A16lA)1r# ?O~KVw"J~5ށAJ%q7Qs',)16J6(q!qL*ӸtÂw*q}5cx%£PbAgJobz>=q%T*J,תMVS#2Wba[30ضrKDŕxH"} ]<5ko0상PN[\L4gĹt)@:my%'Ofŷ+Q<&wʲJ=2{DPغ퇕,wՖ5o{_䟗3x;gS <ňWW <7bx?O$}4֮sf%%` %5(,JgPz|ϖ aZM(5~Qt7$%vQw@>+ JԎpV}hJ42ղ7%iQ<$fZdSvcJvҫ:de7$EpkhGe%d'JL43ɇ}"w2xO7JNjo33!IYkvgP DJ=Ls66$oÙ]4 AN]R(Q9{S~^k3yn߉IȇM =tLI #6c]DssX2u";>qB4֝f 4P^dZ  V$vܤOs %~ۢ3mmBFϔ}WEs7qLcI"ɚMT}ݺO{ِ>,=i'KTI2'활L(kBJE"4vO J s m_i'ydm3\I݉7cF򙑱?+WHkT8?'#gmVwvrO7#zP3ڧ }3s|3s%CoW}*;p,+QΤ͟ڧkhV$[ݦB4Nэ\,ibx)*V"$3~`r9;'UJW'w,1W9% u5㝦 8Vפy++ՀީTb.Eﴳ(Jaty8Pm혩DZQ}*&.tF:ܙ;PNXאfIN$QdHH[djLh hO]gh3#K1.k/N;z6Ӽwn`RJܯ̱\E^S kdeO 'jcť",l](orFXޥ%/z5/-cAmﯚiG׷YG#=٧s6Ҽ(iWw2v$%`z J4i)=ޔ(qV kP"{J@P"D4%TP3|Pĭvf-RفZY%( @hJ@P"D46af#3/[\uHH&oC.υd.1vFi2Ӎ5)()dWwnn4 _çI"sC%+4yYnk#(M4bWi1v2bȕprmtٞvצȜ勫o%5M[8C ;Li5e_;5Y!BĂ&Mj|mJlRIt5 YƯ3s^^՜]%Iimb"آ3G'HJ!KYϋ+($U:^aM (_weg1tNMN&&K'L5D-Q2\V"> stream xZK6_@R#!I \tv in{,ےp}K:w21ghyҘdko͏?ߠ߿sML ?}x,mwή46_tV8H7sk6.v^OtuWŋt=}ƛ'vq@, )H; Zy xښ@4"7R6ȑ9.La.4S7s0rk=(Դ w0GmNS/_'O|fIitcDwVVwcSv*v* oxYC;=42-V sz:hE8t",TάHdh_E*'999F}یQpgꫳ>Y6]Se!N[@(@S,V1@k tA0s~N^#z6&5l]*Z2;3e{{wٮmh͹v2uȭ)8wya Na(L7|x ""_yAr@ `^LGs&4k^$"DH/hĒPQ%}&_}zDsNfP 0hҮ#NЛtli܌'m kLOXCcOn3h 驥@K[ɬfйFmdӓL6Noz\#IRy6D|QF@6{E:aEa"1iٮ:(p==s䡎ێ̓,̳E>J`w3/X"#x>hL6тo<՝_~V]IL>qR?9߰>'ս-; m H#L '٪)SeJ 8(N{ǀw'8B֏%>i|ꩿ2a+BMl@cAFQ`δtD?}qWa a[- endstream endobj 336 0 obj 2061 endobj 338 0 obj <> stream xYɊFWܠT.Pjv c3s;{RnxR*j[YTsbLe=T>:}|兗~돾z[{k5'npGwseȴhiūtԝ6MwE2^O_nV,pkc$cR r;X4`w~6< iwIE)?N$y u!әس٭#C4!7R݅л2VwE˦pO\R %$ Jq:f8_˔|ܩ+jfU-Ú4KW; l ]YFMd1 ?лOyM@S ɫuFrO3JT7W"jt3Nl^qHnFQUaȀmQ-RB__HkF=4qd> ,!TѓP*/>@LY:N*bE]]iWC|HzMNtva[q=6͊D2&iMi`.m71ӤӂNm7 6ĸxJ5||O`oUYC hXk"s[ge?$} ] >> stream xr8pu3sߡ72;YeL&Yig/mzHp/Pr-.'uV%+cYw1?,1I(EQǟ(D  (j@b0$w9qrm]oO{>% f1YǍtDg`#9Mp.Ieq+_c$Wc#ǤP7/j3_l(lx1̃#G_&*5z.~y}}}yGO[/"'[h'lXiV]rkI1nWZE#X>;D&rJP"jEbj% ^S'^-c^=_旽7sӯrTaq ݻ2րDlk .1sX9˭ ڀ9/szsWUjj)A{VUlWLzU[sq{Ϭkm9 foq-B~%fעubQHZY0+Bn/d~LYeBvM Fd})X=ju%Y7%\N=L&埑_pGdOѥ0:6,uLIJc\ԫ^_i+O\Ú(䃵UӆW5DaJ s68>>><.ˇ^C+V^ՆI ΖR'9:%˟:y5bZc:.`]K:8{f:V{UXgԝ}}˭FVV<# + +K)MO|$N^uYq;~~|sG*GkIl.QRkLꖦ_w/k7ΚɠXITų.3n4F2lP7 GxN":mb-?F:%yوqʌ$Mvc~gyJv,VV@8NZrVqD6۳NKڦ5k X Vlqm+BtւU.u&N׭J!̟}r(u^dZ*#*Nm+UaEz5Ž9hŢrݚ2k Fz]Mr5ۆKzqZ''fu+`^gKҚрππhΛ>pl,}ggg`nHSksAxl-=^[7mmX;+S^d۲"$g6X%2zzElâ *bdq+coּXͱtr>Ko>[~W?5 8`3`300]`JҚрπππtm y!nX[$ Vp֖ڱٍOU:gmqf%kiyf]kghyf-kiyfU붟iyf5kiyfU붟i9N}4)܋J֎m.D:kR_j,dҪ7N2 cUs.ݟkLf9Wi5֊VԾfV)okoPnu[7eٶcmu82`q=`+Xhc/-۶VFbH_,[3Nnxb|=ʍ#aqa^ԫ١mmPm[Tޒ6,9PVMcֲ ZVO3ֶkլ#V 0`kl=--^̒ǜ`Bpc2sxMM:Euiɨ.Vl/ʕ9iNS2Bug˒qciLujYg⺃V,֫9Y~\֊qghϧ3_X #XۮUVXm~~~ ṷ6>tk]oπՍsz2aW`u#`#`u*`gLU8~>mV[IZPؕ?VmX:X XXIYv*g^e!CC~~X8Y>'$֠2 N) endstream endobj 341 0 obj 2054 endobj 343 0 obj <> stream xZK6y{4m` %$l%?d!{&! 3mIU]U'}xTwT׀u?}<~~v:U磥/t>N魛 d~>ߴu/jSPdx=>2_Oi^~9Ŝ^Y8A.GAߟm.Gϯ? !UQP@F=+ӟ~pԄ^W_ᓩ!=/y3/jH| t Oh %,QDzkG{Ї-^ӭ ~)XRmE!PI̸KoNq$Q,J6$Ͷb{5 s@\B@j+ @J*n+v̢-Z  ٴE.|TТ1gMIٰٮ*ʑd&Tn\c7i,3ۑ7.Y d͐f9؟)>  a ύEKDeWӭk#pgqD M9&h,L$ 7Ԛ{Kg3B8{zQ`qc,s9BYe=]!WLdE<6 ]Z!8D]]Qv"(ܺ Wғg(Q;Qa,wu$*=`0zd>5&y% &=6X*߹WY?td)E4ɺF5zA8H'Ш-nXqefRI|kB'8l9$-!.&c ?S0Xk HѬD1~>;,KhJ( P5M\ T{$xZn'pb#5ɐ<;_` -,[T6%*ݐ@>*;=SwYZ:~ϴD۬V9XP-ikSN=)4HeaE{A )@ZO7c0%5k)I9&{ L/"Sc%ՕfZZ,>yW%ȐX2Kz+$6"]%O`fugC-y~qnS8PH#5IU&ugˉevT9@S*cf(jVEO8vTlc2m5:nk .liW47'dmlWbXSb+1Z?'=ɹ&b:YMY+ ;VNlFlD7P@Tws+\ {{dh˂isk&;<{8rO5d:V<3Ƃ~ mu]Xr.};d:l&A4cŸOKWK`%>nj7ك>c_^T)YV\3-\vK!bR ~e î.7t}.G. ^ '8Rz(M7F JyH҈3m.L~?CQr7[=I\G>> stream JFIFC     C   M" z) >yΗ>Daɽk-2!Eٞ'}!OڜQQQQQsJteKŋLz="&ktq<s9K˫meΨw,*R¥,*R¥,*R¥,*R¥,*RfNZ}l9F129w\-mTK}5ڝ3]xsFc\6`k`k`k`k`k`k~0gK|ob8Z_1iM"!_:BmH&ԂmH&ԂmH&ԂmH&ԂmH&ԂmH&ԂmH&ԂmH#Y1\1رYdͪ;;.*.*.*.*.*.*.*.7ql`90 l 0zgGGGGGGGGGGGGGGGGG5i![;_-%syG[jnS)75jt7nC|s' LxHepv;8vAc>"M)DҔM)DҔM)DҔM)DҔM)DҔM)DҔM)DҔM)DwK&>k:8}dƖOӋrx{vswoCQoepQpQpQpQpQpQpQpQ>oKᎀW矟?My,>0Î;88Î;88Î;88Î;8c W1QfaFfaFffaFffaFffaFffaFf<$.!=y})95….i=Vٌٕ6 *d)W̘oLFWk<Ѵ}EMSꯜTC㘾З5~&i bf>Z:t1e,#%20P@ !`pSIti4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4i4SOPQ-2a7{h/yfq3 F])㭫kL}oNv-\n5NB9qrsKhnc΍ ϜDn`VN7Ȕ1l-QpB+K/K}X՝WeW-?ZuR jY5Evd`Th\3fMqc0_s62¸DFwn(:Z"7p wn7p wn7p wn7p wn7p wn(910O::::::*ƓΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣΣnF ݠv¸ڻٔǎPk!k8bEiA%8iIv֡(Tq(qr(qr(qr(qr(qr(qrڐ'aTW [sczx5iaxrnIkT;Z i[jShej2Ž;J8պf.El6O'͓d|>l6O'͓d|>l6O'͓d|>l6O'͓d|>l6O'Wf jn8{]a^ij9xij7kPa.?=5U4_E8.0P0eQa *,޶5QjJ2h/\~sKݲWGPB. xM Jب+c@h_|}@>>|}@>>|}@>>|}@>> mk%7cV,YVWrnRyy~ܥwl,*,15ahڍ[rb9(NJ9(NJ9(NJ9(NJ9(NJ9(NJ9(NJ9(NJ9(NJaKFEMFMuJ/.>pMt깧DӊN`Nmm2Ӧ+Wַ5皜;#Jaeq7Ԧu%쪢]qkE"RqaK%N&h, 򧍉hcf\bou❫׻tdB[u2`ۖfcv\XJ\-T\ܖ-NC+w 1d؜qiW PiZxd_%!"Qa A1@p?!-U̙&y3ɞLg<&y3ɞLg<կVѡ:AAAAAcF~M U,K%dY,K%dY,'>㷭I......}uk~X>zK+^We{+^We{+^8~U2dɓ&L2dɓ&L2/Q(J%DQ(J%DQ(Y/>z0EQTUEQTUEQTUEQTUEQGcn7qn7qiWo[Cy$I$I$I$I$OO-a"Q!1 @A2PR`?,Gѽ I*_τEo[Eo[Eo[Eo[EwWkX7+6/#5 CP5 CP5 CP5 CP5 }L>5]/jPj#V[tdHdHdHdHdHdHdHdHdG}둴܉b*.V;.?g}z\zTS[4 ` ` ` ` ` ` ` ` `oYYDK)6i6i6i6i6i6i6i6i6hEѪR AH) R AH) oK~׵ #׺!MljMI5&ԚRjMI5&ԚRjMJuOD;z6Tl)=ͼio&My6mɷo&My6mW[Och{c?_ScvHvXc"__M !"1234AQ#5CDaq0BPs $Rbr@ScT`dp?,iDM4F͜S6qO l<1g͜S6qO l<1g͜S6qO l<1g͜S6qO l<1g͜S6qO l<1g͜S6qO l<1g͜S6qO l<1g͜S6qO l<1g͜S6qO l<0JTU*{֗O$[y[?o6Rs8U##K2bM4~-(l6nya. \YI4f=Z:Y[(ZWn (@47pF(ZS ˱0lGAgs96nYT԰LoevuyI{K-Vŀ**N&v_$뉕w(I}dɺed!,&MR5է{&r ^:ҴKNq.6)(:Q=u)יymԑ :htۿ|Y;l&^n,(ZRTm S$R$[K k\6a6ݕ4!&B*@57DMLWi텵%+gZR<od~X)*,aդ( _Erz”5%hp-I62Yn_qvqw*yIm7K6sR+~vLbk+eKjD2rjpw -ʸ3\!VIqv*\M⇨C^U'f_?p*mD^EKW|:1+!m*29pM3fro,%y1+7Ī4i~jd~vXf̯}|]D[q+J"U(? Q#-b-w#2uDGIIN[eZfŗ,+DN)Kq *RlO֠Ɵ~VV96tQh6S31g0c`1c9s9 s31g0c`1c9s9 s31g0c`1c9s9 s31g0c`1c9s9 s31g0c`1c9ﵟ[NTe!OT+Dd&)W&FO*,圓eSmM:3쪞llTVpN`}::W9.7[m!TimAiMRkx4?k%"k/KKKIn!zolv26(`dVG[rzޚ bar;jeOSXh4[ ԢReiZKWzZY 8g)"2{ l˹}m--ZYQY[ eJhKPm ҇6$V&hO-0r27lm5?䧗8[dE{+zajQ 3OTˁUy5'8i ZG)BmjX]f͚k[Z[B=bDZxؼq^8/{=bDZxؼq^8/{=bDZxؼq^8/{=bDZxؼq^8/{=bDZxؼq-r-UM (P9b`IQ?X*_4+XRlTaNJ.3lHBzB>&$<–S~Lq j?YZ=*ДTHe.K6̥i[i_~ATL!͆y57SLKMm./M{ $WYVqk2ƻc/|k2ƻc/|k2ƻc/|k2ƻc/|k2ƻc/|k2ƻc/|k2ƻc/|k2ƻc/|k2ƻc/|kUjӄl?4Ѫ|ƫ]w j<1|u?eDh̳#Ow j<1|ƫ]w j<1|ƫ]w j<1|ƫ]w j<1|ƫ]w j<1|ƫ]w j<1|ƫ]w j<1|ƫ]w j<1|ƫ]w j<1|ƫ]w j<1|ƫ]VW{;ڎ(9hj8;ڎ(9hj8;ڎ(9hj8;ڎ(9hj8;ڎ(9hj8;ڎ(9hj8;ڎ(9hj8;ڎ(9hj8;ڎ(9hj8;ڎ(@[ nѲ #"].m^qMiOGfeܤn7t+2)&ժV}EWY%덲^Cfz7WZy/yeܰS`MkɯJIL]蝗 \P)Г}wߴnVm%ebUU u-hDȔyK=g&\^Zi9K2BC WhEƗ:zo)Fc9fe䭠%rHGjl_M%(*X*L(mbUlkvLiJTvTT[6mZ.xOHNBo&f(v g]uD!aJ=" 2m:*:?+蛘d%vMS < hBoOU Y&hۼTՋgyQJ/6TUV-m\/ Eݎ4OIT̢K6Z:"$"eMMK&d8v!v$)qygr}44tJ誥m>qVʾ(I艦9Tef@%%:*uhE./eT))~:W,Nl̢LiTŚf课صe"ҊiW_HaEhi#_ G@I|=%zK/#_ G@I|=%zK/#_ G@I|=%zK/#_ G@I|=%zK/#_ G@I|=%K鷫 虖!jeBKZ%҇ːʵB>[(\(*ifΏm q&yVUscFvf2*Kim%4,4ںMm_vĺIF]w }JIpQw#rJr( }+~mPE qi[3@i2--,u Ry.u:U@P~Pi[SC Qeq1ZE2vljի_񅼉 dᴷC)[U'9f U{2'mפm m )JE_`+f--T*)b6_(:s~6]?y*DZ7ߤݢ*~a fI{%Ue0CNZ"*- =<\a,[WRn1G,qKzyLl&uY3Bq3n$W7k))Im/W_EaZL(A0Bh~[pW=n G^+{tz[pW=n G^+{tz[pW=n G^+{tz[pW=n G^+{tz[pW=n G^+˗SV/?hV"ƅb/|hV"ƅb/|hV"Ej?/?hV"ƅb/|hV"ƅb/|hV"ƅb/|hV"ƅb/|hV"ƅb/|hV"ƅb/|hV"ƅb/|hV"ƅb/|hV"ƅb/|hV"ƅb/|hV"ƅb/|hV"ƅb/|hV"ƅb/|hV"ƅb/|hV"ƅb/|hV"ƅb/|hV"ƅb/|hV"ƅb/|hV"ƅb/|hV"ƅb/|\~GRy(4ɭHma"]WJ~$]]XufuMKkzaM#ŢmU$VruCimpU #CI\S(l)h@56FwWOd4*]M<*KL˜e*:M}=*ҟr]H ͯ$qķ#TUK(&9CK XBJ|W z+[`dSo +0`*eaB؈mRJ)zyQ;\p]}sz_'3~ZJZ_\N9ۮLs zSM ҍ0X[-0ʲy$TkXkm9+#ɕeDZ5jz Z+XTes9BP9bd2N6[liQZ[Ct4fV׿D=& [tJt8(Sf2jut_tī>mE:hE"IG&e[LӒB}%ЦyTP,6_g_1E̸m[VA-\g a]@mn90h+)MݚC<4͊):le`nm6V tyjFEP-2+4EYաז!Ū]Ĥ&MIHTʦ,&a68Ԡ:X&lm.PBa#&{,T)+oFч g&\R@pr Dvl˾JTI+!t9ª7\No&ɶTͫ/5:Ml/3.tmPhAZVRj*JZr- %*UlhzN /.!.X5s+nʿGyHvie ;a@J/O >'y&u% t\~Lbi)ih/83]W"cI"]̋ŵ\Z&Ma !̓s3 (ɹ[_XFaӢy,r'!eBچ _DN=.f?H4%A)]} 'NBCVɨթ5 A~Dҋ fHU/LFX/6T:brNwf%‘m *t! )r)M(j#圑WL[M?y$meĶcM.Mm6 ~'o&Ke2` bݪ+.i!T-!1AQPa 0q@`p?!"HCf>tӧN:tӧN:tӧN:tӧN:tO0Ou@}TEI7+fQpALW Bp2VN FHP*n3a$lS)-FkTb$Qh(Q0,pe&3y@AIøBDsք<1PTÄD zPSlp4z<9PP?& ċ+3aF6va=#f LD(6p /腉/ΊgRoi *';?$Dډ,9 6UuU%V! Q C @l5jifMnہK7]ZCӷ8t4G^VҎ^Bh9ŖUUjgʡ l(kRI E@ u-ESӢ[YD;"BkR-:"KU\]% MkNK @h/YW=Z|\Nq+1f%lxsssssp{_%lxssssssssssssssssssssssssssssssssssssssssqP =up eeeeecW3̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̳̱Q迤=/!a"6 'ix$Ɛ;)C "3K~YܟLvܟLAf.0Z  3ˮmlƢx@5 l,9AOw';gr}3>ܟLOw';gr}3>ܟLOw';gr}3>ܟL_Պi8HÎwⴁD8|G}z=ZgF` q("y)q ktUR~ӦaB#hJBM^)#@c|ϟ>|ϟ>|ϟ>|ŌK8_M/u]qOPo"M]u]u]u]u]u]u]u]u]u]q5Q T(r. pK\%. pK\%. pK\%. pK\%. pK\$z'!U=05o#o}~qP4SefaCZqġhK`FQԛ0 Fzp)3pp^j[F `ڲA% @EAlЊ7EN1EC" H:`k![Y0E=IK! '?@3- ^@5h o:1%ѡCM扨T!"@AĒªZDsMVTpgS^j mpzej1B m*VQB6h;i4UrSA45N,hҁ,"u[Xtl:U j_B553;w{{;w{{;w{{;w{{;w{y #O#끷׏Y?ÇtLc!hP kyK5%9BlU,x! "r6P+=_KewЂ2h0 D(eUhU:AD-? u>g=I$z׿8Bs˜܅'AWp&& ֕7<:ϩyzF8`iTaљjsYFhAAVxBJHP? 9i^5"3QeqD(:![@K#e,3`Q C' ;w;w;w;wO_KuEOVw d8m /K]1lfD>1Tl+(L6K;PΙZNp_n PCvQasY(3|AAAAAAAAAA`|r1:TL2dA%?:T3&L2dɓ&L2dɓ&L2dɓ&L2dɓ&L2dɎ>mm鉫7f2pLPٹ~:jGꧫV-ktʍK`luknMuJ>3"ޚIa/rR(]j&NsWo(-4vLS&&1RXv3G1Ϝ5 =kr{[W8Maii16'/-yh|&Xk PD#{# d' gKvd9P<8\3c̀RJ%nlj4nl ݐn 4 [jW9lҲC} J BIäܴR NxW#!!E7c\f6Eu,TZ i 0V;Ge rQ!BL~Q$u 3Z2 HqDC! '%AV;D̷L> |1("XǦmMk7P$Z}\VN(qpJzy=f%P<& w}y}}]{8 0C 0 0 0 Gm((,,,o<<<<<@C 0 0 0 3YwlͶf3mfm6ٛlͶf3mfm6ٛlͶu}]Wgv#{Bз4-M |Bз4-M |Bз4-M |Bз4-M |Bз>UI>TGmO$H"D$H"D$H3$2I$I$I$I$I$Q&OI$A'Qq!a1A@ `?5(N*h'T߉Ѹr]͞_&/gɳl6y|ߟ=׷FѴmFѴmFѴmFѴmFGOk&ƢΧ_gÑ*"cЩlR~'F|=_Xc0Xc0Xc0Xc0XcKh""aAQ?)y5) \p.r]仅w %.K\p.r]仅w %.K\pNĪ}%S;S),mmmmmmmmmmmmmmmmmm?K_֢MYYըSKykӫR. \0,apX౅c . \0,apX౅c . HAihѢ?d߭芘x셇V5#Q)}"t!ЇBt!ЇBt!ЇBt!ЇBt<ʍUB5!W HUB~_*!W HUB~_*!W HUB ԆRAIp P„M#'Z$ڔ''fn,?^ T)a!1P AQ0q@p`?i8pÇ8pÇ8pÇ8pÇ8p uz(q_!]5,u6{lۼh޷T )V?ƂMdTdy~6d0n#g%J{q͚G=sIx]fބH* ձv;aMC(.'NUl]|E;N s9^f'9%<>ֵgA*.sl>#w|ߓ5 s:9Ӣ,0$=;-v 4 X!CKaD闧?"8و[1TdP3|ClZ]'<,rgHYy V57<cow !L1~J!B (PB (PB (Pչ|;ZĚeď  =>3&vAl߾w>9.a\g F~X#Y԰k~RrY-,uw7JK_Y+ 9}i*YQE@[)+ {KUa l 6`l 6`l 6`l 6`l 6_l.ר`5}#<ζsIE7H`4Z.BWhoqUdvtTB&RoT5G Tf`{ ,Xs[08Y#\̜/qѻ |d1y9] U=Qh [ `&iJT{|D 渆{.053u9ARj4 5xQgh .pJx z qt}7."6m< 'bp*= 2:PE.kf U[H!^NBMIGX?`\dEs~&W9 YD,ê 9os䭓M(aF8z;!_yLKa&ʷL~'bf%.p$[oPs\0y'SPPPPPPPPPPPPPPPPt>V &e5M&cGiªX!2@9݁ħ_dqi b䐋|x?96lٳO9BNM6lٳf͛6lٳf͛6lٳf͛6lٳf͛6lٳfrbjw/[l-Ԍs+gKhW;h>լ!ݐD{ZvIYw<Pz$Tu&tKgF..jЛZ>[{r|ۚQe^R@s9LVO^H_6Gmj, DF=ћuiRs=,".HP,ùqDb{,]nFz oШzڎ{)4sz n?mbMط &rJPz5/ܧ#NFN(>o荭2ƸpF>#m%ùA~%`rfff}󻩣XbiS;[ͮ>]+; h  endstream endobj 347 0 obj <> stream xZG#GWyAJ@# €'c0/T]u`QW|{G TW|~uA0AOboh+KpN׷zg1^4yE&^.G o7q LnMJRROOOS/x=ȓz f%f?>|۟^+\@$" lԈ?qxLSmӎΗ/nhxQlGhV+*&xGuPR:jΈkHxf(湦sp#SX lzHen&d{m=hZundJ dp{J0I0(W3ЏsGNfJJ¦9r#$:"LΪV_bI;w]=AeL |5:B]ιZYԞ@8I ݲy&sfP(N]:NVǟhDS&MZtH&,D&AZl(%N:7íF3 )fOTCh<`6i%.Ŧ(sg٫h9H ab!@ ڴQ@4 ڑ]OZʦ0"qf'x[Y,;웑;c!qi2+wtV||t\!6&R裫?]jEp;Iy‘eQ4綝c->nt\=([fMaH2ZTXDYt5Y֥VG&#k[Q`:fDj PYY+&`5d3UCӁFegnJNͨא{64.qQ 3`k(ͮޓ]BL|(HBKTl(݊TC(e͔NG71.jVudXt@K`SKƩӉQ{sNI{I_ B>DYSٌz|C-T c3g"ڸ V8~WU՘h8QV=)-%P<]g%tJkN4Ǡj2QwU# I+\kQ C؁[I7;i}H v kD~UΦ)VmJNذ2uFu+qOQ~}kS وjRZ ѷ&]=,l86PLv5Jz"W)7W#7N`^QtF6>x*X>)Ƞņ{^R8I.j+*YK؏6xwu4V{$WQ(wY!/9&vSyڴ5^lYI"whM&hycQ rȉ` .ZZy*u[cN"*ub.oņt=d29CۖHx!ǐ[ۈ`]:1DTTZ3R -fgҋIn͓GْZ"śݦoVp;i`$jSb=kMK#R d)\fLZOqAD@Ŧ`|;vu+h C5>A@XB<6 (>=ƳkyrIY1!mI֯ !Ź&{5LY-@ ȶBy8Wb3Ea*Zӿ.Q>Tßׅ~N endstream endobj 348 0 obj 1841 endobj 349 0 obj < ] >> stream xK8F5(i%k+]Փd-e#=6!!aH㜓/ ةX._ _o .tСwxِ.$O_Zׅ).>l0Zq௿:?0Ӈ.Lo7w{pQqsNT.F2.oaƥj\qQyNEu.Iood4"..Ήk:(majrkR>g cpao t ' pwhT:B\ Zk׽ŚA( p.t:^O -V#3 pCYBQDIFAHYBYBa@z)z(z[(=czvpmP\ *JUGFMGV @d:Bcrj5ǁ2)@m+bā`Yrb83TQ }@\P/|qmT9~sс8@ uЁ| BD.`9:B\ p.t:B\ p.t:B\ p.tСu2YJp %j P:B\ p.tphX߭.t;K5w֋!Wpf֋:kkS)^DQ\t]sweD"!=vY\g- ӞOlXwGo?akx^Y깂fh8_pA¹sE@؎]]#˪6sOQ֎fޑ6*"엜w[oG$(/m]ޗS7Q \:+X p W%\@"qqLʴQG8柭.ta`K7Т WԞ7qwJ2vwa]VŨ袟vg7=jV><)佻}661ࢎ F0Ee"E -\n?dƏL; \T"E {pQza?E h*i(_s5u7? \tF׃zQ|c"6GK*R?(ʾw/eV\.{.ޮVe.TpQE*[H6t114ҳn\h7cv*itE%p.t:Br.vv[Ɓ@(Ù]Xh:B.JD "؃EY'H05m'Ȣrh x\$Ȉٴ[h.LH% *pS"%:B\Pc܍uB*ٵ0Ù+gpi%\DK s_\DK.O]Eʹ$\$ͅwijy6.ۺuIiZrH4rc=:dA\T%tV5]雮A @*A_gH_׈؅Ճrz׉z$(:rf^kn؅Z\esIla o.q_57 53\,a\lWtg\R.ֲm. >%wAGnܱb!ʁ p.t:lvqzξ"_\$zͥ(/ (.t:B\ p.t:B\ p.t:B\~zL8|>0 endstream endobj 350 0 obj 2684 endobj 352 0 obj <> stream xYKFW`owW#6$L ԣ_n-ge5UU}h=|t;*k/1szW?+PA$xۼ}AM MG|IY-e:jvQW~^hVS\Wf:Y}p};Vr2$E xQ}# _}^)gZ^g0Y|0yu)[Y3NaXΑ,Ȁasp~ew"?%lYcdxkRqh6p'{W8jۥPۥ;J*[fQ#Nt U1bcW+mfe?3<>-! 2d bz$!Y+2*M# \ME-"i1Iow6F^oJ`FuQr]z͡§q + =NΒ`YuӚt0k0u&A*cft 4`'wޟΎ=p[֜:=c@X0LlE pvtQ<}Kfbis۫ *I"b2)QA#upnF(C\{"Xk+g! 2B2 -P5sIbl#$upja=jPag@:z 5Pza*xq5&a(("EٰЈ#_Tk+pa#@=H'cEymz0q53%Rv FETݖ"̹M&, _+x#vME@.{WQeuEV)fb^\a59'`aA%&^÷DIMCS^k?c+YLDT53C}!ao= h^tY,CUh¢ld{ aVn5S E5` vo ,Fp危@U{r6󰆾ʁ幀(aLq[kܪa*oHBKjZ#>\q` 6nB 6XS% !gMNn 0صud"/6v[8qCkFa'mܲhkw-6F? bA)TF n9^s V)pIHBS4iˎMPMy,f\RBc3X k)V\Z$L @%šk$=(+g)%O1%]e`;"kTw0lAlN]KRԌ~VetmE|N L,b񯛵"O,5fpm:ey^l1=wM 5ݘlIcrX[_]'ԑDRU0鵺VKYyϔqL`iQ[ќMн]FTCuC,ݸ cc^PXf}u\G-S;fpضA5(\NTK kѢ&|s!bAi}[c[If \|d;zed ͠~rߣ2(F  PI _5'~NW_ endstream endobj 353 0 obj 1738 endobj 354 0 obj <> stream x-taW^rHWڑʱ#+ǎDVrBvBhv]i:|$_,v_;$I$I$I$I$I~H߫?K$ U4$ysJԋ%ϧ<,T76xiq'7'f4Sx5P4P'ʹN f>OxF˴I3mj{VjyiK3UM<^-s-gssaY{bzS۳RH3XHYc{$x{:e0݇QG3Y}5m S?p>F}~m֝-3-sQZ&2sbnK:H8}lZiSͳz߽(-Si}Z!mǒ{_@=w^2o.*v?EgnX<|yN)0,X)M_'0 c_Xxy;`괡;(DmzwƬ v3T0-h-lz.6^no 70X Z渋U!-s08kl4Xa<H*@tHα ŧت=' qx}cxVؔiy͖: !͎Y6YdX7ɶͷbᲖ22.8S-3)[f`3f]? ej Z8ŧE/@|u>vIZ^ebߋ_OYTVZQ3fpl|Llh5c68'UxlkTb´i<+^u.P-fd$iy-sLu!8k#U5=O3ֈtnLs5CU]?ap~e>?OvlIQOeg I&Rԙ) >v[yTAWiw.f+Y-RH3XT<.aڴNj2mLڞZ@LGi@h6iMmJ-O `i#keL4Ӧg'f4Sx52ZMvI"U:R˓x4ShunlkWVh by29e~$yjd< I2Z$m$i#ne$YSˌz`. Z-L['.?Dmb||=~_.ogh]oOJܖYVJ-?p ?W+ Dnۗb\o< (_Q~xQS} ZPxfMOevy#nk>טmejHh%Z'MF3ƹ`,ori5NneUr,-s%[=8R32\jlrQ8W yZfO\ 4-sjs7ŢVNބV+s2jK~8[meZskZL@:h@< Z{j,*I25edEAː$oB-C!ISː$eHі)Ғ$S>c9|*$wy@zh@< Z{lˋÒ/sy}\߳)F73=+c1k4{^-0fKV/-s RtK30;iyZZRޮmr9cƬ5Af(r>H>iV jj-s{B˼="i\χ4J*-qrl&AɌYmP@ΘY\eN)edu{duISYݬ-- NԆ2\2p+2T@h@e2xh@~ %m6𓷧Ǭ_-S}r}dWhccج˵_<.|qL蔗"}-HGW.|ay g- ÛÏN:mXR1cV,ic/LԖ>.cP&o|{CFLfz*Տ;ʢc/L2覸XRw,ꔍYc>Ƭ_3f#s[末9U˄ps̒6W몏1:-9cֿYŵ*h)+Y1J-}eWg2xh@< 2YTdjGQ!IބZ$O-C!ISː$eH2$xjd< I2Z$O-C!ISː$eH2$xjd< I2Z$O-C!ISː$eH2$xjd< I2Z$O-C!ISː$eH2$xjd< I2Z$O-C!ISː$eH2$x^2C1eH-hHte2Hث$I$I$I$IN endstream endobj 355 0 obj 3108 endobj 357 0 obj <> stream xY˪6߯z;Ra HvJ2$ldɶwI+qꜪJs¯^>@/w?z}E3^u~;J~~.4^~NCIM9)7iG}RayNcy떷lgAq{O/?IwG ~7W#m<2q!Or[ĵ&W G HC .Ӵњ'15P.#ėm@]! S?\Р1}`guӚ>}u쇓U'= &*XFqlMiVB<ʘ 0ED2Lfp^L KL$v'e왘F[Q<h^3ch=YK=9hiln4W o4X$sўLs.2)6`#R6YS z"{Bfocc`# G[Wl4#Jh'sb6i,Z&Qֈ䂥b> bEAx|^.×.D7 [ZWQ-%2.6iۊ11Aᖹ5(8Fo--5WaF"]>$x 95(&$KLZc‘iE`.d&縦u )s-o]d {]o8&V΢nΤbZ?L2ztB|w͎:CE<9$ꄰ -U`+@T$}#)ۈg})PuOWDlsjx:$}ngnaMɼ%WAP*93Jt^5uWr㺄Sy2CvX8BVPހTnŗk)Iݹ*k=t''R)M]K8K\,{W* ,:׿pb~:V6XLoc|`d1 ?ցYVf endstream endobj 358 0 obj 1715 endobj 359 0 obj <> stream xQ&E{f9A>|o3RKO Uu)0~. >0؎ou߿P()M S-]||\>EEQc$y&n}2,B~ąd1Y+9VQ[̦z܎$jnlǗu&?@GU5SOUCydyk_oPv(mwgos_Vn]W *>K< e 5g% .wrZ)yMlUBٳL_Oyz<Ք!\]ޅt#Gzm^ҜMn+g~>בz^'J;`:˞2qoVOd  cGewV w Oq._ ?Ǖ?:F 8_m#aƲ#uͧ?<YSתIS~zy)!5~x0|X^ݪ;~x0gʯmOJ(Ҏ= oKfj]dWJn^ƺEfOd˕C~Kc8h`)%"V˖|gUXvk^mLJIf1QhmoX,t=y`r6U]gE@S~=m,M%gVK6'bwVgu'4D+-WB8aD2.td&U1Ynԝ5a{nUx@NP߲p½hzVDW<(2}4CƽITʟ.X^ ͩxSfFT_c6~ݻ[$hW,SyOx-Ozc&f-q8u57!4}v:3|t652he1*aF]yL; ^=VPP8zenkb,W uq#22qfHp|#dAM@4gRU+izeΪ#߇5l:čq7+">̒?9T+Yӕa̟̯g M[֕<goG y?@fL򲦊GM=|a7^4egM?j^1-#8B~p V9E͚(U2䁇ɯUq?%lޭIlN䯦eF ^AjD+7m]Ųg[y#D)6kV365Wlv^ܐu"?ܟb>Dۃ*@ҝm;ϧC%3](&~<0*9"iUXy؊T<ŨHHf1𺲹M2ϕ{G؄swkZdj\DL@޵/&/; rZ 74ڙ endstream endobj 360 0 obj 1925 endobj 362 0 obj <> stream xZMW<,  M@=ewɢDYӍ7)=$w?k=x&/_v7m~ t÷Nяץ{i}?w7߰~` <i ,/ƀw[L$BRȉ]rQx;λSfp^#RGV4@y%[US6Ӆ4kY`Y!Bi=T=à:DYj U[7HHͱħO N4gĨ48+T<l%n 1g:xLY(5lTѢlTFywqV>f k+ĵ:b$=$fbma\Aór pgCd2^ lUM8Yfd|R0@j,w=4 Vu[HHﵱ;}H۩4`:]>躏-I.0ƍf}wgZjuɡCRA+1>>o &7U%L ?aQ>DtROyNY<K9 %hi#r'*5⡇̑"vp5ү&wMd"#ٕdoO94I0-UݜO~XCe:fOi#y={%i89D;͹W}c<+R:7bi y8Et%C:E,hZ]"6v/I +s~%('^e+C׸.2ǔOGI"Cr}wH+W<; x;> stream x1:@6~:B^CoamvڡzH`z=}XOB%N='J8$> ?8 䂣@28 $vG/`_<([r)Qn C[>˒NQG!OGݿ{lT쀫:աaOLU&wszntښB-E>G3L~d<}J~TI!]8QO?ow0B՜ê˛w:[{Q}Qɯ쎧QG=sZ]Eнj{ytT%[ y#QwGYYiKN xzwqVfwaP}v GyrcWG-Z{BxC@t篯)}JȞp?fomI}^;Fਈ5v/궖UN(uM}"+8j2GUY7{QQ+띋Aj׃Pp&SQ9 *ZtRa;pT\Q+dʼ5+Gťlienf8jI\U*kXLͬwQѱ[oѴ|W9kfED=pfؿFT( ( ( ( Vr(*5CDGŅU*'.8*.+V|%¥r^,%˸G>^VN'rZN]rXYd+ٕsbr* c8*"2we߸*9<_7ʼVN@_Jr_jrI˱F2㨸,Z;A- y0r,r:*};~ 3?WN5/G-j<qZ>/@ekn]/W3?YܘKv/xlE ͣ(k{* ݎº+tRXyTjZoqz=,޿&;Cݎ7nz2sT2}KVS8O[+7/n=e j,kz5nRS zh-dޚGنD8JHF5764kP6׳ ikxߍHR5M9(tuNOհ\N[B̝^}4說v}c澾uGs8jpHGmRS9TNpTtXʡr"ªTRz*rdn :Y6E '6GEdz/n!ekYV9í 6i;GEdikRrjSkuր"r>WTNEIԪ:*;y}=ksOV9,_Oȕe}r\J}/T;eG-$Q+cݺW>~ %s ܌0f`&?iP9TN88 $@28 $@28 $@28 $@28j#X 8*:J V Y-h= Xਈ,^Z"ɺ;pTD_-?׺dQYFPN|G} ǐ뙓GQqY*GQѱ*u6Σ ~Q Q Q Q qe/ c33@ N.QcO bԇCĴ䀣@28 $@28 $@28 $b|@0?j;G_` IpT\GKBr(EG(8M}&uǹza;GU% bqpG gndO0pP8MVu/\ɯʍʻSR5)8H:^YXu GfbN(G8v4יS7Z59>8j(|jn<(8`,zvU_O py9-k]ՉU9AGm"pAHBr(EGmꨲz`%8j#RD>`/( ( ( ɸJ~]0AԳvG>' Q Q Q Q ( -ӻx}?csR-/J]zF]^XIֽRR.I]Xٚ.zIU<{\;AnΠ4|oe5*Xj+ҙ~y|y}e|W"Bܾ5Zu CN=;$S tG Uf;=8I2GyŸQv먳 {a=iT9ɾ^㓋˴/`/Gȣ Q՗3N=RE~{}lrr>e-:]ɌDDC8 d@28 $@28 $@28 $@2n+dpKz uԓRAӎ( ( ( Eo3}E Gm䨲n@S8*|>pvj-A-u(E[";u:p"1(sOK5JW;i šzۗͅUyK<"yQYE˒BpAlfͪQ:Rmj em5^/iSnA s֎ɠloTϩqQSN܋sE;W[tnpG(ecŬ.{tTVU)^R]u7R8~hh}565Q??pqz[% :ٌFb`8Xoav/o"ݧs;zځ{ zP 36Q?!ʰӧy7eJ^2E#;j (4pAA_O8 Q(v<yoadG D GdpHGdpHGdpHuT{3o6!rznbԇCĴ䀣@28 $@28 $@28 $Bə &p>paJ_dp, & 8 fی,GAr fqT" 8jX͎0vs> stream xZK6Wx=T:e !I \U)efӿeYd:ӖaǧQI7>59*i_5tC>vЪo:hS-?|?o54MyvVU;g5U}j5iUk~d6&4=m/ z}nodxm6ԊrATH`qK>_bODmҸAІ #HO,:_8GM|V'S`YNG$;&U]Y$j&$*:Sa z̑x0By/ƠѠ`>i!h/j% C} 0h: !`3Y7~/S3{Xqc/r46f6TU+伥*0 7ħ\:Ui&H~\8Ӷ@?L8)uĽrWiFEQ] ҋ-]ԕ[k Rz u+-Yݮ 56e ԋy/Yi3USRciEݵn+n]q.fS.XF-I!0k-=3ִUp`lm>uq; Ze `EE.ځ*g̚w+hyUkI*;Dl}+gPLrl#P|<z{_6oNXH`-5fѠr`Z4MdP;, *2@{9ok‘xnSG/LWEE.i_ _&PCS# \=Ve< -ɃCk7قANPeaQQcEH#Lx'50ՑfCF /.NU] uGv&'۝f|/ցQ7,^pxtG*_|r@K1j Os`R9&1YAc5'E 5+̨b),1]_L˝0X[P˲QQ|u !8oȅk@ʾmEr$ ,4(VU;]$MX8 51_m)u$d+(|}MRS937|+(y4XXZ{W8Ik3MFS]] RWvރ{UuQ^zW;cvϒ^" 3:HrIRxIl7m@m:@5D!x$i_\+a盛@ v\ 2R K_~yW1pIq %U b' {nZqUPշV/8MI`~s⸌4}P,wn9Uy/K dUZX«CDkeW֘X* ׳wͩ+:d&V@FvOANFDSrR0p|hsؙk .]l$<#eayf } sprw5PձTw}LnQLf<=? Me=`5z0 ZPrKg};~s?k}7@ endstream endobj 368 0 obj 2110 endobj 370 0 obj <> stream xYK6Wx=t$[C'.(]M{ iyH t wu߇F5G|@o5?}j<>~?hkTyKoͼtdNiG3kso!~}_uی5o.^Aq02_whh?ե7gG|^UuFJ4gԚ?Lyx=o ( !U^PXAq\cs|xH5\c Ե͜949o՞^8DeKj[!):T *N2g6o_qϣxڝq֕ 7_ !C1vD2׎PZ,Wv3}FaI{Y"j/Xi+6i)T)ݖKY!N3 qUkpO+B$UGiA/`* tTe[j0"՝|8ܧfulxkPzF,u8>Mȳ&YCm+匙p۬& '>% k}:Àyrf@f:!p Eʋ *6B/(V+ U5tBLbY ;A^@캁]9=#pvy yA7{L*dN&@ֹ`]"K௉-iQrCZ Q#5QDآH:}ZC[E`YM x[.nU$~֞^Ō/ &ڽI+>!̎&D+Ɨ䫆hvY8ȯɈ I<eUwD8WR yYOn!eg 4__~:w߅jk@7_:Na;$͹$Th^2"3 V'l-qYJ!R5:8WĐ,*g*3w!s s119rqNmU5պ\c* feo1.:,xfv-I|e0H=] j=p;BZFn<"nb2w%0QZk,D/ޑU" KW0XSyedfCt- 6wOTny(Ac CE[PUhB"e 2Zd:c^1;6R8;PQpjJ( ~9D-,o~]͑GoFAS;tcK.޽6Vs! TC4ѝVhDI"aK~j9Ԣx=O9 [=Y[訁t endstream endobj 371 0 obj 1586 endobj 372 0 obj <> stream x;vEaBXa 邛@.THX) :$t[[OSk9?jXu+!3эN_ 07 0 s070 s070 s07O? zZ+v%[(ϒݷ.33{΃ֻmwq Hh;g2q>?3{H=H0ԏ>}Hv5=nV,7[п5݅/(Zalm|r3W#ofQr=棚f! 7j 6+NGOWݥ-ŅT/xd!}q:8M@W`k}*g Vu }5Cqd7|-/Gd1>p z;VOdyO~˝ SKqD×Ss @}T@=8}{HޭOEN@\çi[G3,$F^Hg)78G~{HuE_C5@ڛ5=@c]6Rnyd>p˨Ժ+H>ų7R_Įlǽ'= s/.rTuh4\1;bPBmaza@yZ3 3k/moz#sns 2< H&_{#~\8S3?@,@>dFge܏GYH3+@F.}G3{+@@>Bq?[~}o|~~8ƟwwMOzN<+S@>ZTˣ\ Q/Ӯ6Xt$ՠx&>?CPlR_m~(E)WzeR-侩3ɽ2m>Ųf&@us"obbQ5G8[on_ܲ,?43F;SvN'۷7QfcoZ! $} ZBѻ8 ^)?^zʜ HxVKA odgUd .ւ}{$Fk ͗0c^7ҹܾ%Lyz\8#q $?~:)Pwyҷg+skޕK>Og bz ] S^_o[҅;^UH´;Q2p d|'0C- D@4k@^>Sȼ{bfb<~}{z"""$=. )My- P:7`bE@f?>i>IuH (-M7woI,n)?DE}L$8Y' > ޱ87I}YcRb8 9 .NIErH-i`cX c ˗ͦ$Ei3^@,q@u8xNbfb\*@D3@D3@D3@D3@D3@D3@D3@D3@D3@D3@D3@D3@D3@D3@D3@D3@D3/ZjWb)zmbє_m7kݸX X X X X X$abfb j" @9n #@ & O<   Ep EU @,d"""""Ģ$i E$h E〼2@4@4@4@4@4@4@4.~'R,oe@,D3@D3@D3@D3@D3@D3H}_Q EJv/}o"@ @ Ivq @,$@X$H6\:H |* EzbD?@D3@D3@D3@D3@D3" aZxb8 Zrb8 9L""""""""""""""""""""""ĢXj{aj N?ߍ E E E E E ExĢ9֫* X4# q oX4 (=~;]bg X5 @,|* 4y~bfbfbfbfbfbE@ôĢq@Ģq@sX E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E{bĢ$,o ES5@@4@4@4@4 HrLzȻĢgR=p'@Hr 3Iu:Q `Rm|  = Z[ H_q!X @NIŹH6ᜇ_@X<@7 ?Q; = p?٫ӏHy߻MC/y{bÿspN7}6^\"DAD?% Yr~bfbfbE@Z Ģq@Ģq@sX E E E E E E E EudES~fy÷ tX X X X Xt# zZE8ZO|eQ Xt; (ZwݤGR$I~bl]"ᔝ~D_EDqnF:1$ Hnwug'0Xt {ܭ8)/s9}k_32"F>=$FIqewXk@$?gPn$g d}滊Ϋ?-9N@j%F__' O}qlqT# @,-=/aNk)ftf}-kr/m=LT)7.wȂF2 @, @, @, @, @, @,Hr9"X4Hr<X4{+S!@D3@D3@D3@D3@D);Rd\dVިYhP 0@ya@y@§% endstream endobj 373 0 obj 3939 endobj 375 0 obj <> stream xXKFW`owUF`cHn 9L KR[V{f6aY1RwW}gڹn䁞߻>u|t:LK%'9h}|-|!uϿuy_~>ӀG==Fw.߯gݐ3 {iwOϻ//݌ WBwU1UOE]Xknj Ӈ\*_ vA"8F l{剙h$-T$ܔxaxsL PS#a@t# 8r/τPya?;=тBNb ̸h'A|vW$2ZY P?p"? 0`QBs(@4IU>0k4q>Q6eHb8 Z{(0 3I5BdYfd)p,PC'#xkpJߙ}Y(Ul.;!+5WQ'먧@ʰ6I=ǜM.I9kʡ)dqZob0vQbd&ʋxL>f7 E{uZ'BѤ]H )ygܛt N K aϪs~PĶ&`%e7 K vDžet3!'MH/HI|dIVĊ ] >> stream xM Zgէ<=z[ΌGJ{fؑQ~<̗^/EfOiwtyW?&oѓ4i-\+](х= WѸL4'/q 7dsA\NJ f6hW<`4Qn,ܶ Wt8o(4~dMIX̡A/?6DF`Nv[訾}}b㵞X"<- w\tMXYWп=(wЃ͐M5"hlڣ}ξ!E.~}L$A'jto_\hmV_R9+#clxuЇq@9 6}#n:"+K{tz6AsE\4WHt%*ҹ\E\4W͕衝K5Z6LWWƨenF :B-[ٳ^J5U//uz3WAo]*)@ǣn.:H'ߠf Qq?`js: Yy!t۱㯍Rgy1ht4 W/857y3 *q^tA:Bh׍/f9ajf95mԴ1!Q/Y]uj:]wj:NMw Ea"h+$rLRZ1{AsEC;jYC4?7jp(Y'j퀜pvf-(KOG;kQ';bH(hAG)(b"h+$ ]|L=抠"h|< N.b/>F"COE3"{mK4~o^1RxV*㹩оr!~5: zF<$&1oDE"hbkX͕&Z}?. endstream endobj 379 0 obj 1037 endobj 377 0 obj <> stream x흭:@m<[OnX?k{OC{iNå9\N քP0y+S`."]Ě`Iimٷ.JH ɟ|$ox~|;כM=}.U\PE)dS%5607r6zv>kOokbQV]?|箯[)덽~SMV_}haasמ[fpDe>]C{#y%ֻJwbg{u}v!ӼwrGtw<%nKIUT.9mJ+dbW^ΑVߦlWόN2y$cvn1'@O6]z~?^h0H|ֶ7g{^X^(W\M薓f?@13.l64N f|mav6hRW#Ϊjjvh-ۙ[+tQy>Lʽ‡[9>4oV2tugg%OD^h$=tK= gX#ƙ3=)|1L $ [u^ =kd:g9x^y{̜  l{\ޜ6B]v! }InET:=s<H+K <˜[l?hꡓ='-}$wk}ǝ*w}c* Uʭv[[VU.'v l7"m*_C/yӉ9c-ѾUz;Rw tO_G7˾7k9vy/I5 +{/0aD{xݫ +5z}L xxiݏν[:NH__uv:z U2+Yo]ǬNyᇸBx|owOw%ҟ1}I,+5<=#e}ψ3*Wmo܁s~~"lG!d)3'Z?N1i)c+926Gh!eG/}m'; 2Ɠ\M8nCpϋw{jC.V|>(i)#?o{ 2^=ʽO L_W@>k3K>Ney0mf| k ;Nrh!K(` B1&=dz4#aF2 y~Ú{ g.|86îW#X9s1 eM| ǻwA JI)sty @Ȗ)<8ҍ2q+cl׌W0S^اY7圖?vEoOb {>̿<z?Eηʙ^z܉y-WÉRnPIP.zu/9xh9߆py>=1՗Vl.9}"+՝mTYcf~Ȣ ;}Qm˚/OwLyqW34Tp/yA3s/vzYÍ#z>a!>G=un<OȢϛ5Օq<6#sZx3S˝y@|n ]7 Uw_ uK|1p>Cʼ͌x96A{9ƫ|{/ӭej0wt?^|g^'=j6vs\ \_*:E5o vSߊ?lv(,C.SZ/p_%g&EW|BeqxN ͽaUI9xl<@y) Defo͇˦~ WMUz+7ɿ>_Q9gQ*$3y6bC(}bj w)f]߃Zoy}0og([l矺49x~|uy+:v #Q/Up9x8 c2Qq ׌OujaC꧓Cً҇-T`04_Vm"g V؍gqzSx Ot$$1\=sx{ϛʯk{YEȾތ6J002VPYO?c`{:ǟOw?0ͺ>?XΦ\S̡iL5Ma,PM69Kz5o?xǽkvedC5ϊ3[ގpnh'մe |${>ΑVqjOUxT)WK' f z>zvymƞs+7z{Ò70 /-4\g_mŏ}vx{9:;Uۥf2SvMsZ#W3)p (<P6xN*kݞ/$:S?fxPJ?1J>ԌQc64L1-ϫx nXHv݈Vr6EpKm_Py7gk;c7LYMMTfğt=-׷l4EO,O^Ɣy)!uffvyH7<[P}n'R/xcZ2o*my=':e (Ux|w%w9@}~wտӫZP= {c0w9@YčwƢ s*2yx>2k<@L=zN <P6xl<@yeFz~tm (<P6xl<@yeH<F<@ye (<P6xl<@pe (<P6xl<@yeFz~tm6 (<P6xl<@ye{=8y5 (<P6xl<@yeʆ mFzs.$#N?w<&N+7>XeۜO }$lUx`=ye (<P6xl<@ye (<P6xl<@ye (<P6xl<@ye (<P6xl<@ٜ{igVڞ^DpiSB8y5!=/$/T/L;8KHLα=y!=/|.$ C{#y%ֻJwbU<[2ْ<<<HY?x`UJINz |?Wc^-Dy^]nJOyU1x=?y"=.{RbɮOͱKx`h{TTw<>wzƦEzBz U2+Yo]ǬNaVM M~K .ϗvwT_"rB&/D"_}G!=O"H¯8 endstream endobj 380 0 obj 5601 endobj 382 0 obj <> stream xXI+7Wy~-0 ^! r9%@%̻[Ȟ=1WU_-A1Hmo6<5lomӄ湙۰ M;@Edsr7'߿n|sy| o]sr `s{uoo7ǽ9Su6}_NL3 aE 6 U6`ώ>G<ڪ23W-:,t`1&T"ܢ҈~&oPAb ;4di59Z bgE{Jn86=9* fqVz;#ThHR"g ŏp&YJ":TUV:H+I#\UtUbnn{N,X5Fm5Ēfdb2غ~sȜ&YLvaբ.:S;<D+IAQ$u|-6$鞝5i/?mEs5T8 FZWJ^^Ï<,0020f.8JyܻG=$PUR[;ܓ,jNUӵԻCZ쓹п7%h[I@6?%+{:%)C a7MMGtBwoQdB-{+|,)wAgj#z4\F6*D䁻 ƊjɻnΊ|%`nت$pn P/=Q حcTR-g5`mvgԠCG,h{VEqJl2h=o])p<[6d񝍟CZ#B1Ƅ;lx+F6_d=~n/5( endstream endobj 383 0 obj 1447 endobj 385 0 obj < ] >> stream xM0Fk~\-B *w='pLW*?4[h?8夳l=KC|ʻ|?p,Q~ʻu?/ߕC[iOi7;\fb&Saux?HӸؓH/miHS@HQz t2ir/X#蚴Xz]i䵯Jl;3Y;<9pUG/0+987t%S^āI5x3!ii H߰J5{9'-|ꬋt;&kH+J nHki^ wH=Awiwm(M4\P3IIЭ:ҙ^&N&a`rI:a6ש$I!gуtK?fӃ91HQ+@ZML2;ΣTZ Hki- (]v-re Hki- ťMO.(CHw.mgQXH"]7_]6Q(MD[&ҾldPHgKSiߌA:=G(18āhWt."U t E[ցMO.(CHw.m`QE -FiLhufʺ[(nH[iVun}Q}.PR2aWZBqAM I\ E@Z Hki-D%64>&=i- x?^/.h~OZ2 ߔ&v{n{eoAK"y)ĿY/J_+(Gژtp~Zz?w.ErN6@Z Hki- Zdҝi-tW8龬tg@Z׻ug|[ObB> endstream endobj 386 0 obj 914 endobj 384 0 obj < ] >> stream xM Zgէ<=z5[DsN!]ӣ endstream endobj 387 0 obj 1256 endobj 389 0 obj <> stream xYKFW<`o[ F`mHn9L TUw%͆avU_.9|DwI>߻ÿ;:Dzߞh)zN{tםTgqYfgux~] g(򚫔4翼x^/$(D/OTĝ=SRK\8ç>K]MVq Qf8ڳp,W?=~SI =Ip3aħ4"u!&G Li͠-ò cGDD29;d֝?Qd#yq  nk2[ was1#EPg`Jd>vH(YO?`\G:أ9zM#=E&3E^Q+3&XXo @|Bn |:2jaNXᖼ4u1n~aHcDg+`UefŸ]huɮ%")dfJ6<1# ( >I2(=j]JgjdZp9Xsɋ iq.3ZFۦxNCHGV@Bk*Yp ţWJ(\-Ä"jMwΣN~39p0iDT%(԰5&D<5' 6Ŏ]'C  R{PZv!Fe /y"+&Xf:7g#fN 2{or:mǘ`ؾ[:@ז./#0ƍ`=i7,o^/WvB25p__$6Z v1oO4ڣTK/:k endstream endobj 390 0 obj 1750 endobj 391 0 obj < ] >> stream x[ E@MLu H8DNUFXpؠæ~IۖmK%pLzuG+sܧ-ǜTo?X9Eo6T|s3'i␮SO]iwSSi3v{ܲRvs177ŮϽr$J]6^ll gTGT=mK%pQȞTe,eE~FWq/E"pভ sqV9sw}5C߇7.VR3Kɽk|e#w)hrƠi(KrI.ᦴH/N[6G,A!a0B>k|>NMgif2V[j]^-ۖmKnUO/un3 np,7 npܞ¼9jJ%pm ܶdArb~6 sm ܶn[-ۖ^n3/7"!Œb""3INnij@< xܻ:)SM ܶn[-}s{xF;]~sMg+Yeމz!7ƳPěrogYqqSdz}؋_ς(F+},vYog} }7YTh~׸׬mK%p[ ysXO7 Inp7=0ol ܶn[-ۖmKg2߆!bn{-ۖmK4L.w nޜZpl.\_T/鈧r+K |wn1c>JD) ]NJ j')dcUzAi$)A,$ $ow7 ܑsBiRlԫaQ8?㖕ŝB#<@֠ƆܾgK~Ş7.t[r npWJuG ̝ӓsǞ%/l!x:bJx_s}-oQ{Th,G >}㵵}ԁkyyn[-ۖ^O×?- ܶn[-ۖVWW3lt\5!>;!wKa|րqx.xX2$rܑH'rb;Yw`U<^ݣ>} sac|nLඥݏ/nsӋ{hb endstream endobj 392 0 obj 1532 endobj 394 0 obj <> stream xYK#7Wy^-0 n? rXrJ2&^SIvN6 iUiw =h >s|}vAwƫ޿ڽu|vyG7{;>C+i/_w սQOI2w&t: ܰO;QAըE]-?i"5^b0} *C^Y Z,t=b+6{{FpQ,ҡ'n,Ekt4oޥP6,/ .BGcGh 6..y:P,HZG& ڱiop@{U\R#Ƀ2fg(iZQ9ɟ@tGÂp{J’)9j$1sB)P04BIE J"l'2x\$T4x:38:OtXhQpVJN/c-*ӛ"F%rq4X& !A5S!LE)(<#&)n)l*eRi O| X<' D\CG-, 3Xöί2U jbglǬ^{-TPKR۳8Tօc(˺*FPj@_dgEpXH A0uY rit4n v, 9^R-ΡQx %Щp:^$.R<.";1۠߬?Lv:>f(TˊI.Tg רt>/ -Yؤ$"0 :I*f sZY•߆vI r!#5kUj̶4Tj!(poi6-ݴ[6\c*!P]u ] >> stream xA۶ʛT&g>v*:FVS̬;*d2H@BI Gy%  qy} ynȘ<:OO#A@zAY Vk=␟^_c8XqnbYO|Sb7oCegTZz|㷎; /:CSvZxbf L9cҮ9wExC~NP wr!۫ `vOܓA+^$Rb\?C~~ XE{R]b]v6ܟ:3_t:qN!?>BJ;Ns֐Ȟՙ $334"Ah.`=MiG+X<'C]YzC~ 5kX8{vֲ`OJӳ'7:-=̹u۠e둆؎#*3>*q4X7 i`=Mi{v1KnsS]^pxp5 YG qYG z; {BycY>%U<u^_㏗RJ762H|Iׯ񊔲H(tqQe=wcg򤊓ȏ\`=ɣCFn=kp 1BinXO`|Oyx&o zu>&TuF6[7}{z<$r{…% n7'9Jɮ0W]oly:}A)&Is9{L -ԵS xR.M#eLz.!⭽(s+%l=tߓ^LH=s t:3PI%߸S4=M MiXO,0S7BA~2'P Da@&u#>y&Po=yyprLmOȃZ)~2(zdYl|leskx44 =MDY![> ܴ<ǖ5;nŅ׭=M*axh *bF|n)ydzmO Ai0#Uc4|nMܚaFw v>7?֜=N&|nzA^~nלaܘ64˾֜Mqyl 5sSʋOnZ<k#]O&|n2b)[<"s#nLly0M@i Ah]`=Mii*2d+a9uzsǺi`=MiXO 4K{-.K|nzN! {Cd, x'|ng2ʃxO%4Me)= xO%4i O@> stream xZK6ϯyaz%,[4ma %$l%?dْ0L㖭R=zAw>}Tiϯt~}ILNunt;JxzGh?^~ߡӦ{'8ʟQMrzn/.V'\%sz6YӇ]F:^vfvWwt";H"^ϟ>뾻сZEid #h.{קDUw~<+9?-)YO+#ZC.A`Ig4xTqh l Ӣn~z$o`D0,4 2cyqRw>Hׂ8~>Gd\ X,Ey,JsU@kq&-^`#2fL*۞!,E nG^EW>Uo(?@[}A/ʊrQA9*~K%-=CMkq̱.,)>͂C!.^Nl-; "#qA fxw8MȈŃc1W1!hܙih:Yj@6Cˈbm=1F'Qd@ hB6}K;ӫVo bGD$]*PddsD%j9@N2+T)®Y2|~ PDW, cO3ժQx=PS,%q gޚAZz:4pD RDЄ[f^{YV)J. WWFW a @O7w"TXtăW= C@>bIKi7TFc =BZĬUXVei|b|'^Qpjw$y۩6옆;  iieݜ͐yn1,J.oAsUrWUqY 9v@l6cvM!4b1NζKIj"+e0& Y'1,IGڎևJo#5JƘq.Yf:OKHv՜9gIBҢ$,:Yq, MRJ^ӯz&W^\֥]`4VhPHU]p.W(CC۔?Cĵݸ# rEbmuPC)0zPKU6֔0b"ۊ*h%!ͦs~z)뭟}[q@1~-FL URj_;ˉӎ]:p{,*Q P٭0UX:ÓMZ8bJ=8NR12٬ mJa ^mOw/7(&Gά[lR!w_{*JKNWlr(yv~9 s i$2@]7ͤfK ĔQ"17ENy ]HSJۂ˪ŐC"B,, 6j^Eo1]ײn,7y%|%DZ{liM8G[iIFL'sKr̡}% QW:z`ӜCU z)ZvAA?lȾM~,_^o A;=Խ2=C+مʛ^f=@'V{XDUycC3ƣ^3B:K1llG &?+^4g@Ul":k~M欙S۠Պj2{+v3P72J3R&~[pyoW?JQۖ =vUQ1p ˶kcõ}!&+\Lا[- Mo"p)@b_@*ߧw:> stream xˎy{D v;Hn4bOA&%z*dKbfUm÷9 i_>?{ϯlhc ˧cޏ9|NwC~G |>|aM: )}ixG_~|1׋1b_|q/f^/' ݼ!~@k.c¹[Kzx_o Rj"S~hsY$qwÇ%_qLm,wC0JxYf]';8y;0UAD4KɂO!Vf lObagH u񯾄ٗݽ;>v H:=KΣ}g "x7[P%" νS ؊Ke`~l-<38f^< &vqYdrc;Gs47) Q;slսgS,w|A<2x2"ˉ-->iI;2=c""&Vpv˒<\aoqZڼS|5XI (? |5Πd{ˌ1My"|V0lF1=1i#5&hbL -TaioYΙaKZsrnЄxxP)BLl_2`7 1;2F"1yc%wةN%Mk+ed7e(I*c\:lisn[)Y¨ۚ]Vφ+vRֵ֮r7S0׾"b]aHK;,,ۆJ y¸&]afPR[ ll7|zx+|aGG!U i"eԄ7αsRi!BF=jS8u8C] zW1coTUFt DiyD$B׽7w3T2E*^́ @o1Q8\V"A1?tr%<2:JcG~ɍpuzibgkH)S/&}zIKUW͐-ܸAEO݌~)(pI49 M7b), rRu.$Z9VfjҾ KI-K(Z3iNj)kWeF~էcPvi?<2 Z%27EdV*?(KJSm'f?VQr79z(Kn\h'R^(0ד&tF-^<'dV&ഩenLQnod4t%&IU`5Ib_)7S'*ڥ9gʜQ8wr\q: RϺнgrWUT-U.ӴoKd|^JcLσTq]X~fVzYrl< XD 8i݄z;cPai\l0dykUHaT9MlAqrW_pe'egX~1 5 8ц׿鐙~$׃2u}\2n_(( T2IBPh"d$&(e Ai$ClA9Afe*MvBB,YJ $JkiVd'Hy, /Rdgd"4#3$˩4ì&(5DM@lA9AQLvB(j52[QMP^ %3d]4i5l;# 4i5riϐ8FDꩴHikȢR2d,\&Hs: "«b<Yv!ͳ<Ra(P=}| b<Yd!ͳc*x~=c ibXg5|-*xV3rҟ\68(UIb{Q3R $5 HHut`\IY'^ST+P4JՊߓԩu\wXz.M+=,M1MwRmFvƶ3bZN9Y+5|X| JW":K%f }G \89yBTzw{kp,B>BXug?9bRǐoaE]oz{k;Z\'Q~Cʶ\ K<5}Wkn9 ׯDl ֈH xT+/Q[p>>V)D£KnlF6hA?|? endstream endobj 403 0 obj 2769 endobj 405 0 obj <> stream xYK6y{Uzن0nCrh!dM,KVg7qYUW%:AQQﶧߛ>5P]xR'JwB?[y2 Y pķAը.U4\h sܤ`zxmENʾ ҈ѿ~9| wC>DmQ3*GY)BuPHa=Rc;سt{/J z[aLG@HYL `ʊG)OBSEơ;GȄ< _i 2o]6yAl+"7m1,cHtsk`{c~Ej]DeEgڑʊ-XUnP(v໅}(Rd8$sbԐ$R/h#( +lڢ?UB\(kGFq@ 2b  sm",_DS*A UĀZb`< 8BQhWD⑉>:]8F<:3;̊Sĝa>7w!Þ58Ԕck[Y 4o aͥ7"V>'"w>V e! ,cy˂ĝ& ]]''1ZR6X&_L L 6 vq']s1aH G6\yÝ%K$RԀ}..`i>}ס?QF`pa}nfѶ] dP qNВUG$9Lne5^ {h oԶ-sCשrgxggeHX'Q L=_m{Ag<ڂ#&:3ԺbcX!EFf(> RA6kcqs$ 5H+! Z=D LScf$b} Jf6+jybʖ֥rV3Q sfB\e+o)Ƃ^u & =B%{C4YѭJ.$jGɝr7_jhc]_nitlJ]N5ZY_ pUН¾ƨ+*X trHH~^])bbSNX:7vԍ>L֖&8kP.rX`hJb0fJHHg yTq!,~Ⓡy&(QVͩM\"zWXYVS6K0M"NV6}K;]]˭ظrLm5T{LG%ʻv8^^tN:h EL2S\5*Yʻ}G|W.7i{-\~yV41+gSNM@^3[]@">V@ -jأzepM<[c g aTV̨M{X|.-/Q$Ąˑh\I(V7ԉ#1񪳗Qֺ5XoZ`b\9H.oҸ}K-揋DꋷOS(zS[;:aB uz_'η> endstream endobj 406 0 obj 1574 endobj 407 0 obj < ] >> stream x;rHVD%&k\+UWmm2%\@4*rhVI:WxP ߮(A| e֦8889( ("]xLI( \}I\`ӕkq6Hk:#jTʷm϶a gy~bz\~9^}]^#r;'/c vÇe% so߾}ExSxy9W^C7B[ؾᅽ)Z%/V_4Mt^eu]yroo?1a3*^la]F1wgonڳor1@sgm~CqöTK:ge+t׍^-_|Oݟ?E dKүnIWguw|~.`hQcIw~ceWm.[/_rǏ/-qyŐu഼J )O5勳$XY0fu>x-l9,[RG}Wo}/}&t489Ew(~,V+ʡl_q;oTc:V:===_+0eCI5yՒ*vӗ-Y2/Is;`kt͛VןWW3Wb~I=r=?ӗ/sEY|y]\GBy٧j<?l| UpSln/^>owX}__ ?>}Oi} p=%Ƚw$[Q~s51Q6ϫ|U%/3ggT(jke=T\W~iIwpv H+K-4@_ɿ2]k9/Q-q?K^\h2Lv#T1|qYU__zK90sؼ W>c՟7|quwcoYZv$>qόNj?|X*xo=qV띅I'w[4er#cOQ,a}K0Jlsä..{Vjd!VD5NbK|yt7DIy-8_JuYhcEǎ)呤h~^3JΩџZIUc$/?m87\|-T8h({/==ٞ<&'}G\I#:_Q12> stream xX[6 ~_煙$q`$sm@JڞBa[v_sg,ÄY$}NPwV5nO?TXQtUL^?Tq&Cd>S>ߩ= 푟kZ<]#>\d 6sڄm2vrRzRM'_As]Wf3"mO_!T+Y!jK\DzjO+p ٥G?\yfm.9;\@sodG:~H’+ ع ~!AíȽ 6QvEw TpH@Ow Yd@Q@{dPm1@ͺ;;W܋Zu/O'xAA/#3,#HsU^Ȓ=ļ2g_".41cgGv.H”+ɑN ~6VAk.i[$a`&GjUɻ0("9B#BOBDXoa:F3a!(Z+آӵ 2rL#,ë#6nZ1z`vƵ6fFLBm4Sn&& HN<{nS,Y$<:ŕ1lRju, hSZ/ 8-@Pqƾ1h+k (@qCdN\X?(:IIE S}.MAbY6&dkU3D(~?A) sQ5Q9P;0e(܇b"c&&^ 3Svk̦D` n\"Qk@#+UQ)z%r{h*cï,r>R1mt1yM^r AYӴZ3>+S0,e yz]GYS˭&Yzc{ ird.IlڃsIqGbK{$vKd_E Sbz&8oq6TQC|y46ֱ6LXfaw9lwQ}NȜ#i?F14FeT-G a갏<w}ꑽ}nn0ӀZԞR%Ǔ1`d)KEѣsP4C]Xq:pJ-Μe悞j>PQyN@]K\h+vս\̅iUY4/He 8O}z57fM#=CtSHwUAFw=ʀL 9@ft#`<8),)NRWˮs5[8;y9mͤN6ꕒ/UՁɅ\a W)r9%k|YKJ #RoƎ0'k~g ] >> stream x;r:@R#mCdǙĪ6&VS\+HT 53 !/LZl?ѽ 4/';AQ A2 e@HȺ~כC YHu29u]oN5T-Ϫ#{zzT(SU\zI5!uP1LU4eήbUfrFI?vaʴ|U7T#GkLBc=U4.PfSY<cq~9NVeܼ\=E)S/&hSӜYT́(Q__ƓPPo+yeT*@lV&;Qn$|4ƜLPVHLx2sC_ՑYT&v#XsʩSYA!\ڪ?Ze%SF?2ZZVfZ740s>KU+53n?ʨtAG >t /˱jSLNlO>_~~K\&Qfl<(34o_=1)UJk4pc(cHTYP.2؎=\׺u6twjbϧf~Ga2Q+31dcN 7ږ*=i΄p2c-u.1ü$SW9cI2o]ح.>22Zk}ell D9&qOgjbq͗Ms4InDN&QM=u}tNLSN%;雱kjfNrkM׵]eOU=#;׹JM2 +3.1elW-UʘJITeIv}i'ʁ n֌'X&=pף쳿xLuPc> e2euDFeבҽX[2Nu29u]Ld]W(#䃌]oQPh_{wJ s|eր2 e@ʀ!n'[/w~5FH{ɏ2w?-],U{ A2 e@H\,X#"g쾮FtGu2*Rr̸DbIEe5ʌ] G SF)g:Lj#(ɶYdKmPWR* e/ e&_Y9L~{L&̔Qc9Me5)Q|e<3L~Pf&mӬC+0P&?ˌtbZٖTkN)7؄:DVu=&AႁZ* exeǭACbXaP ARs\]?RiF_޿,X`a d֩o(̔Yy@QA2 $ ozet6 d #2\L\e":PF|sW(9e+m:eAT0aetp핱m2 ʔK<1ɑ8ʘ o0LOʄZ?̥x^La/v,+l/ǔImF*=Wʸ 2$C2OLw(4k#ɹ>ǀ  e@ʀ!!(B&ʼg]kl2WX P A2 dF߼jJ J=+OUJeJ2la er e/T&u^eOLj\i eT$1%ARYTXPf0)L)2%hN|1-2*Ӽ` ˂2CQ^fZL ƠL,EPB%Ilue%t^F2~q41-2LǴTTx22 e@ʀ!(BaB2 e@ʀ!(B Q#apDRV8>08*yLXe";0ĕQc:qAeƠLDQFq)W&>*W(7 )D/0 ʔJ21e3 0@HO)dL &(S.NC?߈1D'dVz63`R zSy2 e@ʀ!(BaB2 e@ʀ!(Bb0Xiw9qR ſ(/)qgl2Y2 $q+2&1 efA(ε$fLo(2!+F#Ul22yĬu(S*W(3~+LnɷLdLHe6'JD00QfTB‰^0X8Ae@HDoB+ e@ʀf A2 e@ʀ_u71]M{e)V& Q&gcQB'_=1c6\<ƠL$ }*2ꊦ KH]seGr>dK-th?qYPH_wJze (S(N412$G$~*o*zLn' 08$/JHeuQO=(p% A (u$@ P Yu]8 2n;+療QfU8bsgjiAh(މR54QzʜҹRn#@K-c"-@2 e@ʀ!(BP A2 e@L{_< e=Zr$. e@ʀ!(Bn̽;+KAnL岏2>e2 e@ʀݔYu/J(2J5Qeɾʘ;W"\֗G ޡInqB=جkeS*憶(s6(3EwՇ22a2ʋ2n2ee.*419lseg2l1/A2 e@>ȊCY̽`_vP!(BP a$ْ e@ʀ!;ϖdBB[e~XRE9K8 ەQq.0\ϖ$-)-(5d Ζ_8ە\lJ $& hs0U&rSy^geʨ92\c!(B- R- RvP!(BP a$ْ e@ʀ![YeE Q%LaegPBe.e2Ie'v?&sQw(ZfK:w%5Dږ)-bLȣL,ָ_F⹝2ْ[NYە8IْgAʀ!(B- R- RvP!(BP A2 e@ʀ!(BP A2 e@HR e= 2% (BP A2 e@ʀ!(BP4.(C endstream endobj 416 0 obj 3376 endobj 418 0 obj <> stream x[K8ׯ!s E]Y =4{^Yz.7GȒlg.EÖ/!?/?1\|tR8?9Njߟz ס A8Pܳ. y쯿ߥRtdxt|c^rӯ.jnU7*VvHv#~x]JnEK ח:O GTI<(THXIJᄂ9?~k͢ԪY?^zU-:++8ql=3P~'@w}3b3 S21ì5(HZU wdO*z .^7u~&-#k#dɓQEP, -Q#NqN0T^t-JAy(DeB &jtYg= "x=(*SҧHF-8Qyד)c)>>y)Dx,BeTvGin;Oѝ'LсQA).#pM}ʦܠ*7a`$p-_,$e*[#j'<"Ic?'!W[ȵ)GČ{ J6BV_<.?f9RE%-~&glHIMDuJD(ބ@μz]4PX#F,ҹYXÖ2;'b%fPscl%M2HȜb06IB0 rEUL B)SY mPϩ"^ST{"ҭI#"B+ILon`}(:"YC )3)YI}:cOLt5UJfb>jhcSʴ# P6 K2QX4a%0gtlj%|8mil5y>mѡG LQꪐ}EI0J(,zNx6hMBnTNJj)=VX (a40Q8)@{S+̎|!{q,vj^֙dxGo*6;{ Q<]7t^'zZB|nZ?=coNG5(k+8%PgD)UѮX7API$x=;f Ac<&T6./ţ0t[{xM+w=h2128{u OַutN%!24M1#P_Ux:H€m8m2 CQ{H[\ju< K-cǪ !vT7ajuc^P? uWŗH ZN-~hsz[N.{¸,犒wcp . ҡQ._OJgIvw0uJN }ѵҮ9XoZ;#%5hpV*ö:i#ˢؖp?a=0̝[mT^&XI4Wl': \jϲZ> ,.h: uO5jA8ÃN8R+yP Y/jVYn""UV6ϰ^J |~ú^Y&*0ֆoTNNj 8l<~ŝ9|IPf^gظJrujFWvZ,]|7l_u"0 8x:وvwulM,v+N[T;m J.)$twjs}lhVRKzV -ZM 2 9ZLa;6t|mpiث앣U)m\{I*m-t+r۔ۡe"7l BJ㼛h>E̚:-3Ew?}9R˜ ӨZGֿ',_ (v9)A =@?"A /xup_:H endstream endobj 419 0 obj 2667 endobj 420 0 obj < ] >> stream xu 0D> stream xYK6ygeCch! 4rJ0{O=(̄0[R髪J/ ^m'|S;A󦳃aO4o}Nד:O7듚fsRG _-\pVZS'k >\s#.JuzznzK}#jv7w.*jU\@BDT̂P,jDpC|8i@渓)p~,eД3b1i&ؓDFS R%ش&bI7*̓P )t}ih0٭e޴2UfQk֊[q[{V1&x΀Cz.XI/:Xbx%[[( XÑa'14>B@E$U' /fT%ByH}1%cJj/ 0R˪-3B sw Pk׭ $x0A,qr 3'_s,Zß뚚ZghhB'drի3! 6{]ibIkB~Hh3l n`L("ٌ ƓT֞" pϔc820bJ/* #C+&ȹGCh'$#WB`,).yPeTUSx1u[62%GM*)!56ab78/~ ½?K1C<= $>ؤ+Z"E mb,VwP=ЬGlryznU|HDyD7&S^H zٰ)Rɡ(AaD˲EEHe`=bd0[$Q^sHF$yS^/ lo?&͓LAC!jU#]^)DWBц1W2@OWO*"D~>'̳582JC(zETt쨅6i3%-t9*E0y[B~*IC@\Aڐc8'"&u!.ҮwTJvyeO,a»YT/3`&ΐAj}Z77O'_!S{Wͽ̷bFԕ,{MWŸ%Fi)-EnBS |EׇK7x&@0Se+Oov.^y䤌 ztF. Hhcg(/<͓uԬOe$՝pb[Uۺ Jn">HI> stream xd`0goLޕTRjw;l`JAD=F ;{󗗯=~_ϡ6A~"DFP Sd'1(Lў~'7+&읳c8&3HO`Ȥ8~*D<Oww`):zC~X?z) = ] B}N+}I|7sn_6h7eϛ?<Wu[WlҖ>Nd_{e= #H^kɕ UٻaõSߨ\0< ~.2t0C M``U'_=qξkA ] HyڂkOv/?;8/g`hgcꃹPd+ooZvnnz0ZUu珟_?~ db`f`Zڬ,/2`@i?@W endstream endobj 428 0 obj 595 endobj 429 0 obj <> stream xd00C 0A`3\ Kg/- s H@m.'!>S~a<P Ab~pt endstream endobj 430 0 obj 121 endobj 426 0 obj <> stream xdЇz---2zeY'0M``v?30t酪7eCgv֮TM5DK$z - =}v߿""6?At*T=/">΍7_Z/d-?w*sXꅧ0_tŏ{-0g-4J/v˖@L߿++nGש/:utiT4oҷ3CKi9u~ߚ=ЮZ֧o?}û7.3Y#8e[pן/>NR7z7nShVEP(`g`e;pcUI% x'2(΀gV 5Ar 'X$WЮgO{3Av4frM?~]TSGlvԹ|T1(CgTQƥ5ɇ?yO^xuC^ 3kB3͆ fn[27>9[Y,2Ά ǂ endstream endobj 431 0 obj 589 endobj 432 0 obj <> stream x Q /fd8 \>*0(?UI?Ɂ3o_ - 5OȿwRrm ~= {5 @ͫy endstream endobj 433 0 obj 120 endobj 425 0 obj <> stream x xTա'lpC)dAIDMBb KX$DEAPVmO>UAϺгryUugmr|f}w:w8fo4G?S}4~~|h#~`@=dz]_}lEf-W(m3α DcWh'+=zEu+Ƌzf9MbVzo-sNZ'Җ[ ,b -˿˵Ŷ?)ԗWJ}A_rOborƬ ͬ3O7fSq9Uq'b, +-skΫk,W&F82sK>'j{,eIjQi]>Ծ+e Df,.]P&~77D3V^ci˜Ö~'</hqN@sZ vUV.V2D I_7{䷮uvYX8z%ZEE>]0co6|٥[5b9 Ǭs=r_k놺_o1fVVbF G[$֔9#-_٭gk]M6dZwֳϣ9u? ͩ>\g?^h#N{Mq7&l^3qիVV[ZmR\7<;I+e}٭k3JV/Rx\O̺Z3}P~JK"Z>|S+Y:]L$vY}n9kN}O9w_8/.ײ슳q,6bS7kZM~S~]չV-mCs+-,tқىs粭?<ݏm:~֔m)ݒ-]vҍ J7d(^92/v",}>b_"Aqn̵9q y ]cb\ڢe6vh1KVs˃LQ9sj3k^8DNᘹ>v{fړb;b]ՕvVŰ$Ps9oom+n[Zzsu}5ofɚ99Sg<.?"AɐzC3w3yN;Σ/ֽّ-ωk{y߶M֭[=MM1n忪7ҺE;2roj6vmD^հ\QԪU81`IQiolI冷ּR"ΎOYi]^RtR±FfO #hS{6Nܯ퇘Ckm3w߼Y~̡'K]6e|bb.qՀ4ב?)ލ6c{7Lz쨞'f;D'oY'ljЪ+ \arEkm'쾓>L9~wn3g5q\ps3q)?!,֌<1y G;^ϻ%~*9r?q -m{j]!%an6nЩ"GA }hrm!6u?[ZWYuc-hKZk*+l.ϱ XQIQi8 gN}'u}.ΞT-G{ZcKv,E-H*3>Ω} OyJ=;k;vPΚ?7G^iq]w#bԨuǒ3vHl|}ۈUW]sr9__)ٽϮ~v"뾓>nZTyuǂ{_onOd{muymVڻ̱^Q{IIwNE?;u߉?#K7djq̒Une(޷^Ӻg{U/=m=-KD9^{7TW@~zV$w6-_OaW+kƸ`v=Qn\bn\ヌH? *NΡUӷgߥY|M{[co'n `'s*{+OXRڳl܉g';ygP9Ժfz٥3kg^|,NZҭ xN[F|U;v7P8rزgyC/]ҟ&gÊdde-:aA]GbX W zγs~f\* ׫ P!]?giªl3Ϻӑqcv{)md|}M>=::;w^YyqSs2e܉9|D|}'5/ f&H0ӺvV ּ%Sdcѣ$sIJiW_$Y~-ڢ}8p}?8e#3y9)7ϿӂX+?؟>1-k7F=*]Gb\v=ֻ:ඁqK׻]~nUQ3.ro8QsNbeUnna.Һ1e}V{579lt!aeU &v".ىN2NX ]wEJV2[KrD$}'ۉҙ=J:YS:M_dle1-W|ZEs +.OM'!1S7x8ix愭O}wYɇ}vۏ/y=Fm}ԥgne (T Ji07M89{/9jʭNo sKuVT] Nlϝn'n>n}VNww"qB,'.J*^>dujɚ4XsYG.Mnwp/<שY(fѮ>rm~R֗|~ݧׯa[?_o}?+??v%}JTгlZE-{mu  eP!^1"FVqrv]prHnոlZ;pcmޛn8.:/rNnqLb>v{V5u;u߉gTRd\k]^3Ѻ|uibkʳ֗MdB/{N&XOt}NjOn,_̄ctl[|'۷|;@,ț?ʋ]SBK>.umk ^Mq'˾Ocp:4vC\}٦./]_}6WeSs;1⾓,Z+ }'${|IؒI%J%_yXxcWٔǴrH?u}>+^RFs\,V[rVVMu¥wkxmW|5gH\nP/kt{&sc?Æz^o11so_^(%N^p{ڪ mo hK>fGn79:s\[}^Ţ?NDk##/O}lf|EYIE g -Y`7tvﲙ:sZ|quK}bL;Y;}H\;ys˼ӭδ\S-Cr鍈Gm6myr~zՉOį_Sye^e*{p[ɎkڭjբsXFho=&GfUG3Ο=8?#>VYWd/J]֭xZ)Ƿ-*XgWYehg'Zsim\yXFEkMÈ?hwgemwNG{-=X?+GVA׬N g[Pr6sJΙYZ`y7\}q'$|яߞ~ kɨN{';}Nl^Mb;1$69A1oyad7m'ӫs}̫tMYt˕+e_q ˟;t߬ێ~ \l9njВn7V\7,{¦yc As <7 ${1—}s_-_jߘ/٭_{ꄏ>[tBSHWVZwnhf#!bmߢ熘k놺NXdYelN*~qnq]Y?9j?E{a +?@\klc33:c ϧ眴̶[84BF6ֿ .`U g7%:_{c&식p#µO O2}buk$CrR>ZQd?񇵷&9P1uk_i;X#{ZkW 4]&WAiAӫ_߭FǽjG*""bL9aI#"ShN3"9ψ>#"ShN3"9ush>'ty>#"JhN3"9ψ>#"ShN3"9 ϻb:N_'[C?k 6oQG'MH ,N?ĀbSs.$|uW 4 svsʿ >R3}Fi3(>g>R>h\FϠLQZ JoȲqAqMgP,N&g6p[ԥϠ3%!s̸ۖMgPIVU:>;=f }gPyl oxb)g':3(T}v͟-# * }iLgcOя>ܕ>C0C(}Аs0Ϡ3(>g>Rs0} JϠϮ2m1ඦ~xi3(%`# nMϞ3jz3(Ƈg343(> ϴ@A)YN~?5gP } }g>3['}g>83(>g>RsCs>R~0Z )^N#rG >Ry3wR}H} _ g5}}yaK]B>쳟gjhgP }g{,3D Bϴ:jϠz~?p3(ń}3O@A)>l3($}n2g#b>7f3 J1C+?C$`y}7Iȕ|+}0`>*MI@A)&s#H!,gP } }g gP } }g gP } }8R CA),΢(>CgP>7Oy@3@3H3}i3(>g>R3}i3(>g>R3}i3(>g>R3}i3(>g>R3}iW} }g gP } }g gP } }g gP } }g gP } }g s g n a>g>R3}i3(>g>R3}i3(>g>R3}i3(>g>R3}i3(>g&`nLA ><>4B3HCA)>4B3HCA)>4ϑ>:}Ϡ}D>CgPJ0}a>CXϠLA JaA)>4B3HCA)8.S?3D JQg.SNB'}@A)aﳸ>u}5uf{9=gi a>RkEݫݺVu6ECM!,gP>WMgW6-:}?g JQgク>eg09u5y>ɡϠu}v[c]GWn-χxnOݠ>soNÌZ^q! :H a{G>:M4}@A)M |N>CءϠ&gi3 JϠLA J gEB>RYEQ,}Ϡ}n ϠLA J ϼC3HCA)>4B3HCA)>4B3HCA)_? J 7O^ a>Rx$ gP } }g gP } }g gPt-5(}CA)&e &>RBׯ9$ O }Ϟ5f~g_v3(%>YH_lωn̿AA)곯[ЄϠ/ϻJ ϠR3}i3(>g>R3}i3(>g>R3}i3(%`Źg JgqEB>Ry>R3}i3(>g>R3}i3(>g>R3}i3(>g>R3}i3(>g>R3}i3(>g>R3}i3(>g>R3}i3(>g>R3}i3(>g>R3}i3(>g>R3}i3(>g>R3}i3(>g>R3}i3(>gGXg>4B3HCA)>4B3HCA)>4B3HCA)>4B3HCA)>4B3HCA)>4o@xϠLA JϠLA JϠLA JϠLA J VB>g>R3}i3(>g>R3}i3(>g>R3}i3(>g>R3}i3(>g>R3}i3(>g>R3}i|B>g>R3}i3(>g>R3}i3(>g>R3}i3(>g>R3}i3(>g>R3}i|+}0@3HCA)>4B3HCA)>4B3HCA)>4B3HCA)>4B3HCA)>4B3Hϣg >4B3HCA)>4B3HCA)>4B3HCA)>4B3HCA)>4B3HG,]wgLA JϠLA JϠLA JϠLA JϠLA J B>ggg>R3}i3(>g>R3}i3(>g>R3}i3(>g>R3}iUA g xsaog>g>R3}i3(>g>R3}i3(>g>R3}i3(>g>R3}i3(>g>R3}i߀P$NP(M'TFM_hN3"9ψWw1DDNW#;Lo "S>Jψ[ψ>#"ShNst?emR0^:k޴0*]󾝌7xՍ>GPoď2ް>G|fQ#㭠ns;ox+sg52 F|ҝƫlBX,*g# `Z~I,4zRq&4^0Q*#E1>IJ?x ݤ{.4*:lI{ׄqhgQ9^7=1~U:l m96Կָ7h"4~=5uO!Ί=Q 5^6N&\Ә?M]ͪn`*a/}nszFfn678ϞC/}nsXzseԌf + oOz4zɼ.]u_7< ~?ǯ5x1tWnGg,1^Sx+sg52 6F.9:mn3o}vxF[Av>3ިVhy[dD^?*x5^݊xtxf>^hN3"9ψ>#"ShN=|b=ѭ+vuDDTw}n;Ѕ3{W=P˨#7h ¤#AC 涎u؍yWvݍF .jw[CYm/jon!, 0V0 j·`{W`c fa2lcMӨ>vJzF[KӾ""VU endstream endobj 434 0 obj 9647 endobj 436 0 obj <> stream x[[#~_Q^%h . @C<%M}ߏѽ=aJ%wn29/(3﫶c˗/tyB,+["ڄ%Y-=s}x-rؿӟ~rkj@,% 9L_([޿JJdŅ}ad'ˉowf?‡HEgKrb0_lRJ6*3T fj8׋t[yKӥM922w9.'J]hH;,v*bD]=H}^OfmYg c9fέ&>Ɣ&v '+JO$Wy$+_WL,|w{ ٙNl |Nl ӧղvܝC0 jK0-zďzW6ϱJZ2<onMHF=s/{̨ 7ԡa[R¶W})bx|d}03d&Nb@hN6Q_aphVl3R.WX73zyR˨+Hp&nr[8(h6F9w361%Y8e9+M:0{WJG\](G̬^10:<m0i).(;Sp+lrŔSo8L XRaV o9;`:$]Gd$ݭWĻqdͪH5d@&Aꂍ:/+s oHs +#%DC^7l쇦qQ*ήFB bn:ζ&S(mjZ#2RH/1\@ G0jiɬYZ.i?+E vg^1i{qsI].3;ЕePXiVW1GzCҖ8|l0:QùBGGMSk_3>,_|hEqA5I*颦2CcN+^=q hI FX"j+sە]s,-yCsU $}2iWsPU b;NWsb fCƸ*/4U\4-0]A-ih7}ƼI-e[<T _ u[)y2u2yKӍnlՉ;p} `2c?2%SeW#h1f"󇄜Z9뎴-k GC`T:C^l٥| MƇ#kNG?J`smF-`ua[׹,}[t?jR/(J]UPR5&ϕRò٭I!&g K FT_v`\b22WovPU!;]_j\  =6)({ƀU V0dkГ= a֫E vJN(0΅죩)Hr]\d&*mь![I,P beBE+OLHΦ5 7ttN[-'T#2̛`uG JNEfk[֥8v&;<_n`ͭ26N+`TT%o]Lo\BmS 8(GX4T'1XUrQ^K)JuBgt'}$ k:iBBP.4hGׁNkE_!t6cB_WAgѶ[J29Bf'ʨ&bR*6gҼҭB!>lbkdf(aG43b(3y0{΄4QrFo_͞/]U< endstream endobj 437 0 obj 2600 endobj 438 0 obj <> stream x= @mx; Ĕ $EHM(NAAάjofgmaU;y2js> stream x 0槣(@:|70 endstream endobj 441 0 obj 27 endobj 443 0 obj <> stream x[I+irJUKg0 3}GfU`rblv~tbUss˷7>덳uZ$5Tov/YO~zʉ_/v6_OU\ޯ'a?×w;sGz8Kx?=>޾}9jC&n9u3,E9~|Nv]5 t\+Ʋb@#'2*c0 -;{m8},Wu^>aqcI7OYn^/(V b̍rK;zvo`Lgn[~z(Hf=9ռM`+jnG@% Q@&vŖn'wՈp@IWvm>,2~gB,*$bL|nQӰ^2ДȮ~ ڈlY\ U?9^xDw2gYMThʕ  ?uCő? pRi !0mxB/&]OIqJ&BQ@qsm DNz[/Dx ;s:1{iI#̒ O."#& c&UVɖuucnP2 wW#Q+u -[Lx8LINDY_y~h-~WKC6>.QvCE%HJ,RKGȎ(^zfz$AJHIFp0n*@ɎVJ&U[軭e Hۤ2%e}J׃0K݉6Y;7TEP8/2YPo܌. PL 6&bw"'i[z$ MljeĬ@$Wp=$WRKQqۧ}Ɨ^="u˯m%3n{0;L1/ ߰j0^ZR(f.bl4 T c @x-ytqz⺰5 i+n8F.hk4j z `yQ7̊b5+ʌ)/tNz!>'<^ +[.̪1{V[0J+/Q_7 !,*EѡMVZ~+\ }a!\]XX4$`gJ^llmbN\Ϭv~|sOW ߧ endstream endobj 444 0 obj 2567 endobj 445 0 obj <> stream x}[OAP~!t#') cBEH[C+E@8Ҳζ[(a˶ :qc!L&g|߼_Z?qHu^~nYx<vT&%] m6` ^xEJ`7 9ZM$_h|>_$xT&aY]f&KF#P7()iZK9ٓ ,A v|ͧx;TvvFGejT<?&Nb{"jkj kW^z)`+2Txh'Zbڥ]tqO%:`w ^"͗ʺhOfhk00[ʪ ە:o65<[ݧ~㚨X arvi:Ӵ'ـqg3997^zNX8 <$xB!8!Gz^8twwC gNo endstream endobj 446 0 obj 660 endobj 447 0 obj <> stream xc` endstream endobj 448 0 obj 12 endobj 450 0 obj <> stream x[Ik$GW乡cJ [`fN`yKȒ=4-2cyֈg['?{0IvOҘnPE׏wL/HS|G~K /ʲBu!MeUʹj^#>#~t< @ud+7C`r3ty#x-5-a*{NL[0+Pl?MBGq>sD rZCЂ7-Pq|i"HZP=k}ꛎF lKA])ZtF؟wb*z[ `m# 8ϤLzyum0]b*gd@snBԚFM(o.N Н>Z8\]| 6^`|2[귲"Me$&&nS3դm%$J<^͘N)4-jQ5AIhZĈ$ٟ پ!窉f;g~c$"9&3>ًV4g錰ۭ5Zg$]k90~A@<@즦Ʌŕh0\S`CAh, j-c,v+dcmmˀ4l[LVb%<ƶe"7.m P X40 *vvWUr9L"*0؉NҷYLnda_b n*C/FY=4K5 OA'J'/r𢄅7p7^ sVq!r/ifNRLET Uiln[5156%ƹh rU-bXFD-fKl jx=˨3,r e*ԧ`vWqS}Q}!TD}x2w( /Ԑ48&ijqH0Zc)u-i} p[mb,+,ӶDX c Ly̕B;aU!VAmhaIME˃pc-6gX.\OS նYN7/b2ĢZ6[%uEC ڤvVE8l}Wt<~c.x wWR>IjBDlmKVLA3!b9'o BRPWɌ8DWEQ:hxr*e>;,4$ܷ{D^!l2&&Q&ňOs4 \,+<\+lN); \t*V5GoSc 6l+:%=~gi;As*%'B ST #\Ŗ¿Ž P!ZHz/|QXP5*Xvv# OHnY8> )vCg U;;Q'[ECFk&ԧa5^Ft%U/}m1˂t"VGl-OXʪ깃-甤_0ԇȤT תC᎝wxB~͜o\OO\u%JP<T輇 +=r⭂,[Xq(W«H 5v1*pU%n2 f)C.!eHO+g/ T | }0]'RVI۩ڲtҍhQV eoao#6d[ńc_?$IB SAIVMz b&Uӗ衢l*3>&>UǪ=;OL~Qm-xSeIVUE[NwP@doC)~ixbP Loiw}DOǑc/! endstream endobj 451 0 obj 2544 endobj 453 0 obj <> stream x[I#r*UK m1ͼ##rʭizF"cblq~Nb: ꤂ys˷?or?Meդb|o8@ڝ=I5}Eܮ"*/b$.#~y8.%RדRC>|}Jt/OD,l&3EMٟ4?.tr` rE%+`'`|= 7 ^il5JljFI櫹hd`g? vݤ2ޯ˭(OC[kXhDGDDp 9=+n ѐНnD3d_=k`ۏKe2 x Oj= U&?2 if,'ZŮ;o7Јjءx( 2 /HVA81r)~zX@bQ(*ƻwv[ޖ=#@YuLוlɚv>i(d´3z6c`2p2( 4ﰃ i \C|pW\g FwnHvàڐں!"1Տ3;KýAdLLX,~'hxB@MM9y=Ja)MSQtv~g}>f~I|}+^]PȐIQ9#ZzC;B&/${} 8hl@4 ]ҙaTrPH@2烷 !47񎼨[t"gHSV M(bH8=}([i|aGTJzB4Ň.>@{o35\CjnEl)ypc ͪN+Aw dBgr%H Na֔a(S"pm2yh X o@w\A|%[#C(hdg\gP=T : 3\k , IEjSh ЊIbdXkpG@רl* UL-Hds$y>ʼnT`*o]񗇱]kCFr'JhIHyض`z f*%ζ:-sS71KCɂ`27ڧkp9Q4mI||շʟnc J "ڏǠk[T]Wh/ϒ]yēiuB1v uX6XɽCnJ;V"9NkkE(cH80$+0 Ջʐ|r?PrX.c5; ]#nNXMFc&r*8cn<54JAl=+gJU]uea#znVHLn :.':BVw(%, 2$G2> stream xc`n<MXf' pIJw#?۷N-A44? \~߿߾ kxo^I!V@ 6lظqڵkN uE3@_=`ehǥ,2g endstream endobj 457 0 obj 161 endobj 458 0 obj <> stream x 0槣(@:|70 endstream endobj 459 0 obj 27 endobj 455 0 obj < ] >> stream xmO0yʫB_ d< V9mř[C-A~|oL1V|*!Y.)E> N8}_bx endstream endobj 460 0 obj 88 endobj 462 0 obj <> stream xZ˪߯кjEtw 0^'2"/IMu|䉈W9 V*o߿ }oҘaRbq}y:aW3}{c|_rT#M/5 ᗧ>&ֻ~Os7Ml~!>gJqCJEb0nbUZmiOvKsnJp zuPbrhQU<4z,06x3\ڡ4M>pt.´]O-=x6 '2 o2 l.0%8Tc}ҌU-m0 TLC9}obo˭Vkcw%q j aI|pj&5Jո;$ s#LO-@LnIQ(}sNm ' ںBu!ɤ%Q$4ca3>v͊-9RxwC(#} -oU6nPFcn (+\(e z(3TD_X-;^MZybvY7ĽCB"!) zPQQ s2QYS9bڲez&XdXA:4Q=L>:4/5Ϥ,:!Ie? @sUL &:Ya=~N٫JOL攔W[DU(NcP?P+G?j]cxTPR OK)#*o/әκuy89B7 <wԼyˇOYvԱ_t6ngte!̅H+35TRe. D@VP?gN4 -R]x򬐬l~Jzץ!زAs([cn8N e.6Ylvڷ9岼9YUJ#rB4[==,zQiG|?}W,c2?ʴWud7{){ê]($PjUqmK><:+ 'MtQ%A?3=)9D3S,@.}sC_pN,?2NO^'[V=8e*;4_e~#zOvkmmP3/̧wRCS~9PMcJ rSyJXaROWp7.^8 ^ _  endstream endobj 463 0 obj 2422 endobj 465 0 obj <> stream xZI _sUP0PHn < FNt`撿.Z(K*:q׳-H)k6pgO_|oZMh:;n>|WpC>b/_Npuy1r]=gqZ052`m?r g!&}vI>>%eݗoOE.*.JÕpQ'bn{4z;kՑ^fwQN!!/2Jwtup:'6k Kk`lS:H=-8x#6y=븩37*)J[ÇNo']#(]FriT[5uv)'X2?*ǛjJm8i{Xa?Л;A 8Vr+3#bd*Ro`ڒc"FDo1N8mnzi7SvSlЈp)u V5{9'l&kCx|O\YTs(KRٖ8IN d]6t1ar"S?@X:2Hhv1XAqwUUOgpr'-'_#y S-L#yqBDcRIA,ۂ4Mܑ8!o G`)3D VC;olhֽkpƢ= ؏BlaLcvpo11HU_B3Z#w|\uP|{<F|˻" Y#m mmsXSs =r8*rF&dl 0`![N%NnmM8l&wa߻qy[q=_L<y4E"Th8IgR$QJQ]#r6lrl$9@ D%52n\ .U}]U:iwNS֬:zLa]uBm(OBO\.q4"=bjY:N3yj#*"/O^ =-G$#{ üAWRDєn8U'~{8i:RWK^;F\īB}vo3S-X/U/e*_ ;&U:U nwI{`F8?~t~Q NMZuPo#?z~3ňY&C>YJl32ms1km{Dí&ܰ-r55~XS( ^坭xȕ01fhͲVzXr,gN\QV?rxHw0Tn~XݠyR(';~|un Gشp3ڛI_hW?zRfF"MQXDnkh jTWr|Z ߍ׺jbolor}hAGy{eZC{pHIWG1>u?> <Bj k7P&eYI&V|1,|Η}_uߢױ|Q%pb~ .n<6'?VNܹvCKf endstream endobj 466 0 obj 2536 endobj 468 0 obj <> stream x[K$@/( 2 4`|Z{ fo)BJeOT*C⋐J\ߗ^s~Ϋ_߾ /ҘaV0-ey1\/a!7{8^p=_Ur~dr ӼsobOsWU*xǛ(m ܥKa.I* }Ǝ/zFaUCjAXnUFUaZPcvT冎b~B,anU>ab7sKQ{M-m%/KZP 3hqU<|3W5OX;7+5Ы%(D-‘UbM-V]zq=QjqJQxIh%x@Tlp.khp7Xq+q?Ob^y5HcpQm> ~Q2An5`fY/1Ll\ڪ]~ *m%NQu1g=,X1sdjMڊ'FoNOs%nՆT_GSi :FCG4!+5妵`!юs=|nYFzkf͌2]ӡO(o#I!̡iPtFeZ>d52ᥬ`,-OهIꃅ@Lڐ)[E=>+);ֿi XY R?1)R.͢-)5(vKK_:助kNIq^Cv r &o86+zrD٣ˇyMvQORQߺ&c'NxgDIHmlS%DΧgZ"7 m(STxO峝fEX'i @W5\n k E}'Sl'mRp rB6H\R&L,ȿ%m{f=CbB[1K9JEx0ŲR]+-<\B'50hJLls^<cC3gH9@ӹ|eu~# ɔ)ZikY]ZAAZҜH駂w?q:b*aUM@/$鄼"nWs(jZ fn&J=s߃Էx @eBda&C %'v| Ӑ'C&ӌ{ѲR|u=~#QiKF5]C-BDq'͏ܳWjἬ3zjZ.rWH1k?y!ȼJ tde/E?͉қ[c7҇ oMF:Q: 4{¼ |dh5V\F=#vW%9}N5xn#$7W%wrk{Ѧ񂥖SL`ޥQӑɡLGЭۛBIr(XCٍNK+R`&>H9=')Zp-zӀ{)2 O+@pi ӱ{(Bt8FSNjk^}9gSt}Yk?Ԛ恴nH%J`VU$y_,]Fb0{b5!| @TRRY+ͳ3UB{ *ojz-#Ѱ/Zev{…0z&uJ!M +Ok * lE?M֐e5Z]SLX[~)iL0Al)M057iBUpZ!Ŭ#||Ӿ^ qB7۵O[T?Oٹ?̅v65J6B<3#^EP+)xqlu̹4vȘh5R}Duy@?AG0G[af)Π?D/UW#l|gu@ifCW(c!!WOROȍI*:XQk7=aO4dK/|[74uFhd_i(w^y#$ͨ|QͧmY"\9ZXq6tCCȝq*>n١$=7w4#]Xv0!ՒWr)𡓄ҔDꃤ;19̰6j-;-<֣p .+ή&&9,O.)xfN3E6<ȭiI d~mwpz_bVAhgN$Eotӭ3JIN`(<:"=t'A^Rš'-H|>:%ibfC.y= #DKC̪$!'#1vb}ܢ{VƤ-wkfckbtӢENR(f aK _.Sr:k1{!>s0?Bn/? endstream endobj 469 0 obj 2684 endobj 471 0 obj <> stream xYKF y{r$BNI6؄K~JR55@Ow=\'Jf>s:WͅfӇ'0Aj6h` v~%_^~>>m\ظZU,lgrqCb= ̥irJǓ_K,*vF8_8WQ;Ty0٢åV] Rb,.¦U-vLZ f댨c=nHrS;>p> Z\ϣd=bs$ "A vbo$b^=+^Ǥѣ-d~gyo6sxƙ-O8k^CWf|-nAL6@JXfxZA4R8uLףE`5_B#:w䙇̉(R]0۟8*&db=HQ ^!A0,)n ƑyiI"k. 4rOH+ɷɞBZegs!).$]Þ/805Lpwz y$#ư1 Q/!A&ߐE<;(cvM#h^^R3Ũj τT;-yKth o^죳-RAN..< ɴNMvi|&d'Yw%Whl]ڵ"it WE0o=PΎXO?ҳ֘x*:{]|DB^kX7Ɔ#O[" <9CN ̎0%V#iye!qHYZ.x88at iژdRK2o5W$aZK"jjЉ=yI|/y^;`CvvE \ҏ \[u5.k׀ |80` ]:+\rߛU֟? h endstream endobj 472 0 obj 1781 endobj 474 0 obj <> stream xZK6WQ [zzJ ҿߙ!ŇDI xmI$g h ?h_кQhNOM~_OCMvτ{{^_~zW0.(+ H4NG糸^Y?΢ȳ&1~yA\q /QϿ'&` MhA2ukN]m7苳=&1ee6 JD'پ0Y\.(JƜІr4<`#,(o){:&PQhFw?+Nh2#Ed x{g9 <IWo45!?i.4JgwM殠i :rh/})dnRI}R== m8VF8n0rzPv/1<drb+@O}aϻwWDfɓvv5CyrB* AHf&D5|̤Dx,ڊuWvi4b `,v{OT.V/7ztcsVHZň)b `I ~>GIȪIC\, 鋹Udھ&z:bAo1eɝw+uwS䰅2-nKR$Ц튽RG+kan{VRߝdEH^);[\SGTkG7s""|*s;dU&FLMjT7ﴍpM{HCPwLlZhd-acW~~/ te %ةKu\K&sZhn+(gMCڜ٦ J>H?GÖwg'ZZ-㗅SNqOɪH=,abmБ붣SVYJ?'A{Hu X.eY*NI[L؟fIj$Abv) /0qwS{cԤ]Bիm%й T&GYꑀי=OQE#1Y;_i,4wFØ-dM=Bv5s!&[x^5P15əEީOKTdMΓVb]@+yszBg/j,8;~B -EoW_h6*2?.MZTBeUNfX$uFT,'J-ſܮO|ªb^7UL~u^.jt? endstream endobj 475 0 obj 2077 endobj 476 0 obj <> stream x}mnEy▘ݴbGjBbjgMSS n0N40b|tA(4 !y[w"а#jnt欬fg|6BͥFtE?ѫ+t }S*:~G5!@]ZYvP j }cg-zVģӗE^ഋNy[g}}ZA$POh_2/yKL)`o:eDS%".YF&<2-@feV?}K|@f]Be؀:}(4U"F,B~6,9qцR$6Ogl]HEz,YH- MLNզ%Wl/}gΒ+ d}z1 HP.9 d}^@ :?G qlUCS0Q$+`1` ! ǀ%7H@cOQ>)oFBN89$vmptw(1qQOK]?xCvJgs?9"Ɵ'}*-!]T;J=H`(F$"!FۅdCd,bldyrQ&:-<`zHWg"dGKod}(  p X"`$+ @ UB: tS0QƀK7 Y_^@a `FK8}1k$VC1{ٺ̋\s(j_icCO`Z1M?zrI8ӹBS i%"1'J&?(J]S*؟'I a;ǭM$"%qf+z䴇xF{*uۣ21i`JĤ#q61€G$m jB{ K.F%ұ,KH0, $s); hDH~->2w$J{|R#؟%/R`D[aS5/nOCB;%XKF,4aR㶏c-rآgE<:}oL9=M 3ڟ%.R`vJxfa %H{\?}ɼM58ta[#μ ),-{(o2+䌶䟾<>t( Cӡ՗X$Űg !NI;6'3T.$"=o,kۄb&0 3}$c% ?`H+$4X%A c%/@/0\rAB_D J|#:cK= Y_CKod}Q8,A)10B4U"xB!)7(Qgyh~x<Ɓr/[tvҫk NXT31'q$J}ROJ; Mؾdk] RD0,jkxrٟtsLMTE8&bwLo#?I4/q'gmo]ݣz h:C'V#ct$Yt՗H&O".%Pݍޏ);hDce(:?| (^2G矹kTXB "49?oDUm#\޳QG? OLqDZ?KKܢ)KwR*vSyrhD8V?ĶoD%˒7IsHB%]:HB8ahDHnՕa43&hK7iSH/so;m' St7uO- +g!^$6艋rHl.PЮ'غL#?oۼڻhJ?DTM͋~KD)۟ zS>1` h  p X"`$+ @ UB: tS0QƀK7 Y_^@a `tvz?`]Z%4Y7B٘&0yܯYy/u!oQNoXI/Qr:ʗb˄SvsoaYn ҄KEbOFc&?(=u`:\'-6Q)o+)nl"G{ڙ?dz۟3]B?G4>^hpn(oOWpҍKc粿 uxІ%?1N)'qx%y8ڗ it[I-ڟhxc]o(mYxhG7y`e ʛ(xR9o69[<zۙ(O#1N/2yQ|}jh)'ԓX*!.$"=oVrۄ~L)0܀%'0$ e\Uf4tbleȒ+ d}z1 HP.9 d} "Q%tYwƱ%W} 姬_&d}Q8,A?DDxwٿj][ϿcS<m;fzHW_W?%{ʻ{zc3vuj iWw/[7ݫBD'4#XD[,k=C)ΫOd}op_xģ g#tuQY0QWl }82$Viydy޿_gr|i7WJI>羉sLMTED)^qc?:yWy,Sph_cD5.zeoͼSIq{ .{\eo~r{G^M?œ!J!qSw޵4 ]]uHOda4k*n JwޏQub[8:q<ع//GgOe߲!xC_ H\byuHb=LSyko}ٟ.!Cd5D(4C )^!ډ1T3D$NYLTFP=?)NUa#1` hĀ%7H@( 6@ Dн.9ݔLTd}z1 HP.9 d}/vA@%U|ѻN-DGr.Ea_^eB2/rJ6Z(6]_/QJfDAlqNjMP. OJ; Mؾd^$hzlh/zcv?HK#'zX )n>nl",z1vbi-D0BQ*`]ߴAh_Áw.G^H7/MğF/_!Dv[00yhN<ï/ID)F?K_klx1gEѫkqLg 5*:0%fMBWäZmh[EϊxtȫW 쏾Ѫg-Ѐ1~-%6oT=.оd^HR̷9B>OtT.`kpRUlF'oD%BhaP3Ue~6e~q=+4QbIdڟ%'˭? O'!q ɼHϛM <6_ NSJ`0$ +ާƀK7 Y_^@a `ƀK7 Y_k@T oVzDqlUC)+׀= Y_CKod}Q8,]f.}{ngͅw6# Y_Ѡc^/oFgC[>zӟ'}Us:?ĮCWLx+tuER+xTdGO.(4ڣ]F_e}ߴ['~w/?2gߺI8?-CG'72oM,iDt]fq0o_t[\ۅd!d)tnKY֞|XTbSܭ{UP'#Gн ѳa_͓kc[".e̟AJ)<sD2e$}Nˌ~ <̯ ~2D%0y)Z`t?wkk']uÿۇwоdcD5o̹PݍYޙ*x9:G-Yc:OsZU'Ml$TC%{C=HF@j"[$DhFHyVH2yO 3r۟d*2N_x*sxkaDg)bd!q4V.(!S ٽ];gkzݺW5֎}ڗ@-gr5O]ڄHhôoMl4ѳ?w뽪5ͣPfĮMd#)>I2NZ/ DTϻ'ҋSybĪk ]8Md# VѨcڟt7eD;d{ֽEq>8OEU}۝۟nhۇXQ\GE2:վIMj]0}会9qUZb4:8 {ۙ~=T_:E_ܞS܉BDBa;kMFJiͤs:.CTtm*N6}ɼ_ԨD:6o \H)3CT); X"876DhUϒ9w0- ؟XF!2Y]ϋ~= G_~an?dn9Um"Zm{\mtSAD<:}[۷?KnF䷯jCsUśz'_2K(oҲ_a3x#'IgK8b^9Kԥ"nk9JqJڙI,[y7PxDmBz:.9O$ eXS5:]r) HP.9 d}z1 H @ UBi[rŔLT p X"`$+`1` h1ӂX/,m$Nerbf/>,`X_\E2^M(mDSө@JwD9ZB֢hҘ<+3Ճ7"'<:CJ/=곜oȘ+^wۙ9o r\xaSݟ9H9^1m9T91) ̋l)zh Syǹߢs&04]1'K4U"z T?ٜ+IHB#Ɉ S'+{?o4"sg[pN&'v( +y_(o4۟lUsE;%㤑٨Q%IEɤbf^۟ݤ]:J?Qڣ ۟n`8 %A#eS P'J`Gh3~}>Z/NGH\wyBqr?geiV"h)9)("u=- (4C}ɢKID:yҷkk- S0Q$+:?@|*:U}+ŀ%7H@SC  p X"`$+ @ UB: tS0QƀK7 Y_^@a SSkwlu_ H5_\.`%>}Ӿ g_Gn<ŹM6џI~j޾趸ɼm2H7r%Jk ƛwŖYxbʯ^>q}E?oj KkT^Y0uTژj&zS_%jO{>>|C:WeG2/;kMTAI?N{v,zFo%Q~z^qc?~%{:0jz %y,Evs4?Z'cnBYEIJ>Iu4h%'hU+.?~Ul/O ]2w.>gw.O74DtE6JGVXa."j,=Pa<+tV3򝧘#;/7}[Qoҥؔ?N#}Z'?zS?搼gݾ/,s1<-caO3eً~ۿ{"}UH߰Kڴ?O/y>S_kW'EZa^uޝ |=^>oWF5!s$L=` csj;N<{_f23& | n0owwᓷI_…MdւOO*j_2/t:TDč:kLRWW] ?=/t V1ǾKo@p$ (o@P:߬;Nؒ>SV{@(  p X"\uϚ mF@A3TO g<;_7hE1}m蕒hlv٩~9k'IN폘h#*HT u*zu!?iQʓkcO>HSlp/=v?Nywvx߱i/yھq<{iKO~x~p= '=d玘| $}r#6/9O?c-jbqEs̏b)+jJQD('o|>bw=dO׽_dξudSPt;3)6H)(oo1=حz?h5j9[KZtџx(݃dY-&oЩOnR^۱hE 'zJ8Uq}ǿo>}|s͵ϻZKp/h O ?z[C轩6.Yox*,ull45 nuV(?=MC%Ϲ/' ) ιOH7'"|]BBnNoιPME%nPO#g.4 R~yH|Fs?mPыd^HO74DtE6JG)3ƿR m#h80 y*42DN:#nQoOe?w=)>H߰Kڴ?O/y>S۟ݤ $ o $<-<}Mz h3zzqj>BU`qxb @ng޳j> stream xZKFϯya@ڙfX!āK~ѭ.Y Z]E769+3h׶?_^OzU`gA_U?ppwSw?^EܴGf8-vxrg!:}q/YըGIٯ<5O_N~}s wQ$TLBźQ3`!ZN=mQ3(]W,Oᗔ3` -ś9ʛЄhZ6 maZEr?mu)0RTd:wKӪJ3,8:ͼYlە H 5XBf4h( "꬚ҫIh#iYܱek$i%\rDv, A'R&$ N^ oM1:2:C) }vڏy@~ZHw1Ƈ6 E$Tr2Z=E'݅$U38(kX6Cc3@GtJ} ZV/=&Owh)o 5Fq3꡽z|؜ hF*cUytoK;u䄲W֢ [Ij4ցuaYT6WĪТ+5B1ZR%wЗ~-mvY~t[]Kk x.v-}@zD(6>4I8|2LQ1A6Q-6PظXIy1\}t- E¢i2Ԯ !gy9 {}Y@*ԫ'&lJPKaAU&U mUGrͿ^:n%h\gP(@ tT=}aaC>ShN̵f䟖ݗ=8=M.(Y7^<2#TzgT*MoS̪c Xc,WQ1Rѻ2Y>+֖ ѽE„@gTY}TS@ *!C2Q|!zf_LG[5}<0Ϫ"4^u =ΪnQg)J8s* zC5M&bg&Qv>rI97g/9qf#.+cX5m%GڙdÙ o$;.ݹ~a.@= MDɛ v Z(zEqm rYthK_ 9t(Gښs \K/R ?_l2,8I]V3ۥcb3)y@-1>m]:VqJEv˶Iq~DP% =n#ľ]#Unkm^ |> stream xXˊV+I`dAk0dIsd֣zԕLv=X,*}~ޱ;|"ʠo/Ww?!qux3y=io/?}+Tm|7 HWas}cq_tb3|#5{FB:{:fz/y3{vyw2L5!R8N*:x'Zr09fHB͜+X&4XTI/-xp|`.f?DCH#WqeKѕQ>P/I-Gu:Su^`l j&dR~b5.R+}xXXhUi*4%^uC?( TD9G Y)&Ϙݐ*)ђ=peǨFiM%o)E*%+ k`+4TUjAQF,Ce`4XL@[݂K yZJB T, *I"3.) ؁#fW)$ J1zdvu{-jã=h4Yt"R:j+0: =@Rm-̴Õ[Hnt1L+Z8W{j pVk30W&Dy<˶w9z)i<Ř1-yE^5lwrV ׃l@h(m|<_cɼ Mh9?a5'E? BjR>qAz{z0ޑ<~x2|LՊy4~nSgEz|dj)\.mY2uVhGR &^m!9Kh')FVI iU۶.t%vL6qBr4J@oo/{Z읺/s;+hzyZֿ]y&N_% o/;u9vRtf< Lq?<' endstream endobj 483 0 obj 1165 endobj 484 0 obj < ] >> stream xQr@]x9nf+IϘР:}2؎}-qрOALЯ.7<7>˳ޗiQۂ7Wu`={<޿M+r|c\RRpTtz׾Bˮl-X* M?2P0(Bj+wz ߾)żlg6O'F3`*0/RV ٵK6j; IEUKRmUǺ@)[^ X1G)]kN{)'D2cDlx^)'QzI@&w6^a|>(.4k(U0: (o@t;OzJGwoJ_fs l|;C08Wm< LÜ]6 x hݱ7`/wj LИȎ;]d" ! 0-i4m'm<O)D*غ:og$ {oW?5߿Ɋ)Q-2_+'s(x_ۡou;& b@ހw}~Aؚ˝¨][\v~8(y3 @(QEF~^^@{+[*PXc " h8QQ`Җ~ul:a^d(Ɣ!XL#rY` ~ڼ=ˁ(XN QN 4 /0{S[D!)AtÌPB8S0& O.@$$`6oz2W@2 ? |iɞn4Rsf?Y)C@=O)t B83礠b?[FB0ATˌq8Uִ }^pB8cjɅtVWrB8{o{J(eo yun޾dYDBiF5pE۶<KS}M3hw{ 4{ytVA8 ݭP=Y A&-+ 3&Dv:u0QO/pukݞm=  VrW& 28Y A(7 z)VGX̨S,_Q7"  ; m)x(ȍnv>]ൕ _[CA|ohJA_:" `{x:_PS3яi^eh~LA?2x((fUn &WKZD>h mqt]kW)86[R Z )U4R@2m@>* ne:R0@y:zx((&QNZ1(@4R桠$_(v$ ۱\9v8i݌Qҿez`Ka(v/<6WPR ! FFU( fTj3}m`i=L0n™Υ(u PO0nΖ Ҭ! bިUiR,QJ  L~IOpP/# Ob ۙYurx(Z} >Bm5Xx(Z@"*|זWP(}Yv^]u\% Q}f6츥 #:9n;Y#mcWH W[('/XD2,Ci_ @ehNࡠᡠ:  lY ؛]s r|~3K w pM2x(h"vq`?x((&5fK #"UO| C i#rGM€b}DᡠaKU.s A0]u<s;p_QG5*sCAz\ E@DΎɑ>"r$_@u5!u9""G\.rx((&}X`Db|?` nX(HХ..`Y& t.0˃fQ@ň6\CYhC` P` PȾX8#+X(h®` b 5Ѕ41([QQPpD\xHd( X $.V) Y0 l [xeEAyA TpWpbYM( '`lfJ#U0d 3M&@`ti^lိŇМh* @oȋ U0 * N[D$aZ|h *H9U=upUlH`R#-"r$_@ε(&aV` U0 *t &X[.VV+@`0 *H9/ g⬁@rEDN|u)[ /! 깖/PSVy-6S 2 #˹:`nDA1WsJQ@[9  * [9;&Gȑ|9g lH`R#-"rd~9#fp(8h4f t뀰U`W@.;bGN*ph4@"CZ오eV@tCLX5U H#r.GԼ4`QpK f.GW_+a`$ldGdNr.a9ߢ}0rDE/rD4_ ` D9A 1aq rD9Q@( G# rD9Q@( G# rD9Q@( G# rD9Q@( G# rD9Q@λ%Z 'ޗga_fP Oo endstream endobj 485 0 obj 3139 endobj 487 0 obj <> stream xXˊ0+H>$[p@S(L̦{ے3ӉI->ιK4fDߪ˝]gMEK0t%훽v\.Kn;6Hff+p5^ 6]/Pv}wՎ8fzAq0.}PF6y thq_"Jlcsr9 `U7(2<|VaSeT"BkI(JHS-*C=8?m&%7-@]xJjX8$S|0Lk('rvM8}L>)2\1yKfi?ֻzM+֒2)re':ӡAz\Jɲ%xNsX8b'Xj ٪$seC%yc8QK^sz0 4 endstream endobj 488 0 obj 935 endobj 490 0 obj <> stream xXK6y`zJ46$BNI&]f/*n۲%l2bmR}ZpFÀy,FƷ?N)LQ99-΅ Ӝ }|ϧO?|FoE%q~ Hn7<@sWtW@} ܠ"up~hEk1]_),F<~<Bp;GaD,z#AEC"w&F@] 0Cz7E`kw}`;& _DJް=,Ƙ?Xլہ?Y#֏m=4^ZdakUl&.X/yfo)F{P yзV_URt.ב5yn8z؄)h@Y?<"jmߩ}}{M#F˞Gt02|GXmUlNRޚ6Δ  ^;ڨ@w>@s7yb\5|(2 αHt=pծBej>実&tg-[~_#{Vm&&\ͰX&Y\rΰ/oMur5(J@G۟st(33X%ȋEҸEu6g>i,Y Zgxͦ{Q̚f޴؇fB0q+P ?SB;3)01> stream xYM0W輐He|BS-eҿ9·c[$A8"IƂ9ٻ3(ddh|)X'O_'7湶^.`YՌ?] (+Z l"TmAQ-}ζ%{16 sgvjCm|> stream xZK6y{U%h v? - rJ&^SUlmݳؒ]d:AQQѥsO?hiZlS~:|iڝ\d{30x+:d|zo?}\mM9߅bIɼ|yY>+l:8Y |qAu.s!_M|<XeN!P$Yʁϐ~ *<#%)/pwdg;𑳹li+AiB4AZ>wWcw4z^ϋ]43z;D_EmHzSN_/K~7!m"ߒyEmv "/uKʗr{|Q]YOKtSm垌2^ksg+͞D|L$ȿdl=XJs;ӑArc?r:P8Hr3jO~Vm22aES|tM|;B9}D146h)1 [R\wuRAcY$h0Iy]{D)AHRrIq-2\tls;ڳj+U镫$K#҈wƔgb=3n;ÕNDpFg T2fA|#/(H$% dJ.hkD>i=I> ЍJtg \-7YeMҲ챭@2mxM، \:/ؕ{K^4ɹڮ'kz[Ѥ[+0#Cr ~71c)HF18keD)0GB! 2,q!C /MvB K ewNk,_1npXm} Ml]/Mh\p̅72*1遀 ViZd]$=bt&F1c{Q.3sg̪B]2I }/v^ zA6u k2X̝^HdSDϟ gdakr€aPx%U+jI\QUp#ǚ%ҵM ,@Z+eHks@.*K.#\F-0{}!"Hxq7de4\){6יCc(kdľ2~Z,՚(΂Ŕ\ne!&7u4s4-H.7Ġ7e48 փ8ZoԔe/TeEݍ> f8u~ ˔Hz@;ȴux-"Di-d Wޤ+*P>1ϏFH WU7sEX\{ЃySbɎh ɂ{hbki4#2Jv3Q~ZN|ՒHPʫ Eب_!pn, ̍ܚ58#;oT!QXZm-(NyD l=Ix#\ndJxM 0F6asm"f>g?bc>ԕշAL-lTٚL[ [Z!/{<垔>dld{ 1G.oP6EvlO㬱SFtl,S l@MJ7-|tT&r:(0iKՒ㋷4*}i! endstream endobj 497 0 obj 1984 endobj 499 0 obj <> stream xZO OɊ,@`Nb`6S)P`[^KR%[f:$E?IE\۟.?nGzݯ_AGb4K;=B땹O@v~yR7O|8ɛX}~{'}_Ç;=b2atn1(׷Ƨh{Wxfmӭ x<}owt)jE\@F*7y+b#yzޔvj DVi@@7OLxS@O&`Z`h“/fGA23a\ ^2tIQi9YM(~E4pJ|)pKJqS%!R ޤ=<|z e A3;UkaәJ]FW[:o"[6 z9^{_XN_%?_fܸA,!ꩊ &pTq:iDHU`m퐠ŚL={5$)\/J,Ogw'KxƼs̀lߏYJfvuvM/UBavˆ,h;ĿU Jy94by(CHKx>Ʈhw#eFe$3$SH<'Ax-[(p' ۘCJL>ʼnDU:Þf[{cQ mG~P kUs=lQD)S@g\_!0a cbU+JqfF՟[AN ]zT$DbI4'|Wc=e<| GP8\UtH H3M};Դ[<4w#x|Dv 暶Z=/Z"'[#z.ղ }c~`"M|)CjTҗn<ɳBщScrp5o I*NwgkA|ֱvZ}H h0')4V1zP{/yrtTWuh5hP3G5掳Jq좵 N:uaLݪ>зގk p- VW$^eJ6)#*@T-8#;noARs;#}T0KO_8> \vkا{xGg介)2^#]_(\ /Uk%M-@ݴ6-2圶QEBSu?g^$T55_r%raF*u fae SpK1raMXqC}' DGmFs<$t}Y\ˍ^jV,V-Pp nYln_!%oI$/ggWsըڱg}:|a9+lN޻`W/q3BNFnSK|\l`Q3$>‰Q`P&$m 0':"9H5~Һ8R GhaFf`Ӏo~P4M*ѵUop4Ic>r~:ͱMBtů'HoUU_{dKP~a#dl1G1D",En971&,q#?T)/}сK,Z endstream endobj 500 0 obj 2204 endobj 502 0 obj <> stream xZK8ׯr!Y!Ip`PeO KeDlLJʕeIP?I?~vT ߺ~@ǟ?c:po߻]ۃ<L!uUm}n ~>~?>~4&?bN_zD/wv_?qTIU9Q '<>O_.ɦ1WyO AS?q>Ü*"siNEl"2x0ʝ u2KOn䅣> Fݔf lHSOcgdKi0h@`-L#}BR*IZ^M:\vD9ܕ01~W$M~k "89*jnڴxۜ}h+'ߤ_# '8ٙWYgeI^d3_hFG|Nge=`C2F8Tw%?3 kg6-厃@ڱd#/`_#dl0.?~C8r/'$mMBǃ,[Rg$]:{MB˘HHsM~4юpCyp_]}Eciw;cxo+HJ< uޓ{8wېŮENH9Vt Noj1p{ HVDͳ"S~i d9s=U幾yL< W^,GBjm< Ȅ%YPS=XG)si(ȹdd#$CitF4Wד`'h|n )3u# ]Մw"DrRVewB=Vsi h@C ewp/'X: [ TC*#t* "ރN9tO"E[@GR9ؖD1aٶ=ܱ1U6 3Fضbh\p1镢=fYd)a _r)w<Ō'qquf0K *1 mMe<<{3V"l[` Aȹ$&a0>Z[?b&'/a\VQ9i늓/un- %#{D#al+S6d<{ǥg_j?uĊ.cˎ]ڑ{n0>(g+#ؼ1 t=T#9)cY1:ʥ=sg;2s _8K E4="#L}1'Fvy8EecbqȱwuU!0zUͰVĻ3S^Z5EWje<7>o\"Sa)8 (Rȸ 'f$\B1qŸ5<¡^3a'd6 T<\fgCFTpk_Kj; U,zސh^64~Nm2I]/$L-0U:ūԟJ0 /d3\.{*an{l]Yc5sq g//Vu ֓up!]EKO O9P֤]tG6HeǼ+d˃ onHYV(|V z'6FԚjQ"A:+FFeh-+C֬4y`j>l?]&Y}4YLj:ɠCK_PGkeV޻( Ey4gCwg hYlڅB:Ƅ2Nr,*zHf#8={Vt{"<?ů,5~vUs8OTGv%!y?t2$R{3 ZTl[ BUϤbo+ڊ}UcY"U slrI}`pnprUЪ[Ϡ| h=qyCN[ʎW%Y}nKf >/7X)(5W0/q,xU k6ELM> stream x[KF0~KA0fXāK~_/I6ĠJRW^v/6h8߆>  g0A6I_>Ro^~>>]yaz9U-E\nˉonnEּrrn1_o/^> O9;&&~Vω⩎OQonӷ\ 5qQu 0PhDoWdz,%qߴ꺜F/pQ`eH@% ܲmIOđlr$$SR{"# TPcMH3y!xA~F?'P9@ ,#f((XA`|n;Ns*J6'dFy쮰fpVNJG(=>J:V9'ri?k/ 2 i-grMx;s, x hGՎ<%?ؕOk z0(څs Nήoh]򵢱7-^/]޿6x}-){QP@]m7| >rf̴\e9}UL >0i|̖Sz+^4,`66$ѡJ B^]7Uv>IhUҥږӆ tw!*3iAxRtMd3.>( :-r-R>yа ^҉"-DZ,p;e҄wn]FPU`ۦp cم8x@=t*$GR53F۝G 2gEuɒ gc- _9p`<ϑ y3[:ZS[Zsf j--(! D2QZVgaBJ"r&!XBBSSrpѬoipltv43@\˪meD 7cb^N îu4=jRSibĒe]$y#42cͤ 8cBA |8)/Cu09/KdIzHS⽗ri&-dK, U開$OMߠF@"X:ZE,OR|g)۱Lsa,uMut9 cڜcjTK`Hͭs+J \]5=g F ]yOt6W+ ˜) H[@!B P݄:-JqVE:E55PG}P/Biѭ K0+ħ ]KS/@̄O-M-8'WU+l'Oh#]œ&,*nCĔ1 S~G%Z;`ʚFE͇u:R.hX>"P ݲ@SӳXh }g"t? bĪ~Fk}sn;b(&9eSxXS pϳAK2b*" abϴ6yg N=ߝDpZ]35ptCjS, $*Man2Hht-?4SQ)qM˼AgS78a6"F}9Q/3 <sSx U3`ig2JC3X?Nƥ#`0X@Ŋٍ8:@v:umܟ)*O1/7vTp ?K-Dr^X2cBh%ocx%O mS:In?@4;d oʗ9_Kw—xwiIvT endstream endobj 506 0 obj 2493 endobj 508 0 obj <> stream x[K#7ϯZ`ό!- rJ@6Tz^̒]j뫒|Ħ?5s1?M?~zO\ilҫy?9 :e3W{?ϧgXjWίnf%=I4oN n?/lny;qx^{l[b; |K^ߞ>rflE)DB4yO)iBϛ_pg@Z-m\+n{ ^+Z;M)Ҕf%Lɍ/) lמaQpDZu<>F /] W-B72+COۮZRmG_/K+1GlqL@wpīwS&  e3$`j8L;pr'VG5Yw2L}#/_K$/aJN\xƣQ+C Jx #)$X=Nkܲަ%3g6-VٔaN^_nzΌKWq1؇%wջ(%WpKݠ{sF3 c=74̚~ UZ#>h y`/ x!kTtK 1݃g;F\tNN)lVc x)ѵ$ @\Z Vͷ8#wH\XsL9sós)\]Yz g%@m!;A%LF|J[AJ k14n$.WXϲol*{t :) HnKwFXFuE)I,8\;hY[!DCZ\!=Z9BoŶOɽ k0}?Y' #cCER4 Ā|s觐&Y,)o1OѓpnduA}i2_R4Bw 9w5)-Ì~[tc5[b"o:{InB9oɵ gi=s*fQp8oYWtGC;!!5G:AJfzkLsq*-O(v{e:T`@7- Vc"t;2M2q'ߴ1ީ2_~gR?q3=jY8xnxf=ִ{fQv|4XtAؙ_}p{ԵA)ǀX$j1rԂJ>3&'HvN]bwܫ/3!@.1b.*51?x{+Svgr(e 颤x7vsn$uM !i,Cm&JEO,]3݅#`rמ#af8i\S[^!7cz*@Jen+0#]CTscj3 _!ek$T9n=EifSb/E%h7rCT0.K{>'Brg(/$}jMk4w r@K 5I;8CקtIo-<')SPSup U[C{~UJPɬCuHjXx w3[wDƽX(CEQk3{IyNn)8x!v٢qpBr]t`9$ĂW2\sŐvPc99P 5/ZU 8TRy!xhxJ)̮Lb^JϷ5lz%؂9Zi=Q~d %mS>\^pk!3䞘4|Q1zBLmY'.#)F&F#M-~@5dٝcrzw#,#뵇7j<S@{fF ^9HX;i'^{Z`}qz֨Hǭ#m +jpXa=go[Lw0̈́t^!Y8gU {I)5|s}/9Jy>_¼@Mn7/-(*b)}RR]9#M(B:DJ:T=r(oO1wtܹKEȺh Cg*۫^"xK @ k80US:$Q3n|jɴRY@}Y^|c*Qƅ#|8 ~x>xZa9^C_~$>I* $zAGgoq&`}=M'yT@|(~'joao- endstream endobj 509 0 obj 2646 endobj 511 0 obj <> stream xZK6y{U4rXrJ2&^SӖa [K_}T469 ځkooO?Ϸ D >@S/vS׼|d,QE;G8 3ʳe<w7؁ Ϲ-9%O~p{9|:|jjg!8)xچٯ<rh_}&jE\<.]q9C-0^E'P4>AJ1Վw)1>_Jq{cUM0I̒]q糼[YEg1Xkя*۠QiG;eui?1Ǜ3z/_xӚҶ<\ȹ"DDŽ#ή`؊|FP\ US.̊ ΰxUr3N)xX=el :LPJG`[(,W?IbZjGw-<89=ĂI;~5jQ ~p:= # Ċ"Tjb U~Vt8Zl]]ae+d ܚ!w쒝?9-$lHmvPL1鳖᰷'c/!2NBTw^ z;&$4ڼU5`~0z$.hW=G7YSQxNvh,Gώ^`[F=X9.6Ƥ3baV _,:J'܃3BhO!tt1x}&mwnSHmYdO+Ne8 Jl"rSQURG9%+89gNl蒤=6 RDRk\k nqJ& bZF|IaN,WIMD 7݇ O* 8'BC:@ьX7!p{ڡJ3 :|!Jc\#Ҵv2⾬J2+erik„A0AҎ0ayeMlF4UEFTM,oM*]{* *"-h& ؘɔا'b*aW+8rceuqo*ANg;[~,p'Q]:(tj' r.s4UDQgXBBB4p6ntMȻFu00QETu[pdH^M iy՜Sb7&%6޸gOlz45k j%Mρ>qt1!gD1- ڳ ZP1T3FYpnMۧ -mǙgO:$$ 0 3A,y~!-^;TYjsK==d]$\`[dj_jh:"mk09)%Gkk=C-? %D$E;iceKn XYr4$ZD8Xj5\3o49J5wt%xUNm]@ls&{^Z/SC9cB7YQčIzn4/X Hg.:3W(cl!WJŸ/=V^{̺D`\tekV!!y[Yĭw =b͚@|CiOx{?ZoҞ/`ݸy%%Yd$v,jCn٢Ē:=nx֤>*y@8MepVmT;*p$Պf8@{t1O4BӈBbe4':O=d=d%Jpwiscϡɧ9-- -˄.Z7J=vLT#,0&!D`Hw2x=NJ2qJOQ{k endstream endobj 512 0 obj 2003 endobj 514 0 obj <> stream xZK6 W<@(K' EOm@m1{/IQll{*db=(>W:*ooOO՟]mmMNU4txNjV:Ңj2Ws|{\_>E)(=@hNէTToϪk߶gZsVzn.JϷjպ5hf 8돇e^8UMF.νo_X\L^\[MjSls>>plS34yVl{zGo-?:Ьk4EY2lbŷGsJD)`#=}ƆLЉiD]X彄VbYBҋ 0"J@NK㽙]ӷ7\jB^fX ql<*bL@ @Nk.]EY tǔ3Tx5WzȆ)Q|- ّ^-/Xqtԉu5T/*E9$S3P% tn99ﴁ_HtQ f׵bݜ Kۃ@)$GathսZk@T$R[i٭q].!/DVVux@8E `0.{h6>!DFh4Gb ZM[OR Y90ړόcBy;p΀%;ոҥD@]c lݍ-(nk$nbU&覞Hxl<䁥DsU ,tW 4cHfGUEU'MS"};dlr+Dˢ4NIh UUK)=оB!?8~'1`̌S`!NBG;]7s5lVYkJaA*akD7ɠs!l%l8k/価R&Szt\;?i:N1nka6D;~'ð XX-tXgZN0B"\dpJؠԌ#o+*hˌm׀5* G$*9F6k {e0u=6`ޏWb": \J-@Ad+jb%7\$s35BF *2m'x~ 6o6m~R9#4sbRthe[ OuG(|k[@kYCq1OQ$,k:EjQ3$gӠ԰OT8r $ɣyp؋ѦE7ct3heojX7 t? MHW%ӷC_M!rt|)śݘ"pnApn;ͻ)¹*Cwx̣K˱T˛)U@zïo 2/nɏlؿUbog"_E r<v^iK4G-A@f!f|t} M7L^v'´/_$Vz[*c!ѽҢ1rY )$ *L[K//2Y,X0t0}UJ%\3N '8-iL(E( ac{')zhtOba'3fكwU5,@JTkC{jȕrBLiS_輗T˦5%CS?}99 㽇-A0x{цK endstream endobj 515 0 obj 1852 endobj 517 0 obj <> stream xYj$GWy{2#3kWoƧe0wlֲGRUgdċx/"6^ Zk7oO?woך==K#޵y|w9h¸ǫ #\ƽF5c\[0A[yqw{=힚i{qݝ< )*+("_~\jh׆ 6#1'FC6 F Q@ .4ݢ#\:>&/,xǐGvnN2GyyeӂCV=f |ʻc{sUŕ'Lx|]:zApޭ;ֺCxd^`q4\OI-%q`:+xuB'q Y^jGAס7&o:BZnn5,v3-q"n/q0Lp$V gOvyYЊD1vDԑێ@ǁC0Ё ^W4JN#[y7t1Qd̚Āz˂:?.N)Y䅐pYhZd5^<{i|Fe{Ҟ(KIJ]?`==Fj h*hr(,ޜ|X}EXQr&lR{PriAV╪%䒃})[t-xy|#H sV,MbH|,<6*+$ 1m-?-c紘T}j⬕K> I'obv\`ۖ&auNSB6FA{O"qYOMKЏRBYd). +=*|.@|==Sw Oqe$nfP֢]:ZZA||B:NM!0V;IwpBz< XB}7o,;ol? #O7MxW=琺i̪J /mguP\q}N12x1h(&67!-lxWvy+5_=cCɦi('OX~*OԨahCvmm0$,[ܟ8qZ^NVf߂rыvTpHblYjhu_e"p#!ٟA#xސn/X`q+3%ϴsr0Rs$U Nkʈ5R'wWǦ9Q0`Z{yƌmnc wVՑ|%)HHFxw{>UQEz endstream endobj 518 0 obj 1597 endobj 519 0 obj <> stream xoƵ(Eyi_ h`$eW%-[,Yk+7u|㠅޵,Ү;k&,=9bfl#ӏߟ7Q5GG? HĎ ѫ&N=>ytspt}ѕ.ձjw/f~&15>%zn> =9]N壿=w)16>%jW|lDdeg2Rksrcd[z']{̙A afGO rx6Qȫ3V_E7NGz'=Z@;b%7Gjxp/~6wZrg- % q!2{~x_;U,W?>}|Vi\CI1a@hzv񎱪ǧa/˝U5{tcsMSCr.J)f?wvo=f%ф2N )>%s_.'+S*'MW[?z|շ;yWy1_=9}ew8E^;;cprekrq0v27&erQWr`icC;Ƿ&|Eխ/>xn{ha0huDj{`/ZV\^};wҽ7O^n;-|'6L!vĸ(n&½rURHI(퟿⳹' 'gP\ߟof$us\5O?I5T ~18Q9ᇗ~*bfl#UOvڽ{7<>_ښ;:% 3;xek 'Wv?+;pr_jƅ2о~RavθƮ(V>5>@{Sl{Lb8طK @3<;);1Fe"">ejUW媻;UYڜ?g6EzrcZbl7T-7ȃ9>}lO8RhOon|zn_Ǵo k)nfc@~Oo}xGGcUNOO޿EG9r& E|MoYI+?Z<On)&>/j#W=hP}ߘ#$1,৫xƉ+[H % 3;xek)_afl#|̿-E؊uxq~y&oU{!R5hK<;5n>:Jv u{Ӷ@xw?"#.7JF|Mi9EjoږZ/S% p~/>~ +"> qs‏&1z=fplo෶71X|=&>k|M>I|oVǨgJт4-IǴ:xĈV>㓞LPK}ʸŮ#D&rxƉ+[H % 3;xek)_afl#I"ŢȈ_׈H^GNΫؾTow6iԕ;J}ZڷqLJ\lpcSb#ƫ\%j[}+m-2_YI$d~Lho>(/b:Ϣ}«h|cxO"G:G#>~\.@{t?oV0& $You~}'' |cԘJ|(_=7=͑[~ܴnW!9  rOS< Dq|M5Y0WƑ~HbQdįkk`fl# D#Mn4wbbo<۱OvH~.aMUMaޔحӃXh?&>N]qoڶ i#c9;e>3O5@bH'9m_ I[w/?ˈ)I|gj?zBWQ/%><ae.7?p˺dV_Sݦ>Ss?: w'5xoll[:{|&pe*{I'bfl#%kb0q|M5Twd$E"#~]#^#3;xek)ˬE{Wz ہROO@*[Av Swqmjj*7Z0iݝ),6ILh~_K{Y Fv|\}D+(& m152c& wD/6]I|3sg|$Fg5_S%h6{M*{|8Hk@LG =>M$rxƉ+[H % 3;xek)_afl#I"ŢȈ_׈H^GLcN;YzҤnj4oQ_*zY`.aꖩُRwSڻZ >0 u >z^I+?~Lw\IoLJ[ƦBT/$oOcW}o2j4v2AS=31m|zum[;"srh<{[KZ|ՀićDz=>4C=#p@LG E_!uUogO83;xek)_afl#%kb0q##)RX)+[H_f۳'GI|Y'P#E%v'\w2n?#dӥ@bmn)wOqp_/Wg96狘''>T;xi\%c_F|x4a >SVI$ y0^%ৢro}>4֧ >ɩu3]#V@fuT]G~4>a{I'bfl#%kb0q|M5Twd$E"#~]#^#3;xek)S:a~sՇWi)i#KeS{#m;5FZ c/w.FL7W𓣾0^6ML7?x>x-xO |)S=blWmHSd7/ho6['WR8njWW<>CZ_Q_$ ~kc`8 ]6|M>e>[\!^F p@|{uœ0N^GJ,a+[H % 3;xekH)EFFF fv8R#uP-fnkI{WƋ7}pHٱOk@|뼺j1WMc9qX0N0 ui[8:`aP+ZmD['f[j|%kI!Y?{ Ǐ*XqO4 9MwVh\ =/EʈOkhg;z?9f4٬o}؉Kx<#u|Ja3﷈*>~G~WW< Dq|M5Y0WƑ~HbQdįkk`fl#|Ҍn^+9 mm# M-a>Eт_n(4\xk/2jm.XoJƸ5?ⓖMoQBCg >FF.֛F a%#MWRKb#ƫzD.W:ѣq̊G>*M7OcH p @р_O /'a5Y0WƑ51Kfv8R)R,uxqoNyJG~٬p>CMiDw|bNS0J%_W?@jU7Q8~]Ɂ7|N b >!3>|rom >ybu\>*Wu}kHþ'y1 8O ^]$1WƑ51Kfv8R&f ^G;?2"EE5?-fbcuPfU@Wzq`@c2ȿW]PԫA)߃qrH̪.<m+'r_VH'ڸX?Z͐>B># )D~O)k+ lO|̶zo7TLG/+ ~qZ#%pg$FrXQ{F`Mh줵}'7U*>qח_i'a5Y0WƑ51Kfv8R)R,uxqOG Cf1k7y<kX~g"V"]P.p۸EJEE|Z􏉏|SWS{l%URU5 $Y,>~/ 7u~\_ UM>|-CFփ"#id73^kO_OGmaI8v d{N:ysG TU}@?@a#Ek{I'bfl#%kb0q|M5Twd$E"#~]#^#3;xek)SM!֗|R|qv|)).a4HAۯarHG|b[6u^(mx/+|S| &T__r҆z5H|҉sô>j|LK(ЈOشNlxԾu=\"OC㭛|x:OSo&JODS^_U"T' gJS]G~a05#ܫ+q"fv8R&f ^GJ,a+[Hu?GFRH(255R0WƑLc N/~{ ue0q,.@V\ɿF;1ˤ> a|淓{no]8~v0zt냋+oyuZ~݋^;Zi[j6m9%&V+_W_Lq|2xvtuo;YNn N쫖\d >8O-"[_?؛LVSomNnl,=|Z\ߴUp>Fjlmp7Z__ո {GXlWeugx>8-oxnEn3;xek ֏u'Njz7Ɨ֏V.)Г{';e0du_vrۡqָâw GY|_Uv{o> stream xZK6y{%v 0)@d1z)ahw[dX8o1k~4&oҘaRbo޾ 帶g;la- i}rRr~'%Y>޴ρ?zj"nW}*/]E,~=IOD)6z5%(ݩ)sjԫƈQj܋y)f3(F#4Ȥ,83ZEiCrid1% %&1@ jGrl;oKhT`s+Y|h!sM*E {v+ƴpE +.gy Z7t IFH[6F's6F :\oñ#Wt EBη?(dSI|HK|` F OT98Mi(ON.j"rx(Ah@\?)f0SS8I}i]sWG?>O3(xxY!-~ `ĨcTB=p膒ժzY$dE(a$~)HA5h2]Ē{ AEұyt.K`tAp%P4,yJJ{aT>)jsx}&ɑ'g<2+J![fUUO4tg:ua!-źe얯݀ โ$ J(iTCfuؾBmQM%`ɗU_rC3,"`)#nQ߬@`bYnع=śVytV.y'p=q#;i AaNa(-q& #+LYҼ_*.2gHKTYNޞ5k=L&-Z(YQzŽ5-V_\Ӻ&vfc ˣ~k|e/weeM|3ﲰ*W_ LZLrO}2{P V j%;.8Ux0;Q$0Sm q|*_.tGF JUJ|1aa+DDe7Ѕ?cLrT6VVfQ%M]!vpRad<]p⚆]9ud1Cq :hOY#odAeۈkqRw"S#f E`zvXvX!IvYFZpleē΄cTY3/k*5my(#Pݏ#ЌIR<\K<ǒ&-x#4_~ISԑ[|6;h1`K_!Ī Rb6^)So";r. (H~]Y(j\pמ#B)6#m\guEjZBԮzi\n&/tqFR o.{eub7Z%+gq={(׈s5ɰ-SO0J׊ (3+_պS:Wzz_Ŧ|ВٺQi^@9`<m(}uS m#>m BVN||  58]=mmjba?_^ˠ/BvىrF8QTk&!G2p~ ;NoEdvޫ{)L ]C}{ѥѕRh,[y*NܭDg5Ha}eEUpVjUw vOEtň(A:~RC?|nR4÷q-v%͟9ʊVrl..񤾁/V ]0;RkQ|| I=hM/\ ~'zJ׌/' endstream endobj 523 0 obj 2398 endobj 525 0 obj <> stream xYͫ6y!YI#6C@{[xC ۲{-ے}ۥHh7ߒ94G_ul{z~]6i]44/Ώ xo;45>g#>`Ϧٌ:-}O_5CLknN[_^<>>4DgOifw5Y x<O?|Іq1 !.gwE_Od2JDwvD]w7~z,ŒЊnSzS;MA+ pLtxΦubj,QW]nt`.YPacK39e Y0$KLxL2hmDmǬ=ٗ! 2T3}!mmaaw,b4MbBfm*F/\W$JL#{?<9`0Ͻ]ڭ"IrY}p:2ld&tDUuElU!+ ֐rGYyۑ]L1p; qW,w#) <@ ~!_Jx跮#R8B^3V~cմPuUAʆGT̄+%`RX-=gQr2(],VMݘ>TvudeEy*#X6F䑢if 3ZvUqٳ[&o;2>C\Y,;U[l,&@Q 2`F;:|{L*hCEN XBw μ1`ՙ?iU?jޱ_=C5S2W-2ĭst!(3I@b E=gASg@ΓY=99P^I+U%sY2\$Br׆" Ҷz=VCu1m󐥘 ~P&nX=Q^UK>yCDFE8M˫Jx~XXG>KVz."fbak<+O2/åǸ>L[xVf*uI =Gl<7hJ$^JuN^xV^'"j3?e{ LJpD oYfK:LrNdZc #u`;S/wـFЅN[fXOk&5 z\4mB{B ȃV"E4L.\gnpl9 o13+pN| =<dX˞3_s#*n600Qj ] >> stream x D&vQ3dQDlvNޖF9nw߶:WE=(oH34<ǜܝߞgUif~cfmfs endstream endobj 528 0 obj 131 endobj 530 0 obj <> stream xYK6 W<@)`hoiY`m1{/kC#I-< ZF~sc |%L*ϟ6s PTv wysqw:Gm>xW| 4 j\~/>P\~a-]&69هV`]lvyslG8Fj,]U9q:R$m9س9VF'\pC.@~vŒ{҇BG/AjSB , 7dJOI֓k!kP KK 2P &Ll5A8B aP[Gcɐqіuow8{--aLhp79oq 37Ny% 8_'xt9]-[]buʥ-ŒXJ4g јLod^ҌHkHy?Hi$n#G QP!ħJ>q:9[9X:^FxjcOSe>wH;C(>T1sY.3N[C6Pt,@i fRBB6:I/B])FSJJ\WNa)X%UYfU8-M22KV3$ު`6pwlϩ ٥:Otabd'̔x;gaz, Y2@IK}\:S4*rd U^:7`']{.>Y7}4.P]μ+Mg+ȁ{[Cޏy8qmY_ۓGO 4%9цr{ɧߌ ] >> stream xMz,YPgK(J\GwiGvBȏryhҧBHoL&yQ| 1K=ꦅK=&]sJ1#][4)a"؉+VpivFMΧzM&@΄:3vL:vD}Tm|R +sQB;#go@yY;u@ƼvoIoHPg{'2޼<}7B|ֹ?7wgO#:S u{Pw<nf|oӺm8{췍sս3<}akj.0lS~"&uЅtaff!ݢ."T-\(`[IMU8*aLۏp&ljs "{PH]LfS~_/X~z0#,)+TYA\?VQb@QbwX;k‘.\zO ¼!.#0:пoTU_˺nro3oryUfyCr9w=A򆺲?p|9rЌ32<9F8̊{b0&sؼ!;q -9[>,NBvUsU4oh\eG7&9 ǞKbؓWC⯁y$DL")J$4>iz@ .x9KPY^Lzo8yn2q͹yCHW2L&9`< [ =i3 ^k'|ѵ[j WjzCm+Ȃc]9Z 0|Zl 3L>Wf6HI60KR#g3sHXLV19반+:[HGM[8㵴&Kq^,Й4M+*N@0s+xjc*Ƀ =YvrקD}Tm|*\PDgbliLgLfw%"N1qNf>\ސpT Y?驳ʪ0QTs߮MkR7pbԇ>L;{Jmu2x}yag>aaO :&4C!!93 ::7$# K^qN?d6nF endstream endobj 533 0 obj 1404 endobj 535 0 obj <> stream xYK6ϯy;RI-h ~@r[!dMؽ,[=]zeTW*Yu˗Nu'_<}~C/Zqs>R+MƝ]{tO\u2O'(?E64~/7⚻< d6ן^/_>vIO3Ĩ϶yڧlYAx>/?Y6"3t;nc&H/sENoE5`-82L= 1~ TT%^ꚾoh#z\ F6Or|5)/'.M u$NG6Mf& HU`pk MEUycٝ aN ل)⺕ԀZHߏC<*V~ͤ?`-Z?F7!00 &` ( A+U3PTg[Gگh2>vD7vpXZum30e.1DaNo.|6bZC e츀{Ft"ظQkX&Nl))g''L2,#?Bʸ+S;2&\BZJZ4]Q ];𐠘kځKG$/y@Ѵ*P3Ćva??(lHMqLAgf4[Y'($T\/x^sJ,$GlnXhb:*W]hQ|tOu ljwy]B!z$7`i_LT,-ƞOd˜^" X49 'XZ>~k@"@VC+Q*ӆE%R=Qb^LSVčZ 4;!( 2l(q&aw`~`FOe¸PR1c?l9C1C.Rh+OZ)Uߤs . YSSKA:f$vVRBE O&K'j{aK:Q-0gOI[ ]ִЎ(:x1wqct^?V %1vɳrf*;|t6gUS'"5eCTzKe 9pmQ]`zSxhUG2GXPpgH'8]>Z:~NyB=$\X<E[LK#nH,.)~ح6r|bybYtܹZYgrc;Vҕs7jn4%;!Ә3aۗ!@($w&4t0b]F `~̎1v`qz=FC,3$czcގ7M'۱Go[BuC/f{#jNnE6/A9h#=f`(K%̖hc}J|?MQ endstream endobj 536 0 obj 1895 endobj 539 0 obj < ] >> stream x @: :UI^6iHE9_͞Q?߫=S?O? _.}~:ӡtE~]?xWRWg_yξB(}60g"`R8fgsT:?`ȗ9 F1D+ endstream endobj 540 0 obj 255 endobj 538 0 obj < ] >> stream x -ه}N!TDrR/p_ъv[x4 wC`^K^Y7zUSI/ o^iYѿ(~|7<||6䓐OB> $䓐OB> $䓐OB> [K>6~JeygxT^Ȍ\USW33B"L4  V endstream endobj 541 0 obj 231 endobj 537 0 obj < ] >> stream xr yJߧǾGͥr9a.:Zi%Ov]ߝ&Lu( R:q)G *"J`9hPQZI MH9Tl(H;BF87g鯳ġW ƘI ZԨUkMlI D ~I.<0r 18%(P9Y CGW.iy_C(K7רy_%* endstream endobj 542 0 obj 435 endobj 544 0 obj <> stream xZK#7Wy^V4 m` S 6azI~-髇*l1`]?_>5llCmM /6O vwfrxWyg6'&W^~y|u׽9 noaW?ؽќOgsDZ34l-ly4ÁRc8PY= ߫sY\!ؽ t5{5svG1-xDƽi3kHchYn1׉"1$ʱաkD4i]n(l<D@i@8M7&b7}*,IG[JKnkO8׏f|EeU n9(FW\@o^\4N(uPA'Cf\!79SBAyAoԛ ĴAQ`d6Gpb;vq#Fb< /9 #:$/J=pG)c49rb?B!^ x%g3pgMJuy8lq᢫LUu1MGdwP#lq(VP3fjź%bzpZx*Z&ڹzJ9qnܭ6q<c=ѥ/`L v-lb3G D#YHq-v$xZi=ߧ&,/zD܊^ZbN+lHDeU֓庀ƴ@ƹ":.8 gMdžύtC*sj5]*QYr7_ّV1v%SQ=xnGԎҏjҩ+JRO.|QX5ٺ>z ڽk<.RGɘ.& 5h L`: E;o4m>E%Noqoe¢ X`[J@aFhĿ8W)2Π1j"[A==jx sAbJs:[FbB&=wSs$)]ܦ儰aX:: Z{[on6jZޠ4X3^NGz߫mϿ~4i,Mlx ;vC~3@H~XSx ц0\#KH):0 ZNql2Oemԩוj?;rG*QgBux?ζ3R [ktL vK_&JX0 ύQL-5MQ3IwM[r?L@7bJLCJ1eC}ՎOkN}Y¯\$|jPcd ,҈ף49KzVWc75CA>cE]f>jXhO5tbCr endstream endobj 545 0 obj 2009 endobj 547 0 obj < ] >> stream xI0 @s: > +0u:BWD#{~IPk249xQ% ih%7K%"[  Ҋ:GW%X2-=!UlN@)fIwR^ 5 KNЈ7qzA)&R>sk'![brrfFF :y?PJJpS>@i[)r䑶b8 hC ANJacg>YQ?[R偼_P|7<ãS&)% ՓV")7|(#ɷK'e䒲f1X)wLq*hOUc͉wHGAg_.)NiQV.)0Jz)_/U[R”ޞC`Ehߖ\ tqPS1䓔y,E *@BRT A+E4<׊OdJ!gS/` T .)ڔZY9R|W7`Ox_%)E+_(DZ-)zϯ9ҟq>f",k hcӔM8d%Or{__E )ʧ hVHDLRT J!P)*@BRT A)ũHbjS oc;gPulM V9 l,b}%(2e蝬ZC-ylP"+ endstream endobj 548 0 obj 879 endobj 546 0 obj < ] >> stream x[v @Y%,/f1~v*/ 9M@nNSE{ A,Ǭ4acb %8h靣+'STb1b+ÉuR[ h R[9&T!Š=TΤlޞʤP\uy% -E/.D `)ןL7gR=@R$Ӊd| dw~pb)tKt !'R$XE$E>PD46kI/}&)<'dm…_6]R })EGVpz{x9HzI߽$|HaZ\CLohۚgLP%Eђ2WJ!ee%IYwFk2^Gz iɋRZ,Zy8g%hS<~NʲptK!ȐaH0dR2 ) X2"SO՘:)3فRܴ-*#Bl^ֲzN+Y)j$j[tqH1NzgPB-NRVJ ·CJ!%+%=l4| qR'n=BP]b H`ɶ;qg#e/*v8ޕHjNDqs'uR΋P’ҳ7gܒO\|ϸ'uި0JR^_%/6*<ySh0F+l%]xóIHBrؚ}=xL/V DMTw7⻦y):X퇏]?-/KZnJ;}h 5VpMÊm38뼁BW-<8j]O;wVա$i- ]g.Ѥg)mŐoW.ޭ>KM "īw NhDctzBxhl뗙;MS0y؄diKdX· endstream endobj 549 0 obj 950 endobj 551 0 obj <> stream xTM0WydhoC[(lKҿ8d"h><+ Jc$ֽlgA`{AB !?=P[>LbWx<wIz ԽNcw$a9̑0%f$&N%{0>8GXqJkDKU UgWa}͟=y(۷_`VH:&Vm픍s+s o)(KzY2^I ʞR;u{A4j,^(?8hME1RkF0GT7M:G8Ь9Upi1- 9 +L{f/2:f]K7ukE[t_S…r\n?.Z ] >> stream x * YЬ=ۡng-*@1%ꌗנՄE"z鷞|wNkY^\|C>|.\[F1kt(o<9pppR n{^8yVXG;in{=ӆs۞WCεLrӚsfjh3-f,}4yY/9ސλH^Xڐ7TAkLe[8D(sD|:~ofmጢ%=\VLĩ.(εi(JSұ)шNٟr =b*e_n@So8N݇s; \;.`( iSrsNlvH^;KYm D7Khȩx!DvN8apګ8#8~e =7l|ݧ/;"PڷYPnq=[-~t=Eȯ;\!a z)ǽ!u~k|U>jYj-mݕʿ]rmYm|ʉ>Jc]r2ʧ"W/IYssY>ԧ9m9uI3N;qٔs&4|Gƥ(%%b7%KwJUyZ\%'-E &~3}HE!`RApFpшJ3Q;T1~?tcU:Θ2><Ə;8kTʍ/;h0=pᡜ|%#cV˩N`wę éų36lj=@ʹskTy>!E䇨BO}~Tk;`IAxźЪ}I HAes 8 '/ '/ ۴w)/%~/9]wVw.d~525}=ZEP2~do&S$wBtGz9ߡl2FC{QCn8ibNp?~(y o8pЇ p2rUEstY{x028Rpy\ _a9~Mw*|ߓ0LPs‡;~* ~;&w{;=A; *WPE@'g%Α8>$~;%~qN^N^N^N^N^N^N^N^N^N^N^N^N^N^N^N^N^N^N^N^N^IW3 r1Վsе 89ˎ89dkK8jk۹&wDKזdz_(SM,][~ek+y_l™jmJՎs2Scn8M 9??_né`E˫%kBVŜ"|_ g([(ar|n`\f;ͱ6\N^ /< R_&[xp>J+$N 3I}fώ@u3Zp4}3BrUMorT9o ~pL<Jvf:hyoaBsNŦRΰz[g(ɛq~@ai /< R_&[xp>J+$N 3I}}vUN?$>Y.=WxU %q%tp"ZjϙApcLkŨ.Э4WǺZĩB~[%C yfNh3gt$^J9yM}R_h4 endstream endobj 555 0 obj 2051 endobj 553 0 obj < ] >> stream x r0 EnCSo|b[2FVcL9Cݒhpj=TD:yv݇T/ڍvsUGPف.PP>: xTOKڪğ&NfaTiِTR\Gn.sr**>lt}<\w'*ZU .<T8%jXNixe iݪVXJ/6Mg*-`&!~ qK"U:t%ULע*fbJU(sUyjBZ"ـ` @b J͏ {m4Odvj#-ػ@U}/k ]Q 幍jan#BCrU7Z>YAhUsu)5a7c۴,Ll)b6!,dN2e6FXfe6xXfe6xUwhjҴmUiIJDJiU+a "EU&e6IFR0/O9 endstream endobj 556 0 obj 774 endobj 558 0 obj <> stream xZK6ϯy;Cn 9,%!J%˲-& c-Tջ ?/w({~S t0i: OS5tu?=Cӽ}xy/77exSn>^@kx<+WJ0\սP[ ȋC D Q{+@Wf[e ySq Z% !:=TnF_`Z٦) 3H>lLv|B5r\6|̈WpR`rKU`>U8AG)FE2èhc+I-Vcj#FBJeFY=IB@XFN4h|l,{y^rC/[bG\(+7c^i#bi ;EĘgwNVdzd%gN%,s ChSB]'(\1u)ݥ!큜+MS*(]8HWI"#t["::8i8CCфŪ:d)Qmiy#F\0dsEVv)a9GR^7:%b^uE3&f>F9 tpJ.*@)[`Ʀ.#ھ wd[[[2fiѹ\=\|_ Cg]|-rU;^V~.&J^S6aEUU*j7D_ک6P,x>-݋]A[âǜA)E1jX}+Àpٔm|nD \5jDج5!6[>@9v!pUnY5h0KJqE{Z4yEqDeT-zn(|:n T mKtNoiDlw圻C*ˀ+ˣ/t9؃zj讒qa1ֳqp`<%lcLX+(qH%>trm]*T ؖ(*sJ?TxN~nDWl<+իYY1!MPjLE/uN.j[[k^Y9G:[{2YΆ'{ OwEů$CLMx3py=ۈ_@ g_g #Grzyğ8OutK~S۟>x endstream endobj 559 0 obj 1856 endobj 561 0 obj <> stream xYM6y{*I1@C!$l%?%lK,lIUU=duo~: t[gKAW_ \c_ѝ\JC|.t5>յ;j ?E:7i;wH{|?j?=蓩t{̝=7= ۿ=|髶OZ0*h~5zxCƐM?+5^`=# &t1ڂ[eeHRv*plQȒ.3U|,2X CQѪu;մ+P6a[B,AP4`3 b6i؊<ƛh>a-upd$ZƄʱ}{?ԱB;QcAG`^L!>T?B4sZdst\ƭ&vuK_q9 ]b`W;н(j6Zt|F.'Œ@ DϜn.\k=5`gXK"Kei+?j&UpCSR{|C2Q`fGeX))c͎ǾPWT7m[> 4 n !sXYϤjr < Q)') pX͇guCXφrdiƖ+db\ qE2etWؔfi;;1⦎8tzoSVGWjI ,߱looe܊5f+TXMiV>L~s1䀀 r_SRID5s~ϗ5RS}HRZC e~iaΘtm_,d'Ħbz|k!E 4r2 qIԧJqBv-sQ <&_l!jK _'gW^Bkʬ8 endstream endobj 562 0 obj 1601 endobj 564 0 obj <> stream xZIA䦔EAo|0> ߱̔MZ-{|)u?~j8)uZ翆}~vn`o߇g?㠟CnLh<^籿_~c[VPHa ?~QzZVu4POo8PsZ#s=-_?7t3H4CFtpU7m`Gg4^tO0n'kշ[Xχ0I_zr:ۆn??TFMD`WI!\GfЦ^$7 WX5*MJvf+q۞fF_ @wgN8%7gPI!]h7BLb#jey {jW~.3J^"SXL 7 oKmk,$c͂ Q"ǿ)4@_ȢS <(uI ^CQm- hP+HI@0w,bmKZ0l%>,MLRyؗ1̻yE~3.vgV"ܝ15जL >Jk;{UI{AApWYvJsyU{lL YVJvPmWMfFa FwmA  ;d')wb2&|kG|%B] r^UpvpwQdE/@N?-"CO=da5 SPf6˫hW,n=Xb )QL 1%rC-Ы;lzFAŪ٢Tf(xgtrԟS:2n5U>mpi7{]\2jZI(Aԁ5{)hUn> stream x[K$@)( * 4`|Z{ ٽ[GHLe횁,)$}S*:"N9{_M~oR,Ӭ&S_~!0_>ԓT׏o/MU/2!>gJqwi·H/&Kן>޾}>&y5ײ[J3D&XM\ʨxb:p@zńG8|&4 `39s%FiL:yI(<$8> )h[I8 E5ث 2}kkawMKtD )Ӹ,heVV%p@ `Rjޕhkaɀم\bzSB+Ei DYRZiW27U8.%&E["5F0jkF*y {+j%n-mR_!Ҧ#m{"ZDg_ . Ë+ ED.AD 9ic9ۖ"U{ձ#PKꂋaG=ƒ9ZQC (c%u=@\V!pikj|m0_H K+ +>[l 5{ @UoJ.=8hT\܇01 Qوv723 ,܊9s!+i`ܓiSU+~Om0iB<(7SSR=U8wUCU}yfGᘷ\dzX錪kgÊ28V5n(3wځ٢=Ԏm wA;4hDMu͌Q_SYyƹZVnP~53 :Xʀf|P+q5;#qƾlْ^: VtYB٢XAd.d,YRWx̞h=1 rXMГ}1ťZ]!ۄi0_yG$[Æ6SIY.?#9`IJ_4UǫŶA] At0`7KG]nNXȜ׺>>JM#peK%IvyդMbn /LlX{krO~!Pu ;䉞b?7L*)|7A]ۙCϭmIL8%;bycCSL$&nx^姣˫%p,p24L MBr#vÆc{n$$*G8AsFcOد\#MWd.Hzw2!@ L {oܽB!iɪ!#JXcP6њ2lz9cej6Bh0F>SHj? CXZ^oL:8&{̘"󻊉ɮG닅ۚX1wu(KQV,_- F,K{SsAYb#fem״)U־^l?'<UWJ|Bo].MzvW}$VL2D5iJLK+xY=DUִ{*ŃA[UC[5K۪9IX`Z(g7,f~?׹}\KWv:w V鮵tɕLm 1&Ɯsyg $ `~FR]{-@+Lf-)V)Dq"gv@'nv۪CxZ lP.qAp};RC)o3Olx}{{BL$h3mn̻}ͬ*%*2\v~۞ivJ-r-cCuhϟqXkӫ?4nώ#@Uߡ:Ԃ:"qh/US6J1%4dc鵽vTbZ19xΆb95ɖ$6ej) [Ŭm]8$B0!jQiJ6h '$2*2G 2V$`TA` .OaB s& -}mef?u(6⒆(v]K{p tG'%\16g)FBo*&}IGrrZ%_h."#~|ç2nز =Mrz endstream endobj 568 0 obj 2713 endobj 570 0 obj <> stream xZK#7Wy^ =!- rJ&^S*JRK€VJz|؉O^'6|5\]ߧ>LqJMVLҰ=i*Ks2Oj):tz x~/?|z=}|"82"ߦw9q1|g̟rOžG~g"gg\9!q> ?KxˏSlqfυ\7&( "4\'ҍ9z8KY"f p(`#YJ* :aB0_\p3٪P " y9: m1QDFrWC:%zbp^A?o-̤JT1 m /O`"c͔m&ԶD@/BM۰2]ehe<,"X["µt*GG,$eˇB2vOț ${QfZxW%q5#C]a]Yze=ru!(sy  Cn,KVvC~O"Q>GbkZZ۠Mn/ҁ֑N`: x{Z,iqJP$44;k[]vZoؒLF;8$q\ܚ pC$ 9h1l=LfL) X.給K u:{ČE2׽}EkJc2MutኽXd.VS{nh*MV}A"U c:3[ +$!IN,9BT/ZrBj krZB0J+)Eӂ݇ji!%*,䆂 M'B᎚ܩ* FSl\4)$3.!Qe(OX-=p )B& UoL4o/i?A:M0:o9Ёl4|jXhNH =]YVjpiaVZxkbZ85K7 ڒ_e! jWOiPBCf[{8#LS"+YUQ4ZB Ȑ^΂igemFYQ: t{jY؆w$9%FEu+@UpZ#(?t2ڣ!?q H[' B5oe>IwZ5x,$9\S"4"xOڢ*OzԶZ_ 4olɮQL]uwO尘ݐ:[ƶʗIi`'|KS\;'k)Ry?.97C,"Dsf|\urcs{= nOT(ZР!{]*g.ڷw\]i0Ic A*I_UqpRݞsɘN_;I!MMݲ5LTu4]!y>_~[Ue] ~5>N1-/f̙C9{5N<̀ WW6W WZl/CxU4 k endstream endobj 571 0 obj 2384 endobj 573 0 obj <> stream xZI7_gÌHn98p}O-ZJRecIZ$u/5|y/y׋V0Nj?ooo41Auڋ'tW}Q\Ԧ^' ~/CSsך`moo?<^>|vYEݠsx;Ʒ<wDOz!jr}VոA3"739mr%Mi”]OWlu^:F_4טy=-M5Ѭ0!ͷhV@-O3Ncqi9 wa#ML-`c#p^>ڥKq\=6?_~*rZ cMl3Bui+Yi in$fg:aLseS~!f/KowHGF%&l s83/a=hg= VH"z 2"|̴:}+#|F 3-x]"#6a=Dʊ` FżRÊԦMn=l]sI V;Z-k\]W_>RSf yXVӌ4V ڋ"u`ԭRŨk`ׂh,n,s0pؠm1lkrR@lkҶ `7<ӌ-X(= ]/n̽2\mר.eD bf*:*g~-iX=.a-0[ eJbv׫γ;sB F~ 8CZU6T``mcl"911 d3Q)oBsUo jƃ:o=^*bd"虬H B Ď%-dfOn6*r)icmfobqr~vzd,E_km%HuWI I/lm0Fv2 EzSP\7G_f|x.<W,"RF; f.=4L!lQHnrY6DC `I[Lql2եe-yx9z;2T9u kW K3yPΔoܤ/"ceƓ{[(kU/d>V`![̓} -S!\}}f50UoWSln[lb#QxB'-yŶC8ङ*TWj zL"74sU@>N Ng)Wg*#B;ϒ{=@ac rT*8@esRVQ3s+wQԿ%Җ7s~#f#yΪ92ogC2y힖 [{+ٻ&vtHG~P " ?02~w;LJFyI=˄cxp97yݞ6ZZ^ O=P҉[hoݫeaDL ȩ1%il&/Pv؂= i\bdB;9) R]Mc SZnT"e &E~DGAy9 7 ֡XHV7R ?iy^x9Ʋe}b ^wD[y.do&mg>֕g>erȶ(/k3lwJxL6U\;m?qH4\%Jw􍍍arߕNpR,>BקA gUWP UKvD2b~iUt%@kժ:8zK"g,lzn/fCZ]&X:ۭ* &YY*bhχ:9YUaQqQg)y+7ÜBC frRl|OȅHH10GGmJV#o 𧔓&J<8W穚f*W'D$P0zC"uNy~1p $$sͳVv0FvǼMx3_GoiU"HQ?YrR`LvDmL[}Mpz+VoD~J\E?yٯ%^]#em7 ӱ RSY\^vRh>#Ӈ/xYȟm 3ޖ,a¬J3+"n>͸:@$X\XM+ 4( PTF2);\Se]j2NRAяj?Y- endstream endobj 574 0 obj 2425 endobj 576 0 obj <> stream x[MW?)<{<={B,G44 =}NP>qƠi:?O:BL>@)>?D.>o\/W\HF<ʺ6弢+xFQzY[we h$FMnӋ~[)t=MbP[y{:}A}$&c0և!`T zsSRzGcl 鲓A"h k70|4a|VO?jc_wѿF0bKF]4毻CRM[7DT] :W"#6nsU.ZOIJ +䛩Vܨ\J+pa ό*P'TFV*7SKnT*HJZFj0*EjARG |RBFB-bںRVкRduJed2|3G+Ք2GjI,#P#f+dRV%)KeZ)gjIE@<P,{r),DZhTZUbB)bdV4Ig#"ydVօ# "J)M*<0YyD$YFGZ*($(4{G,OLF ޕ%3?샪weTaē}t,yI>d޻3/#ڻd c'ޕ%N%l"v n% ^N=jj^fzdޚ ٮ)SlVyG6y%uW zk.d] VZ]|ߞ[]CH^)B#~oLミ|3 RGҍx~aUPnemV]Tm|W#olu04 ;\8)a$|)}R!8-zc {oFW5kyC~R%x~7gW;YnqٶSFSoWyu|^3>DXY2̢KƯDX/ <Rf:i*-z3=A7cwC>$=ee#e!R\:L)Ƿʪ+VH6Dʊ*O>#mkn?H_*Vֻ§v.@cj HQyk-tbJ>K4l PDnª"mKbI08*J]U?͒ޯ"jCtiH~-$zzw;y#2_z8iJ?1m{r1_\Ɋp--bugus9E'Yl/`+Z<\3ͻ)+x'>ˮ*%voRi;)I#-9V+V3L'Mz{jӕG&5_[l=&w{{ &~^Vp|[~pQVM;΢_`Ly'k(?h !.0/] |+/\&)al:e9 endstream endobj 577 0 obj 2831 endobj 579 0 obj <> stream x[Mo#W<&!{69%A`lIE`@_"=_n)s^׿e]߯߅a>N~Z S/B&ďaڿuӷ)]Lp?~xBFO3oJa8My OwC̿}^D,a=c/ahO !]zaaM叿ەɣ:83#=~ݸN▚dIkΖ"Qu1!@qɳ16F MڡsBBb*=OЋ^\XҬ 4 (Q"#*=+ڱBfظ9@(EF.T U.{VcŅ*)ڱqBBYP Ը٘֎"h$h֎ arJ"T U.{VCŅ*)ڡqB:6i (iIxSX *gt3=8$HkpqH~cXTgTb T.{VcE*)ڱqB&vA\<ڱB'vY;6.\h\1 .@qɳ1;/EHѬ t.t1Cb7BgOƴv켸Ѭ 4abTH ݘ֎<ڱqBs0xTԄ*@eʴv輸P8Y;4.\bbd]*B PgcZ;t^P8Y;4.@hʨt1 T U.{VCŅ*)ڡqBsJ.Q"6 Prٳ2-44i!9@(E T U.{V EPI;P$q!ad]*wj\lLkKj4g4kƅNJQb 5.{VCŅ*MvDFt7.VvUܴ vI0.<*/@oQ+rVBxqU*DXHMXjƃ\6 줩5oHZi 05P@ 0VQ@uxqU"f[e `n'Vjjx lEձD[ UЌ Ghlxf^I? rZ(IHa.G2&59&rBCԢOTAEj:r9`EsȸO 2lS0}뛪vܴʦ4mAnXHUL-CC,LFàAȸJ aР !1J ] # .(|'A Ԡ*?y!CќZv7#(dS0Oy!CqZ ͍_jPмK-œ5 ,g ClPsJDZآOr!s[b0g(T,4/d?;aBs#CUrB#C۞ܰ[4XN aBs#Q!6Yh^3A.(dQ0h0cClQO0!6Yh^Ⱦ]?]`NoEм}[{-œF!6Yh^Ⱦ#r0gю<'N93qn=!Z?!arw+i"7'UN2漝(|df7svdX#Cnܝ gU9ȍsZ"hm&:M8 \Lk P8W̦5rw|DLzu@ndZ#5nܝi0ϸqw.E=r+Q7n)Q톉j*W&ּR$/z bw䝇r?DybYiÓPA\J!foJN ȗD^zjylojH'29qݸq |fW,Wsoxax<%t/.A}:w+mgYٹБvBBj/f̱pr8~xu7{A /ٯH<9 IWKQ=PGlMLeEGl!C8qPnTgGa Q y8:an>y4ތ7Mz~[CV uNGqY`ΣI"U_ǫ!32ӸnD/²>F7PpQjc^)4uD0JSR|_ ':{#E9}qZilnφ T4}[ʘWE}sp%gZzW5xXM|!57QvDk٪QfA"鏬j('lZr J5QyOּ+Z7='//&f*n#mpʵ4+5f@U̷^W#@> 4O]ds@)2^||zUwV'Tux}i4U3x֡ʆO$}ue}]~]څq K_Y8%HC؊_߭/kDp_au㺱,n*/}Ֆ[}\32`ס,([m "|e6|zdէzsX76sl#7,_8]pBbkz7蟞bXg|̢+jZZ+{Oi2ORa|7}+ٸ{zc5ז-~nv1^mp77EUߗzozlAsnR\vi9-WB?q*xqǵ /2~ m1.o:~ۧ-f&_4aՒeuKWsf' Ǚ%ڦ<,CoMmjqӡG%~1?~꺿*xJ̴}c#NL}=>{=)W*0nsrtn9r#.76/ c90 4DaWl! h(cna/B꯿ ~ endstream endobj 580 0 obj 3076 endobj 582 0 obj <> stream xV˪0+W#ɲ Iiw).JWmoKiZr7C$F9s摑Mh,]OWa){{Y!z^]hx }.k;vp}?>_t?3z! #b=)&Ü觃`ƌۘvXؘ~5a (MfO!ovff#;OwjRfxZƦi oll:̬ge!R`sҢ]mWY9gZ FYZ>O%1mg"ekhTƄMe7`f fW*_P ܜ,T1cORaLr ]t PyXe)=u,ɴPÖT_IWmETzvgv@µtջlkL]37~KTJ*&Ӻ5װN H#fƸe8zjH2h٘vC4fxdxChu)7N? 1bj~ر0;Tv;, wy8r7FE~';Df;xJ̿w?.gY$>l`ю Zz|Hz䨗x |CjԵ 6}ԂR]8=k8ZO^pab?t1 آ endstream endobj 583 0 obj 717 endobj 1017 0 obj <> stream x|y|SǵWmɒ 5` ؆Pl;זe^d$cJ% $ M5i -lb )4IC%/m6[:~Y^^{%ہ>t33g9s+|=nA?pu:$ε9 ~ @کkڲ@k~WkG_ˆDv/vHZ1 ^}uԈZߌ^sw~jsK+zؗ+<_ʻ|}?8!f}**F_~T!K!H3 ˇ>d#Rap"qգp א epl.P8r#G? )aȅЗ*C1>C8vB /LVz`)~ a%tA7Նn zc¯C ROT qp'Inz ȥ1 >8 ԋ$O zQV#u7|@dPT~ N#V:CdYN3TBBC؂T!8< |yH,X)aucLѨYP3^< /%t|C52$Ai•/lB,VmMRI.$,w >"94}RQ/ ?&~2V(- ?/w*?BBKi}GxHƉ.t3đd-F]Vr'yD>%sBIxR\OکIXߍ}턵סݸc"ϛQD2H >ג 9DK;|E5Mt*>6ꣽ.">/ѿ/da` :R*(P{TU?S=:iׂ_ ocCcá!mZbމF~G,ѡRlD4dق r!O@ΡzeΡRZwnmtBS1AHf ˅z->a~+YxG\-Zũbh bxj7NNo%5z^QFΧ1x|b̓r1S hVQTzאa:ME."Ἐ~C?UTF:GNf4O^@[:r-=Z<%v7&шb4I&!a zU-dw#&r G_xQ7/GUy:҆p MOU+@t-nۄ|1U6`N;}@ G9+/j0C"zc*b/@*`3 BW6|+ )`/$;ƾ`yT-/}VڞN1>`g *( zL̰wB|]~Nܱt0L kC$BP O85vGiMux-,ZP8`nܜ,Y3gdNf!Y-SRSI q&!Vj*Qm`fcP̴]ye6ۜ80phdѤɘlCtD0QZ r|&"|sN rxqXpF.meR4Jeː`Lt1 Lu%4|  ʃ)2&AP^lY[[^Q$.[SlK;GR&. j8v7IYѮk5;7ga#߲`w]$WZkl0PnH;0K ޻vlӗ5,C{PUr;jdNخmlq- llDӤa]_PjX-H-km4[,}0IqH)g&Y'8:*E4KDA%$6Vk᧎`3Z*m0.dl}P5h>_'8tg@'W0ۃg3єMQ%?/;kٺ6>Xu-Egd04&} ҆k F6s*v- zH`$ :ci`%{o2Q?E.6~: ŋ/,.P)Y]9kv!zR﫫Y?^AmZ3cxeBOB<'{E~~COݿrpbשkOw ĿLJk~9)CI)vR.&`7aja̲E :%:zV%]JW:s 8Ȝ_d2+2\{ 8jE>c|&xڞ L>I_ߩMW6 :z} ; 7=VI>VKYX8AثEq6 Rb Wyԯg2{e4fRLlY0r' p1'KCFm ܊ђhws=esb1Zɦ¤40lCfD 65sܕ q1={3>~d˙}/C;wv_t5oAz֡憻r,OrjQTFqozWk=SV qS UtALQEp-{ gJb-gBfn'L#С8 44 S>0KTl1[GX5W~<~bF.|)hW]Đ1 n<ݏ>P\1sE8ebF8#H׿H,MM6g:<*摹6`"tg摆_0oЎW@Psz9rنHzl%11=(Z4f pb.MR=zvĞQyEx%bNTRɏJ}D$)J0ڴxէnE"?/#Q ZcW36Z1pL(=ō}5a1y.vBLALQ}pXiGkrr2,jLKcNx[݀I1Od _c %z"7Qq a/ #>QQ˂;̮цgc|[2D!/., %YI+Vd(OGk61&dS{] kz&>n*FPIeM2Kҁ :2AQ$j:v!aj!7p~h?1 %:i9F*r:UV7D%bxmMuu$3s^rU 2G&D!;?y]7}cڴmǍ-WuoHHu{_{ޖ:rj/Iu opЪ}?J̊(2݄ܠ^f2Mܤ&e213-Xklek0C3EB)6]ЙVNyAk33,_ER&1~.;fĽ[N V9 Lr%*[БԙjۚzeOMIRH8}s)' g5 vЙZim`x:cIήS0zA fd#{_,M"driى7YJpڅMN9y3XЙLFa]&RmΪk'Oth;<2th5*֮ح3o'?I2Ǝ%_a9#%&FH{<d9RCT. KITcvUEib̴<~ewRJӪ7$nHY֮iqw$4^昭];4ϙ__yݐE EYM~XY"ͫI7A=,Yiq#.sFfdlM{7n<{};mۡCnN==G?o82zmllw%84)ZXޯ>!&2Q` | xӡ*7)Q` 4oP`-W((7~iZ10'oP̍I BNr=JBDu V1$j>5|~QFgmd̯+0R+0(eR< 6JU`Q"F:m 6V`dP`ԣh85cc^fañi^fp-خ5(CZX|f1L+"iN`.J3K R5ַXz=5Ռ+;9vc纖pȃDL7N@Zv` _/A& JuD|΍T{JF-2"_&S7}+RFzvB"j>=ljdEd*{ԲdoZ>T% p-CY$r*>({뾙{.kZN.[)2ې'(k_R;9?b yIW{EQ[=O]BNEM&J< rmz9-wx\v@шKTExZ`+v)#=\̣}#53I=;Ua.~գT=Fa\ -<;qzzx8~[ϽKwiTd/lrC"Sѿg;IҰΚ9V>*gQl[/,7+ږ)gy'סKٿ[tؓw2ѻ=bEL'f%ƽ7MBt$t&k.ax-ܷ%[n|"[.{@r4/Ϟl'Ԍώ{̽kGI_da]^9 nytCOmp^/;)G>ń1>HKVw':*ʏdU44NJͱ쵩l0ܾ.e>Enot4c m{tuZҍy\JWҿ/+__JWҿJқ8{kܓ | E#V+.āo =H'o_si8jCT!a au.J, Xb ʈv,'3!y趹ln͑딻yUurjܖhs ᜥr;#Kn6Z$IHۗXz ! je!IA"PRSқKi8OBS*1wrkj KױqaIY]]Y@"C> endobj 1020 0 obj <> stream x]Ko ;>cf}vhI*ă 6A3C]F+ޜ-x+-Lfvh$/T¯Q|[BoLF{ɻn.t@ث~mC~ӌ5Їs}#صmdH+lC_b1(H,TYVv h/-]/> y(Ͳ2]&]OޣZLS}N>/gcr\qq?kbv. .=o4k,vY endstream endobj 1021 0 obj <> endobj 1022 0 obj <> stream xԼyxS׵7>Αdh,Kf[d˶l l`;` `0`C djIHnh ))D--f,^ m 7Cymn~> =9g^^[W^DdHvW#%B׷b$!ʷ]0Lb+[\߶,Y4#.B4I- F !Wb:ʫ6ts+ŏ_}|ߕ]9 ϕ]5E7VB{WXuv=W-Zfa㍘Yr j$Yl]`(W*dm]})=%m0\gWS\^ n- j8?̠ZAH7<^~r:r4g`|4j#? Q<7NUd< w}7 *؏Iʐ~u/;>{q/bN䭙d y g?F `>d.X {÷}9?-p/]4S&| xN3FLjż߈mYyt < 5(>p;_?"[E7:}ՍAW/-?J.Nf>^ /ygo_}2zH VO]1.ݔMT'UH8TzJ%.fMFCq^'qgMBʟʆir}'5`8:mVY@mٳ*]g ~:?]}J旕s:I,?N#f*eKɴYL=vj ;'wolYRV-FhG{ J"l)mjge- aMCw\XD𲱘9-&[|OT|~,c \}awwϥwo6~/m4ۏ4,g=6,'Tvd؄a16|VJ펥>ܼyoxų.,-cӁMڗM(to~H;X [,?zWl2q {xB /c-]6]2-7C}#q_6e"xڗڱ.ז ;c͛Y`łoϸ$؞j@]Oo]*T]Jf.S͚'0$s 9>VZ; j##慍j_U͛;] S޼ߧN o)cҿ8h:.-B@>8{ۊ7+>,uŦ-ܦ^W qnv}ioG1gB.ޤqY.OȂ'I6g%J3Xɺp({K^Ȏ)60'J|plz_:0}a Ӊ:{a?_B M1qZ(@4vYYM$:'X6!K粔PU"w>I%uj)fyXi>OQ "_ZlI/Gl&u j1]W!{u?ÿb1}_978t&<$3(Mӧ+ko 37`77حbΪ1ZvT.VM,DZh1"y$wu |z]d~9[K$E_DA6IMI$5T];=ұ{zbIH$i}ş[1*G]4;El|K73H,#j=Hϟ2ґB(`>e/e,|l)FݑneF2G4-B/E} cOY+B>~n(ApYNlnR=PR%^6 ܖ([;sepNAQ|sj'}⏋rGp\/zYm֕.Eu |jjsrpkIO Kpv{лNx۠䢎:a``0 ԔؓJs){ScuPǦ.OYR)LY  hsVE.&CzW   OO?9əCvg%D_&6xdfF&{Ӱ z֖mn-DA$m ,AImÛ8񪱶6 #sLM`M]%ʑAdt 9PZC8±T~Qxvހs/^~Si4\1 \7:j.Z<\`LUdI[l)ʹu>PZPetI݂̾9?;k<"KQIAb|.m(JRS{;.|eesd`\P4D1iAA312iGYHGliQRiLjFA"2"8pv'pLbjg"% 4-F7dɖ#`F( Ql9ԁ(X*8rEQzNR?`:maRhREvME:hT;S&b3:=:}i=_ӽaAgѴUBK&8m]V['My:7=ǽ &=標砷[L9>j( 6 HeBXH 0z[uʎ)ؔSUC99.hcrZkk& V08:G0ĤNVr)-& 6VnբHAAU_Gjp||I4'g ͬtW[ᥒuH8kN,&Y~DjAƧTU8/tu|L`6; oD?QHk6k24ohZ*]&^/$~$~!.A3 28%Ge{12/.` șzt0[Gc.WD%#haVVUgUņjs>竊C>52+a!/ug8GwlupstZ-9KnōL9nG,[ꆣoKTו?M+x*rB"T*CoKUU& E{%)w0UBUbE-ȭLkMm4lO9)Ux/RL!1GL>S餉G1tཛྷIW'r7ɜ r'HNJTHٺT*#J^ WMJH.4nXI=CϨ\@1&Ze:m`BoΠ=z:q(AH.RsE >Fw`k#4hHg`^yS6جpi!eMQCڷka @v幻8@@Lgm<-8x _*. |&<=p Š+VtZSJB{krO=^] 0 (S>,nƐ:Œs[Яc *FOЀ`YaY UĦTQ.¿ZDNwHwL :=۫Ot:Π^LYXn}qb@b'cb#`H%L{0|d۪yU9SSݗy3C}c%癒=AV1`U 3\wiR2QhUtv$keyw"M=/Q6oX4g5|4>{FO+JeOzӞJ$lB*0 m6eF7ZՖ6HZ L)H$SC(0 ǾmHal>p v`naviawN̐xr}YGgz眇٧FPT6GW Nu2 N~-\/9% $|6LMyÙa1NbjU)GV!Xfph^$Fg`U=Wu9f#noqoњ2`^يe\GSuep"e,n]"gh $CVA^4KV9FN2?&בD7Z'f )$7SHf7| Mnp=*-R WCⱉ;'!ubW5xT'ĆAlؾê@ k21~~NQ-ST(V+R *u)!U!z%২UxآF0Cf7?̤g\f\.ߝ6m]k݌;f.|E -<==WٻY:*zT=&kMޫpIՂrZiVqvWOE-,f[G94Ln`F0,,,  ~d6D2٩l]yZ)^~1xӑ#$HI]Ta7Slq>cujS Bz7qOJ36d\=WMck_'OzhYSe-4zb룈+HԒ:qėtibF"I&r)V4Jahgw"d049nP_1F4CuAw(Y(Z8D]T#,Y?$ + pb ޞb$@.jH5pi KƒNx0"ǜ09]Z O|%9v]t,]UwsUWzqoWrrri動|Ѹ-UJWeE奕*|Rc. b G9{y)H};|\tĮσE+]Ko? j AG"i/~N?o:B ~y}g~Rʉ~zeU\x2|[2S' Wz'yxC3*PfQOK.+:A"N;-Πi']Pqǧ4x2@2 h5]5\)~x"-=,^-$P$(G3;sd9Zuq8N˹ sk:rF*m36Dz#ȫ'< CF*DL@7c'K]팋.H^ &Ii:4'45v]3>+ks}'JhO]iHʗOH2|>]tVs@9,,̦qF 60'YWidͶ=fU9b@b^M 4QGR] hGVij Ur6*s6M$ fTNC4;L=aΩ0N fxRWZ#i0AR@`bٴh6XAҽRn ^AQe|热>v"%dvC؎Uxxnbñrd +l}pRy~̶;^lRUAAd֍c1{X[ k%5Xhɘھ`x+vQ ?[VbcH-B"cfd*>b򫈨l6/-MMTkS<Tyw<"=Ȫ$I  =W'ő6`-Yn;g<ő.(t}W֕;W >p?Q-deqX+sb]`{ S+ܽ>h1z)Kiv'i =^Ԍ'g\fa̕2v>:MA;x"? HhSkK4kuJK RxES^iW7^>&^HT*ѣ-PuN+&VTJmD7Z95.W^SR:=.ՁC]1Գ5[iM:P֝b>ۇJ1 +n2ؽvS@лD^QȒL*'N`r-6ؙGʷ,}quroPemUOIT~V#jP&̀ВJH TeP՟*IMj$xٽ=:% K^ rʊ-qxxhȮ>Y)r ƕW>U<&imI.wk#ueJq-/:@2( -(>/!|D T_d fcWTl3W m6-;X3<V{kdY@y ]^Z-KZ0_p}f؜k3ǃD\\sAh B}>msF7DA[Q"HB*mki[vX6Qiem%I[u!MlՑ{B=qL$m!$̉[k`g mX l,ss10Ďގ}cy*=g0`:5Ji4WWז $5{9 -ĸ!g&H3YcK[߰r+`*V Pgk dCB$WCЭwC\m:B3Q =!  8䤊s:"Aj?~ w!<< pw:L8^}^T)j*P u-xhznBU0{LŘǔ%ܼ^MNnMjS[jدVƏš̄Lۜa$VY2:*L1A] v4:?OݕWpKcU޹A14e0'oE*ŧ \ŊI?fO50/,ٞ+','Dthܽ;ɚ+KlW\jvwk_:0I.0 pߍsi%\hr P{J\}͟FY89X2y+~I㍴fҲk"/ UHd?GaClĆl5[CңR+e0 UG1RcfVY‹3Vȁדoeex, -*ZM^l* \~];Ah)pւ3V&!p{szꔡS-j $g'`{qZ#0jcն*rF{*߯:b3p{Ō *FSV3p[a@s4ne~p}k?@-I 5\cfMFh/Q(&=]b KR>iIRbY-@ZVlm&Kܞ%rZ-k[XTXX hkQ>ɒplw+Q Fgi~Z5j,TWxW_d+Rl:m(+K{|8+mR'\qͽl;S&Zㆦ2nGIqC!cq1Yni;C۟\|m,,BՎ~_xLvg{*cBp?v7ȘuenB dʻJ ˡ\yG"pꙿ5'N\|Q_"`:9O N40 @:(#@ƌn?+"M=GYOÂުi>TOs. tUu@<[yޤ<1zxXt~]C6GbJ<Z=%;us|Ⱥpr]z P n!0AC Y^nʷ>eg;VoAVz8)q@ TAUT*<$s9e?ZAuT%S#oйtVPTzz!KGmo\B!HhO>lm>ݬg=BjyMhl=xN,‹U#}BCM9Q e!xF?60i|sAg8 Xm !ۦF5,z O$.D&.7 hJ@yJpYtP)nQQSݬ]1ڮ9љc9NqH/NO(V+lV 1sru_\wSWT= eGlsW) Um3^Tjwվ*Yuc'WY_扼U>&snNnWMw5ѓM4A2R_ظda6N׳zqY6[βJ'ݔ{ܜc*ϺJsFoPa3d*_Su :pP,s s:w?yȏqҗaةPgGT,`*eBs:P'M )kDlHg @WOE4Ψ^[T$ }oGIm4#y 0ux/xQ$A 4Zȑ7f]礈H q~l1>>|P8A6)2EQ !J2E: pC =ʳ %U_)+kzZ=ܭZAXGa&}.8^^XZ3ts" "qHO[pg^R!zVzc+'lw%3l/fR`On#<"/XrZ Y`vkKxۤGwM6qQ͙f&0Ui=Zj`M jBѱA}T4w+w+nwqIIq 3wXjZ*t4f5R;v1̑Rr'7(yeR(P6cEcublI};~} v# ·q>S{~F5|’&8fD9gb%Y:ɑj] -ժ^,>9'vnJsSo#l}~6@*.ϥZ%gA1A[s@rJPXk' "!ATLK%nhOT :Ղvlkea}:utxۛ" ϰEj`d`@] mgq+hUݡ0ugS䪊 0-@^/ސUy 'YB D*9fqr,Vɝq:<F<Fl&@OM5m8&&.3ϫ}'^_SF|cMīJCen_|ʚCgb̳(sFSS7PK,F Na#32y3nS}XqkPф4c~T R.?ڋլ喥;{d\콺ku0V܁[_p@}Ӓ`+aAʒFZ|Q4oE7nuVw tv3±a:LDzc1uhZ(sSi .|ʓhAS&h >f,`[,b@0ZTZTCC@9]\B1s'YІL:-Z #Apû:@ i+l`Am!8 ?^1xQ9LÓÚM65]w]]d{fcɲLnnsZH?}ZKyEKUwUU{W]UaUb<}pPDVAgU*ucήUի(Y8'$WמҲS^k}fOSi=N]frJ68&.Wr01a9C.iyAwAw.SrYf')#f23Vri߰3f3pvĭ*bf*V᪱WsLݹB/]ՃA&81'eFHlh/ѐvV#azX Y8b[Yu1.#Ջw`Ţ[<ࡹ0`D VO^Xˌ?\! !)iBB6+B!$L%#20B*ꫩYWfFYYKL[\ .xp; spoJ K9Xj-.xaA^/:XiZ#4Y;+ gwT@]$.OK$=vjTw#rn7ݞDb; l[VxL(lK sm[0ͨQ ͣо>!Am>hviڳT/%I%NhdI:SrV*!unh8 _~!:*.rlDt:ѕK7-հ>Q'`sLvoWPpWj`W s F 0:"׽U R('y?uNG!Q`Xjh\q@VLlj>+Dٸ"2rdkQp{k|RTE96zgg#; %فA}3h1fΰ? *NE2)3QH.ܘlG~`悓^CCw4lUKL5B8г풫nrCńvշߵ1xbk>~ﵭm(̹6;G 7ܧW nld;u`OuC#'ngtN ّ4G5h5tjVjvhilp:=T5a-I goFR9(M?ʭ8VAs+ǜ$bB )I{U R1Zdo(j~VѰ{-b;*GCcB5D }V$;^(eNt%tXI䂢: b`PbٲtUEsr$njύe~18,$"QIqZ}UӐmo[ H5N ]HWfNS#ɲ BW}rd F*U˜0BJx(tj _/BZeR -qd?ƙV@RĈ6Wn$| #|a_nxz@=!zyv{8v\㡑ttS϶SƭpZ+xOy˼<+Kpd8`u\] VW7\J 7fq͚ner尅QmKeY `#a"f(Sc עE2p5zgfVACkzZUWO~c~)\4NR B2nܥQ@Yg7#bfbXTK V%EŢnswy)9> P5qp;Q QmvXb֎/ӊl}o~XG~:gL8iZѴ D MHhZT-ETTd`ExJ ͬ[Vu:CLTGXsVRna潤*VI|n/3KarDNU}H)dQӤry U5zz̩-<' vh<е&9ϱÎX4N3 nl\4^[X.G,.\tX_=P}vA~Sݽo} z_w6,?K?w~H;w`VʫF^z| Z ͻU^|nޗMKwXRQwS:R)Z<\T^պ:dLq%"MiH1!rdĮVRnkn{rd#Pc|ŬjssΦ̋T:X JN|y؉|".QDR1[DŃœEd"8Al@Ѝ\T ́ҩ5q()'FUѲD<*, :)ùKJj~^ uxRea"(f_y93XҶr|{zlWAԝ{ˬpQ',3WKy_4~ܡ&d248Ztr(zRt7Tb `ibg{6~kaȚ(g~Kbf ؉-E +Nj^ 2U'ڐ'%xi˓m.vy8LqAaJ ҩ6wP0) עG&E)zUCy;OViɊ\%==G:̘V<ݺOxKt;xNU#ڑzF(kbDD+5 w1jN3'l2e0?McX9 QN.Wpey:Kҧl`fϝ=>{lb_ =>Sc=4Q5cDv9<| =|5RɇrNNSuJ׸ 4VL:ڪv\DVP͢S>l>Ytѐ%$b5>܍dEPaz>x *(x8o<&] ݇\b|ٲ78,7oͼ^[[^u%`տLkv<5F^yApjLD/(w&n^drsC )=p?V9mV$s# 7z<~:OZ(GH tǁk -= N.@̂[`ߒLF=x" Bړ^F[Cwcp+_s~6 ²4,kC4XpZ8 CTm.z]kpJ{=_`Y;QP(@ 4rޙNymʋ6P+۟mx ڎp^7܋ޙd ~&g䛚y`U|WʽG4a#5YƘ%hT(*BBܪ$BN~;^?(*0Ph5 a)/yʭ9PPqS&՝S©lj< T8>'6HHye Fẃ9d\[\]o0Mq\YqxkKaoacxK07N2A,lV]3ى;5W' |J߯ zۢCe1)NݸEU[|IV+4&$5)M[nȺ)4 I(}i1Us;1r+u7zjdMk7*Zb{GYag6vbTC˞ y+}9A%yk|0E:NG5hqMji>ɑe5VㄫqNbxffBjK {ʢXUr$Knӓ ;7v7Gm=C5Y]4w)VV \Sy5"$jxJISɁħP`6 S3<s=teX_DP4g݇UP DɜHd Lv%BK_.O9cuzLiſPD9;p"?#cGyd3!s5qL6joz֛H䠅I4eFT*+rퟤ{AU~ZuZi=}Nv\#U:J?TkVli̴1H$v6 Zk^uZ2ͮrp]P>ז[c-ozWoAWiAc`}C&qn@5nkטAoC h0÷M` &:6N C&`ZjtLU{0>oxsFV((w~-ՁT)/L|"\P;*PuWM:8Cq!"|O\=@~0y&3TZWb'y>{w؇C>_Qx(!(UQ Ƅ>b-߲SKUkZl4-}JM(醙.*nLT]r3ge 9i&I`k2lfPHo7>o~?徯7G⼐Xw73O߳mj4J^G Fm :݂7N;ր=`Zֽ@{5ΫVjzNYZ9QRDsRVmjV:M m|Fu.",U kUdUl ܕ mi;<5+=Zhz*;~hPAeö [ZЅٱ,:&(@Y.G_ѐGI+ՅW<r gk;|lU] ~6Bu^%-@7eh]ve䠘uɃ[0_ߚґn.#l.RQrXGƺ&" Wՠ)VL쎬١DANH+R΄ Qâ"ŭvqxP<"E$U;Eۉ}M[5C*X G1VaZU,顪NtO!7n$2nfn,M=U9`pqgT*j!%cQCP10JsI]pɞLKSm>7Ok-@UTv>NXij*|8 1>\ΧJfO+g: ծC,/yUWѺFV ] |{*x}^&HBZP PazWϫ/lVV<{BA1 &:[2dHAE45#J̌N ߠ~ ;ܕ]P]]<=. ?k :Apl]`Ltr0pnn@n'mx'Fw rZ̵_)2c /{ AI$ 0½oDPo"O`zތ 0Dމ|{"nQ<^4l`?]™H&6$6''>JM:0Ճ%l|S)lEGV 7gO2?&Iţ$ u3vxڳdIѾB_*S*HPı} -jԖG'=MrhP4dDV6)  -Wn +(ځy.=/z=JH}=z<\߳g;ypG/mkym4ϳm4ϳ"`>plZl/=;gԒ]NJ]QuDg?NIcLǺicf쉐WH]-F~L%,ߠZX{lTQ'YSqUg= G1›TԬ$=Ŕp^=!FrQ\$;*F7i hzqgmZmR\Z"N^K3KIfr~p0Di2`4dg S $)EsWY B}m5w 6aa7[Y߹ˉwr_"VrЯ@U/C `.r0B.mYp/[_P/.Jv).nt½,$>v (Q7K@JJ>tV:pV`Y20#A'n7X'&EdUh)t-o-o/#e J] !,}pXM$R"4Sш>M_OmM["/GD/eT.`JaJ-aVI$T@jjAh@.|i[-.q{Lf/Ǩ OȄj\ 5տزlkuLvQJD;5lg0kmO}r~_?ѥc"6DRX{7/\0'J!X`WՁu fLóq @Otgxy?N# 6a0}p "{ rC__/}[ufr*d~s;vFs]i՝nimnj#ʼnA=ĥx8帘^&!~aLaށ&sS[Mm EVV1<^C]*{22H@83{2("S1ºCQ}d% "E:鋛2vh2Nãh;6 V4ҲNm DY}|sUc>F"LkEsSgu,KmҾP9iIT:ːE_/z&ArFp(t Af -=/yc6- ;\o茋 ÿyԟހ_a*9{I-8Z%b֫A V1I+ ۬M"QA\'; 4&S? N Y] 2] 75J%pUljĩZW - nIv:Ll={b6RfMҲz Y?Uv-'0v..RF#]'P92Xʪ ,<!ٯjϺ}>Tr״]z4CG<ڞ'H& ]9rl܃zG8{n sKȸKư1kg2aD4ôG9v3݇).8(Prd4Y>V<+O-ZoѡS\[Mk)+t VI /%Vv6nDO;uhv3 $dD cdKbc/>ji#jh솔74Eh\$>1.Ӎ*v\kr4!OuبSvhߡҎɊ7$UmŠzW~J7ТdkzJ68Mu8:Wwaˉ6Wo)m@nh +nnBKI"^Í!9<0!kh9ˇZ}|owh"JqK9o7Xo,w ^z$N ZCe&7UtlXz̦DE[#OlcZF^H&(/c|h?r&F `}nknO`5 GgȌRjlS7w(>FkCmH44%4[{r2kr:o5FchU/<*4FK*r{q2">=48c@ֽgƎl;;޻w_^}o/$I؝|9dwrKB pLփZ`kuuř\z5oNR:A(D-5c\V|Swd&)A|kKW4UC9N#}vbLb}R5SBK<<>AgH/W76/m&rz[WB8w\E6^E[9f]SlyM<0l1iuȼZ)S&l_)_VvYs~42GLs'Q< RvrG(\# ͪs`: N ^4U'{$j2۶+5iLstn͞y+-nl/eES2FEl݀aMHZ̚k^^^~m^#O]?v0E|G\Nf̼3#҇04Z+L^wj@p; tWʠ~Q\R&F''ikszO"U ~0݉ / Q^̨PO0^~Q?gjs؟|wtwN)Y0)Ώt4إkLww5Im\zJ&ah_ZЙJ j}HZzRQ"fl1iA_ l^U9G-W ȵ :*uʫ.-J zyJ>X8J{c !040:=p ^|!N@N]@W\=.|_g[eC־{\ @ 1Zn{[%vt5@q8/QKVxI&3+WR:;2|F. 0\;AJ U=})vp}B^NqsX Xه?a?^SvM=Wǧ0>Ti\a8iCU2R&10Q0QB"D#"<ׅa0$ë8zrIȅ 6+\@:S/ $XW_Ի\.d\],BH>Z7<".pFpBs::qN08NdpW;ssq^jp@jr#;zF)HdFց'093ppb, X[l-㖭},6SM(hZZIF)$g LO=>˟@ClD>;:;tdܾf0^hu |u#Ouo-lH6eP{?@mrt%T_*vXA8;S NM;{,>X2-TSDŋ#ՅuPG"(H=ٽ͍BA.\%r<  s{'7bp YP} Ip%;=Wn1D[^!c̹.0&4෮O=snAXH-& gZՁ ْe`'K|ʾ!.飳GgF%QaL.;=5Pզ˛jl,;D1!ݧh94VEmi{.FZDjȡ%/Qj(yz] CoUoAkKv\E0,Ֆ2OTU=?}$3  l#g`^F@-\ $O^"UIS!zc"ߔс2zv7 l}~yuZFwh\e0V.\_bC4PǩXky~:7VI`vw}%(~X?ӊͶn&OtZh;ʊXre-e em(k!cfġ9CYOJ2ss{Γ:U[L)DƦ2S?i҈i&wtqZ|igmٴvZ 8ܳ[p,ڌ[k;]kN/q/ qU<ϒs eag7%3:0 ޽j Z@DSل|~z벖գ?NzV6aimuF F#t?iH/o{;ñV`[㭅Vl*hE \b1dUAبSKE+K~0{3S_e%4MI'B0 }zʼn^^FNfooC7 .C/rvmpts7m<}O|T 7l &,߱WDxk bM0ݴ҄mpnoh7>god eV@=DY0wx]= uO1ؒ0;QN0dTJ]*7XY.QNitӖhN5 e%_+Gvr1 k q8$wtϔEM(j:oQEvUlff׷ Wi J*(72=,9Ǹu sAse@gS@g:.Йźuh12ãOLj[1:FdE)&v\UG> Ҧ:̸qMn5\(CgMk~ZmDMȧOWN%mڲ=$".*i4^M)"Q5O4;vG?wٝ. m2N+X=uro<ҵilx@@myd֣?6us}o?ow 9?m-7px0 k˩{nM\zW[}l~.K2Sa6"HxE-5W{ې^Y[UUȫ}mZ7&l\< ;ECWoѳJq&g&FVdhѤRxDǴ]òe"P:=DŽG:=iσ-ВPLthutہ 9ԑKo>w'N} JM`gYoϸb8 j)2J* ֚c`oY}囩+~fhk2h8rE7lO\Jh2ew,o+U?\m9,g%>[??xA!;D@%Nb,W]tw.բXH њ+D02ح45Þb܉iGc;`sFq>aIY.\oh(6tm{KBu\뭻:]zH!Y@9 ſG>߱bhgGaghXTPؚ64@5 hó o wl&}\w4mEߍ6wXoA$p-T:{)2gt0>E>;C_ g[[̿ yiE=@errrf,c1YEqz}xw^Wҵapa}B$࢜!0ҿ})l PjDwHC;@HdcQ pV,,¢0WlQ'8UJPw‹4z¼\ 7;u" }zj]c@'LmqHѣ8mIҦ? 9TĮQUr(`@+]4ġAT6ȐpD:8omlłGWַv4brY\a!ԐiӰ34(ihH0 8>;%%([ NyԍvәM2GK2yl #+t/8 E{5\K:ȅw~!1NB`'{n2dC`ZiFߑVZ{m#X,˵ ႃL-=㜜pbx–x^Z - F Ȳhɣ3#dE?S6): T`Zp(tlp=3i\U@>6[g%.p2맭|i&϶ɥk:Տ~Z"eyp- \Mc{ݝ_f&[~1{| ϲKVeY\'f|mlVv~!"'~v@tҦ6ݴQhBm)Ц6EڔhS)M՜*jEվM1]p),nThSMmm6ryrg^-2pRIZh4g"Y<ȁbki//i}𕡯L}`qaԏkCPðfNq_Fe,v@`1RВE9=6QHS#LMT55tEBQ{Z[IthcbR%fI\(?HZ@$҃*6@PN1^м3ߙNw&pMal-`+n"T<өJT|CC _B ]2cSʙ3m:UVZf8Cv!ww7u?Lt$LX C@^Q؝NO[{Mހ 0dsm6i^ԾU2D3&jת+m}e9 L&q)Qs7]6[іW.:=~{|ߺnCNz]''b=<_N5u/~K<%r3ML'2 5'ZsGL+%iVD''Fk0S' #/L`8,;--keY,.hE Wϵ^eŌ9د{S^(;ԕz=/C\xm ei[:}- []Tf[탐ޔ}:K422/)C1(%aIT*3*K+xw̺&Bf0 ; XA&1<A]&3B11ެw x%/u 7a]=V76Fc \忐JrTy ea1 ^6]sȿ>0b@(0QuJ H8ö6d70 pP `P l r APQJyIr@)Lhѵx2E_TCR*x,e+JN cԤ[os[of^&Z5K0֛{fʁfQ|`E/<ș :/L|pjyww;|\aJ(G`Cx]8%Ԋ[auvl7m[w&ђ$Z\D %,jt_3fɌ6 :{Re=6md*6 )zq(8!\d%[?xzO(?owK/TбH_UzuꎠV.lNߥVSn)ijSfq'\B+Z0QYXXSm_/?3ّJr{{m| µ+~hHJ7nKɼq}WxO\ZW0t7z".Ѧuy5;띟y;_C^m7CO:KS,^4Cˤ.N- RV2@|_ xjGtv`N [d͂UE$:Q4ZZv@\l@8*^c[* `me*ugS-z.`fK}̬ͻrM)Q͙`sƂ*Qy{ˮh>bz&|Er(ݔێ6r tO1;D9_'5|Ƙ¹}:-YcI͕jm*zp{KuwI59O|=I%#*%KKI^rӨ,fsп(LU\6YeGiI6S0DLwɁjVt[N4lwmvzMОj=%_!x vf-'Jl 'Ws0$Y"Z ["؆jpfWT j5] U5Yj+]I29 MgHqJ.*oQCVHIڢRUGOM)t:cKXvz+s)9QrEIr<[CN:Z3K=Ps,)º-YSY "#SG* %5t3zvj Hg8x8N61'XWYDm&bQk_ozAEVlMoAιʽة9EymLRkzS*uMr⣦k=;_?TI%doXs3E+W?Dʞ)ظ׿`RRуcXG$͗2lejǚ9OD4$ Lhօ8)܂cfe%azWaqn:1o=_! TϝcC(ypyF8B4G5jǒ0JXë=|& wz\Py98O$c_^eyIgt0<- 0vV>1(Rz8Sl{s66lۜ}g}ֻrmZPd4t%ϞMOh\Ei`qQVҒ$J{ ՄW'%$JڕD%ᤩ.!$A܂d+L>Lˉ|WkND;pr_ȵ͜WV tgçoIzd3`$6/Rfͨ7VQ+Zl,LDo`CBN=sؙH,֒dBtjK tqX$*c\`&l1?nYDOq"$@$ρJ{33SӮ_c "U^#1]lI؊mb Óp!K>2^4E,)>)4 &Rb)%RAI\[8@^;<.6Wѵl!|{>,1z..qTB.9ϴGr sQ'<줇2sU`:6?fAo0  fA'x6WFJ6`;^壝+SlOlZĖ yL/\NaʋBx~vĠf][,sE'd,1GӒ6JNugGwřxz+}4)4IgOEI<g7>!,p/AOFVӵ>4BhtwB"\3L HMз8V5\yb|+[4V|_&w[N[ydãZELg\L3.vD\j-~p[QT}8.QN6 {>٦i)  @&l&[ZM(-Kif EWUxokK qcO\(_c{-{ VՑJ)!1M>ʟcSxS7( B>$5ϿO]َKb>'`}j 57M5fpl9?SzbTQq_'<]@ޥpJ@/ ~[ASPU"bK1*qr%N qWr]=Գw^}vM}D,kkKMQ InIy-y = 鵖gu YiHiRolD7\lzcʥ:JTM8N;GUxnyJuAřT*7g7=/M~_KB\JmʹDz'Y#[+{ᙍ+s{#)=k96NCxعl11w/Z.;VuGײ+\ "o{q-wЮKJҘ2.z&݅~Ʀq}ʂۿvGhg:loXo:vv~.N kWGVJ?Q3/ FE`k#;vYgHP +R>¦f1 ЛI]5T^ȅ:PE!l!( X2庱3 ft+l@t`87pǩ!ofBrc~nuzܮ?':V4ʥl 9Yv٫!.iEwvs^}yl72aTjAGji`Qr겇Ѳu%kV=3?<2;|85XP/P V .*],] lMQNZQݼfQۮ j=Ze_c_^ '*/A~o kj©:nᡃwZrub3Am_fNT'UE@HCg _@EwH;r%]b Gy#)@c~C~UyDʆ͚mrrρwxG* ,oGUUͥlI5<2 gR$K;eϫQFc/MD'ޒLW&x&Zm]{7:>_*R-S]7ж|5E%$VWi[o\߾^{wV-IH/li {;Zei{'kVב_H7uߜx>]]*VNԒ+#sїR]Ncf{L.SwﴃJQ^:ZtT(Iz^洈BәfOn}^@Ku:;W܋$_{G+ï^ΖDmu[o׿plAA.* tju_lCdsfj۩fIT+YcWZk*Q9x#[X%M,yK))i5\[SW;YeEyeH~|R;]A-r>5dR+A)4bjfˊsJctGLcYs݆Gml69{F2B3ij8z[TT1Ux0sƙNNN:~ |6]!*kJnꡪ5XҳQK#KJBQW]HˤNpg8P>_ ћSTE$%_x37LH oa"pŤ!\1k0R2 L'F1(@̫\$j]BLN B$P+bw8>g*c2^N"+ <̌hﴝ6]~yʅ#b>ߧ\=Si|3r*L O $p񛘼OoI)!oR:+kbUj+Fuh //sqT~ FԎF)t"UHD(PFz91hh0_ѵ29͹=ǟc:@#-?%e%!ZuGov ?PCk~t_"%b6kQ#*#HiiR TC6"'.W#<7P_$WA M 𷡕O^GEP:Ղ)Տ",# ! "ABkHDCeMh?6C|Sx' ]+<[z⼏UK*Zy HB+Н Zi<ȏz7SKF 0xP95)('jQ<9O!#@͜Ag?ߧp*9+NIKQH{Rnnf^֖s6?[7[/o,~Խ R]G\۴ѠZiw)_5شrb/Zk\M~HGϧ6I:6ƌM'6'm>tsUsۛ[~]]ܪy˗B}6C&$f3 #F]Bn^A*b5X '/KA 1 .hU ӈR+ղ)/OW*_Lz"LdcQV,!2w1'Koh-ZCh`Ԩ6jY G47rszoR`pw\Ɓy*\t1|9m0jP,!a`ENEHe(ŻgePamar,fiX{h_+mMeGR|9 +r> צIkbf"'4_n:0*R պ!0,mϸ 0 w(iy :Q +h_\+!%CFcV(}{̧$_,A& c)axU0b៣SWZ(;r[|JJ뾤'2cPF.5b%")rERQ<%J.RiQQzLw(eyd0M37>Q{j&k\ˈɤ<~伕aPo:rIC9=eL|+P*JfE%܈ŜLA݊>dgzFӲ)j.iQ^F/GXK*0_ #OGg5[cZ*eA.= x|zݕ t%ϧH@VCs9''D,a<5V1zd 0uRyN vEkGe\1^i;^}ze雠aBC | U >%rWŞJwe=2)/<陣u;_QZ bgIU9X5eUy< ,[|V_W~TM"$"}_xB{}wpp t{|=␗xARo+b((qgEA/,a !_8S ~7S Yֈ }2@#D1D!߭;6 wk+C@T쌆O*U5fo:C #x](x;{`8 {ipdm#\w9l6+E%@l UWĹ@QbUE++_ G09 _Aފ7nXU޲ b0P)[{|?qR|7"st*Gb1$z|_@C=]b7"nu@@ 'ZH0&A&<9|ʯᗁJe=;X ׏cx?\#z*?ɸ957.K֝weLopf&[^@- {=w}L,"Yi"<{cNǻ`>co#:lNVO^W/ãߜul?o'{?5_$_]}[|O}ap@۞ܱ"#w'I2<M*nTjCF0[p  aP# `f$gl!!a0H6F 0]`B`xփ AChe{`7B568ns vKy&-qqtvŋJ=2`RӔې9pvcv /]G p[Z` hh-xMFDž&^ ܂נS`pH 1҃ L $0f'_NqTSt10 = f}_zI/zN| 9vܑ#xu|9 d?_QxsgRN9Nsv񓍍)'FIͣ?)$.N=CMz\C{pHF ׽(<'$OM tk 1MB>`xO(Ɓ ׁp.kx&m:MeBx3^ # vc r\{vp7 \3+w-np[:\X BrCJ4(ȧ5|dNlrC&hަ|qd8q`q$d"2AeCzD<x4#8bN=zQ X#s_zt.KeU:pN7cr>xb_x6#AfcȈ5>a0\nI&=,u)!+W*! k4dd 5 v\3 ^! [Jz{`r} )0g4@<i =%)Cb?-ٍw}.Ó8kZn9T$U-gIH(YM!)!І ~ `uE9?Kv迋c{cv2qs|pDnn)ޗxhB!B!}lrC?L;)z L>7GvseGgew = ybx 0$+>Vtc> tmb$T _+&NA fQ"xCFxQ@(P((l Gcn緲#5CcTI[@ O߂v|A(`8N;`!0da# #{ V@ $p i0 i鴂xYY_)~먀O:TbuLkΖhu ;QS.Aa6 Aq0t[ A#A6@ؔ Ⱥ%M@wA$d+ P"CA7C ,ʸ቉͛t<1q]k]I6IR&dQv;0]`hC~~ߡGNfA=*@ g]CBwuP5~0vp<:0~ v`ߵ_ωqiυڿw~^?B;~Cދ8I\LpJ)~ϣ4Lz<#K {{{u:`юt7Ȣ4b'8::JN0}'ys9\>α{lCHc7 ոc+<ǎ;;vaLЍ9Ȗ1OŹoUh1ʅF:ZjIJ*jk`Uns/N7֦jҵ險t+LGKdMq47Y7a960]Ol L:mF:6( uj`Іxg]fc[, hMJ 2Yr*dDVa@e99̍ӱ i %$i @ Ȝg+*<`qxu%źEN]SVqNojSӴJ*hU\CD,&8mgy4S,'FpdTf4fglP]Ș Y؞jSgjGޚjͩI|Kڡ7cě'&\ZZW;8O-vtԼ@PsjO={Lp zt/ssq؊Z76LXu7Ī1M7ly$Ǹb7M > endobj 1025 0 obj <> stream x]͎0=OrڐHd"e5 H ,R3:kr;}7gߦ99t};15!=k'm7zLeq_:ɾ/HpԆӏiy>}p fᲬԷ٬c2_c sAJ3>MuoIBnYOKim,d\!;˒#{r= y"r@ޱ!ﹾտqB>0c9w[_)/_"ӯ6~Y_~E B= s~A~^ CG诰/ľ$j/ ~~|_L\~k"/+~ã;|#ߡJGO~mx~+_~ox~~) _1W;{t+~~󏾹{_6e5wqq\9G=~{;>+<~ӗV/دӿH)psE4-ד]v/F7<9 endstream endobj 1026 0 obj <> endobj 1027 0 obj <> stream xԼy`E7^Us_===svϕd&I2@Pb Q]uuceWB%*עxod](Y]̯gX}L]}Lus|]1*@e_߼2@n+#~`%KK9`K\Ӳ``eQ?ac5 qOiX¥+~ʿɊcp%6Tt+Ls)6z ?1㢖Ek:h2[6CpD$9 GE%xiYy:24]?!4o1r1cǍ?oI͓Ͽ`TЇ<8Ss \}OR?S=j:N`8;p[5#x( tP6`jUo@)沀+A<@:6z*N[ VP[/@p/pc9#@>TR3ܷ%[X>4ޔ[{ R|T0 \=X~ ނ-hڟ[4a%xqгg#*<rcssrH04UF`#zeSjpX6C13MASg 9x47>= &P[J=_C 8^Yp!\vxp'?_#iSE@Nt})@]@Mک먍NKK z=V4Vпyyzi{-ώ^]]9Sn -ǟgoxοcAAtyk{> o!\ ;%;<? {_Ҙ G[Q}~T)UEUS ,4[F/Wүi(<ͽ44k2ւ2PPo 4# ßSq䃿ÿ棚fԄ}ʗ^Vʈnڄʨit2݂f)J-ͤ`%M,$h{P#FO,EjoD aXU^{`3h X́c:uۖw%h-:̏f U nx4nDQT?Ё90ZhʂC;CLK:^x j|bo1{vj Ooo wx4+P0u9~G7RxbiҤzNhx څa/Hz:kٙkSp-1Xü4|x1Lx:lEOsNh2x79, pN9)b퓽uX7RpɣXoq< ,{aQ@ ?]X|\,,%v,yOXCq1nX/:p6,wSaJFWЕh|BF)Bp^C0 k,uÿV Z cEYk\ߡ0!iwS@مm"~RxG,FHDׄAJBB gx@3-CxeL.UJ"ҁf#/qL%GV|VSNՠpt6F\8 ?qx~ B'_4]vValOT?V(u؛ST(!D9dRn#_.SQ̬1(E]*5;sYCAA3p(?墵khQ!iYkgwV ILh 9Q?~"s~[2[Y!2 DtZрS@_"^h%=b/! ܰ9 z*+CNӏW_+wNcOyG/3v5WZoc}֩Y@u dx%3%]a]B5ˢ?ۓ _Z7HQUewwWB_(=3'ۺ3'A'S3=, ,70ø! d;qM&!s8x#ho_šRY^&uV FS,I5$p/|vuWO}0.>@Zpqv5e\S-YDf'%H$ :xUpR ; }g_th>O//2.,a8dЙeЕ{iM̨թőf.ZqqVi|2~#Z ~Ådz L=mqLa0 w1Bs'v2w}wXidHA; IO' ە;mljވIp1Ǚ2:8xxr+q([A| $d4:=/~ /C6o|ᶗ!%f=ЃGc߇ZCwq;"}N-ub1ޏ5L%SB72 %@X$,N g"J2i5v'|8y,r,y*r*\^o iéP]YŤI4!A\ 0 ? ce3B@0@Y5ZQ1*YQQ %SI5aZM q ˵w|K}tIɌHII4,#ᰔJT2]!¼&iבhtYYi)29.xD1, ^DpeyrUIɊ$B(Z; 1H \l0h b>X\pDgID0cÐVC,z N8=mg]8s*;Լ/΀ajk+9s퟉Up}s1soע)j'p|mlwH'IZ00oA2wRD YII=~{  *> avUV&qҚ ^]{qNAMٯ-}l/ǒQŢ V*X%*\qKQg0y>hњ 5Y8A/ wj-f,ziJ1(΋=OHG(eQ)wDNh؏?N>mC=Qٗf5h[f{aa6~{G7F6*e5c{jt%Cqz[a ,|jۙiq ǣ l#6+%ˤa:QZk3u 1IZNݛ`S`K ׅ 孩֚HpTCMrly{Z .mm7yoc·byOlN*hkicg8q0Z,BKf( +P8dbg#0{O@tFDC} b '!QKFkHոУ 1wx J3KëmmXbƬr c>J{2p;ZfMkM32~kg5IgǨ9+[F׍_NS-5r>rxIpP(f*M+7;;/ōN=Ƨ|, ѻcMk8"m%#I,/si1t vc (m2]Œp(wCL] 9AzlbE1{5djÈ{1oi=%so`K ?>,RYQ8%{n~VW;\? Q;zH\8I9\[~s_~r$GEݑSҒess\_^}[ɪJZzߚs#bW$),co%c\:}i$+&Y10ӰAcpU ͡?vHxr հ߃'i=n"2*$1WToyΝ髺rwb-Nn>n`y1T OJ%*Ë1®3&qW ԩg_}o?^_e{ /!d #O[]v*p<ȋCGFQPR}`?\B~8I9:mG=}k6I&a*X"$(lr*4Wѫ?pzqy \XYsgw9 au{_uc~N-&wz31%t/gPJf.oyӃDVY=.aAS];=|r\IJp[Ǔ[O^F#يn({^#4N߸>k 6isP=턞'qgC,;uD' A\@##;趀(M2߀GB<ŠQ&?{4T9Eiz*U{[uG&v鞷nwZOT:P1HFו-)W*߯RGiH8YR#lw 5ĩq2Ƞ)]^JbAF $Y rF$ϔò^v9WZr|a~a-kc#FԽGUy.<=6Orf5pg{a|tA2wW̝ϑWbϽԧTugh]@#2.+wjs#uҪUsKi}^IrsL겥^se1\0`=4;[>fy;wg;E#Mݛ7Aßޝri9]+h vh _'ffnQu7ԭIo;y]4Y/ E+aIf9C@"Dجfʈm&1=lM.II尼 ޫx5 ҺCIe~U9%.q 1QZqdFUy"y=Lo7! =HWbT&?oe !du9G H{`n8 W8] Æ1Rw57)ƉV'0U`ݙF'V#r:Z,=vzBxdI;Of bA)z#JE< S=QĊ;ӣ*n6b?JÂ%Md\ŹqL;ɢ8O qp!{[{{? ZILoVٍ Œ`- YCϖ'WU U"9SUyyeU0^e7 )l An4 't&A*&Kp( UUR(ce9pv@p` =>v3i#J p:VcVo#D&5hY99j^(cԪKw[;Ɣ,8LZ_W}.9We>[g&j=}P_mІhIZ8*i|M*uyU8àvAw>"ZpF@< ĆUTV}pڽsېMÍcQoO6>1}QwN+wUi+%XixkXQɼ'P'Hi]((e5U!* aGh(4.+YYm% }ӈX7Ƣ=:h۷(<9,G}PA {U7])]u~u^ r>4W^23_HŁ-XBB1Vk ۆ[mk;=thwnwnWSԍNi*T6=<0t谆`m^>%6spG 8S85Hd3 QpTAnTjT=*Q]]֌RHMiTIZB]VIQژLeD"*9%V H8(GWEQtHHhAq4 Cقs2^ߟ9) fKyVܖZJZg[_*.qF31EJhE35t*04P[fs_uOo}8]EA:w+t\l;T@ϸ@} gi//]8G|hkhխʲaMj$]N|Q#]Իp2eM|%Rng+ٓbcc cHW,c.ZyI\BF!XlhXyb,\2f{DC.ȫTm;U}N K Y'~CNBavXL_HvaLtEvP^W9}Fy.{k޽{磾_UWuy}n~/eOSz@RTb1Hڍj`w45 fkO^W,HU1UfI7ꑃ}_EmOL'rVs ~{9Dv=%Ȋ ,{,Ā nniӸ6u 'ݪWwwPoyL.D8\YĽ}yt [)ݍ{ b^mr p x7 Ep2n>۩٥{U[ֳz?NW={19-3 dYK=T"SL,Shc$ +Ԥ.xUg萳 Ըwk=ۣi#n7~vN/A?}%A7olfQ d! uMWhL,ʣ"*o~Rά^[&]{P.԰ 43a&QdgtKne|}>IK&DWZ?41L 2Lfx@ƑVK!Au;[V gOHS&Ѻx.CA?4X--KQw$QjhWII7mkB7.O+6 jz!! =a8~_ok'xl+|DJ_O5^caAD%`3VY|cӯ>sZκ=$$Qr$g#|ξi81ͅJf0gz5ϋ>]j8L!q#^/vec%xY޷͛N.nL l?Ab^ z9%+5< /~}<j6yJ_0k<7=ޅO8h~dtH<RxW ʰ C,*a_@k|%rM,Y$^r$ \W82ތɬcwoaiaf 1ֽ5 H` kjTLӻ8R/r԰\EEBQ-jS(vxPXby:s9CN(D#U8hzxܦczLqKANq ,Ӯbgd"dITjgH g}d2P*㩔 ĘţQ_Y .QFMpԝa HE66117h h1e 6(B$j8ߞʼn5.Y-(C/Vx%B5P9C|:?J`g >Hg)gp]NZze4P*Pc;J0iy+;~b(C YX v &}'rD@Ca$3NżD]/3^LBiMO$ZzeV{Q۩ .qm&'q۸!-cRϜ 'YTViRiv@=p{Vʰ2 9/(0v>h j|pz: ̈́ ]Q ɐ 1ʋe`6a-Һc),9xdyK2lw33nq՝_q$6ȇLYl ?~1=]t@sPT߭J t% 35I TM4.,1]3^&ƿ7BpWDx)}=԰@8z.kק}R䮻>!_{5_2 ul<1hnf)6Q*C  1c K W« kk M-In0|¿N Nz}ej.ةa.o*r9Smm_Uք#3X+#&ʊGD١yim&X .ՄR qu4yHT 8 .B~fͪ/7 R rM,b!FNVWA9Yb8FUse.FYe IjlNxі$>!iI/zUEp܁ O? .q"E/X%=aօyďm{co $[ݓwcm(1T؎Aly}Hhh],!X"`;W d,՝uԇv- aj`0h$eշbA`le )`3h+;{٪"&݈q>3Kdi@~baaA&X1x$eI@"+ڳf;.Sܢk5k~S'j4'!OA$0= -i?;:zOLSʖby م;zRX/l^ YAurQ䬣c1i4~c8x^yxIuՎ{]hp>'>W!߅ng$x8 qjqu>Uͫ—Kc3+x\DJ!Ka%L'w0bao*r10k%3 + Ig0@}c I46i &hВ[J/!|n1({r*MI1K("((D'\Y5D)RShcQZv%{ڢMeIXe.IolǓ)‰ϏэʬbX>STTI"r"!a >X4,t7i YDHlGݐZgAjoFrIHԬ sP2cNn܅"v8JWoj鞨gIp1 Ba\<۫~n۹*9X/iL8 LQTunjn]k%FK1kbZ =ȥ /b:[\<׸,];\?čO'|Lax1QLtV(`::]txN(tErpWDOv9Xa wxbѠl6zэV]X`Dфccr:›Q:r >GGT)ӦzROs&^y$qR=m"-b;o7x\q| 0:nl3~I-흜ӕ3 5{hm/zAu-h#Ң-LzQ_xa{ч%\fЍq8#e% h96vGGMyox6b I gy 6ѨOW\%gh=Da4<ϮH< ' oA(%-6)'&˱B3FPʣ<肭f~XPC++<{R 'خRtK-%?Vϼ3fpF!e%?CfD",_q=¿^.Χ&Knwli0.NV`?cE-h(&;oN0'F(PĔ!O >=њDfA*E刕tEQ"EhAyyBn(Lu8kkWdԥn5,9 ^D;e|90hs~0c@;Js_-}+,0(Q*f/̠u-$rݨަ Y'Ծ{݊}k _L~7} k_ 5kUbb@t.Gە=)Zu߇;' c>f(%ʚPeBzͷԛ0l`f#eOtogLk_Q7SatG"'OU!`,@WD~`~N'Dk‡3tn9EvN=d(zRQoBinׯ2q܍kjCy(SU C]L W鞷g:N{C+꟱=l~kf,fotm###qċl1sP[156MZޣKlE"ezB01RY˗@ 4*>w-]|'*%lޡs++#d=%2.Խ"91 nHe lI=RO(V3qH }.f,qd̅E6ZX{$sx-,0q$ ~` L\_myk4ga B9oQ7>*!IU b0)m2W1\-6^"/iJqq@}6PS=zZ5 +d~Ԩ=*Nn+{e?Pٷd^譖ހcI62XV&5zЂ/,8H9J6VDhZũ4WΪ\^IJ:RyU61f`Ž%Qq4n/r&0†z9ujkC@d[TEq+ѥCc}AD}(ZU8qk[uk_ f1I EsWSϲYxWC]BgpiyAru6Lx"u/wȮ=wMύݰ񸺵b1i;Z0wxA Ŷ_5bШY[Hz pو+#|fq9]-I[*[Z*dbHhFoHWD<1O"d0χ_KP+[H[]TDl~dABRbkT+ EQ篬HЇ"6s0g̓3:sI))`"}}=g;YTjqLẁ]S7:m5DuP;>åo4٣H/+c r%e lUQ^rGф`.W֐HVU{%\@<ʖm28JfN6;nh쟦g׵LfX"T,-[a "X.T*h:|Xi>ʪVPY> *86%Mc *!@O 4{ܼX֏x܋p(d4p

    d`-f`-mi>y&S19 FEXԇ:N_d۵L+l( g!-_W/op;~? wk~w~h0&tvoEvvG p…)YD qdN/h[Aֱ!sQ [j؋3~bGoXOzEZl<4#|n_:L]Odҧ״1`itĺÙ1'ƈ# _..>[ ?_~h9M&$Į++?P.? Y g+'˝肮1JZ?ܧ3 :KtcMtng>SaQ%d߯hYd}|;S%cdO9]v_vA^S_\ыVkJZsj% ΫyZւBdYJn"H, ]dю ҢUc$r. 2S>zOW鋟G|zZ=4CoҹĈ711:إٳor89xoU)Z!rL?Ahlѣ):TtAFǢR!?tJgD\`;" 'S%MG|3@P-M>֞N5ӟu0@Q6Rg6[40׼ιaV! R)|(y@G>D넣.j{1gLehSܳɤ nKvC[ Jܮ ZN޿[h F.oytwVY x#,"bтhIR1?v>!q< cs} cƅbsf* ǽ3xGLmH.չ+9S\ȅCYyrA[Թ~O|yu-U娦$YB; iEjO)-ŹPAK2ph^ͼ v &aVuGx7O[(Vjt:M4^tx[K>p8r)j$xIÀyv%W~$iUK݃ꁅ\˄|Nw |q}OXZx@KaJ!R,P |'ٙSc`bd:i2luL,._szvzգ.uP\KG 4̠ JB?Di)Z!n9ۢGXS" , M ۡ] RHGjU)6 =mpgVTG%!1]Hۦn\G' }O4t4R:S)kK!lI ʾM9p(G[ Ʊ[ I µM\=1b1o\SM\Vc$r)lA+*hXOoNtv;WѺ[-Q^!tF R趒*(z&@{Ɯ{uO;Խ/}rHD@c[ f^h{@iɺr谼G-[,Fcž$$) <4N\cy5McS6ucaoñ{N]z9b Y#8Q: h%yf>EY4n55Ψ`:fwA(.::Y_U??X4 jDMgW `KLLƲ0)/|6PRfԼ&!@uZnkPlMsaZcq4"=Us[4A贵N]Rg"qDɎDID$ ؿw+lƭJܮZ; L]11Æኣ I7\I-mP5Qa: !ozIjDxlrcaeʎ:!iY{§0N?^?6["< ,ZrSЕ5yw=Vᐛv•apЍ2h-tA)=4i^ Y%jQ=7i-FX4E]Z4EÆZ]v`Ql\F4f9KJ1-~ӗ[l5t2liٶZZ0\rh^u9un¡ySk- v8@NM =4tp;o|s?YU߆>NWMcr~u^Moο+q6y>dy>)R@B BQ΀H\h01G5Kj:(,q(76B@H!F wT;] l[f;kgv0nM?6!9)9:'^ċA큠uFy"blxANGF@jy6ڨC h 5s<3dzr\@6:K$l;=d!Y"sDl7b{5pz:ΉNٺTn[dǵأ3L_p_5.h }^uu@jImiCET fc ֎Y-TPYdVQLS58v{/'=xP:uSS~A/D qy?\'Xެ?%d9\bu-pX֐; Cq]2l6,W<͕M ohUmxnASP Zshp)|FQ2 ݅?Jq`XCU§X4(IG4i'px򈫗MLC 0孃/Imc[6=ʥG5 jTJ\{px&Ю KʠѥD{Oy/9[fu^/Oh"}֠ ,f`6yM[tbɚMTdO}jPl*!{ a2>g9cM=6o kc@&\N3L؆C8l[Gi[uo [T41m-)]4l_(4B8LA*J$]dpd9b3k:Dut˩46uHzYo/Ûf{ ^.ՍKvNh'xW' y֩i1ⱡǚ1lŊ<-n؎zEc79#yƑ<'*פnmy:1i[ Xf6 &[ck[Q3j lʡz :p;o{u? ,}p3샒bb|1cٳ_SRtYoG_Yw$srgY`c1B-|k>œ}A1hK)ܱdN但ً>C~5$3xęsr|CfVru:ZzXChJk6gHV&3s;_ᗼs~ɓ{|(]sva=htM:K3ÀfSZ~`B(Co̶j+)h;)eGb LI/;2鴈M6uqWXb &PBo[LC5Kt!}V eO?Y{躎>갭w\ R`$i:i1S B*AAE6*qFR!HhIhZdD=P.p 7?mp'(*U0`MYyCb;ZLG:ܬD-t AhW+ɱ+qژ2  >JwD$ĄDr'3F$RHnJ%A7U8%Z+b^DC /gGlIµާEDLh8A9ሿ# UdUVFfO]ZIpFAذn޶֋-\0kYXĻ'0pbޱ7ϴFTC.4"m;4~11eO#}݀F6WCW4RauQgE]cG'x≟>?Y\9h ;f",#`xҌ`W劮XkzrhC!^yR Aq/̂v=i''1^ݵvQkư=gԚWN&]ۉͲ2Y4GcNͭ]s}m@­;bV-$Uh_lN=v ZS61$5,fe}RDJZN ㊎3Jd;DGyco+Ĺ T&11> >NW|E5 ;m; 6Mrm,dՀ8>8 XDKg|?}z-ZYŰb) A7?jo`Z%_hLh{ѥQpHXRQ~g W6jea pp8c7k^@"3subuoX%͑ ַE*" ]R%G)88DZJ^z-/X]vcI''/c@aWI}{ I2V&z(YKLX>:lH7.ND3Gt Ybi]GO6w ^"q)lhnk^FpA{3|1`;bux{v0rA%4Ji fw7Ň >^?û<>:lv%Ϯ8-;%V%31cOD\l9iQk`T@yZ#>g/lqp $F?-(Y( K8U_ol^tY;fVٴKI9 ]>rrEƹBX`:u%$ۤc{ Po(VEKMYCH JL(YZ%" ٩AA2DŽYNMEك1jo+ 5ğ`%2z/3 Guo,-x% 8zȿH*$ԗ&͕>x/*jp_=3&cs%?w0R"l'Z(/apM[zƒE5[<'7ɿ/ qFטǐMY-h6P ʥA|kPQ`0=/q֓{'xOV@K)=8ga,KC5YD]D iĊ+Z5A! LʹՉ\|[a{WDӐ0p^ eMKwm754xԟ9D<{{ /wJZZi!U7(OXθJd8w'/W&e'OCB-Qm68^є|dwz'Y,)LA=c`gȺDd kXVi*ԪAFQ[ [pz5!S.՗j17 >C9_A1"i]цV>hBj@_kdڠbLjܤ3RjRRhEvV@ jvcFmI Je6.F?H75?d8:T0ΉACDV]B&fAK:Nh̤7.!o.B5B5VhZQpX)Ynng4BwGqr>_|?%*O=>vutMq"qy9Qof Z3t#YF,*jv{IŖe ]oa9-cǀ%#؟O!,*aPIJ8E+Ӄq-]A lv:) :)k6eMF//` xjYLA60H_٤8ڢlL*mRkEI446yS?EM6įlf^M97h>rQw>2lGpY ܂w ӭUbitx_Ŀ H/]PƗlL]6k{39?qla?.lO3Ox*5ѿHo*ڣ(5 3,cRQ^? ³ٞtP'5ʼnԵ;6ɗmj\Yt8~⸽v,G/B"d9_—5'W\膁5%Ť'x'OX>Nf>w9QEud .̲1|L9qszEm;]6[o,I*ʷBȄOobR^GLM<~:anhO.kgYBkaMi5J!f˜N6B d!P*dY DN_fTXT[I^q {n6AqO"9;@㰣R0vj{Ǐ>MR,>ߠ uZ!ӊhauv /=^OLjWѴ%zp0{8뽧ZcbRMM}NjuM{^;&|Wbw-X+X}X@l$[ ϗX1ގzzYL<;Ff +v(1 Αn>s\۬XZ}VVBC_2f )%EI0h1[{+D(M8se7Xr9%Ž`17fkF3eNS:?O#D7Ai>Cn;TA#k\O\ùwg7t{5cgA_4nXm6tY5]6ê[d[dbuBZ{ʯKʤ+'bXv5*;BX䄬qF~fm[Y/lVvul/%1>`ľ !gیXX+e Xjbex";huVkwYt',_PCuo@}b-$4ɾ YXng(>?GŴy˦-Ц%U^]u<;ȃ O\wBX5Ji=@.-?`-ԋ"#M٥5;jpK!¯owPl/:Nqϰ KeԎ`{H`&Qxgc6 Ś!kbM7XYOO'x≟.?ag<'YEphU 9G#a}{EئycIT`pɶ{,1B ~iAmCoiCy3 3"4\\/XgK9 ќ97M !f"էd@b Y:~*㇎_O-}\n2w3F;L3eQ*1_-A>_h[`,^]ҬѪM5}sɅ{'8GFM *!Y{z.X;8ɎfdeyXkeK>pa~ ~UD g4W1kʭI C>Sa+Mj ~ѠiėeGrm`_R6¦xPewt*1Pz(-I(f#9fr?2jgXIDgp9c8h5:~~KBY qjz'hQ< Q !򸢩 Ơg_dц %T*ӝY_";D⇎U뚫 9/V{yտ0*ߢ4'`և`2oqc̰`wR &Iha٬;FêIKO}2j\-:1.bDov{6MP{ڣ̰p^QԑAshXN>X2ib\:1®ɎҾK3vʅ5 ;>S=UrKKnd-slY`IIg?,~'xGil;F׊vLW)&[eu^,M$* );/'xg10#<l|&UI!hSBfB@~ حC&zh2g7Qd`T ?Aĝ] Ip^G5#9%i.A"'qxE"&>縻ukqux/W!OLI2qjCyKf0-B4&gg#fوy6bwHܯj(jv'1T;U8b{ގWقX:ĩKt( OF =0ahRQQ/(gY}"#1|#J\caS |kO6Ia;Z+0 Cg6nYajcFV#,R,RL2̰Au(9D.45n|0$jE ; H!66ؘeb|1h7<=GL1I0YҊsZaN8]yuѥyIsL3S8ݜ7lLƤ&y[-E2&1eFOlH]qQVɮjq~ZW8N"` =aew~}Pm@c4vSI8 .NnРXQ?d_Dw!f^28Zr<2QUl1`0[sA9E:t:6IF^5I\kmt#:݈nwiV?ďi^oX̦'Rh̯??Ywxt{.y%$`6`6`sۡ=h'h.q; n`ኄk=>10!a):Yد^R /L'Š0+<&EiQd)rY}+=. R4li!B]r*3X\ZL a99686Ȏ}ÆH6/ל{wt.VȼFӠic'ވ}&G'cS-8^wW PQ֚0ܱ\vY]wY}|t𜄓g^Q%b}b8DET(BB`{.h_D:JzX U!cny:+ j?[L]rҥ|cC>M }fo,yx~dbL2'8&+&XG?Cnaq?.G `m{"FHQ$X'~)]P4 PC`4\Ҏ"VƐQR&sRN*졨pOE Q(ȥIJd]cal!sbf6u&RИ(h1w0ukrӢ,r"Ǣt ' vT68%+XzD"8 C`lVEG5dMֲ\ %;> mMa4j/^;>P#GcfT % %v'g:3L1Op)n?űRqr&/Cg eWEYTh-(CeؤGRy,7# c>7u-ƻgD$]@vB>ll~l~LU,6;pl%g/h_ُt=o?KT?#=?AGl϶OX)$$92.|5d &χo|W=_=KJH ZPP:ְcbr6'1W5er/mM=t1}^fw梅DXgI%ҫٜX[l>Y$6Cחܟh;tKhK8/l#OVǸ7-G{^򖡘BF} =oE\xd[y'dO{LY7vG=ld\ָ Aç\ ϓxg 9OQWzFrSg/+$Yح;*8 \+kb֣f,F*[)N; AAP~ʐf±沵ᬳc'CP8xAw8+逸"R 5N؉[qpg܊6? 0* =o`Bٰ1lTaCF*r3$}vCaT4l*p 3mJa^wlxW?}QW f=nwEٚn1eS|[Ms-IG&R\VEqY.k7CEwb~z_WxYdsۉ" YW s}Ɖu(0eEA-/>GkZrG^=xoWC3]fm1| ƆUŽU~H1;;lHN8oiWrAhF&Qd5N'd6 vn% 8ۇPD].^M K² ,ԤH4MC"C(ƶ"v}`^ZB%D2/i#ZnD[F;/(Ku綬PRVʀ{G30+f 퀨 Hb8 ʀ}-#Om+h| ,j_c EI$Mfiu`6!] ͜~9cP9v\.YdKhu"N]5 ǒ.G:[ hx%* b`҄;GΌ'WyBB@BC,`!8y1[cWjz 5p粊wȖylMxķDCuB֠D+[V(ΊNHYM­s.oжCa{((k:{>WN#NmdEdL!9:g쳠K ^~P-5ł63ZbF!uֲBö3`ngiլdP!1"UA$-u.u/U/-.C)ՂFUd)dv\2KPm&>TH6 酇p+jn>YiT2pg eVHK cX<(O$setLhzMlHӕQ#zKAݗ;!:C~aRL3CWK4Q Ggr|q̧V].v13Vjy',dk(*0%ƺRuǡ +vZ. "ɰȰ㱤CVЄJ@l{ kZŬILLnDk ɬ1!Q] {g>[/87x8DC|VQ5p̪G \&Ok1hY-$: 6SY*NMi+̜G4oDê鰔ƥkZ"㭈SզM6!-ԃ;~g`8F%Ŕ\*՛.oT- kg&kiQgq1yYV,ws#jnj_^hR.ϵ{:;"oi2h A$߽w߾芞b7r,e,$r>uıb)9zYC7$G\HI@aL!4BѨ::eW#-w- aPx:C6!+l6XJFO)[:q5[bc7UD[_oMDE{\1f.u<ȯ9gٙKug@=qN#QyfKS\cg1~Z㘃Όg3~Y.`V BݾBc+{j0J Jȓ<(r ? M)i!;Μ֜Q֨JZe%u@3P 9x5Okڝ7 ?:'XLΣ}08L`1.1цJJ{}IW*#_ lN??>pԄc޸~Ֆ []r϶9f6a(UT lg*&K%V1.1AI3WS> jn6LS ü#6e b-سNz]]:jЎ+ `;=gîɅ853"%h)^woxacmp XWc&1wlGzX"&\cG( :(:UЌ MQWzc$K/EEa>szĪpZ A:҆'<@s`ӡrքj\^!Y~/?A=W̆}ftC%f,Έ6GyL1:NJ2fb2ZrPm&ZWW$n(Y#ڴ8 EcRycP5릃. Đ%ђhEF$ ZN mo1Pi5Rbʒxҗ__>r59 \C49=GuTF,ӒEI2,p7p 7'W@k -Ai UDKbl 4Ybg5u糀'#|x=w>ބfG 2s3$Oqd4_n5V(jpaV27h'zR#%j K`):QpϏ! jTch ,cC,) 6g.8Zq(Il&*ͭQB=UD&i5YM񨢢@~/̶)]0Xm6ӆfJ٠2uTR:k$ѲGN[OH7 e )]J:E6lgm+4+(h#*I#lE(i_gBo荂8O&S ~&)Vc$bF'جSn#S5]mF jC,λzHd2k#ca:JZDXwtWKvKv%S|+H5zay;7֘1XuR74Jeh!1V+כ1&kvKsº sY(y*J m78A ҆zi^iԡI J%iR6dѺMKc+W0G Xҳ& ĊR:%MRz>U#7*V#*rKJvB\'ϔS"(JĘĪOnX,.g>fH\H3jh24Y'>q䲉lЄ%WIV譊(MaJan[}Bp6: aXؠfPQkPczМKڂ^{kETԚJX{£Ysfa#MRav'>D(xIH{Lڷ66&=vHsZJBT[QTgk4 }Ѷ(LDMRĕC"m2ŠT2f#}6MYz wc5E a3t'=`qJ'$³ T+ ^o0\ccNIp BHJE#Rԕ%xYCZq(U|RPmH2Ai$"<4 mkr xjsƷ찌dKTfjC1y{F5X`҉!,ٰ|%) eƩb4h zG3s:,L,֧.q%ox aH C!rMRx~~Eң B#BgNwqxǃ䨢VR$I|y:msXA(E7rB͓,];gvO9잠j&  vN(EJ4#{ Uhb Iц,*la[ltIW_sipn2TvI+z{F P@nIϘ20 f),d첒Agsعd,.4j4j[6U@TZ 1!%ʄXwÜKYOA  ? ' D#i*u-`MnᆯLr߱W;W0MHIkTe7шxGM$dHqNXId %{O\i.]۬=V*M v - %5 JS3(O%#f2->QYT^m>@ky*әgLdnXmB%1oT)YX0}M'h/t:+uc'}NlCdpP.bFElRh,\&}uB'6g~SrCC.a[bA[ 9TNo5>ZQZfP8:+uercwP%KjLkZ˲hjhr~ŎsΞ~Ǝv@N4 !DԠ/aw0yT_ď\EQMQ눾ҏh&KĘygYYed=O#@6]V=czU҄r#ÌvEv\Ά>ۃἽE{>kFYhUAVA%mLrR(j|wG o]^,Ϻ<; ^jX"îSI>+PjVAH֊v{Es^Yvrg {.ĞM1)*M&P]VhEڂu!& udbZmpGͺl!fx6íFsn~ Z ?)TYfssʼn<#TyHN`-[9XVTvޭX..].2BhP)naˌDيⰢ%;!c tP٠z)~ؓAfd<6I?4c_M?#?{ޗLl#xX\h|~/gB؏zn?)b_qS\J]sϹ58&V[DO"`f#(Q*E@2 H;t ugoOs2f۾Vi#at ڶ̳aUEPrihY ȅI(ۜd\cR [#m^c/SZQtƼ` JPf&%R}J+bE!oRd1.tJ#i,\E0')c5.pt騂VF*ewkE0_ Y  k^鼇-u/ MSu(Do7Np$iD1%m‘zCrJU45J3k8S=s7z)*du]ffҩЈdkF}'|6O|]<;֒[o-I(RZ"PtT[|5CrGZ'{SxS z6@;+v +O-I2D!]:AB/HX eiftl:LŕH)'?mmҧy 7+ pBV\ټ昢x~pf@V6x6%Y%Uh.+yiZ+ظ"pPql@9imoQBRAU1)-Z*mZ & \+@_^ZyS>eyߡcnޥzKIJTq#>i4 o9"CL=urRAU״AC+ u g[>ymW&ymRhs6Ec ;\.ǬDQSl-2 6`dq}DϜ#N/fXha"ؤjCm(D˕2`Sn{ԼSV :મ)u!mئuH`5;f-یkz7ϱ,_DENYCZxl>\h$Nu>+QD628} B}?MlfMq2 krޟֈ;,ZK:VkMc*Ԧ 3meDGH.~an1e X\wX;d*QƌsC6)F7#MoHN]Upu͞qvAT)Wv2tDjԲA "TFk*tJt}bjU#PtMh!N]r=t*VKr,J$o~*\ʐ1 ga>,hPG 2E>w;,c MQCw$ZLiqNsKe+s>{6k7I"dl T=W`PI$MEcr[J$lg.͘L/jE6zk)zZĺ/:S`J.{:6W$L6MoPo )2(sxKfV7C`x'~qs}s}>"\5dl5SL#4s,#c^w88wm \ZE)&[3"H2*24lBuF>rf^*P>wcE~S?| _c/;|G>?$[?)L( >#/~?/3cG_^c?r}=R5?__"N¿Mg~u~?gw 7|Y ~g%e1fz@{:3Vf@[71`])1 r[[PaL HE9TPT#漦>)hSIJPdb||@[B# +HA\ nIp78jRp>qX~ Dܾ.[Z+F\CޯRlұ`c #pDƠ;ke]Hmk ^O5^jM͹Oŭ7='| Fc., sGܧ U%ã ý)$PVtXұ撎@*\xD9 ?E[x\r4m W.FUSC/BCfU,:l<)Gw91K˰KM)K<5BM^ shT{'}7!xuMjI=3oIVa!uO:DETąNTxv`~+rlŃ8ؿpcwsKNVaJ>g|8{*;jDa>h`0j mX-=[)n"EphmtY h ֠X}1ԺFL~=rHwT9KsZNLkMߟwxt}O ;S4;5M_,!P0ψ)(ѻQPA.Q)TE)*Ɲ XDŽ]Elp28*Ѣ-"f4r, |("At-(b8RPo:1ɱܰX,z]򾅰)htF(mix9С! _`Rw %NlgI=@24pY!.ȋ5\hfU=JPeCʍn>kEjyLdg.gwͫWlr0v#0rhʂ%fPuԝUG%Z LL2J2TblBZXMN<"9p{c-CJݟ=>W3oگßg7~WR}O,OH)kO ] 7lÛoͯ/tgyw_}'|_/w^w 7˿¯fr9FQz?*62'VY][͗2~EOFfE: p!A[%הh)Q(?BQ pB,@ ҡ,f}VWinդ0g NUZ-id[%+]nOϹ<=To5{C>W=K=q#l#*vŚC{^9LqF|d0Zssc6+-xfΰ.)mUeA]AZd<1>k|$o +XR 'ܾqsŸn+UШ*R \$/_ؔ/ [gdĹ˰ 642Tʭ%:O8..wICf\opNpe¨S]S_S]ƬduWXw&b*Q& 9[3:c&,~Crav\2|嚏?]ڪm,oۯa pi%QsS:ۙ|O G:8$߂ieNYrw}+͇"hO:Tm6ܗpD Y}L7dzcQ-5(h4S 1ѐStb1TE$ZTmReFW8`x, \E\4-"SA* @ lI .XAslDw oܐ?2IcNOOVi^ȇ r i (* 9s3R6b/t, %'+&g6gCA<ʐq5``+p:>h>/'"ޓ$aVyEY WNv3B:-8ϑQ_dr4B 2b?~a fcNoI,E*_Q}~Om>λ?_GO^<_})~:_~e2LO=/El{#oֿߗ5c'kFʰ)2PR  ڐ4 wTcܛ`G{WwɎrNq^v#!h_ecpE5Hh(ʂ8 !W$£ tOuMP-Y%,sg%\>frX ⼍Yyŕ9%]4.hk!Yeo>G eIg$Ȓv~-KH|hp },]a;,쓺6E U N:SY}u0򑙠.K[~sK[#Gx^w1uwM1Թ2G!a;<|VN5WTFar׀`S2,3,*K tʱAu\+j$~+GM ]|p*QE}&{G݄'onsRq6?Ĵr,323,3e&LrwXx]W~ȰsQ5Fjx]~CZ 3(߻S oaʙ"K:Qiu2 z$`G%7y*o! idVCeZW+twoB}$=ku\5^NC0kTjTF5ב@/f)=mξ8VUZjIT-kG&i&AY5R̢${|F8 o3O53%PD%*~qPɂ\=> lUcXf]PKr=ORXBG)*ԸL,q _&e&q(NZ"ٶ[ɰȱDєeKHdatAԅK*X<.QR+ Q;RYYF" l5qmTCNANGC&+i9k /]hMA '=zjUkUުzxur-ߚ| 4A~R9(s\gܭ,>\qo+U > 5  2;1w78Qu+N[.h-+˶mj_1A!vUzMǽ[KqZmER4-muFGI(tsul,If[mG4[ZQ4T3r \BP 6m&Ų΢uʎ<2޴9{-ۭ5-XKҩќ^U6dc >'t As'ɨWA r=<=~~?E 'MɌda^ج.\k77荂3uT݅_lG CgՍP9P3Aj$*S VZ#* 򐽸 IDATW\%4ڝ Ǽ`rrI .- DJ߀@_#;Tl|"%M**WwT΂#΂cNg\Gh RzJM[T4%Mu $kmx0#)S5&^&{Wlu. ^7&مIzib Vju`rj1j>d H1 ]Kы 28zn' (wXX5T5GQDQѭp\BBA$Bj@Ks,3*q8Fc&8vS=O1}6[|BU.M=֣yy"*\vC@5eԻqvX5lVCn)*:rS>ѩ%-sA e3WdU5Im@u( u©tX똼75 HdtFiXFFE(Dl -jHÀKMخS$m&xjo~a&f\X,M]rX(G2A9('nAq@:4hVd8xA71tkuYzh{{}2"u7>~_w_/}]\^r|tvOa/.i[{n߿WO48ƲvN_^Uoկ~}s|k_7c[n[OV fHzΆ#} mVc_W5ԃ5 U*ߙ-gZF{]Vw;~Zo5hQ {/+oj&zavPH^SMi~gH{ j3zڔ6].'k/U*CРLK0wwXߠΔ;<|g./b:c:j# A(BTl:$6n FV07 qY%D!-;YESPoisdBHr #w1{Ki7w81I~Ol2!R, N?n{xN2q@ ɔZe?"ۜx;C\+½b VEUdz% 0[̍&SOH@2V2 ;ePW\1/Z,&I\Z C|5T 2tTQlhI&:DD&ft`zqӋ B3H@g=h h}D؍(X[\ͧX3:)wT va;$ΥDzlpc6>C>=~k.!B 'ɻQkύg\7>>7l&)%’nሽZq1"zSǯ䖊RM0(Ր)dg,@iJaD W19:ucCPԝ V%+ٺ֥ZX϶z<>b~"_dN 2(S(7%]h1-/fЋi\7adb#W JAٙ@kh pvd@RVwN Ri\S8g LrO 2hJNG]pW9ESJ ;ǔ`f'9oBB$s&gdT >ʒ{_0|4W\|Q!P\x\-QVbn~r?G=(cbF9 @-A\**TJJ^r> S|IMF5F&_.Ez cmE(/o}u~-7&_)%_/zu?ŗ_2RJ_W_O)˒(^m{g?o^oҗ?/7_{W*"xUGGٟY~)%_y-5~ւw)ۂunjKpb%\9L:k\ލBKD5 ٟ4jNjd82n%H@mi$j"LvmL3H4HJeWh7ׂpG٨\+PzfFuMOK 6[BiSSڨ)6qdn,UVe=in1vlzWHs@a Ԃ<"ecRP*% :(%$*e)UJ 2E/][f$E;A[Q56E<ֈijP* aW"5As[DE E";>I(T{kvS 1E)JUQ:B.g1y2i."SEHPSz1hmBi % DdP!jQd+lC2WpG qITĥAZNZZ*Hc`I(\J]8 D(@|m*e9^kKۜ5T>l M7&+ (l%*#"*b*23\cU)ЈK wXM~ Ro0sL]Evuΰ>P’$4C pF:鴤X.a#Y)) \P*2Wд|ܪOY,Xd=2i`Yn}KOIIqI(wcM3r e7[k?|w} ~?K_;?+CA|/OzW~ܿ _|/pqyɝ;G+◿_NO~}_#UsL&S޹O[_~ߺ{O'''[n及O;<8%tևCM#4b}rrg65~L5bT愼 WAQa7+hwo86y1$nnI˶&5VgĀTas9S؞DgyIrbPa>~Jxfsu'8)3csvNYSMYyd "1M&py!cf*KTT v Hqb?HZn](Z7ŀqnK ̣Ua-&*eg}*ѵKKp4.ʋ= _kӺ3DA0KJcgVvxqra *E 15"Li ZڜfkNf< 3Ztq;T儭rv}!+ma9a9B03 S(3)`z:G%[ }$:m`1fi[)Z%ERd)'Y l5bqq0W ¯]YkxjMK\q\qT(&23 JЍ HRMMԷ|8NEg+N9or!x5A1̜SebM<:Ό=W*l}aiUB\\|k)d= Wg6y-nhsƂ=']g\GH W^p|A;~~V۠`ud4>f^E5l4ʙg$-QJOPQl4NhXe̐+33te Nx-YbsGdʒ+Qu|H"r)B[.~>4_+~6y;?ÿu+O~>>u?Lho!+_ _W~#n[)7~p{=jrZaa6ۧ6ccGDZ),6LY{&So&6'!oFbX7)I@Q@7MN@ U|:8d>u}}Yuԇ呂jdE%L &IlG֑ XSH5Gb(*+R(Ndny+2jįO]̣CLqCWN2"8#2_g淉#yƏ= 5L$`pA1~N&/?#?v fUNGa$د]p8T*;(,6J8&&d*F ҉% { zWo>}S1H3c[zdytvg8h6Nx!Gۏ<Kڀ+^ %gmD"<{oEe.ӤƈMbNY0!+|QT5,^M:=woqbӋc4'Ks4lE:a wOpD"KJYrM.|zyF8%STJX%zntbUo =jΊSEOS>nLJ}ox wAFNY*D*lr 3#{sˡCLR ׼9:xztqa-LV FGlb4+Hӡ4{zW"uT5!UD ~u7yz{\\p!]pokr( l۔chPr-r˧Os>o)=\!,֫*G*Pn$b&KDՐhbukE\]fQ- UM9.M D)K]_Dz{h)Ȋ,!@6*IdM öt!ёF\ A᫨U)0 6Ţ \lmamKAAR r(yi$ g^'"}[M6`W|5>WQj* ld&qajHUYcB&QU͙z6^3IYdIXxƆ^D9(ıI($uP&3DU 1k!rQ^iH_È3/>N`4I0UaHR+*ٖQҧNinl.I\!BjIGIX}!|(} MTDD]ndDKhX2CJvx-%MkNE p[a1kD zJEҕ7^fZR+iaJdP.&CHY(lj_UFvItօܪS_loTqՏpo !O46Ik&.'Д}Áu]9wԢD-J\Dmrl$l*NdAjDKD]h`bZLp}٢./w wj#SiM`j T1I LUMdh"G%A+]gNn.>T8Z4B'dN D\e)E"ɐZTrR)CmAVX\GUa؛{`CYJ~b&(VC^=!-L$LRŤcOK M˩>`Yh%^ɱj)ND&QlE&erQcrdza2j9hzfVfe(⫈PETRAȊzH\ҵnZcNbpz6mfIn``%i ڬ|ˍr-/>oyex\8r~}b7 b.˼ڠ6 B:)UH,W$QQ(HLh#{)xl]6-ߩ6j 0(K,مSFZUU0.|v*7ܱ{*ȡFb[,m-m3qq8 7N0oOde2]vU b7#FH6=crΡ~UƶUc2TqurByq}+=ԑM$B/AV O#L=Wy>Wsͮ p5 1>3X.hg : Ꚛjt9BE+ʙy9#.l^(62\@qi^' Ҹ$ HgpX6{K"Ȩ WV U*OjMN4vkϵ{,n8(tC nNzbc9ydP.Ļ[nZTj<=.LJ\?ᣏk^dN6OLT_"_WpNwJJQ[DU+6:@6 S /ytoDq2nvitq:iII0Rz.z wG Y]9ts =Sb6e~HƝ9IXR=Xqp}]s')v ;GZ%H,вp / x?~=l:qiS#3s:rNgtfa$fa$xAH's?>/\BA) DS+bDE`W, Ε#>~Dž{ :h.6hy>{omDNGSn;I?x|w ^\ݧ/|6D|Mfj@EL1>r1Gw9iX 4#E3JMeq]J4fnF`k'<T{Fm2x6x]fD&EոIG.EM TvOR֒n9ABzc>iT5}1>#4-#GeC556iͪgT!b9 c8rz1d) 7p$IcF6 [`Z zOKyC'}ӜfUevwƯW⽞S{;FPg44&<${"SmD1yVQF"{.#leC)& 2Z _) Va:Nç}?`v k01vX`eGATxU0Z\x;-"iS*el3]vy|ѣ=~ \keм-ex-(rTU#=e.?9`W:w>sAqop> ~1\,kk6v1%FdU܂BRBh߾۽VT=,m#.T%4Rt'Ez a|r,Y=qX:OLzc9 w?{N{K!UR#*Y<VW ³ 5zsFQQI _Ѡ%S~q0 Jm.bu"rM:׾f{\r9rePb0TR%jTƻ k5ԭ ʚ=YV9G'.G849놾uZ\{\^ |ً6$(*TTDVqNeqKLDѦB~aoo&2Tv5)Z)on9qi4HFCNUD DSV347Euw% B:)V= CfѲZ}ð6A94'WjLG 8hf+PJDQBȺ:PȻȻhq1;juҾJ 4P4oob{}>o>6ѳq03;3?uIen#*DKJ"mRT Ue'eUՋƆ|Ec"ZNL1j;SbA3wNҫ;i5BբPTEϩ>v#[ܐ:dq*vk}F}}fԊ%MILܲ(+JaucKO'/CŬyǐh[5w9|$RL7Yr (H[H0-&n,NaC&NZH_+i~fƽDE9HPl-  I,mJMaXtJTn11,q%)w\w[n<;k&u>ǏiZ'3)mk{Fh4|̉gm664䊹](Ue]XJXQ= +O|fF`f4YuҎҎhokStuޝQV{s1^mVuUUߣlddmkl*۠&,=Bmx?Σ甇 e[eΫD/l8TuEɸ3;;5ckWΒE[42G'C/20G]<ߝkmÍ X&Ե%od,l6uti\Awjm\-JMGtlQEX:sUӐwhp_E+ΖRSܜv:%xJW)"z,e4!'AaBȳıȺ:2n{Z{{#ْ=fvp:#u^UuzH1 9 P`0 H$]V]y33r~0£nu/T|U 80; ~P<ȟm8}[_Qݵ="2R^pwG,wYy QMWt6|ciEw89"/B.oTyd%U۷ѧ-'9#'!5S"kB4}:" uK݉펹%}1@P($^[s7nO1ax8GpcrmpSpsq@qSy>棠my6F1GF]>Z(A5[ SV a9\=g>ސa"OoyS}˨3d )7. K}Ƚac:$TAeMbIw5т;`4"EhG"[ ⠡+~֒G\]1Ѯ8‼w|NȾgߺfߺaߺ)lu1?a?ܜꈛl6,kv)s.c>T/8Ux%N\KS%nS;ք)qUA+ЫVE~~ϓJ!<ZdP"j4r"[2fJiۣjZLSaC:V`wTo}3>Ϲ:yϟE=g>T/9gPN=ʩN$/Z AcIj[RJR:§0Blg> ݃%|>q+eb-$VqKqoit4QW5\Q5CXZ"JCO/xfE""VDz豜XnKUH]9T~.H] L%0)@L5ނ77kP`\QJN#zQ Vb5GfŧS;=-eo (eD}nC*!|/2zނ=Y:zqLjj0)يD8#ydc е,L l$H%fh[x0 [:t4›ijMxc")2tA dt~U (zl6 ?ّȿ/_+wc GG)h_'?¯K7o0t<!)_XG6k&!:zM_`_tC#2Hs֊˛=hbƠq;Ǜ%`xY0؝1ܙ243zJ%\JQRz/_ 1Z9Ÿ1Y&%.^P?;O?8韱|_?Ü p*0U!y1=V^o+i#5CCO#5B <{/_B%sh2 ͊'̽>˶ǥ966p2~ PfLM=Ĵt!;s2sro^Kݱ[5O*nC,R0W}$/_Mg 3"f-:lDDː O/xK=l>/ |6w~ @ZdiLo\L &|_:e_~C(p(0ŢzYFCZg%~R>"2d40 tY+whSukhʭ3!'1F`A-ڕd4xnq+?]ٻܿgŘl4Z gE!\rf@@le7:[  C #F-0yی]ġ7)bVJtQG2(ҧO}b30:zKӿ=?Wax=Og?şOyGBSW4G+L,hn|r EHԃ@TJo*'9\jSi)Ur_QW.\g 6t\-T` J? Bm}2-tOSG>u'CNu~z@r ,Ek1F2!44Z0!!V`q !7>}c%;E#&嘤i!_,>fZ*IΠBY bY j}=]_oyώ=u(6fϲYdˈz"&8HQ`=i(H ICdWdinᾆz/dn "Tё ;oy~p 1A l͚]sܱe I)L{;5nPqMeTKjQ,=eR6IaB&$kB6itȫEKOm8 v2z)or8 ީWܫ6 M$eb%_59J\VKK!BCjC^#5/s林= ^vHhP;6U +a a,wnZ Q y+k\a5E:1Ik Dco)Vaeui|3c ^nXeYUhWFp6yʽڥ$/sw)]TX B.#& +ۧdnh#Ոw7lVi_pic#@ zmfXo =ui;>N`Quh֕aĬEhfj=a9XA͡s)ސjl=DvZ~}lG$eLZ!DF7,<}F7Y6 *j–UWx(.ےчulݳnسnqDEl6NډX;1W>բGi3OnJ\oko6sn!t-N2Y 7sG9n* 5RjUeY{=acĴZ{,WwP`tV qn!tȚs3u CU߯du5jגc 5 eL KCђ KP)%Zgya,A]#**QbSa"]}!kHZ9nJ:LC"b/el 6SeޛW\lh>D]ΜWwDv3 ڞvK38ޣx>FaKmCXĉHzof46#=8Sy̤1;4yd/' %hơŦG"Hl4^-Ivgڧڴ/W2MdzXկz m(d3,;*  )#Ί,Vf!̃SKT36ξW8_0델yKQmnI8}nw;lַSޜїs7q+jaSP9Z@떌w_pttNɸZr<:FL d)(;@,uFaTקY{4g͹Esn MF`}(*Vж͡A}pWy3=%OS.c.#n%E5>O4E)ʢm.#U\ehP5/?{/>G"0)zvqu+lSSX2 ܇#}&V.y.-h`ʸs{^-=Ǜ+}9o/2#Vլ+O; 9o5ATaZeEX4cTu^~M8\}Y@.$b2dm'8)' rZÎY0ʦzs~L?Csom7f 6zwj52klQo=4;RB]T aѬmtȚVԁFTw|6H@(gHAnH+0>ľoPU\C8QI_[ NɴeRѶ/<@{N4ڊҸ|yͯ_ a9[C]nL+s>AbA8 99_qѣڧh꼥5MV\S\}ϗ01rAmAI,_WUϦ}.Ҭg=Yip^{͞}^g먇n; JMݏ/ IDATb٧vi7z`TbCӋJ?HwSMxGVUT67!0 oA'򓇽o8lO_`g )Le-+jiS`o3|l^`gxWo˯vW|/oF86Ю1]0lkf;usIcc.MkEg`>fLy<>psGMtY]6BA\:$_;w#<#?>~ JZAs'h/k i s(*.c.i}mm}@X6BЗc3t1I}&$:H-H}sasQl~7l!,=s \kn!km%>FiQ]=2߯TVB!31$q#*ׁܠrkơvt#ѕ $ƢƆaD!HMH\l5vI$7TʥlZKakªkܺL\6!ڣX,.a=f~vd@ymlR Y]fbUNaj0Q並&" sb?!v6Drւu,ELfCC]1A(HEĎI>). l:, (ʀp@E,w.d*@-]qC$2"clՆ(Hs4S56v`U-Vh\'>A#+peM'lV!DYs!i+Y XKX ƢR6P)X %nNYr9>Cue<|p<СT4`ffMz=DTwP)={Id6ԕGFX=L;|lp8Oqp 4[x`8n`!Ypvq,Ѭm!A}~sA/nɥE\6F9ؿA Țeg/ɣi@mXyxQOZTE:q,;L\,N.#ˈ\ |:S$71:t; bkQ{Q~W[di:an$\HZB_7}]K۔TsY|]Q]͎Ļ#λYgcXx=˗ԵMÔ>S1`u@mJ㠍'J =CkѓK&)V>ɺr=]\Z\ڻm#=2yGyG,%pYTҧٳ%NA ڣ=&i6%`Z}ZBVdP%4z[E;UjXB&.劺\C@gVuP`=% (":!v ab5Xv`|;\͏?C.q_⩇^<k-+d4[ՠVcD!hfs1"KCnn 莗t􂮻k-1v)#3aLч|\s>~ҴƗCA9ˀbS^kIԾMD,͐IWUIS>gxSw3a⌘[\#&źuϝ_}6V_/8Kn{_d|6GX^*+/Ёfs,O{ԧ.eRiR{Tơm.G,}d4-{]__b3>fx8U?wKPǬڡsBlcnb'C39_n}ф Nħ=li 16c>bBAi{Ѐ3kdU*cT2!\_"A=2'}2;α?[uV 3v );|w)BՈz)¥swɗ{aLӰ43pt4"eIˤأ,ڧ;@ D܏wrs^o:Ǜ;XyKΎ0@ZA1 f"]4ˆk(݆/V~35UF: |2W<,o|~4Exp6(D RiaJbv˶UQR{O{>c tnY_kMb!\FkAUԹ@6$6c2mvqw wGR-T5Pe ZxX.kvjCTF}Q 2aE -YjȷM#i[4 SDQ H2JdB D^F,Lfc"*),350, :rɲ(z,.ˢd!7fHٺȦA-LZdmz2x K *cI2l=AOV%KL)JwZ+L݀1 # mC*bStkO5TKPFi,tY!phȳq 1PCXl4 fmbfƑ9Gl`Ȕc_^3:Szޒfv3,7}Ci9-Z[I+-f{}V.*Mc>gՓmgjd؝ް7Ft Nt:KZBniuBh+ŕ5ȭ1+HQA֚Nz匞ѷg9p΀9]E\rFШE&hUA ~+)GVh}>W7d":ZX۠aSC$e9듭B*[ťj{+%)"2,S#S۞㱙p\ 8oa#pm5rknv a)6%NSb7̈́n$LRܤ5nS6^] qMw>\Qj\)k^Pa@;ԶCԎK$^/XƢPu"RE泮ԮM۴R!;-*8"mffácOI"s.vT3RB/E[,`Š 5A͒$h HZcZASIL l8ͶxA C9پx?T~56>~<ȿ=R?'Q~ٙktӐn4 AJqKF]户+xg҇U2q@o`t 7w.]쒗.-;1UjT٠ Y6C[wi+2Sg3d0I\hMcްftٚhE-hlUSi =_vbc9,Lb&H˪lIʄ`0u4nQR_ZaSihJxXLg#+Հ#D4sGWX{٩Uņ+1WG,=g{.ۚ-+W셷x|S̉<3h Bv[z͒OZr_k2ǃV i%6 x2\ѧV6n''n19/E͘:^];.+ 'pj\-'^wCdN[8'%aM|yA](ss`C8|[}!7'\Yhlj0Ga0.4Eʣ\AMCv,٬;$ͺfݡ|+I1?8g|xpN}&&1y Jy-V=Cdw<9ó 5!O$JEXmlœiO[İAۡ<>ܲGn\v l3/+?Aí˯Ϲi͚Nf]ֲǥ8f-:\|ؼbqD6`m [LSi}2v ʈZ ) ooƆ]Qz`xun5s,+r[JPcn˪QVrdU Yi2} }sb kaHm3FєayЗ}ϓ%ِ"d쿸@qлl. (7CB~΄n/6%W-:3v01 ̀?ȟӏ˿x~P<ȟiz>'OѮݵ35ۖii!Hc[ֺ@]j7~uNn‹)?|Oz_\ N0}Cݺ#1(e-k5uP&cʖa/g|}g9y_}uLU Ui?X2x::~@FSl"?!#g{yoW ^Q43$+ kIնmBۖ$ZmX/,BeDKE[mJ\$C??hvw9|v+Љ7vA`2])jKX7`g|I+^{o9;p~'kbV%=bϽNJƕiNC,M+=I:>z:9rѶt57dʣUD9;GƝ 'Lv aqѧnIx!|E9ɻ9w{[1zvلsOL0]YvX_Ǭ:lcN&{""Dmhk #/rSZv,8<+,_,l6,i|1 tη,,$]7;dm@[.˴cjk;0FoVkeQKZƪZܲ)_4ƶkX3$DV[ (hd!5/ Aq+XEB:H $Z@k_s=Cͻvkk|QcvGoiWUK*Z38#quV &dyMߺVe*fR6PWVxr2Zw3[Wӣay;._I6wk83?#8<ؽ˭&Cw0l: P 7G4|\|q Grpx뽾z6iܺ{;G~?uoR_s&.6[D"N LkRt$b Q+0 ȑKri/-Svk3^J,䩇[艊4DDטc\rxF GQԒu^O|O^c9`3=YP\Bu (3|-Z:o!sط)yB*9Z#jd45"S:1w^{HǝRB0 mRbl2LYQ%jBCKr攛|P7PeE/<ژ^0a8Ta,* RA u{MMkB3؆jz[ AHG&T$(H$&9*3c9OVәM]bi}܁B3rgGx!*}3^zM|~6_Y|!$D}ZbTXvm JH#ld)(-AN*ZmJSh9 =#A61H/ Uœ+ } ۷ Q% ~)[i@2* /зΫPf͌ѣڀZ#<Bn~+Ao%jB)2Qۨ@՘Me֑BT@Ƃ]>_B RJ"l"lMX5:pX:#G 1 D"i4ʚ1*R[*Ƅk4M,idzq`Q*qa*=,!.%(BE]>?n.j[UeF:!O\m}2-]nsw9o63%! YEجY^gW H]Bi .-qED78I`+OrP缿EV+ ){|Yu/-1Ug [* 4ĖJ$l/b}xRGu}E_Зcb-YK-xpٜ!1*ivauVAf 4fFc[ XR\ W9Xk5zY7 e4B]'.|+/o@T |z8 Cv(\~g3_~}C)??;;[[e//~|# S,sᾜ⾴8M^iY 2QBīٮk٭_Q +'[|e>.)nWˆ\ Hi|EReC \(#NHeHT.~\{UYq͎7v1wr-Y!$K>Qƶ~8SwQ9`#MZ14YV+Uu }2o:sFRKR| IL#k4wgӭMLhS:)tʹH?DS2jƊ/=ًO>cVy{ĖŪ~ \PQ{˺֪&MR P(Q`.,RQ#z+v49iC#kjFn(} %ck\4PeA.4@[6^dlw[]萗:]99֜zkA1 svaJܚ[ w4vg+bcѭ0L`PERbXxn#(ϝSajb$ NokȏuIt6Q8$7'WYXf*N{}섽1{_qYKQeEЌM)Ќ'>^gk<ϧ^YTgWTMy!J"ѝdvi VRQVp'VViVlž Y8g'Y }^dF9xFlNU8K]γ}6#Kze'd ĊjgFGkb-1NQ:bS܏< o ,+T q5쩧w8<`~/+LYdpnVsVA_#  j+;dUIEVIiX-;>IEJZNRK)/7?>;UϧrJM)'VvTi@`s/^&)oKL]ƀl_%-ޥ(*R P[:FcTQK& RE"}S&Z^P:.[U8@+2^w^4^腾{=~!??zɟ䓟_? hVFwYxnWY_א HZԾ]ޞM+5>[;p'13ٛ5X;HQ"PP-|qFQNH.ŏ=Y%]̳z!޼ɣ_؃W%l "gP P jKpJp3y)N=3Vu+LiiMVƱ0JPg&J'T)Hiq~̡v1yhpTW)-`[^p+9b79v"pf!kqamʫ_Src5|D)mNNNJ Z{n4ZQDX;X-']swe]۠AEnO"P(ɅFeEVJ5f[,h]֙K6V3bwkxIERJ5CJfL;czᄥ^ئDUtR`xcN黝DT%yH&$dLJVBA NsUQThkڊ&XEYg_g_;W]RŦgSI)``vNJ\R]iesZj&:H4X@f!kTV飕)x \sP JA[,+KcyRP ĎADIk8gcOIYOG|)7O [7^gR2ipT7QIs-l-1d_(j*ee`M@smqnjyHR3fqlF732H_ PJjӘmq]*mS*}bQP"!u\?ޥV cn}9X w> i F쵟 [+b wza?? V]7 >O}__೟,ԧ_o1Q岺euˤz@:YQQ׌E1]&KJ8F6W*ay|,Q,VXDUD mQ8E(R-AEiw+Z =%XgUf ;97c:H!! !]@2Rzbʾ>eϽƩ$-N&'J ^iF6wVnqk>of Cg=Nlq[{L][WTŊVd."V $z^KR/K ԼD7rjQnolx|We̍3vC|uWjyjŽ8cG+d:k:kjb8Rzc N0ܔ( <^.r%KK\S9;3ߦL\TydZr7.4X*u.~s+~+M;M)RBi(HCPs^*Y,G}~@,%eGlV}etkgƴS|^~f9iOi'T+K6Hbftxf~XpDK# 2[̴&3b-=62W aZ!<"5狼f['"Oy;|`7j:Y y[h f0veg]5 Lg 'A)=ьUa)|,K>O뎏 Y_%^atԧڨ2C\dFYtDY[EKR#z. fՔh ,)#W(" Tt T'GNXƂ4Q%v5Q1p/i2Q#4%#G!5 rۤpMg#4U,idV1K@U4$)!|qk1v%R/cU ȴHS0&=>!NNќP\HF4Y+\k̊*ʢr+BC;DE81O%#BL&%Q&ܰHEXy k! f{Xt2O'5RGfb\%XE7Q, 2߸{Bfd=QefiJ 0Ռvv,YjpatN(^щ1JR#MD&SUV2I.wyVLs)ig ꬨ>rlaT%.' lL?ɧtk:))lRmȶ =ŀlzuߠT2/_kO9,8OqRnI#EF@Dz^hvMWL)c-mZJԲܬErK:&243:tҫ^{X :=QEWVYc8vmXHcJ#{GC7s*f@XR3x SKI5`4YW+-"TI g~D 4% cpqٸjF$P$4  L {nTg*<LcQPF%E*^@:p' p7 (5Zk8{a/#R]kDFdH 8jH[COY3RVkkʫcop| -8 Yr1>&?_ja~3 ^o?o)zOm;B/B%3~>g~|k?3V\_ ~g__3 Gf|;d?>L`V66v OeeUrE0Meias]ؙ4g4s+:g&qt+}3 IDATr%XF62ȯtZXcCE5ItaҨN5xG 0DKr!5sHUV Q*&I-ķ}´dyQkcm qHpqhT&Lթ41M+!tUbQ5ӌ[7t]{s: { Zڬ6* d>nNIdm*댲>WɀmbU2c<^SOʐeHsT{.c̱TDK`W !F9P99OUcUX 0H XGܽsbI/ص_\Pyrqqzbh< YJuic&] IfYdΕ~Px"o2w\[efD-!7T"۠g]RT^4s<ŧP͜PHL4H R,&OGG7uXEF;==fsSFlJnµ/-.mt&${:]}rT}=lJz m } m$(s}2`Id9s?du@ N+;8kֻ~Q)/dO52F^IDFX!z"I0&倅Vh"A0 fFt&Wt@1$J]ҮLiW:}f*=I[wR-cNӘA ˸;iEYca։_Ѵ1}kLZ0.;L.g&O1{ nԏ8$q  TVGh;dUl̢r6s}ke}.O%c 6& )*6rT)@NUT؜Pq 5Q($r71 ՗K`l`uN1W f-j}u>0F!(B&)^j%^%}Y-JP9}qT[zlC![uZeuDQ0 >K=^蛠OگwG{?_ZQo[NWs{=~mz޸}__O3Os?ڛodk_{}/BnI\.kgwxxȯگ~OUU>}_{6yC'sjEEeeuaɐp s0uRˉ:a8!(+Leif*[<6<DS$yd!;VPs;3"-IZ4kjb$* b![-nBX$5^1זI0hZfԠʚ:kTKÂգ:ˇ / w4R4BŜט=Ox>lxȡ;Ɛv}JRyZb].آ&7鵚L:Mwy=i.[RNS]t5 |E}@ >V+A@% gMԬ4)@Yx́/u7#^78o σ=c7V%]TŒ_S D$a,cK\(l{I0Է =jW+%=f4Kv9Z#GeB鄺ML&;<Wy.IjqjBk:_[S+I''qI+xC8’w˶"%=n{Dd;[LNyoL*ϴ}R_-%ɂCc*ޛض]]vMtݴ8 D! $$!F("@ϖCOV C 8ݷ޾瞩NM{p.]wUqs@xTvCZXiWW V7љeۗC&FyX Ay!).$ť#okq׌qn:a:WƀEN@p :^9RK%[/>yd>dGs?eo8qyhȡ~oEE@|gY}C.! F l,02OJxae ?~6 &Vw.њ9Z9RTKD@+ ^H: O]c/%M\Cr\:h 9rw>(ю^D.i<l#*S~A:ҩu=pP\fFzOXrn5[NVSzg<[5y~wWd]ԙO6/O?_,g_??5~7kZ{]{czoӄ?/`F6j+FnN)7;wHeH3AX1t ] BdrP^+ PO!P=aQ::Wxzv=q'TB5C dEi" TB7Q}6c-?!UkR,ISD'̯u&Ou*#Abd#F6c,, A&M24rjr j"Y[6V:F4uan9J@jZ &z[cI\ EG.˨8GU;[n0eP*WFjZX Jؤ Xu,T7/i v@kd91o-V&DZ!֜vr-ln76e@ #1kkZΔ=cJKp2RcM0uHYRef|tj(EhX"(T)x%_%e. JK6RXڮ rePUhKd`UJJsywpxWZw`SԸ.|XZQ|N=d1{ ')lΪh )@%)H5Pd\kk0U]$4`)PȀu1l}֙ϡ~f4%Q 2(Y.J)Tɭ}&=&++dT! ]+0#IpFܰ8/9^k[wnŖ1=Ƣǒ> 2n<.V ) 0Y q %uc%^=ݘqX<6 ksŧo1cav|Cҡ~2wgBOPwWL=g}&]3Pӹ*Zou6AMatnTIW^WT# TbA]H:u2ᢇ)R')û7߻"4cF10IeYX-a08_a,s֋x3Q}PFakpu]a0lvYc3 (FlW`Y6k$$lHJ W>]ԙ`isՍ;&,i`1G)aYng- NJ-n!C.PFu`)̊ J($B**e7V iièܧSN3n n3oDFb[Ijv`omBo;#߼13cު@,,%-19 @+U֯)_eo7659uQu`=*%v|j[zZqe(D9${\!xQwe#~103<#ٙ:ќ\qptŁ{ cKX2A%0Xc\ lf56Y5|&F sE1.CyЏKt:Z1Vw49Z$3-,2Zrc{]yW:N1F +zW4BT QAtfU٨Ō.^*ʡF2q׬Qc(u*vsNIҼ3 [DNxf5"#k:)f+chYunf+~rrAz#c5qu:\_ U@D+jc4DOihve7mNG]pyFޔ8^sIgfeةzh0[6]~q|U6oėEmE5-ïxFTU?oW!uw1NJҰAc3a_q}Ơ7t~"~f.[QIq-YC;CiGׂ"Ӓ*4&*,PB'[ 4 uk}X3ی=Fbg/ /FOx'?b1N|k%biI1->x&79{~,d$KI^2,%JԱFAAԼ%A},dv0?8?벞FҬQ±\7d䒽AcC%h|Eu[t;Ysb}kF>brgE'ܹwʝ܋3TWkMs`4tW4$,0 t)mĶXyS2,:kFI& L0ʜx1v1.)/$噆zD (10Ӛ`ތ/\ $%L.G~f0)k2fwa)|I_ŗbydvC;eN. 0׸FLtXwM*hݙqt aj&E94\׆{Ʈl-Ʒ5gj4B3jM6i"(גd,jQSRXzNrcq~߻û?"OߟQBr'>aF{?vݟ"!|'"w|}7_ֿkƷ6|O&O/G_D8o7j->¯[{3nn &ְ^#^sx^4؃_ɤf,KSʤ %rSoYNt<(7:J-*[w"[ϨJ21|[cI4 _$D_6ZAs* W*CzR|ʖH?Cy/ <>)DOo![)6+P+72I,1!6Ҙ=qKi5(@Ԍ 3\qh.$YH3JHl=eeЗ'XLD!Pj-Q+A]Г;%O7?ǹ:}*`#|1&9.Р$sD5UPkTEZX:tce h=Y".rEZѨV9Љ-231mFYRK;!ւ2(}"ЩigxnH#XЋ'dIz\Of"ZCO1{ "d;;$=B BXr4*-ѮK D ^~3AdAAo1\pgq_FeWƸyB^I M# a%d9RضNjll?abVVf$ZExDC+Ս؅1p!z-'`Mњf‰"Ya.μZ7s+QN`r;;x*B!>qn3u_-vTdcc-Dw5Qfse])-^I_*E4PŴsGB'\E aоA ^,`Irxqq(q;+OkyJXR:JvJg= ~_|HsGDCV蔱@JiJ~O|E_co0 2~峟uib[eqqyOsߍkr_xֆxۏ>~Gt~Gx7l>z13kS6|ـKE9Cqz!Pi7wuY57 qOko[nc×wbBΖpC˜Ksȯ:ԾXè n NmVh]Cs0b1&&ONk0hܲ׼&V* A_hխFqQ^.v"H3iA GS}[qX]V:#ԻYVW!]p+J]ߙ\;eD l#D8{1"V$CR:T$Av!1gǼ 9)NkFile $,i/0cOz`O4C˩ܿ *8j_> :D-H8z]'ٸ7 +G2ZN'ѫ&46K0$.1_kέgl=&U&zBE8mn=VQ26)j&eݯ1͂yftmFvTva1F{AZȈИ͝wRNaddYuΣ;8QㄸnD8n)2t-G9.͕6m¤heVUȲb+x9a}PC N}X1ye+2i ΜNcFg0hp M6`uZc՘}LYj.SԼӘn4gԂ5*!!sv哄.yfR)A C#o MfJ򈎠T=A|a9hpY|6UFl}5@oZIZP8UHb @\)譯L*8;p)ÐNvO'o&pqD-l5b%M*WB]Dcټ3t_0H -Q-Xu.8b1t:/-ԓ;a>fӨ-1J1hy IDATkB(#bz昞?׼߹`WP{F<]S2.YdM+ HRn(5?|>'|>O?Ѻk?Ɵ`]}7{?zukk|#*Bx/~/3~|7v{>o>ҭrRg׉Eb (/=>!ZcԜvcÓ o=xʥ!>K$-ص-L)Gb̛gy28"HÐ 1kڐVV1պlO1v |=Doi-iay.w$%3P;F/0O$&gP.u($ܲkԲ61uGnʗdR#mjj@-WCDKAK!Z ZʑT4*KO\6/٩;[Ɲ(YMVerS%ȲYun=!./{T*{ǢQtq?j+'LmZvk[Κ3#s;䢹ϥĥ1( jvt p%vr_h sT|妘Z_oX>:vp َ}n=elI10:f!a }ҭe!XԖ2]tLG7]6#q cڜ'>9HrJ"X^xJx*~>!]_Y=],ى0WO9ܟ3o9joclz\mRn A1rasɐ >+Duc5od!P>t8{.O~!I9w=+~ /0SwB?DR';wTj1W5*}j {NJ#ɵ:J$ww+@ ٵ bvn%x{Z)Oݠ9ZYPt&>F/Ň'<_yej [#0NANWht.@UVա Z{M6v5?w E>qiͳ: N3ptwz[7%np_r\_e @+BC M@!b+ZX5uuM}n&:B *L+S t[Igrgq rrh31ZrY(@x,PHQuRGkT89k:{Fudк||rmc̿c033z:[Og?!<Xˇ<lv+bv{1X@B౫xz(SRtRy%Y7ހJ2*!bHzE#R%6! fHU ]5&^,p8>.<+/pg>w--2w~R4BG2Q+t6XSok '5M$UND*Hu\7(upK+QhCnn0drn&YnN'Ɔ>`p AibA)&XSG%XFSψY& @_ kނ򛽅x&c5 | |)ƚNsB9̙> ܪqt MN<(>欘^njDtV DUR3 +a9a>mfqIVYzo|sC(-N>c|  2b[,FtXJ:F&-+I1h+KNZ/92vx:z%Lrg Y2 z݅7P*ft L>OINSr&uKAL>d=L;!i$I^R782 ?9dVBjbPuʩɬbl1m&[35$LtKU$nxH<'Ya3-v9i"KM=xyykm}\o<{oo $I24u[đK:ϻXljr%is^_8Wl4 W>&sb.[Bë kx?%Hg'ݒ&W7CT!>bK# =A.N'=R6 YhRZpԺAZO -H ҃(P$v] -֛YnYn&>ei2-<+`9َ́QZRCmPXw=o,4qE1gC\&kLҦo3L.r8.8+;L>GI J4š$5%\{D+hR 8)ex~#L %!93=m U}N`%$7=SoTA 5a> ddN%Ҭa+.Kqe: P uQ]kTK+);tz;?Kj{+jo-[!9ljhqIM폩>M8Z1!e/7t-5,R@Q3ެ>`|n` F!_k~ؾ||&+p W`hhhM蚣#DIupkwT 2z[@9l ,.䬲!>[jpC[d6b^#p]g79N0.[ , E '#A5=ʢ 4؇rS5+Vao}2l3!=.VP3.k>A)w/N$3~9nD-o7~ko!O.yG'<:~;Ɲ6cCJEHRʲbz3p[^iufl~GjL&jQ5J_Gifxhv}J+v&8FD*,lVNR9avZc{]<) j-QKKDld6зɞѪ]P3WT =,Bdӷy$nhKa6SfsJ5#f|P>Ւ䆓K=&].ǘlgkADwvnNV8WNWyW{IWۈ  *)QB!G'|h9qiIȲsbihr>L@UQҠD C*% }f [xb~%dQ|e\4m$JjTL$tȤ&!jʏpϴ SP 81%X1棄nC1o'sscMXsWDù8eyUEo9cޞ|;/ }d)=2`Vj# G,&Ү(TR4ޛFyzϹKw&32URi6t? 6FխJUY+\#z`6H7@=.D|.0/=Ð%hAڤ6/,brI5{IS8eӤfЩ9-VUb%sup'Al{oy!{W4h6j^yӼQwFS]{9[2l3<#1S\3SɀtoNg_1<飯9]2Hu0DOH_)щX2@J6sN6/Y5] A#{'x2*;+';"P+)"ڈ&)){?hl-.LLe۬MxTBG*v+cQQ԰DE;IFgͶjanA$ e`P:uSo%\G`LqڕmęK*$rtG5jH;> wyS@rcO-ImHMF2g nW{mybIHUXߊ+z(j} ݢMZ-gGP_i[9(n(J*EQY4Y2dؽGZ5QA8}RIadWW0!ZoB<!wƘ;{ Ю1Z5F*TK 2$< Oz! GO22bUe76ydS6EWߙ7elP <Ʒ"Q4B B*zX%]^2ׇ;,8MOO&LHKVEY25$ ]y,}7t["zd`(cgnMτ̰&EiPt& 1N]nNV״ RŪL,.7'L.IajY`9(26):IB࠺N >5>gQ:~cJD*r4C!,(N4)j pQHG"^Va4[K67`**D (-l,cT. %3' 2ﱡMR{]pP;ڕ B-v}U] A=="| ECIrB !̜g.iF]l@(Dp 7Iqݺ䁅Ut5V3V"7m:8.(I zSm ʍIifi_ Y[<35mEG[E *S8tYfm# ,4 6a>Ia `#l6fUuY/d8jp4F^h$ң . ]V ?#H]R%RnxM&Y a3ٻ Wr!r!K.u=ijb>O3&yt0D͸ Mb̛SVFkt4YcȜJNX[rcQoLⵇ4kI4'B6HaQ ˀ۰}8F46yۡH Һ܉ +8;E-f} z&Ê2: 3^ϟbW%2ۛ i?;MVn&GZQ43Iv^uX/z^yT5qe>Ub).8>p R(4P[6 m~U i0 #vCyeqĺցg;>Q/N#PM-EER*1̊(muIoX>KgҀh(1Շo2m  і-/x:/U1kɥmmzhri:!V>cV{GrMrcPi6bwL;&Sk;F?Ή"4(&Ed4n?$DTmUm&"`8.8 /8]^p[qޜrޜ56HgEx'na}tuO9>%څI`oMt@)%iҨ"At4#fwg5mŪr9`pfXbn["@4C2G0cY==sfa k0hG5- ~%rLQ`x>"ZdYh V۫ W A.$х &Ds h5aE|0xc.ӧ jDz2;ӳ?[ypuydr=L [_+f_"vYF,ԘJldɡКsd3ilc^_<#=GBZ ]TVMrfQߙ$W>ŕa9G -of yj"׉vq' IDATV69%㳬:'橢y x Mu?O ~e;^ y#{ĥGRxܾ!Sn^9s],^,5VZ0h9 &_ϸ☯/ xz zlf=dgu[CpY.S1!4<wsvxYl7S-M8ty{}yP ?u(%Q`VT#aeM'+g1%ٖbb^S-tO'Xt~_*CAk69__Q)A+u%I*wܝ;O ?S|ίqŒͫc&2 c\+/W1da~؋F "g'(_Η_iA+^;;ߵOѳz%ܝ'tR`6US S}O,{}298z#b#U1w+:neȪamsqWOZ,.z z@UlV rհW^s`\_ri+uH)BrditYaMcG+ހuaC}5k*Ȱ+W>7-n~){&3о0"W S&\ Mmw( j]" a4HF%L+7<ǭ+R2eFNb7v)w>9-=lc\%^-Q(I8DN@ۄQ(jGiVL+00'L NȽdlָv!1~1YWCdѐW6i6YmS.[I KfŖ簺fhoCEIs q4fЛa"&[Som@Kv;'Oq˄qޢ*򖁖Y(!R;ܼ哫7<;E51ԄMա,- /E]xrhrxrGoZ4 I|LѸrgm@)}gt[KI6:aК(0#+#-MI5Oy3-/|VՈNegx#qa Fkrݦr Bi ,Әn!.h!J͊$2q3?:Q gܓK{9dm1$u<R/uycecĞ}2tb!E*״3!Ta9](<v261G\'nYUєm0P4t) jJ^ӫCK<#.лRлaoE8VECU$+mfse=즚j]oG0I*kȴk<4QG{e#-H `RE5T(2$56.)9'/WtzK]|d4?coq` '_-wR)aBIP5l6\$7]ڧՌi5&vs»'ܭK2x|ŤK{ị̃.WaY5җ+&r#{:m:ޚsˤCoN3ȑ' *臵7ZAf%D%~ᝤ89[b5 u7]!Z *(MOPtv1 Q 3,ΘoOh\E[mxu n4+zr|?yN=6!nyr22 4 Ժv[6T;ig%!5551 [&G֡ O)^`(I>Y>Q셍8Vȳ RBZZıqCRr8fZMdS7o.6uĉqAe cCCMcv@ n0TVeA3w?' kcM2qƠO7^3ΐeL;+kjCmhk|67Dh83b% \OfƪrN_ԘJRcUM5bS )KKGSfȼop9$J}'I=A닱|=5(K[fxvgǸeD٘+0VͪW#{zw"\'s,ČtAZ3!nȡB U_L2!U6aR;[wSN03~\֟`6h",ڄ-7-66xA,"UJ k]P9)ihCsI[b7)0cǗyyz_ {W2c|}Ck|㰼Ҩ̠X?N|2鐍m@*A;וko8+,lfqmY~.*6Ue}pk"utt 31]섟ү' qw[szDYY$E5,Н*)czjP_::ni[ slрYu7<5_3ӭ%&+c"S>f+EVN\{3gf I­ kؠLLg!5z߲My}'kچoT F.*T#E6Jt͸22b.pz9G37%B$V9U";5bS5[ c% kP|{ 'D_Zx@}~`+  Ė]Q&q.ڊ8yHnss}<iK>j5Ҭ:5kպ$-"gUwk4PBgw{LKR呬=7m7tDL[CBV 6M53Ii4D~1%VRJC/KJLuꘗs&S~ ȻHt5c֊9e1 6a޵i$M~]a[ԒDe{4 g;%pC|7s"<38֯869,>Q*"EsETn\s^66Ϭq^b Ʈ|W (T+ĠU 6*0.qDoĴ-niuVzkF)=fQP+q Q^zY|^(TPuB hɮ'Q PjI)1ҬVMi s sXqc,!^nM6hI %nH4&=3ϐIzc}gFBlvw7 `-̴(  TTFS`9vT)n5 ZӏMexAL[˖FIGВ[|-JKoxnD5ZUnL]jiX&gX2гYHjrE AMڡ-f9`Ҫy  l5VW]¹oOZ?_ { NNPNUnUdM#0TA}hE!vO=x~I!*ShB~l7C+(D B 0"9qp[=ƈ>fe'G>X^J TOCfc{ș1̊l̪{VuYUV[~MbSmr9H' J{J';ۃ,/"ڊfIb9u'H!u=jSr''lep+\#ıc+1hZ:EXFg-H5[)׌?atKy|ד#z |L&yf3M&\'\'Dq +.vɷ3OXe]Pe:&oc{[L\G\'\{.0NMfM1!9u]+, +c@UdkfA*t5eE3.:%˒ܷ(rl[JpN0/ܲiUfـVS! |͂3ed3zrΉ|$ he!#9eޒ&:9PC5c1o7>'lKgY=_nX.uxΏ4L y?c)uIf8GZ5N/aTNi[--SwYDF!]sxpJFcQ->FyL&a_c{J GϚE_,w̱2̣ aɔFIBl DHkY3zLZ.;bd k9g]2J%jumz}8880 DD)$3mVz J*ϸ](eX f ;3-蔕N|:dX=ȆA5Y8ܳr~N"BEh%6%D6Zf O#4jTGO~F*a7чjIPXMM* J$=VzB<+KܿhP(XЄ )v%VV҈ 0<'|;W3]MN=iRɽ2DejCtR"4co}Cklvη3l$]A?d<_1QŨ|ԣ p`$HC"&gQ` >@ZyMYqŋc13euDAtj)d0^0Ht i"w\u>7jMNIjKV wQ`޲ݲ7ɀ/3-fﰞtiU[jAY 7hn7=fWg$Gs={Ͼ{C& -'91LweS)X E gn C*@KJ 5l"ǵ^3 G%=U2RWr~?1ڭU":Xl{tWWyb.{֦ o}K9i]ʷT]25Vzu|3CF(bZ,9{`s~.g*#àD|*1(hX e@;ycf'%dMzb~vqى>cRb+HMW-dR!kjI KRn{=|݆ ) |~<&yϮ'V ޥ TK. 6$e9&gL3Z-MAL[{ߊ8qs)-ceϕek8 o8ʮ9pMr1eК]njN]n9 Ҵ"R,4E\$'": VN#cs;8^_qx}8' \"#\"%S ̫hMq 1`ȺOȤMA~}c&|>9z?2pmn1w=n椘@KID0`'Br?U]S1 |pk8.xI';Fy=z̛\p& IDAT~Y+7KA[L7d0 9z)x?mډ>@̝o$m1^oA_-3'~+>AHן3 n?fM|>+>`8H^ ttRQat 9ےŢ]x?ɓ:,UI1Thf[KK!uE9g刺/_3ܖ1?.ƾȼ fbk_j?$l4uN3N zւ5|}S97 Em׏QtW2K' B\$/9WYRS5NCt'D"-?U<Ӑp3 }~['z`@^-rI&q"{~J@wk[5e%.[KHV^p^pKK "t[$]eTͮʻcitZI\CE!./Ow^>p[!n nY_GX(̨GGx$*UUuUEV% $8SPȩuLI'rFEM}[[ϥ(Hvi,_`UO-/O$0:'5Rx,>w֌{sƝ2#)m)qlu_)/kF횞43p!mB!4;ZFj-;~XCT@U 6͐S1^P*"oʄk,R,VREۃӡW*_j6.0G8%AJEu"蟬jr]j攵f@ \2LH $ʾE jLT4un1bl?jcn*K4Y W k:z)-+Tr bDdn_-&snsČX3̶m "a'VzU{ʺP \ KKMrxS5RTHB&)aPZ*4RҊGYilv}6CE~CogliBԱM9!NJ$k#,#q**ҁI⛤V -3*m)H{&[ˣ9R9':vjK_.IjjI,D! {acNH,^64sIUhʱNU ߷oIS葷&#2tPIck{l.^B,3  ~˵w+#:e[FtM@7ՂPH^P$a"]n%YڸN_}$.T*Uc.W;(f|_kZ= tg3/p#Rr{&.k(N-̺Fjl|Z,iP#NGdIIn09iPK*Qv 戲bKk zSzkb(_1,XeC;=b}A{lN*xW;aԬ=/OXAʉvChhnn:sQMxR&MYb&%FPf=Yz4|RhL{ʃ9^!3t8ӂY#S儇rceeq=M"ʃi.TNq)?.q i7(V͠blj\oa)`,!ĆE[ĵI[R  AQ_פkta,LS\ o(:Xg{c@[Ɯ.{sxJsk5t&(5B(J[{gyg~bߌo(@ 'dƦHLښC `UUW~ݟCG"NHk;Vemu[ѭ '[~Og? 8nohIl [ܼ~%x}o= &?\UὍ9}{ǯxӾm?PZ֒|v)f'h-js/\)Ҭ)ui2k8k8kpW L=٘ q%Q& bM*;K8 o(F]4eM'gRX!K1bt *թBk_/ҟ@iR Bk Gs i_0RW挕Yu,{unc۸r;agtkγk̤;mCdG)2p5%`bpIu4Z }cLp#?BF %F.߫ĭ@As镴o8'w2#uBko&vh> 9'~wqssF$|vt%|&:k ?VI1pN ssgy_.XRaZY#2Ij+"@%* q!:ĥM;],Ę`(\ҿݲh(=cfSHasw]Ke5̙N4Gٖfށ!\B.R*umABdSf!EV@*HAUJ4 cbID(ӊ8OLXmݤXuB m/ m!0&)WS;41!6DsԶBȚVGƘZjVqСՈ`o\3ddp͐fqqa49S<Èsᦻ(~ n>+:V:+5hC%z\gZGdS(1 }0'6nm[xE[E~ǸfrS1ʒ2(BYV#΢k&ق~l2Z)9> 9ŲL3ôR,+%UQbsN;ڡV =on8Il5D+\!m }sCO,2q'(qKĎE48D45Jՠ-ynf.A.+g@`J <;%P)ԟE߲r 2 DyxsW[TU;DQ+6qRqԈȹ%M|wCŴ30U-j) \7(l,j@9TFUiW8MFN c[Fcz{Q̂[d$-_*~l7}vO)EӶՈ[Ѵ5Qњrc4@5I `ztYCvO:{:U@[cކw̹gn1W,% M. 2)JM!QWϵԇɘx ҰCpP!to'=/OP.x^BFϫDU* m٫QF "ye O[*qⱣK:D5)=Yh}a<%펌q qqRs$|gy_XW.%zrEd2ww w#9wwgsjKj[R[ Ia1$G9UO%xj3&A WE /B&͚yuڱA31`dPq;jt $2PAx HTG*5na]J**; yKk Wp+OyQ)%iaw vC rIN:2x\&)lIp_r_r^ax/Ѣ+m넘9VT^R4qp|x肙@>V vO C  l:=>t jܻk^WWiNQ.O)Knc&,FD:w+0iW|NcMF蝌FNVDC! #=ԣ u_pyé~MWJR5R\uX SRҤXKx풭m@i2жtb;f`VeOwǿ m=}6X}t@5K~Kh\\4/LΉCN1IF~ tM,^EFIaxgӎ՞SItxh-DBROySs%V0||%Jk1.zhZ Wt"!*!1†}{jhdKxWV?5g3+u,<(3s6Q:F/GN ڽީw-fx})P;(po^p'>ԸN˯&x`9"3Z'f\/QOLTLeG|_1z?l|cYGnÔXwR5;5lk9bUYcKd|pګ^8-֓CA%7*ʠhM, f b|a^8qU6KLykvVWܧs-OsS qOuÛ?pv`B20ͪn/sm~Ϸiux~[1 G܉;ѥ`8P9+7y맏H9Qٍ|n`£:Z/ -0ܭ2ݱis#9KAæeYLx̎xHxHCR IUIR(v0d;׌GNm/F f06 B9LS)b]xm}fӧАfpbNή5vuC-0l>zÿvDt|kQ6b !P^?[;^mgkW!>E[ LL&O|en._q+.޽E 2iq_0oMT,4 zo9o?qf\2/8*L 2㰯xv)tM5¯aihyIzdGɥ`@Aﳩݜt5z])azB)Qe_=rOڣ%gW^ygy_pS1aIub|y}@ŒWDT4(d]b m2iU:m+)[ȶF"&Cz8Zz&iWViNb Q"C[`ԩ,v\L%C-^aQ Fu.hf%j!1>U~iS/F&;yBhz4W+LЂMRdl9OXN/X)#I*iPԼWC 7r^ҫw? MKͪmAmeF VPVd%U%:l{V=]sie8vE򳣮EJ .1N5J\ygyXd̿D(]cҹ60:>] J!_khP ZR*bͤX0=yd2zb!l!dŜw/p~c1qu`wb$5u.)zkc~x}sT@ss3>/Y@;1h*TE^7kb IDAT̳QGW &=Ҩ˒J٪:u6e/VzI+L`+ n#nc#bp]>ULJ2oP 6{ G [,AJnS6Sz/Q%j@srv[[#3LFO;_s3:v:JL`r# A>⣏sNk&5S;eE;aU(4UTmUFԊý"Z٢(%>fyt6-e-*]\%&/IүG*Ucmx)GŜOK#BR!K+)jw:ѪRMк edfb0͌`Q䌮rX eW.WJba+}6ˮu ?08+nF+ƎHX |E"7Pǣ=QxLJK5yFl.ey,%7gd7 {&:j)U(vI]K( v;ڽ<+ƚa UB3HUHuX#lў`0Q`"a)*>4$ꏹkj:DRcX3ZN3<3o+!#4 .~0mBN'`shFUiVU')G|sW9+aa,.H7~/h\IJ &l]dې&z@ܯ0o ̫;ˍĕdH.TJ( GeՊ//Z(j`c( sjթ+Ɲ'a'eF@JroRyDZp8(@w+oo q[ЪP[T(ZbnWL n~? r@:' =A??ה ;4?}s.s3Vƈ}˻$i99jZ'}? s ċGBg N:Uh2A47S7w ;|6rM'w  2BV?/xCWOfׄMD&"#\QV+,L(-zͱzFkW$LkdT#\k'\Ϗi{ϑ{˼sTydMx\/*^G }%&zv\ՈkqB۴t1ُ MV7qCybol4tGQ"? %' 9R b}iEnQub%!i=VC !ZD$`Jh.aduI@&m'D([`7XF\'\{'ܗsWsnGCش ߔ Vo,wc w#Q*l͋{NQP R4RKuR5굆mG8~ 2Ib45ѲږT3B5%N5T4T4'{F5v0)hBvX1TR<`k1~ $vص= tGB$ae!PsYdHSv[]% \}HXԼ&ڔN[ $5l9k =̛{^U{>ɗ+l>XVC\\ŪF%جȚh!K-\?`M#z%+6V{kƥz@ġpڻL=rZDT"!T"a- 6#gTONJm >e{ )ڜSIp'F x1V dS JVSf*kr9=:WN8' %  qS,%vMuLS ط9ч5Ri!6"lstBʮN,Cz!.+z=ۀ^-c2C-ϝQPASIR')l'|iD7sqߓT1H 5еcZ9# D"KqFkA`Z3b͢*P YGO);5i`.+k}wƥrʲGW>CT'ߢ~ge&q`.Yc6D{!ݖv&h[A})* t7>JuǕ^FQ[|56)\iekĪ5dP)Ԅawɹofb>*5Zf5TwME5)l )Q uK*%bJ }snOsNmIV46jmuLW8o/Cd$bF̹6u&{;{'>N!Nq=zEz<1f'&3<3 b_s%(/C/:[N@г K s߽5+0`.K]9Wl>|LT;"UUGX$916ppHtxf# ნ 5MRSPFgaCV.>9dD}b\/xYsytB40=!Z[b {JxTjPch(B $@ 77{üFHvJ,kLE$' @>0nCXru#ʗ\w~c8"ĿbHMc3?܈豩l۪O& {`p78~:<̗i([ ?GK~m$ P -bPs7 vP*!.K9d+Meh-/ԟ8Wp=AC/h{S͙fKfO^W973'&aSuљ{>[GntG[hM- a6x9Lv9?R?b9c>D#bGZ,c keD 4%k+$D ) $EkIJAԸ~kv 5zU٠QUJhhA)B*iuAI"-&]*ELGzO[k|eQo4VA|}gNeJ*UeDhxG]gt΀MϦ3@msB5"medE@QkʶIb} TJ^^+EYf84AjۇspoS:p$N|eQ!iV嵉hZJth9q .z$cEB3z@\yL1;٢Ip>\gkSNXz(%Sm2a4*,3GyLגq!-vbK ф'O<OWlaϗ\{Mf?Kl ɄcE_1꒺Ј:Z;evX0ѭ 1;9a.$0B|=$#46=c^x_Ci3a%{, Q|XmjCp]_pSs]=#TCl ֌DP@bz+;ceSD?Q`붹\Gg\GlNb 8dv=CgFF#d߰Tz,VQCPš@^(nzTB,$jR"](: yS]F*"QhJC@*FSF*IR$KRzԊg[|q}\pP 5G sȱuˉv1WNwC=|4._:ZZ%":?UAJPuC-71%r%#<~9 Q)KspA:mJ[gɦmB&)E#4K~v_Aıc\+5#̰f}7 :a|Rm.'|75qa){̚1r̬Z)C u dہQ {$EEfX5ee6>QQw7Glc9 4UTB*U) 3"|P_6ާ e}NͰQIO'x_/^wPk(G5|e=7 ; ~Äo֐S~t=zt-'n!|R|䒏{bK(|tJ 86yd#G,鱕r4L0\?cU?G>\??/vĂ b΀w97/?w? -R |o+Ayo38.E-R Ec09ܣ8 @ `n&au`lO]kD\r-/X6g Syˀ%k:ld5n9${ |(]𐝲G|WjkEJD ve}&l~^k%UJQgawnQ:Cþa2+%܇'<Ǽ^ l >vSwWZ0~d|`<%ߴf(d/f" z\!Uַ[3&#Ίn{bTFU`F]m"5 4YUQECJǂ┦RYGܬ[mPeMs(&uN_og35xH,u:.k|"Qrd-Y0eUסi$ff8/q$wi ֊ј1BVLp˔I:eu.yҚ`$uȩk;TpR4JOEjF###4I,}betY]c]D!~v\~(4B]Xn,ϽGk a+HmeXt5lM{Ú1H]ıI\PEJ*j"1 2`N&-%Ym>*d LUʭɣ1A^;&Xj=:Gd J)Na5JMS%:uh dyTFL<ҞDUTBq{LR9^FO,dFxjFT:vYﺤ̓r_߀՗h'53kHfY4=W:-c+)V"t4ut@J@v4OXTAI ){u>/a^g? FiJn1˽E<ϑ i4mO= FIj ʯtSu0z^(uZ鱾{CM0.#NL(ƤؘB}d>O<į)V1 IF! *ݠ vGk^<|t4@ڂ5IԵHU `@A0 h5(gJ30OsIB1hTh]Co{܍<ڄvY}FL#k(~.9ndJX\glb*Y9bZ6k?cY2cO%pH#0eyW{-'-qe"Dd`J}%ȖD@$ rpB]HCTWwn:LhHD+6-6bCCNqv x[\/I6w)t16s˩(!~/#4Fk:yN<_Q/1e_PH X03ܖX%]'#bM(=,TnK>01QĶ3Jxf]I}ƻK޵_mFv:mڐF*eL+}-JQE1cHNwtdG+ =~+B9jeׄ\NEKLY+ҖE-SqLpU4$M"k} h Q ۓEK'KKA uePɚZhHMErdY/3ֲ钘f'a0rs6{>KquL(sᨙr$L)]wFUXj}|eϬ0k,P/%ƫULS"l-E+0%T*(f4&d*J`16:ºQ43g3<;x\OA:4\D`9Qn8Uohw[`dn188^yλ ݼ`N1=~wGzW?XTMSk 'O<O+6~%BAm4Qy-~_h SṷrzʭrBA??]GE @yQ~UM&0zƚ# 4w i"&QBcTN[Mnڔ3& &)o|)~L\s=K>\|:.>opi|3k{HqxPO}{Ayh\WZ8`9&fV`n y9/ T *Pp bIh? >w;~g|8N9=­}=c4_t0~t.kTUzY\X79cX"b u/ SC5S0g g̋!֠zԩ?%_+[/dkT;?ޟx?|v͡~ i{<ǚXIVI(UJ2kNVA3oxDf@x޼7G~CwstlhyZ x=wġsǏ }kTQSF*EPF* ĠƴKЌaJh4TL$m=4V֧ ۊZ!*=$C%"Vij y!E  ]9԰2N}b ;[4ƣ9!(ߟ#!Y)(Ŏ6oۦJ; RÂO<O:?Mˢtjvz)Nbv10x|QN4V痚2R(cq)}Q0;r9f[U\T ~H8kz@TdT0G, GVdCATA]ԅN-RYn̊ NWg\\YEOޱ@u+kĹ@ X$C0I4EoHue8IpSωkmݣ(M¬R:)&)q ݬC6]"]xiDX364@d r 7 r$L4m G&'q;j 6K|-4lLe.M;LB[ =@lluN :ܣ{Ӹ*a(6aQ&f] V]0.Og ]k ]Z5X!,Cᴈ+ ت ZFhMM8XVIyG2P=vQ)6DM }_1\V-:DA@be 0 `G M86QXS&9&jШ *6 nwa$j zm^Ω\dxOxƘl#ƑTm1WE ϧ/PV XmֲFE"t2`-B{J'.q.BwAOSش:|Q) U@,p)jܐ&CO<į_3M)Q>!"pĽ5bq=gd[Z%HUaw_\X[Ŋ?\\X'6M?Ry#eZÃ2* ؠu`>o5ފéAys<5#6xMD|L3'QjcX{dMV:Ftu}uϹq˲gꍘCJ.Kv?p '&ݐ%# ) cX3w7g^;bMecDV8y_o Ė6mlp)QXevYulMS,Sw£Dٚ!ϢO\Wnn9q=Г[TW.~&4HЌ@A h+#Z%xQ410cS{(Qйx&aĿN,ĕ˼p/'3udOQU_E'[N;BcY=Avhk{]@0aZg |>I@61mʹhxBOKSuʕ~'knzTFIIOI_>`j MW%0]QC\!q{ rL"j 5]ORTSڒbqUW9JRC dC#+;;D 62 E|c1))%R?o6cXnf9)6SuO4/ˎmʙN.-nSd*Xe=^Ƽ5`_VA Bk0p10\aɊaU;I }5t+Zꆿ7~tg$m-m `&]pF^<6)-';e4[o;L(MФLbgOB|.1o]W,1;W{ {ycڱl%AaWuO3VUUt ]e)rZc[j zGQB:XuB'B#%ech'O<į_3ӢVf@Ąc=} l<#Ѿ jD4?D85]k!bEoŊmBueZH/l{{9QQ !8d[")`z 5ʹF>w 0yRS;Ș8'[xߚݙw&u"Y ʭA,\6!]8pU[oh fِe{݇xiJU3tg-+/V[QVgjӧW*鑙6a&a zK_i3:JМ sM6ŧsZekI:6R?W6|{?qf` LqBI =vtTQ7*uR5*TѬ*(e8֎Jid+|m|:qVb')vtx7KD =PyB q\ ĖGZM6?y#/v[eQv5#Onj:c8] %<(}K0Ճ:m>c^%pJejj'|SgD\״5_0`GD@cuRD5J;gzCSk!9,!Yj6icD8H#TFU #6C8<5ZvSN0(CkuFgM6y睏9H}kοw7 %|kk<&܈sGle7ˬϻ%F#D^0kڭ5R@NmcEDkb[k #m!ZWiUqo|WH_~uG^+?alsdseL`$`3g r@Zz~hU/Sd h E&3\2l%+HE*fRgf@iDsJ#QE*NPL(LӠa$~H7!vt5=>( Y[yFwH7.![:D PhP!SCAU/&fݸ,}!M*0VDC%2,2 e[{ iS&}b>Xaa Xt#aseꡯ*:5+ '7$s*(R'eE1 ] J^{zꜾ/GG%4R*UT*nliC[lqvC6Ug8IANk-v6im36cSURC[-5 M?iGH] 8c6yeal o{}/0% TI6y@)_$JRyh"qE3Ps>zKyQhc59 M5DmuUSSRi&#|2g8''Ԫ&id6B44ba]C "uT`ղ(J$Cdϰ KЂRhN. ragUlUV`+8$HBh@ R Mڔ&ŮS*#ihJSӔ.+eM=|M ԙNH.@ jkgYcԢ"/L!=vuMaGdEaԶDkVA*,c󑥂Yd9}A lc eQkZjVnr-np:MޔHJ3g< očvUes0v$L"^7Slj^)ȩZ=#9e$gHs// !QlAA0aYGOPj#5aY蕁Vj@I%U6>& l|<5K`_ ĕ1fEu]leRL1?)4bMG(*UmfaU9U*]lO<OO5~g'jGo MASXm{;舰v|ŽϾ*YP4*RTaC Rב>MifP@f,W qp@kQ.MAԐKqe7dg &j,d?oUbF[v䄱G(qq;gXL{MT5O?~= r c.q%N]9ނ`/*HUe.Q푗&M.w#7d:zK%5Z~a!:f'eYp5R.UVA pA—fU}}yF{sO/`2\,.(y0 mpxus cT u0f A-"0g- !7ԆJKߑvU$l[,]Kw)>ewccwe1r*9N"B/w [Uov1&[x#vωP< 7qF{knk&*48ܾ NR4;"LdMv\GxKNwXFaܴNX]t@K"=Aʗ:a˧Z)T;/hK[xo.X=fc4B<}- CM)s"^e?ɶEγ#5AlĖCQDkUjSRcˌ~3Ŏ0DZOAP0RhFIwo-菖-SX:&`c:1{Plvmm̰ FѝH>R{Dž~P.5iA$c';!eXĸˈ};`iD%(]U2(!p'x'~߫'JM#]b#]Ƣ~TYX|LUSL4JKR@lڟ_=gWi:2լ0Z)Mi:K͵zd*-JY,D _ k %-c*īBGuN%Vm !TST EPl*Jyi}o1%>] )%هHw)u U1єP~5ԺN!W0,j P0[=%#NqZsZqZ[ @W RY&mbaUXU=U}p>r>p=r=۬+:)wcrOg 0rjRLM'e--!%DP*oG/(GSuR#>9 eWˀ$ASxp{YJ󻦵 ᡞJU$䰻_(2nn" EcY >n2-V;;;vf3J+$D,k$: K[ 3bl)Ɩ*$2zrreء\T%RJԁ8Vb7B>?f[5jQs,{THJ!B$<3CdԙB#jOQ>xW<$Iko*DAwL$??KAԂVImжL+yU|Hxxr81koxU*׆T=wX-5&"h2ZYrblx|{̙GOzF>AԤE8$Ch]M%iMė垿.S" `h;dF3KT?GUm|T =sG]*Ф]Kl\A8x< , N\M?Zf̒茇~uX>(7œAS<TB~|]B3_x|R6 Ƣ4&l uz]^WNqQig:!c̓ / dQQ}']^x^xȯYÄ_Q>#u5]QnzD=O.mq&&-]-;.TOR ٥',V)bInE=vUJ))R:!n,ńm1$[ -J\1)O]bk)=-QcVnZF#}(W%(y"Z/+ o迃ou IDAT?4b?DtA#b%G+$jyRAK:H\w9FcT9FQj1tI",yw5_DEH[K-%`#5$&=vz3be):Q+f<|^}!rҁ8З 579"i9ir*?m$!q:g !ԝrOn W~E E+Měkb!ǐƔK<հ+Ȱ9>?ʀ: ]Y$8}2@U kԝ @Z #$: 705s6*24Gu;_ƿ%MMPIB[1;>9[*Q݁#_#H%vСRUbfGDKC'$8$2MW-lȢ9#jT+]'@HznfmFf|MԤ80nR:!%J҉;Lw(Gm_GImImg.8woiO1NgmP4&"SbJz\ka1"܋DHxkFG [ >}% f YNQ%{QI`.\8{YP72}7 P(OUL/\" r %U~>r5q2tDhD7 NFw5U1kObx"#-0I1ѩyPꆸ(:b[~C7BeJrn jo}e5ЛQ[J^5j^# 3|UD!.pA8$uDYa)1l\L%$EKHӃy8](٩έ}NfZDGԹD{7LKƇ{6m&lRa!hMfPOd1ϓia _f84P ptgS4x-aR2#ٯDCDÎ!eq^k$FRk$Q?뱝iGOޚk g109,~G |#H<l(+DS*PA茎HKzkBFacTl⊸tITwSH_ 4BUn=$DlԄTt}>)Tգ2dtBu88K$ E'=v4C[,%JCJKĈLsLX*AK$vJZ,3^5/v' z19] G,S8p`xR0Ip`ӗpI$4}I+'NO71~ސmuOfc(rr0z丄DSa?f%o|6~δ^KV. 4@g̓Fw% _b=aI!#+ [VSV6ޥ >aEds|̧|5/o[݆~QcϠ^z"In,IkHFK<31FcqmrD#_o} Zؐ6O y-}~`Pc bTXJF Ȑ䆱qww3c9Va9f*!;:71rƲ:e2-f߬[Vg坰ml!fDwqvsj)'1~q`{6֐'ƣ?cbjiϦH¨+!`w=XvYIc:U3d:[e4;C7r4%G2b\"\Y'OV$õ"9#>klC!0QEo?-.21s*=Y4Y`)eS)")^"!16JJml+fT!8zB=-9DP(ⳕOXJ3L=h4UTy~JuHpVEdRnL y~ ޒ5:ʶa4N׷icƐi2!>73& &myM3b[I ը쐑["T;Nt!;;vŤ]ru|P:vƀmPsyhuA_,',ޏY1ͫ۫);-Ä=x&u9#  /¯_;N"=>}0@RZQOGяZVH1IBhS.Hͭ9=A)8\䴷*EaV ҡ{%a$'~-ی\.xuzo΃eJ<'b4rns:[pj/.FFRܭ^dMg'OO{ »'nV\qQjgorSd(TB |$Ӵ9ZW!-(ao돼ffhdƟ'~5IGLih}!r<)ĐRш,9њQe*3>frrwb~3Fɍu|ȗ|rƘNnf(M;pmc,-I|nxfƓ){89]ai`,4rxNQ x}oGb.^:;Tzu4\;.k*IA*DV뚧: o^-o>R?(> <]Կ✺g@Yy7E_m>|>%oSjFK b@6Y#4zNۈ[D Ŗ?iӞOJ4I2D1JlْVN& )"㏲X@}\OS}D[0 rssy@NCĞElYĪE l{댛%\M`9$D¥B9vi B-+$>렃6(do)2JIAIAΖ!0bYMYF3Vˇ)=)o}jEAKS*+P65'b;q߅?|>0?W|7 nfaVф=Ohu^0ўpop{!+1fQ!#gmx*ux˫2ڑP8:ѽA,lV@1__^pJtSz'(fmK'ZA4rW.I 6pMױ{p8cQ<~dtd%X/5FPEV}dX8s1&xL0vdIԎ`|{ce%;bbbȣcdM_6OH$W\f$v҈uD c Bj[ԠOA"L$qLA?1q*rr$pzpj]*5UKGf3U8HE@1Hv -xl-b"6LNg==HhICQ\@KL?L+E СC*:AmF#l{,!֢h)ur( rH[*$Z P;tĪC}>Tʾʏ/]av$X2m7RFd:G[J&}u]=`_8|Bz'⛖Xk#>z<"c˺ dd \ݐ\ؑ:i(*<+ s(m7bӎXg#wۀr|qxbrX1Lf&+/'o]DZ.>} y YITT6idʏL'3O8w+/;L]/ڟQ (Ϗ{g ](]+нT {ɎxyDLEs'gBׇD \3VȴUF-~c%L]SٖCt Q-6caNYcɢ4*WFy, mAi a4Lg9mQC%>i|/ԿbN2]nۻÜc}5a+)bSF҆s3sm X OI]w^Y',1>~Uy.=Ybu) #fZkN1Nc$ZT:qc]OimYm*(b(Q qG cߨ׸s)4dT{8ǘ' FQo=h4>am.7ٍ~Z52` r,5Ip !4@ik 007X37 ˊVUKO[S| ߴ_hqfH"z.&Q{e#rmѤHm%x힓n3_Z{%k)[w|O9[?pѪ (oe06H+'Ip)cv]A Q.dSX.+ U@3c++RՑ w9Pښq7_^9k?e f!$@t n+~~?<¹bzùuYt N-u>bH:8sF=`ns>pbtQhxxds}s69e2xf2z[L7CkJ2Zh]6&oǟv\A u9Y{ƾQYhmxxisx^xW̯5L3ӡh h P kڈ􂁷u!#2)C4]ۍ0UdXtEG~6 HHt40!`kXI"SLrG'Q,ccUZHZF-uHYsqEWDeJb)7vlv/ؗJMCTe(I\guYeԝ)JzRD#$4A+TB Z!Ng[2[6ʈT_`D9fa9=@#+,)oRl?rUC*zRRJ+zR!"*SHd#)ӐI}b}岸UqüxdRpED(JDcq!gNRv NɄBi&a)Z^)Zhs26#vׅ(rbU$S1icX#~Hb-=qLc*4D:n[%[!*FZD!%-Rҡ%M)hZJR%0 Ji:n^P ;N[},Ʊwѐs,8/[љ2S3 -)uθθ-H*%;<n^&u2צH\ʸXSW{.?rrZhv|!6U 1H[iHVRPGJQ;KV4>eX['drԶ$sxJU5!néW0d^R*A DA%hJfM2nH B/ d8W*&LuE#dtVbzڞv@&LVɘMyj<'S6SVQb.Rqe6)F?•\;@k p$%! VHY IDAT+ʏa#hkJT+2%<%L; iѵ WV2y\!osk1 pߡ5T)(EIHhP(A``h 4(Yb+iO  V&%f3W OhJ#b.;Ĥctao'PykPun%-eTG7iW\twHRI*{_pMH.rfVԖB:0R̼y =Vqqx9l=k6"Uizb=S~9+^tN[إCMցb`Glydc#iQΰ  eY#nc:!@vV^טI49wz7a;n{Ip#I-2~/0 [dSHS0]uy]sIga mѴuAg3 3g^ / V~lcS#V9 JNоNS3']:FkJɬ{@kFij9?h鵍*ST%&B@"Q*amC:NK "R]1࡞#Q4}ss)9QלڏҮ9 ͨB$n:":b)fY${C~}spfԮj+֚Ia^3Y3~AJFikFh%UjN\2"[r]| ig{~cZ0OaP;d3 MRXugvGW$Hr$P X9*RB%D[ TQaiP2 BISɅA&LvϢ<1?af!q~{K}+ABop_?|~<$=HeMUJBERC6I .2]FZC*:DQ KcBwlpf`& o{4d>Y!-'Κٻ=Q/Rh7,S9~0n\pO-4 Sɐ=/''H):, 8Rļy|,}[~NڪJwTtt4gՠ%|ϼ~U{L}fN ѷ[?㹚Nc:];~[:]"g ]aNs&R%FvPS`$T M@[Ku%`J)xBX7Tw*սBҭ;rŠbc'[&3 9 '`Ė[F;aOĹú:Am b,eDCLQw{ob]zk>ODg*3VcVQ Ǟ{`<1F# MT.dYRuw58Ruꊄx`{pNxkߢ*rv>W_n?)/wwq|a'O A D(eM  5.n-xH)E,^)BJMRFuXa&) -LdFS1Y T7p&3;l$JRN-JB EJl%+N3$Y,IcCi^(yQfUL^NZhdβj r YfRUFqYa-ĖEA ւZ#uɶóc9fMo{KS( b,Jܪ*WjE5>[-oEeI%&L6ظ.Ө&pY|G>>3h g#ʕ*jru-A%Qk|D]#%rV&9.ƈbxJIj+ǰ" L٥&ﳭ\ )A YrY+6jd2W!uRQR]"W(y]`LcicH¡DFSB/S@P26M.yzZθ'TY V{>ic,"gfARąI; }d.)$a;ܲk%dsYTqLcDŽ|b2L]^l#*8ЮA̢qa*}Z]ck BДGTF$6KBQu(wY,j' iQpIi#\{BPd C WA5.C3XB\IJIb@Q?ƘJYǴ]eS(i@Rk$BBBUUڋU*Y2+6">G?Q5cB^#RV`#Qa% "I M a z3! b"M[b##y"ޤG- 2-vLs}%S%j^`i1!ΨK\)BFArj,=Z0АVn|qwq/5|6t Ks8+D}b b&j,wM6Ҧ@^H'fs{H5#X^4+)Q][<}WX ̧fiٴCZu*Ge}"šT=QUiuL8/VeXV*jRꇼkǏOP*ƠUZƂ1eh 40 vD9tFFmrqqIB_ 8ǰRVp $@@3"V imRddĸpF`~avnFrd7GЄp-nʗy|zkJK"@h̴80J\TIUTR ʼ9Z` ob!gdB+d¥8di4lDQ`rpv0b_f9 @\fvHmnpow_"E.K|yZV$ΰ[ƉCm 1)D+{7%6˴f0k) ]$R!uYl0W[qfa8G[)ӯyt;[f TFʪbbm6K=VJb|mfeÐ2n!ϰK|iA|d2^wl:IJI&47״N[XM.#yi>`vM}"(d'qd';DE1O\ mS!L6jF+юgeㆸGƂ^LhBo6731{\9\9G\9GdҚdm6GkhzYs]6M)#iW<->^t0}fvYMVżG ź0tQ]b1nwq_TuJT[L=$ um%rJJ0'6" nkĨ@ܖ?''JWxyċ#.M/DDOCLgGW^ӓtjGy=$T_I3u*#IP<(=d3}"|)1z墧)jKBiK- q>^7~]woLn&kVP(*j?0w''^ U(v},>gđ3(< N9V9>4B5 [cS9;9+1W ikd%>X颓 0G <ٞ2XWkx_ZMiBHjO74o6ӏF8ق!7؄㜹={Yz%`JА2ToHVռ ǘiDJl\Ǚt1=VR@{"KQPSٺLoщg{bL3VQP5%2.^x? Ut<8b'v-$W)uu!H=+~{j%4__+FmT+J k=BC ˍ[!pdɪ.4Sҷoi fQ x1#ł+o8Zt[|x]Ľe$su^ , )GϦQ$ʡDv5LT!1MNqRsZ,iJ({qm y>Q7!`!nc,8^dg5i"r<}ʽ3/u3^QE~s)Q Vw 7NY>u] E"%aes(S̀٦K*V@!_gm&RY"lBfgڄfh`jVo2QE$`8 orh[lwNh%Ko>GLYʔ6p\щLH7y< O%5tc#op-vnlA:ѩFC$Ō;!(Ly-R uMI4W#MLPdJS R*`V=uRRDFK,fN#Ԩe ܤ8lT-Ț yW!LGbÎѕd:yF[#{‘ 8nQVN1UH6`OwPi2b1|ULSq-Msΐk|KQ&Fc͎ i?ϠU&eW|2,;#l8&cP9nYqJV#K ,G (G[ԙJu1wдܡk)^Q&u"C;6w埍p4<Q@NL >UxytB)B%B(uU.d@&t_xp3ܒz gg}&yU}##7[R%*OP#8K{+:cgS&IG6ZsUkx iz3:Մ .o9~ޫN@AjTޘHr,?(IHU"9Ue$HoS5vP5T+iliKx;wPw]=mAXBYǪBՈ^&T}Ϭڗw f&Nդm5?dNqX!TLgwqw/U?x%v&UU?u]!J.[e$/5W dJ}g6!Q6/5ÊzZY[UyA`yxΚw3ҾJ%l rlaܼ8UMhS[bxQw?^d8p])  4FD=lKQĻ V'd[*m鲭\6]>a=Q䒬TiK^4I"82Nk=k~ʉ _]#L "1EJDEYDG':ՔwxcT}E㘰kCCvMJEl0MYkbU7XÏP@_'+V41ElUGÀuRQ:k,1SL%TSybTwm"m* &!) *C4$*CFS2WْxcM苔xu7*q̭&av&QtrI!mxX6*.;a YU 7C[# |`1]+(GsVIetBV!69 *g4THD$ĵAv)."حik"DR_[>ݧH d(p)kNJQ1Ċc1bLo>!u5ҶNjNkڎwt@[bvKQ~m'*%\Vc~}Dk _avbYy? frQ PMhjfxF!)[89?8%N\{,E[ܡ)o-"n3ZIϾ 1WTOGLCٹl,tAUJLITD틽ث; ;pt{6I%D1>RHj5k:̵=c6!yFG9[lΕCnm@tmR^KHv2QѼ H0PQ$lkj*J2. Sx2HU&8GnHjD ;/MG?.G1/Ÿo~}{TUwo ?7 XTn^YL v"!>~EB2*FM=*T K5*WoMgNӝs28CrJFnelX>qc 6|Zݶl:lv_~ Ы99pk9nn d !ZSZ{U򖊯!dT}uQݧ&'k IDATǚg15/\#Uu_1Aa>X##O!1?&m H5)C!yuy_bMfhvlNJ; wy<hK݆j'tZǼm챋v+ݍnX^m蹷h% ZzGHZt\;m&\O1IzT l4Y3P& -oF?ͱ]&:pmj*1 '7(iIK V!i%32.(BǢdX-fiyaj jLsc j0!-}A}x Y>~Ĺ>O1f$D*VEuj+G_B"/UZgYѨx=poAD|- 6& gљ,5)"( N)) 0v뗼c|dL(dB&dQ͇,6ycZΦdƶm=qw5 S9/E)lR *,$.,"`%*Yu=[i q1ʐE*0[b['+W"&dm! 1yusݡu3*֖Ro&˼'Vڊ}cd@jgce˗*wC`$ AmK,SmTs@x GoeJQBPU6͢1>sc&GxM ŋ^Sqzp-Ql.n?~R;wct'vv~̌3EiTԢ !KZ)^2QG)9_ ;qwq_k~o|o|?#L)~w?? ?3kp;^Zh?uC} sg;3ĮχTDhȋ珹|~˳RW+ySOxlh%YD+DBCe?0 ,~.k0rANrp8?_8^ S"jߓdhdhEA=՚fF%/:ռxe3 L/i'f\ޜ;lL1kƿF@rQl~ǛY-ꎀ&pCϜy&ŧ/zqH;жǴ !ƛ)o^j@ k p1;\)a+h]uƼ`n6{ M{Y,i=_tŋ/gn5ty7CnVLy\>Qc>Dya=adΜ{7ԆPC!ox>f3ϯqԏk'Pz -A,^~J:W"Q#01H0IH0Xp4q.b:g 5 Dw2Bf xXW9/|f,dp]C|$\upq sH674$&$dŔ&;6x{<|/>9]|}/π[0C/E.JDcO] g|;ǼZNG98OO&zDK=Ku:H2|Ȼcpː22_cmgdT R,>{yOa -t>z\g%@pp:.}BCٍ"L'&F=ny)P( [aADW{'KnYXΎFwA)QW<,aWX JM% E2 )*))P uJ,rdi߉;;҄)??4_2WWW'''\^^ףC5V+!W!mf#tvN ymiGIVzᲞ$;5NxPweE zX~Ff6yrnM]jA&h&fM4ᜦv(10:OBr'![KǤpgLF!RTVOG@$Z{VOf|hͥuDhHrWUUf(eZHEM!bVA*v2k2fV\{m:,i,`FG]~\~rH`-i4%vwyxRMymzM([(E]EKbB`"eAmT5Gw;_, &ޔN{BϼY-M>2V5+tMHe:9Y򘺒5x՘i9xAv6KPUߡ)IX3=V] qAg,%$js\_}Ê܊w럢(9qmp'shV4 +@349[;,6 uNclAs6$ Y%5nRS j^3K$Dnbm1`0@ݒBXxA:qK+ 6M""2]JedEPDF%HSŊֹηXyL({IU'T ׷(H7Hޯ(0pWdFd3_1h ᰦDa}`)iY+T$6,.c"5EۢdVł(rBm/ )/nkF<#U*UP/!i݄A1A~gܿ:[Q%-Px+LeA>H^gÁP .wlEG?B]ڬԚJk6 `4y6}fwJmSiԇ U_%VEQ ˘S55FԘ=6<5譄>@$`͉8;X㳮}6xY5|6 Qj̱R,i|#>;;_KF}wßztOILb;a"<S\rPgB}d+ gORNuM?j%TʃMloL5XnUBJ TĒSL9RR,9ciXX[+X~cON)Y }ݒ9cMiCNX68`3R@O|چ.ʐSfqgd m 'DYosgs}WʾL5݇D`AA),v^i%F>+,M`x v{+f]zCDQzs7_rXĘ&rZnӚ0rmhwҺ]2 f`$)J\R2[R"Vv^5iq[-=1"4fu[Oajqqil\'<U64#:dw3iF;ED Xu^@a` \Л`HO3OP1FdBp9q5ſD Gc?R11mmwWy=&h+ʶL8m1\C7Goi3{LӤ:}mB4AFqw$9 ^ Nj( 2P숃5owb;ޏ{ӯ0-:|7򦄭oטJHONiS 5Q0H5qVdȈN5|TW= ]3o0zF@OJa"/Q0-tG9WW_aaca!Sa_f_g透~6u-QՂhF5'4Ϲ_~?x-k_W;/"4|6BOo}~!UU|[S x/Pab~I1z:ee5'tjKBJРpUcg.îiQx sHqYqU+'PɸÄ^oN=,SAHԩ*i]{dk\NHB2,"5S:!;%@|KYsmj!:I@-PwJjQPzB"5n갹 V:*cxMg=M4nEWbP$rR"ڐL4ʔ!-S_0iFs0vޛHeg+<9B ^__ Kߨم.9DFDz6*po/3 FH0}]f*"sS-W)lZA]KʡP.ʲ01}_#bgҬvk\?,9v.qoScbW2YOL'lmM$ Mn]W]YY :) HRJӣ tI^WTmﳡ2rΘYr]Oyb UcjʮEY%|IENLBsGhDFeUC. !U~ݚnN2t?wnEqEV8q7̂!kef ,t %kа`&8"h ^|ѯchkc]~6MC=Y.|v6jhځ(@ I}[3]ň+%lNE62F%[!iqM/_ O#*LՠcZR\Cjȶj>X1XV%U50F4(=DVS/-2Of4jPX.)3cH*m?~O4ܸ>^ ҩ iWZԐUckʱ1VQ%}hJo`"Қf,h"h6wKd%]sP%$a:lTS7(ma_d!$X\H? *tN3ǔ<#1rYGyGfo뚟'Wroo /}Rfր2SC8ITkbUCliSPcS!' i\pE}Ľ1"x/}JZk[_˓Ⓕ唛 6*@;)esL5$Ͽd[^p?nXl=֢! 8!jٚ%Od* [OхQ)9n8.bNhFE-,jaA0O )HEM# *iQ~TָM`?|ZS0)Mt cH8\_1,hcf;tY z̆fnu:8/ 1Nj+NtK"w1"{y;2)2$ =VA DUaAGA%Qàny~U {d3=D.zf^QPԥ%Ix:]ѿ[2[0]k+YDkbp5ǶuY8 *܌sks;b^SH 62m Xru:;\:\oh b̙fKQk;q \pJ_Rʷȵzy#9>gOن!NQ*q EtI.v'îJ7_2Yh1=AsiR֒ڧQ.o$eȵq'oxv.5%AE!mQ(ƛ eɏ=g{$X/w7= mqO!+>'lDjzQʘHe9/юطz힕USD)(KK}̥uB$(6nbv<"tR|X_Po@$h"RsY/KƜXkRS-.)ꔕ<6Z=O(CzֆVkMF!2-z_)h|d"Gd2eۑnE6+z@$4X<0"S>zY=f qIdNwɒ'K+K\'f#_UHa]<#<fl/??3M? Kz NyzvŻD E4wJ#>*}R50F Ưc™$!֐v-`/5e)ʷ,2x_S|ï?e{!l%ΥJ$u,QF֚O/쯩ɯjUl&>|%Ƨ55YCbCPOx([>k^ɯn!A,zDK$6]QkM%-\C43sS hi,S! 6lpv`6'c5g˺υw;p%O0qp}Gj%+b3ʞd2uo:51)2dYuY-v@ lqs& IDAT"-kÙW1[k¹q{E0 ގN] Mi"hoVXFEt7+.8oo82?p)}=ٯMap>f<5| %\g%ۧTҤ&g"epOqqig[Zֆn]xWu]~}u$l.:zeRl*}_zL]rocgͿ M?YеV{g7~6jqO1vؘ-6^Q-a  9}ca_m#:=+$K5`QYVUTdG^bv 널"uQWͿ?~!Z$uDR흿7~h.M0g0n7:",b^ ̈́+W-0F #Nɵ]즦91/>uEp_O/SPsZ" .VXiI1=5ϯOy'W--gKMJֳ7g7qZ0: >#<2.>^ie1dTTa{ x oa> a9qn9 'p^Q* +͖Q$2̹LKg}3 h0j rc@̠*MZъhl RXƱK\'sRNY`ShWSOgzGOs:֒%=IwZB%RW#"M)lV6ZIJl0܇`$f"zڷ ~p3'.y.( J$)DHiUenVjl$ &4w (Ls=#ХvM̀Tc.j̬JDR( 2\XGN] V]T2'1s#v{"v eYH̀ E,- nhc=s!0S.Kך"z)1{D{dKªjE@mIUX }l 12rF%-YV18ѾeMյ]6B M&~I>}b=dMU!(R; 䴭ָf+ PP IeJjiҸ&/hއlAW=BqlG_ V3.)юV#\&xI[H*LA8=vm VF{1f'#-m#ؘoZ!j(2*UF@7M6*`h""+ @RʐTMT#yMb5kƥn$m}鳫۔4rY[ܸ-֝@b-gNc(bcic;eMgvc!4@I+f(! f gt4I3gܾӃ SBkQ6cVWSJ+GQ8~DFֶ*T-H哴|*i1wLn;ZюìIzfY0oy,HK](lJs(ap(pwt6g kȽ?k-ik"c69,Td !ADx&[%Xkk6 nQw[#*8ks5;IM$ubw, A91Odx2<# MnјNj&RcH0 U^N AKkԦEXQmd^-ZK3*-T-vZҏf F3S##k<̀d]w'Dj.W9zF%$M S:CB'ع3Pseq]q9byiD~bݳɺܥSVYUH:|*"rXD`ܟ3:1XgSnS)Y9@L􃁞 Xm0{5fԒ~5gP/ Z(;BsKjT >)rIu={{ă=b#;1})7_M 6&5! 8a#k :`cJέrP4='9Ow|j/feqjՎIyϳtXZ}n)CYAQjb%vWq Y2~'\?l`n7d[Z,t"-~+c{oOyk%䒎?(1Uf#!mѽ}o%6`lhl n? v&"אȿX7+qEϺfFlN[(~/e# lTeʉuHs*?p^ AiT$!rn3}q[S8|e1ᮘPz!XUӲzo CnO |ź&{c& Dx{Gy?\4A2ɯWDf) hS@;`Y5Q.puF[m?F{4. %K% :rld-O8oi["ꌛ~JP:Q1ڢ--h0k`ۂɌ31= *Y7ep@谦FtHTQֶ!Z`gD6_.#32,dPfaөWh%8\rQ^q#'\n Ka,}.3 N %;C*aV>e۸Egk G5SèyldD!m  %6MEB@Vx93̀Mܥ4ldT Eq(ɇ6*XINls~Ƽ 52% 8vP#5-v6΀&N:1r 6mVG]VK밲fMkB1 -@ 1g (# 'RI' BNgTRpGm6 #ό$BY> =.-oo -> dɄ;hHxw,h "%;nFiJ]y%/L;·)lߑ~my6zCkY\XdykZ-:)۲B뀾Z?1gQtiԍ trC:gmX6gbVbxtr9&a7&ƌ3r9j\fVu4Nlx6TtYQk[uwjL sEJۘRql_p8irtz1iˆ~0ħ%f倇jHڸHBD ,A*v2E6z?ַNz<#1 |#OOC] J9 dְ]r>6[%\yx0]ӽ_wW+XsQ E`Pfeh愧iVsV yPSase y`ă1c#Gv꒺E(#g 7Xh!I;&isۺ/PAu Twwa7D+:Ul>zVX)8-θqӛpqvm8-Ƥl,t ?Z}p ѸXcpOA.A܀#LX \<ń+MCMW<Hd@"B>180H` TcqS s{-巌k0 r?ǦDa#eadd"X1_?1M|7wc>q_ӯ..o )vRӏcՌ[V,);<, SiqM)_%&0mnyU}E_.- *ȺDX |ͥ*w}4~a#hw71]+y~ɜg4IU91e1g!4r&l4]VTVMk).;O688䊃TY1wP'|q5vէ|lMڨDOM.XBKv{@s\f):k0#<#?`~o:PKG1gbŌ-H-vDXDTbEkp{}6w]`5`:#>"9g<D3׼5/1 1` َ ^=??Z`0>>ưDDLȒ1֐K?~ɴk~e :̼#Db7~$}TV$ˈ*"yQ~q?X( e6H&mvI6վ7JşGe"Z =wM8[b5FV1m}oZ0¢ƤƢfZTwDܡ _xkˊ.Bqസd/. cnvYZLɜ.Ŏi}M~K-֮uA]!-A L3p C0leo3Yd]f07z\q%?nnAĮh11oyf`ЌoDsqUDq\q\1d8CP!_B[P!tgx=$CλOW'SnrԷ&ӻ[.ikn)_OgTMYTDd~բoπ7ƶF65JPsY fy9gs%cqNF2d% 08 lQ")1PO[Zy -/oe- o s)x}|,~O/[ӏoSy%QMՂ'ÏUJ!LJ:zEr ?E5Z3SuM!%/)BaTu#Y3B1mLk~vu?hFg|b+Ř2#B,0W}̀y=^ڨ$_-^~ˑq?#?NcK8W11 B+}nW8vg'Z$T&5S'y; IDATGy?;ԈW F>.Od4ؘ4ZkV %f0jE\Ӷt5Mb&!C> Cا,@_agE[Os ODװZ|x}|@ ٔEetI}<'SbqJ'qY]~ųR"#P#$!ƜJ;1rMufS8ES%δyQnX9q ;Kխ1&2ўI9t(KҶ)cdꑄ>%6.9-x@n`^1IxFF+QMڸNИ57FрX7VK``?"Aꣁ53N3p<ߢcI;v /Lf(2d4$OZp5pQNH0Û渓 w6Nc  ~K(|VZ C灡3#2vXw,d+u˦ET= A~-f]t !<cfiTHQajo ;8Jnx|%'!ѳW2 ^z'^>CIMfuהV]Ac%¢¢RSH<%R0}&w튻JYo$Ycgs #"#3+nR ЋO 4խ{kʈ`G'}vyԃE?BB't:lg-EdIJ ?r PȦe0^;nUz[́[,1`UΛ%gW fk +*u8v M#*}6j1K,dخܟ qczlKq:G%Zʢ2-$o,aqQ{}mk%jN;XP~06@k7=3<M~ﴁBz%<ͱ i0(7 ìҬV+Y%B>l{MI5J'oLj4H\>Idȍ|ɟ[{$&Sk}IP23IhGS@T4ˀ"y\Oi_s<׉KmI}h/< PL[W&OjTY,|0IvZr \[`4*fĂAe8_3ājg5RGT\.r/f E>#} "0 b3ͱtj[k#BkCZӳ6 a/1F5ө|ܶ8|O4Sj_R!h2$ v1~ ruúb:!rPS 505Z1U + 54PBzZ%n0o*a!@/ss7gk7p}}6uo7钗>rl\ޟ/_;~o !¼jMI4}Dm*kR 0 c>D${IQx{x[S}Hzn'^kZ4/=vm> w_S5nN9:f3MPZEwᶫ[ĄG1xͣp\wdr݉q) z-Y[GΜsaTY'Xi[(IZ \k.#;E.y}o@ƛp')ICTIeL&꘻'x,ͧ>¯XSd@zPJ*-D 3<3+ZB9%a;]Y_ W%ϼ.=HDJk"䲽 i$\n:G:Ӟ&~^/+J C7~Gnwg&7/ ʅ!01mVbf)`)Bk|h!7KW|ꢻARHΠ=2~㤸BZT^,Ye|S4Au:Tsꃂ=rRuNnqk;%R=١7@ ]x( {s{>Kg ![3fq4d~ɇò곲,'}ڈcb̒6)S4vZ^ ٫ Y.\E0!0NH4 GSrP uxTQNM$r\VƐ`Ȫv9qDʮS]O%՜b,{@,S5ٟ+j4k0A52hg ~Cd5@d jbJxϫ3eSN>l>#jjn='~W?o`i=GzGdOՙXLG54* I)$%45^l:ѧKrĥ7|'~"ࡘhxoFS^6 o>s}~/;>}|=+NL&󮲃ŲfL1ے K^Z@_V8NJh5K`8Z?Z3,y,{9e!F#쒼p(w=xIM!=Þ?>S~|?~wr%/˯>qbpr3BD'M$64Li?q^揤?,r!}F\32lR&,5)4E0 %^X*Uacⷰ}~RnuSV:VAZ[Zȟ=yg~>ibP {b}U9d]8ֲB[A)![ w$e pڈ̶B|ba)5G=G=G{&jrrdM6(ՠQ v*@k0KOKh34u@rO` ="aTHYQVTޙ(Q-]HSE SjD̙6MV}vN.{gjm#"ŵ6(dIZdXafXaN(움}iVv?@S+eƎ6[mhtEtd B6vV 3qp@?.Mf2%+/r 4AP Y4T9ac{`I撤I쒮bD+MTN, E11E6.R@rԿcHh AktD"H*dqwʻ-sn?Z-2aq0\6Ǿ ԚQH96(ΰ*,vZBs0>z3oU'GW8rC\} SdZf{5ӗlMexmB3J7ĄXq;%pP[2-)|hryD?/_mq1&k^R{˓!ᐥ=bGl>'5%\.t̰tܱЬ0T)2r9&Z1ʭH,QJsUާ ;Fp5:c?q;~𔡾b 4؜q-ΨudX22~uAA56F3n 6Aװ}z4ИC0f_Sp JVf쁋'.O\Pb9uD8TB'7QG*S̼Լfbp%ׯ5=x`a0Xl0?ѯ蛈ɟ) ڿ=QI,]vlpG1b9/\ҾK,=̺*r+Mpژ3nwZ/18 Ŋ<6bӦ 5esMO+f[ȶ@}ç9͐7SҍwL9\s2sBr||>cXnĹ HHL^7<1ۜ~ȟ3{uϴxxy!E hԭ2, 7krSC,WXӘ=y8!#``m h]ݰ|räxqt}Gg\~r ';fkfkfj|0 Ȱ?ۑ8el=8 5c횛Or%ڵ<½pc$1ot:P/<3&OkiIl k: X r}P`|(_JsIԙd4Xt;f;8©"{޶6y;^4$!ꖓ⎣RXk<+rd^}淧ӟY9}n3PMJ.g~Ng rxkf- g /[N[:WTJ4Nӷ-88ĕOYTIzNJsermpe1/^$7ox&ӎ!Z+َAD܋3~`%wTFfILf:fK,hff4H,1`Yw1 ʆ o{YZFӨIiiTF4JaɂP?Z)I,IM Ղ y^6/͏Ԧĕ*k!昅>aa9j=EQƠ%7"3`R_ E {m[C#Mx8NOTZj:h'?j'gJZh-fN`Fցp̖P-ㅸƋ2¿K|[QTS #P(Ae+Bژ+>\^9 Z]-mfIkj/ g=FȖ17~4$4$ǏԀչeOp '|,.Ubq {)wS>Ϲۜ_$Ktmm-#3疯g/Mt'Sީ]%6!o?6"i]k~Ly:b=-oo^/?w&FFgfStX4O&Y"CV7DG2rH6PQ5ұYk45 StjXe̤aNIKZd@P <>' s^̊{n)Mݔق=y3zԢHN3?3Hespz_Lwܠth7#́+z[Tl`S-̢k]ygy~O+m Mqڄ) $v(FY 3ۢ*JDѢ5leULi1w d D8T؝0\ hfuk5.IuH9(Y5 &-tnCkf6^ChJ.`-kc.i;JWltJ]mĘͮhmj* YP1=(PtA?Dg#Yu]vKwSPBF)Eka.6dY4JS!Sd4@)&j]b\z,Z4bvx`_Z6e6Yb!obEpd2/7)?*|kJt7Na]DQU) ( ѭffE{@&CPD6ޡJuApe4u髅BB.v mHR,( Di=I34B]/ -!i]_J[@EׇƊCaR Ѡ c]B|gDFJ4eX$}2ikASKFjeS EPPS.D 5iA;A;A"m\Gl*mPiZ4CVH;,D JM1Cmͩ4!N(8Č%z]`g11(ZN !g!D%yn6&EDheø|䨚;&Q?K>pĭG258uY}bPDMhZItw&ל{|gZI}MK Xt+TNkjuf߆mFFˎ t)Cڗ #3i/qyySV,?9EG{-F7r5&HuS![>Yah:Ih{9b XjCVb Ff>Eitk-,XVe嘳 <86N-MɆؐ&001Q(`f]=>84/glW@5u mE;d,cyT|^3Tk[2_^w %PWpXCSL;8f]I jw{^׼>*>O]V5_hiKuNNN]~b_8)#k sx-bْ.~™'Zi$cx쒌\ ⸜SXz܆?t)|%k~/XJTL*:傪q+z2J`y:<{A8-fK_ ew,Nܧ>Egx'^҅bW$g=үE'(z, sa saAcI!˷ք1ىAvb&Yfz=# wm,Wؠ5P)S |E8_̢PEȕ:5FSa6F]rq^r"0L3kg&(7 IDAT[XsXXC5YhpuWIUJh;NB);P*̸el?5f]`&G5ZK?AUccs*]bdtlV]B$~:%Ď/Kĥ87(:Πonxs vNjP(Xxw;qupfsHLiF.ާ 3ϡd"l2e (-eێGqvd8=[@9 {`)Z9W\x,䕉%JTAL(或{FlȨ-xs9QHXX.6q)zgy晟 ?_wf cj JNK?B޲Հ3``8{* cewiv[I"m1/i}˘)}wc_g( pT.rP5)IAXk=VXYC\3i|Al;E8fV[cYCOiCIo02?q I=v+w&n*Q15LM6F,]+U2 il\vX\ǿX̆|x]d=J09n%67?Z ~}/~~䤚3I12F,[ffI c|MfԶ8_2Ζ%"(wy7?Uy6Q)A HiD{Ŭgl=ů=#ƎcYi6Yi:qkį CK{vƑ31rT"vCX=$4D\4P4r͙Ca蔦NaȲw' q&>Vic/=cx[M 4{Bm)sJP׊_$=56 /K ݎ*TTzhM+o Ԟ̾c2x${$u1/(k>OjKXm _FBbl-7[ -6G!Sz/q-v7I 4I ##}N\ h hZXU~>覛IBsKIAY$KB63PB$m-uPTAiYb8RJ"#"c,fdVT KeU60YCvUK>n-8N`u8FDa(ƈCpψ-)5!7qɗǖ/TȣѠY^wx~<3| ?k[1C-eE dzeVJXCL? N ZS, #У }_!tB꡻9*ϙ 6;RH,v"+mBY1 l^71J`4HudEXd&o,Jài4@-r[K4D^?›aJ Zg߄T)x!؛>nP:p؈b}uf#9ԙ4Ĵrlym=$oMܠ, Brhˍ}; I7DzCrٚqb)˫_jv`lO!CCTꦹq4I됧p~ǞpMOh4Vԕ5͆zw(B-DOjX  2gv\Ox߼uLZ'=R&sLr j AKs|2>ujT:j_{%!h#݇c }aaXouK)tJ'.[#6ZH 1 6Elzw2}Xt$NU+K28ꊩ~;#@؏w1q9>gU[+KrbcʔQc;XQE:֨bE>0MCN&8{N-DKy/Q$xq[@5NMUc%Gkǝ`3jX-yi4WT}bn3Ǎc$Mb̤$ $LDC-(w6c00G[Lri4kIW50+|`&G@7 8yH~N N{XNS8""}E<ʾ@ lkmےo,82z0smq#qČ%~1fS ږ]PMWGk'FӪ́1y\SY}sW?bo)(5Rjdq5'U!x&N:a,'OUl cE ʭQ^M.Mz= UUĖPU;dR-^LG[gMlIJ0dݎ4#֕AH[h=xqNq'OqöAכ!zX*(12>sc 6{3|vM4Ȧeܧ',!ybRGxghH-цts1cLwQ2 sɬ 2D/y ?=3<~E}ĹnvƇݗ!H=NOvaQC,`!W"sbjvTA*G&L9S끩1mcrѶ}(h67 r5LObyhϠy &1+縝s9> hM%L5oɰYSd;fo6w,ń%Մ)đx|ڤ ־a%l0 _H{g'L%;ಹzŲ2r#ow( <[bTNu\sN|_<|4serr2o& #c^1Vµb9^sGY%!NE@oSz",i}/?pJPA Yc3: A9Z=`xS/e /&īG^m~|sј3^q=9Wtɱ83dEFKJ8wal iԻΌ& %FSmX D|I`?ג,Kzyhn} |fa8l}kNZ9/-3v3o*R}-l'tjjW%wl=$qT|g;/lfثjWh#ڝ̺Ĭ ̦ !̎1r #z/7~nX > zGE8 -[sysvmVUsϾ+27ޖq3Ek#$U6֔$pjFUc~Kb-,.+٣hmKk|;laHaKumK&787)g 1VpNvJ@]U65n?czevA*UW':l;za,@3[A*[T656Faw T7uEZ1Y0[YM'd Y+[;F`Ț54]D]:bٔ6%kv׫W^b ٤}AaWt+Nx]EL#Q*eJY dJg6qKC̤Y[fےn5aUrk% %3h1NL;NjnA{r-Zp9O'x≟+?[w\?7&GkϾc e ꣕{,a+a%O>n7D Mp%,}eP9`Vcq/3tOMv?xnAAs@7܏ka))VbXjAHįO$ 7Sf TBP_ zbE̚7 h^q{)Y܎x]q`#5O޲6|P.]5M u K' ﳿ%\. ٘/Vog|3[,d3X|a,7AJd Z 9;~;{NO7DCϸlq(߫b`p% L8LK[]mRp$?Кkt?`B3d/ uK^;\5;>he9/9 ę3 Z7=D G?_fKy ~&{S}ގ^|c+t@GB˒)J-{Q`5 XaM.˿ӑzoӬѶ 5(O  :&ٹͶ2;S4ZAj:Jt wهUgoΙ]ǿ PXHnp%qTy)|4(ѩ:%^JƩAjJ-AC>f|ʖ/"q3$G"çT 6fHB1T!?m?~Y(@8ӫ!(G*Hhui}iX=F1"W,l'ȹ9{,5YKJKE!B5֣~0PoݢlP; R\'\sBS zV3.E d$hc0S3TTɶ-e*+uXZHB5{-'{{ڵ}]ͪ/HJ(jU ,Q -iLJC*2S GvlK>$I7YӚ0epdLp- MDWJEςo?ſO<vlߧSXU}Oc(AHtJt@7K4c)`JJR*REA@Iѐ>lMn}LZ\*ܫ2h13̌QyBꔮIZNE@i<'#1 Vƀ ͨX[nC^[/ Y,Ĕ>;bŘ)|1n xks^N$[[6HDטaJ\ׇ씀EnbfaRHM1[L1 %G8b17hY+S =wh3Ii3Yvʰ^PW:YђnE?YO?"s-Ij9KsYG=:~Y#n7Eǭu'Ԩ=Vl97tf-K7`X {OyR` ]6ȑ)ȑU2 Mnp5: k7?z{˟p"l e{gMJf#om0: S}Pîp;)n?IE|2G X0P ľ,9zZos &1;ÐC1iO-KIza/7rn]ٓcXU=VeegYy{GskfN Ɯ^x)VLcqykT*nP\g4 ȷԵN^V1j0hV$ßTq!:%_#![VI_Ӫ> l%#\6NTJ](XeNo|!fy%CEǖ%} *t*NƠ[Ԡ n l: 1xР(A> f#Bn7G|>3U;]g)PӠ5ނ5 5jf?$U\mS46i55}7"p7@ݠJ($mvv!BP' ֫p55Fb-UL@ ͍MM璲#)v71zSsx'xgV]ݟ 0xi'1D1-7E@N@~!ިdo5xQoTdHӠ- SDC*`CQķ;Iz$bPc x$1f&fYd / i?+ 71) dѓKx>= Nuy <>gnfWxN/? jYJ]pssrʰ~`$lUHTQqMZ)Jۂ‘]"G17YwTAk4BUKb9f?gd>M1jWKVt'%^Dxe0Rx5`uXCڀy:bY#JѽYsvNfdLxՉuYx}n#>rN@OD->n[gK*O##*"ZI)J) r|v݀'[4yDGo~8U 2Ct[B">nRܱ0,1?on5Ex"[2,nMKh+F8PleXx8l-VVD:agSap=xXc֣^Տc>[c/uX]޶/yӼmi%H̄5yP)g貤MAZ! G[7H0  ,b<6tHЩѨ9לqp)9S|C|ˆXVn tMٗRQVDxܩdIhE^DPn˔v6wS&Sf3:o_1G 5~ůi{`<#c)s. > z+~u-ĨF1jqMvaS]jKq![,9N"eJ], ygK92jsڌ>V3jEQUjE#o,Vtn2y-egUqKG8Fo#):' x*Q4̪ mN1^>pqVG/8Vю:+޿OGнauZD [ <_}Dw߉߰Q:ԊFT:1fΛ  sO8 zbA7_rp⒋?r 㗼^r?x\phs(ȥB*<3icB5Y(6և݊}Ǩϝ^g|#7_g~W%kX]޷pROѵ Jd.Yșj# Vwjxl`QQsþC_#0;d5 5HTuH  ZhH vOal3J.Yo;nxb/?rxz GIۘ aS25F,cmuC;bK@vP1HF)CgG^oR*bwW8^L*lQ;eSrWzԭ*׮[MTMAyإXjL8);o1=O<~¯([FZ^XXGªPMI:S P؏Aא=աc@k"B("46!Rlm? :B XA0ln$ :}m ~L%JYb İRd!ɅQ[rƩRD`DIS&lRԶFW& kK\/9nl.x9q2њj;$ PéGg`+"# |^WWϙ)RbdÄ;n1d0TT(TF5Ҩu\CԸ &‘\<4)B<4HB+jfhs: aC1@Gг:.Ј93W|Ԫ[X8~Thn")3B)T 7-2bcvTuFy<[&!~؇ɫU'%=gxmƨ47aH*lFY![.yl,Ui%2l=eX c ?0  SͺA[ĪGgǜ$QN5'p7F 86jYK=Y}>gDxO<O<;\bIQjZyr\< ݤtLЄ 4f[ %M|ʠZ^9\;Z/Zթ}b%{ Cޤ`j9^_d`_0 z/& |,0 Ye=G<)MH?#|.sXV1c8b ƣTd*!_+(X#̀D’916h1շNVjj}Kޮ_ҵּՌK 3FT .Ke'E;#gG(^K\Hm \s˹sɹD5L ʮŻM[S^.?YuFDǍ>S\b-S 3\^+32TpGقAo#Vq\NI*L0MhcfAm ]Ũo0 WBȴYCQ@U JA 4*4{yq6vb/zʱvXkcG;m #CF#ұO̦>>1IM%,F%FV[2R 6W.3>3̴ׇ!fi Lqd-3嗌wmWѪ :o_BxE4gllvwA`%z.P5aL\Lij9nn9VnIwUiP`[=`u9}(x`;T)#!e(E1 NnĄc('!gHò*O'x≟-?cc/r'K>bANhޝ2@z` rݢr,BlةP(P(uu mtIsFk&-5]kB X> 1`]wɖ6[[[eՎWkk.K.k}@ 4H#wQLksŐlelFJOq`} V2$ķ>ɍOIa%{^l ^bUQx˴ç>~?k)Qxl>%~PF\܉Crř{Cf[(t5gG\3мoX+z Eo0iPDKڠZT̴HNl#\K*]ezK~igSW\駼v_R:^q0^*'8f|]H5Dkvk҅  UsN_)Y)hCyR|"h TSU?x[M};i7FD G;r,YM3i1|y_ЎT:-!T7'5fjitg0e$B),+~o5ߺ4cޞklDL #DoGQ~_ Դم>[:}&B5HR*7"&~1#9^=V¯6",<.68j;QӪ ԨKIuXfF=9,n9+> S}čqȍyĭ1A Б:PQ7tˊk6_߅l>?9 Ec7@/ kNkޮ^kn|3Q90*¡}΀A$/d Z*QxJ֢%vdw)xWOĴB{^Ay8[&웏4Jc4J-P]O$*;,vC˻!~kK:svr!Ҷݘp ~47%ãqBi E O<O[~0<-NvV9F-tҷUW` PLڤ-ZG;'hlJ Ie4Tj }{ɡyHacP %l\0]B+ F0j[2A3Vev;%&g i.XnQdm0saI}n0j 6 8C&2נPk0͂Щ 0ZWيi;BA_FRheJ]I:Ң:T$VTaWlB72s\+t [Gj: kR]6((J]*Ieya42Q0+:q:hJnU @cvLs1AH)ѴMDFYe[ִU7pP$C"9B;1WZ*UW@}.< iɜ%mo9lI?[O9diawYFxFLk( )KFP I&@kjtGO9ݨ0Šf`.,WwւIzixFkĸzT2 %lFK;q@5S0`MJۤp,`:8 D:8-Nq+hHH_ Q ]eÁx h#J zI}C&&=]o&jL ,Q&;l-jrFq9e\M D瘢Rrd+PAۨԉA|6]C`23Lp_$Lʖ8$ä#{7OD{\̱eJd[wXTCE,shs -nqdF0L9>7YbtJ {=RKX&s|{+be"Ѩ,Y7)F] jJ[q811 .yeQ&EeRV&my:fV0cpndGUvw!>Ocf.Nd8ՃER^IgslŔPIqH?_y{'xr|ߡSRIZn"RvJ\ yȟAPtN7?}H-1YCT` jѩq;)mȜbeń;J7/=1YJsc%(I;|ܜis.w{TΉwhz(-Ǐl>u 7E#IQEq`9>S:v:|uuJ.J QrL9X8XO 1a1bQg,pP:&(0tgSm4L;{+R. t@ t m啄n8$b>muggzc<4uKdZMǔւQن~ո{;oBd(Ƀw@O!$I,ƘŸg"<2`vzLO|cSD:U`iX$ƚ=8=Zsvbot42TF({3"R#bRD*M`3e<#3l8rrnq:UOT] 4d{IN~l3X%IҴ V#4u߭C"a|ᐚ.N[y[{4OG?g~rLqp6D&P&QhqNOpO$xfƒ5bdCRj}j e`R)T[/`vX. S*$6^{ErXcC6J-rl-&VsmO<>c]QK/j "uvQHQd.1 yfSEedRnM#*ϥ9SȰQ QJnIڶD]nަY;yczčt ssU32x'x;?#r$IF[7G#V:jHFBY.elGqA6ZlUҢ$b FSj)wÈ]TI[ |R.LڅFae av^I}|lw!qJ6:ϰ/q!.?\p^ُ>OFh׈ k`X}RftQk[ͱd]:?K" MqS;F)ģiN|5w`6F>xf[j? 9\W'l(KN4˪x;$Rٙ+pWrq;zwNQJP5vI %i_p? WGL1HBvC{_*_ ]bwblI-S+UN/0с&T|h^c6}e璉B8:AE{~ 5K>+8MsΔA%qh[PlR*y$=IYNQjNY4W9Rs:(9JO$}OBh)߷l((64mUA4J!LҠEt CvѯVL~G?}"ȶt(KwiFWy,Y/37%?SLZF"f(01: ? .sTMX#Lt {U4qpq3NpR}[m6aD"x,-ohuMp ũN! r`= ެ>r>`>$"7U{qg$8Jk&~}8b=3iHJ_# lFdNejTvو UcdMhTNN?9Sw2F̕jnTúB2 s咎agwvrD+G5vs9$f&G|,s&ՃA`R )]zw!&*:CYq ]J`4uAl  ,/k9YЧdMO<?W~_i۔Ǧ)u>жsf@VahV[\^P(*ؖ(h# 1v>&jn (7[r$,yl>D#X$sN$|  zo=duH~0u@s݈p}u@KH.+G5SˤFiHJXfr5d2w;O\[.$ Iҋ?(^2pQM깻$뀞uȍqȵ:b" yCl l kQ3Ɇ͌zs-d v\+Zi1.ҧNuˣ,Vv)9SzՔnQ>Q-{dk+dR Oy +ZbI"(s֨$‹ȐRUiAn:$OV?55Î[8X8bO鯁u4r]rtNX'1dv] $;"S #ѹ`5Fy 4*oP&YⳀZ44JGx)*v۔e 'yiрEצ. RiFܛ``k9(jt1r!.UADW hАԟK[tAߴhcI[;N@yR>(Sm@u 'pOr+>+K%>+ÿ?v+gfl)"?bv):5̵m C[riS(  BC=H]qMjϤM!^-q;?ٍ2 H IDATDALM<ڥj)UEtLYJ3 CR4tP6&eeRWMEMV6G޷1ѯȅD X\8mEh %tdm 4ĭrOb|3BZ2jQ LĴ2|kӨts3zь~8}[+}VceNoA`Ad[|哨6v7.E^HT)*c"a@ t+##d^4@v bIټ^c##1(+"a2,k4_b2hA%MJ \ /h,%*iXT#M$ub,G,:]a̞=e`M3zjAL iPH;y%PhJs儢TxeQ58Uhququq|5;ے$h8㠰UM]TIԙtd!3L5RnF]5+圎Ǝ]d7K:h toj2veq& aF6=C>yCj9 8ik<;0-6zB2Jlr\a-(<#N:QALյz\m^6={t```~߷|]OtPP2Y=ՀYgYvWz/8Of/[OawЁFlu/bI=x*K:k/ }%ɖ1>*<'exUo&/23 kfL?]yhQ./w7R%1tS7g.M&Y6}N%l1ƘXo0Kn n'!R!FE )MJZX 0vJ%1p>K`󀥕kk efOu9޿ fwR}r`45F]a65M?Y;4sbj"l"}쌟O)1ט yLum׌GԿK["bzٜ0b5a%b}OZCE\Gy"#pm)]{FWLy9`L85b%b/%X/[Bb}-1'-tw$':)Ns|7ǫ2<#Ê4tY. %րieiϰx$8f8ao7HQ a\q1l6-}Mة[,8\>pczQ6Oo̐.KL[ѕ dvyN({gs]3T{i!h{AQ¬fjh4% %=H1n1KJ 8+%X=h 2X=S.sn#^+o-gּA_]fdKuk/bEQiqV^qR^cT5rgFH%@M#KX,Qwۜ G[ړ5bE3^H`z BsS}MItkoUVA9R b OXf,0IG_)|@d)x_oƐĂ$qJyL ?$C<*[U0b mW 7Δx,vF=.^[/)5~L>~|1}}]r0R S0Bw3.gMS =y *:ފ,6FBtxTCL*r2zrNmuO$cB.3T9mǵ<+6yHqG88ܽ>Π>ydMǔ 05ujHt-VXs"gӄ\|f|4NQ 0xQש-ӣ}!yb r٪OhY&MMɦ97W#V!J'8,!hX7#&rDz cYcjNIj`a5zNӫt傖"WDS:&c1wQ9Xϱ/FE4R߭4Pm&r<`!{lE@Vt%cE_ru3熑6T̷ؓQ*^5xaJ 5mBZc%%:k;dkʣغTC,]8:[> bEj,6]ƯwR~V;ϴ|gKٳ==s"W8Ħ!tR(!P %, DY"tE'ko{4XC9br)љ=Ayw(;Y暗 V3̬LrԺ忴ժE= 2\-%Էh gl>k#[ ?,~m ;3vٖI^%Ahh sHjmȔMp9?HU64RW)ґR tj&֐٥U/1@XU-hsPw]Rhp!?`%^gY~3Cs[cgzZ:O 2 ;ش}V~뎮@3%4-FqG/_g+(`sz̛Q[t DK= +J<@8ygȔvgI3X7ܩ;3 <;ų߃7LBJriQ;A>a9ot[s}I<$}Ĺ"< ք0eNlZlT[PZFZ[̼>u{%Ml&Ml+ȷ w(PRi1ꞃJdE,;u*9eo]@C I٤CuBGuИg[4=Ni4Ghe0>w=O6Oxsb=bZ4FȻX3%h΢3/̫>El.$E\i-R ,lg^fxq3*Yd82c3n̬>e`2̄vJX_ЫgXUkv1kb"7lmR.T:]}Ź,ii+!osrWQ}R; ^qV C@^b2X2 -=KUl=H.cS(OO `qtAs(9p[ f>߭_q-inh 6DޖB{Km aE_n ZE,*g7d~zpPpݡZ%FZ-TJthȻ%ﺯxn,8uGA=cP0YApܾ'cYDUT u+[ 1E`1!ba %D yHYJqBcAw[d8/c/?nwؒ67kA:cK8'762aQ@Uιe y!QJJ\ĭ[Q؛UXYX Io|~zf=2 /r#/8 IЍZ^ĉK8-+ZU [oW.xW@k F`+Rso0w -9\p#ڠ,j޽ _ҷ& *j[uJ&+\M}g <4,_KjvHkTyq" |Pcwo93fN3G5P`S~~Zm+vѽE {;Cf#ED9vƯvuD̉[^Q`Ќ<̒>UCrQ) jͤlRcpȰ?f3ZvLdi11h^-c<1%9Al"U c:( LLOg;5G9-}--a8556lwv:5IJh,6+="< yTA'-?,JL%r,(1W O5h49p5v=lHlnfiKq Vh﮳BJϙw{LԈ3ZQ5 \'/iנo@%VRbf^fbPO U᮲rVC $ڝnyDkќMRh(]i?[2\MMsAozo+~]W~]_̾5cNo. -{5VURj&ss@mst~G3p6Dκ5T+~ABߜr]r< 7mVZdŧߟ;b \ JC.5d|ѼԑC}WKnܦArؾ N>2Snȶ5O5Dbñ՟ſ ʀ7U/8QtN33F3'ݔVwMԍ5]F[K\ѫ9fNP'hHV-*Jikk>[Ch1ij٘4+'%=cij*̪¬kՊwG#@4mK97<+nj5-sg&fEZpb_S.[SY:Qk5xN49 S iB(5^TH̾gFBZPH%Ph60ACE}텬ϸ5b;INjMʤ!6IHTS+>#Qu0.1E3z)D_~ .("Iۥ,#]J«rR-xkڽ-g dъ!5!xhmbl&`VCȝ%z$9aKdOU۠TO+S*4)+6hd.W_`L2,ٰyk&!V[j k"#1*u1l6IIs4٤IKtttv|JppqA:vc4)C-uji630yϩ J8w״߶-ⴍ+39&tkt+OClX?0IKUƫDS1Js #vs֖^丸!yBPld06:,6)9{=~2'4N4y|@:J>:\ҒKESE+̼S9gVoRtmCѱA=s0 r u㕌Gް̽6 \13@1kqB))u(nq{ ^{ ~C;(KZ N\"ͤN %(Rksg#4I+ji0SX , EYL8ο'6|\p=}% IDATeh9GkKؙ@ʖŲf10? |d2HK`/13i07\xS.u;9{½qJLۿb/dhIQ@W`To3Yxz'p{$Ol`w6NuȦ PX)o9YPyc9?4hhZYvY~*w\t(7aaNgHvL J}v' htK%Ծ4 M5iy!S.rȔC@R66uir]Q>3"&b(KȖ.^1Z=0=02ǨAk$}R>l@7m΂c ,k,7].3.3.32堺紾@293=3=3owmrPۈNTn9PU挋z[戇h[*I5$Dٚ.= ?G B.&ŀQR]u\jtV)8躤͚X6֨}9b|;bD ԔA4e7X@w.[k"cM$W}_pu@:'Ok* 6b;sO}67{Zcw=I̍sčsTlW&X@W}ުW6߬~ =??IL>oH!mmGZYizE.ld&SYF6:F涡ֈVoɱyIll̀XZ-%6F |R e)y˾;Lj>>KIl5<8#E̫;qO{d\:PF^}\#5R\#× |CktY*N .[]n/}o7|ߣc{trNBP32{St+:wk:WkEBs h5f;, B2WO3W=Fc^>~G^ |>i8@)% 2+~ z'{o+X"x7'/\s<-PRA֕A.((v鰐VVM4dž˔~ȉ) C~2M rASV=4HUvՔM!t+]R?V§JMIssș@ tĊ[z]J\QFFәR802~˙}).'\'lMYG$$:kc}οůjSt@5%]L5[k~{f~yLJυ~DIqm=ckڻDGeKzḿHo,OYe]xvv×s/`g-[q=9W?wk _=O<?Y㧄 j(l*4l,Qc ]phL\LkA. )Uj.|Vrұ<~ORfUN@ AAgt bEy706 cSbljMM^AR|cKhNwA`FlBtaEycY!s=n#0%o+dx =h ,DUF*.kd4tM#=uF(K@)PP,ҐR1#]Z%-MVl91(l6@Ф^clkҙIp$DA(1=LS放=b>uaRm0Q{hBb%֘2ҩ*5&sނ&6xdتĤ@aeA3<;W+<Sq0q ߁*jOQT /anh~hI(Ԯ/iKePz6Y$e2B+R9q \7!)F%kmRS;nvЩId\4[b0r kΏ>NĪZ>J!'"lmmzl|i2sY& V3vH;ԘԦEylG-.UeQ6Uej0d i:6(Wc2wC uw XX=17 ҧ/>; 46IS]ã4ZݤU MVjU[]I({fOm$z5%xEol)d7Z?[{*>%M oW$Eh(Ԫ̆k1`/|Ra #<#?Q~$þ}>'t1n9wL[Lc;HEV&oYD'1x@:Sw=AL,"s x26 :G[Ĥav(yG”2,#b"o-PرS2W#;3ћawD4D>o(\h<™n{NQt{|q>y*$nԑ"aha+ނ"-BoEϫ U)Im+>8i*h*AS˔FT*Qmq`(З }oMGk;|eI4h$%YCXV݉ ;zs1y$r8^^D*iN/ 9ihR:sV Is#l$AquaGXflp?i" yc)-'؈ q" Ktt՞*ɩꛚ+hx±6}`ڟqf&n!X ֒$䗸閣do& ,"xBc vFsV@>+/tf1ߩ?'R/12WxwDYQw5pas1Gc*+1 K ohe7*Ń̽1{kbQ'2{ġGyG~zd쎿O67?"4⍷ꖩaZ3fWLILT.)Ր7~Fu$k4C]58eo{l"[X;Ê> it0~c:l}(ZIYԎLvfu /Vx^NQsGOpףy)y>qCǮ]`v hď(=e,x~GL9cLxp\Q72u+S72UgdE)J(kfr&]q&jѤCJԴއ/xv̠`T iz kl#"dƗN I$UHhfS_0fs^Ľ}~@ZAE"}Y!U!մ.SIKC$#i@ܑ9dpp.V?t~ 4/jp/;=Ιs54P?{kU{ѩ|]1Tk$⾝r<k>jKƊg=73xFQ;7k_vJ6q^Ui0F,7v n1|B@H$r8F=%ZAd~J)5.Qj1On#$RD̙HsNtGuN&W(-(g *]5 P},QPeYQ(fC*$VKwd[z"fC6?26|Ak p1 )^=DXzDOTz x|uKZkHUW8n},42;uivz+)KgLx~̉{ K` y3$+U-oyҿEᰧQ>JlĎE5{U~C8bwCIoPȰQ44ZEAT7D͕yFyskoe]נ6%WbB#"m֌ uP2 VQ5 ]:%m5`Hp!{gѾSH^4؎:X~4#W5_EyGyO_|~F:b-> ʂcS{$3iLrAz#J:v2eZ $Q%2H"eJ%"TL=m0:DHr($!7(7;R'ۆUDFBh*(ۇuG|R8*AmvFejԆJ)jF!4Րy:%ZQ\HGK&b% $3>3Vj?2))FUZ_["Bj*6ਹǩ"@mK6{>NLΉsThjP13,7%B Z Q`HH5l[ZA˴D4uxI+09uAȎ4D'4%($6񥉶aUav}}YtV]wmZM$)Ox+39qf+X*4 `ԜC%(>MhV ̆V>)3d,LdV3gח<{A.v:eQEPDE!it-%i5J'C.\h ohpZaޔ]nSnO0@oCDa':于lWΆ.!6  iZ %D%7Au0B(y75J#uZT"iLƄ8G[,GwKF[2H7涏dtCcjejGrvx޿z Q}C-S JFJjO(ԕL* R U@PkF閺BloPdʽzltet=/ˏTBԟ3[Mc>ȆGښԕ6j!g"F4 e&ҦZl-,u1L.ي^ӟ;LTKÞH i#QeaR+2 Za)^Cm*rU'W5"!i,ܡ euA>nC9&*۲CO0,qZ1Gy䑟.?Yw?':~4FyNUDrYcHU?$vi{5gY2ltdɘFF{ZǼ8.Ҁj,Q%L3Y4B)d.^d M.InLgŚlN6(RM2 ]W6cnd'rG/kE"U-I$MMl[ʒadp$:zȲtl.a(eۏ=y_sB~qiBXJD;} CiD`<0sZb{쟹G.sg1ħ2L)bYjѪ3Ry|;6 ఼>IPvePvIM{/ M#Ny茨Bj;1z.G$IjR]a,Vr)MFC:P_HH`Z)٘y!yHy|/Ⱥ._ƗL5{oH oG/pEwrBkB68!?FhmS%D(Sv<=Hwl&=6k&>R-(jQۊ(sGyG 5~ wVjfZc>q͌^W!Z Yc9B, 7 h>Όg'w|}򆯟eu]JqJIP OQ 7F}9ʠe\MX%4lcl%{A ڽ?^a}W%}$7dSv{>\I ĴIOL$s g N+CP=/|aM؇ҹI[dF*d5{<1 %Jps8c>?b^-.ybxn~;ގ^{KNJ%)Ĺ^xGTvt/os)1g e))99SsPR#)5ByZ^E"请ŭ/x& &9ݜ/vКјKطxy+=bbYޚ_A iCe5O4Տt* I1S,9R&QLhWs,݁h'Ռt#m[@-B#ҚtP?5zOYYnPo8J/Vȝqnq?lpllh1=ci{Xb򇫭Lf'\P9$n?]H C4ϐIo~E]'5YCvnV65EC]KhCҹ@ υkZ1= 5z^o-w'n3]fbR&9RMC/ 9Zs=*<*=KV~^0U~cT%%-}iCO41):bi,cz5AoN0cS 4Թ]NVOijgyaK곖+4D\9O9C #S b >CYVH7- Za8V#c\T5- IDAT`]{Cҵ7؝=eGaPF'r1F nGܼ` SO7L2R2|"se|U#_6hIW[|}u{nuA}{&FQϺ̑8#<#?Y~o;SϗK8ThԈ%4 I!A3a:Cozų/f|Y#䛆m߯WJkƃkP?ѷGD[4LdK&Wz*Ws4t <<{O[< NwǓ _?=A͠ϊ>k)|nѣWV=&T38b~1aw݃KK 0蒿ޟadBzNZUF-ǘ"E-$̋~F8ㄳ @ITR)s7[WAkjUHZ/79 6nq7:77WHe_+]W\g|ŅwNq_2G~ɯe8n!~K<+G} 6 =P2.8Tz{GK13:NQZ0Z ēCҊ2KwtIJE3I9~EVt_I sb^mCsО'} ]qp;*4gP7{7!ѡ{@} 5؉1W&׻M)FAI3㤹㤺kmL@(\ۊ! @=P<_!M!+B&S~gp? % : #(Et~}sK$k^Uzz‡g>9:52 gODלr)[θ)NX\YvXߤݔ;^[(}밿ys*hj F-0[ hq0Z_\w]+~C_Zq̲COYVa(^>̱cT5 ,;ko3k}u.9V<^%a~ M"tt/!uL~[Yqmpn o@|ע3[[)R̤ISnx ( Uu&Q̀7y=#<dߴ{?[YPk2R& mf?kum4vk ,Tq17$O  (N|;EtfR\R/Ї9V!ZyXhE ޒNa!, swBMF' NH(d4Y6c>F\2RػsonJ4Ndeug X._ԙL`x\OCz>(%r6(Y(MzuZX֣?h v]½Ođ|3A^Ԥ3 ꌡbo{lF}E>:NĕMĞ[K3Ds*im6SϨ5Up fil. -JU ]KsO)AJ}']0r %CwZ08u|h鶁;61uN>g3,3УywxyݍHX3@|đE;x-?Omu<#2fZh;]gK[3'g`o׼W_R 9d Z;B_"لK$9DG㷹l}4FOmp}BI2|*E Sn1bFϞOŘ;iL9NXBԤκAJz _4aEmJW;:b/ﱊX6yhS )QB?F[td`A,|7d6!$z{G,$D9D Tm#+5rD#0zXrUކp1ϏF6/$'6o05G3(H1D.Wpq$q$Q JRY>u-#"' 8wڰwθ0s!#hqDıJR.jX1^qSg*d+7!L2eP ja'!H-cHftEЩ 2ב-R.=.D1$lRX&2ƉZ# }tcKy,)lc?1XRB- rVӮ yx/lSϽrDĵː% Okg%۸pV>}b٨pc?ş2bϥx% e$-1(0Ғ=qGW9wtke9K~W7/)*U(&KfqqvJ]1挤ciN0 K& "8Xv^oxM4JԡBh6 8I٫y]a,j3q%< -諬 % 7ĚO3.s..g-se%U{ VEU+'1C,-%UJܘAܚY%0Re<}[ǯ|- [5 Y B\IVBg9,j jK2ejK7X3z:;y- kFV`b]U6 l@񯁫J9@>#w k%L|7[^;>및$Xy[dѠ]ilA1Y]R>!.uZUS.s.s>̴#D!Ӕ Usr[GrZ!ȄV8>08 k:[ ["95a5 .`n GZYuôgR.kR"T}B#T=U~(Z2G';䞎kDs(Ǎb8@4 1w7"Sv%LFdY:kP-ż!}ېe5+kJ]6ToiJR(t5)k6=̙T %HPԵF^":䕁h!/6LS*r`T G <\" uL,U*EUF$$AU LܢuXthbVmhyh˻<0R?fdHfd6,04|~ZqJʱ{)z`uppÔ{;;|}UE8rFĸJy#:KDžsƅsʅ{BA ʖJՙ\vO+%S$#xIjJ Sa)}r]FX]rQ U c)4źI;5LbBXlab-ܮ]4>,[sKK{Έ7G9#o؛1ԦL[,!> 42φDy,I9f͎SI1DM船DBik])0HhRM]&HDR)2Ua>*&#J= jCavyC_PUPR͢1+:<86=4I;>Ҟl tuxf#b fMT\ψ-vA9S:v@4(A4H <'x'~[5~%:;Z`B{nTm.Wg;4 62:(jok1cco#m"uM*(NꔲZp%r!N)<БiPꃶIs[2خKTIJZ-yXcGڲDYt5NsP?PT:F9F$g/om٪58VnDe,o/.202i YW9@A5! @n S@UJIpTbBĒR2bM>yb' I{*Hg{N,gM9X P)|R4Jd; eNdC:*iSڬ>6ww_ݷSKSд EpJ htۏ)Q+KK~l}˳ξ=οdc._X]D!C r&V( Ш KIЇ(p/2N^_bmS ҮA )m}LIfkr'r²&i3`[/xzΛsW\W[^kN9qӜ3VY,2}T&58d qXO)dgvMdYmCh!MjdI,rt$h&(&ҭDDJf9lR.6*UR vq99Bs دrAi6Wt5vPD:`HNv ?p8eӗzM#A%$Z\|.9x?{)e,uO<}}¢@Uj 'prL2Waf=5jJ$jIjjS% S;a9[da ՠ5Fc9!75UeuP @Xe]x}pr3dnt%aԞUH6dH6տ(c.sMkkB7g{7W/xs#o n.ы )P h!:'˦D[N;= (wUػMa v+L+EWrt@W*@mIHjXrL*YJR`+ IDAT`?#Lϰ6YiV',ثqJQ$CN;߱:$Ԋ血P$jY!S "ai]JJQicH5\5W)N^Q* PhB@5FE5ڲBhnjvNЂTQ#J }T% "(f 7È2$[G<0+))1-$ŪT4A40+,%B)uQ&Irxb, WJ4+@z Ȟ IkymvOZYꖲҩQ M#V,b& TSG5z*XiL0ʌI>p]s\s^s# r$dP\nEZkg.Ew} ]fܝ`HD QKNKNiwCnN?YӋ7w;z5C 25ҦAُqM}sm̢{[>a !Ccĺĺ}Gш&Aek p%2U&;auic [,> Q Eț6Ǣ̚b`)2rXCBEHaTRAN$CS8fxg;qɑ$h$i{@Rk&S4c,3AjCFq+TdDuH%He [[ȑ+#FE+- jWBC4O<[k |H}fI1|؍CL;ǵs\+ŵDx'L@:!d`<#Mc$/ł L=%9mt-|vMSdXM^l.kGwϥ}cMqmqMqL¶LϸNJb3֋d`~a_̴_/N4 Hy'k>OI*UustVbu0/îjYՖQ3K8&Jnv9KnΆ)%)&Erd퍟UaQ O){M#6qz` cu 5/MTs$@Y!d C0uΨK0+̷!փAqˑI9HWՠ(3>~B[FQPw}3E|õ?_$Ѳ76'&]:*BGid23F=2㗒3Z -cCkp&,1 gL?p\ppœv^:((=E:2 e#=5iov[e[Jt#O"\Glx?~!_ۈJIBh1qO3ܛܙܙ.NP ;;[;@Kӂ,mgj(5w6)QESVzSzzCk4Z'!dJmF9d*pT,5D5[ӣ˂)7gܯKz%ќbsa՛>fSttN5;:-ь!yސ6M)n˽%bEdAN&*0*P~eQĵ.Z(Xxhu:z賾X]V6\0Q ŐH1(Ѣ [ r,w-~}\r~+QTm,G+LjE:lEkQ=+q&`,0Hi0@x\dII&LQgz ^Y%jUq]R{7yQAMjJrﲾ39\ydz̳!Z Ej+[,+EkJcq.!-g-U/-0K1t2vv=vYi 2wV|}%'JTl6Ҹ2/h*B}^a}Tak*C{`~Ɓt:vȯӚD(TF%Mvрt}99 -d eyy!7ڤ6I5Ad3N! &,[( BJ#Sr١!z4y̶\ :Xd3L*UCl73.s^or$?1#o'ZYܦU) rm򖉞5g6&,K2s3ϐKATNt5ǝk>`>P0e )=m/TJTn9cn9#dPsL7ǨsҝnǖSlp퐖RҤ`6 r]Q5 u#4$Rl 6in@lQ+(j+ѴU`X8 RcvC[l1!̈́[M38 Tc~&L$K00[ұ-MLՉKa{``p0cT-KՒA$-"c!F5ڦ46I$e0JTDBk($ʡtdyl@Td؝L14ғe)*!-,T'x'~[G=k~4 k~sn7'gt5oE[hkqL6dmhZ( )HxNt%*vI=Ҵd힑&1lDY/r6&>@ֵϛuLX}Nȧi&&!tFj ?(,<:11v?f|&˟ LJ93.Kv~6[Mo5 2˫!ŕNŒ1K1$BQ$7[s>p\],c2Vj+aq=O 6!eMaQYVe4ʐbWFt5'%G=~rv{|'Owt%bAg]$xAlǷ_6G Zm*: R*&t@=U4]b9ѢgccI\q{ru6>\c2vNZ4B9N:2< WG+me@3%vрxn2@m!obYtIY!_xC1EFK cK`Z Ⲭ,c^ѩk7P \%% bab!!$8$($tY;z-4ǚnNotmPMʠ5j_AtmRRY*$cb+BM*s&?t*aPC)t9aj.j.f,"-²ņ[V2&bQ=_9CJ4DD(tYJC: G7 ćb=\kz[z;42ԨBK̨ĈK|?>?M Ӡ4 S4GxX422N)fEV /L8J4Ԭf(-8g(%u-]f>T  *LE:( Ubj987I@SKvnvڑ&iy`oM6QE>$8֎s8й㠸ÜelV6+ͪGXuq}K=v+w ,I"cGk? 9O 7~|'x.~g_kG?'go{JbxzH7ddִ a)a +(~;"Rߵ?qc}N(\qˋs60|~K!M7.oV;qӉFQeZ rwc2aT6 } PF, %UI:,C~9gK&>m~HTW$D}l`az΋+7C47h%[Zh%kL6YmeS$?*R&՜{^U9-h~Q vhYVdhu.2z`J95(L.!HÚϢg-H%HB*T؅m |ygm^Ru <*`+[t*1,&2WA4{ =-o هհox;|EZ{>>>:!>%,cV!-7`2+š,c.t5yEhΊJQidZVh6X8ďU.kblBO<3?S3 ~{|쌛_{_'&{BN[حC`>Fz܏1f;C-*$&Vx_k)Gj/ASTeߪi=+~ R[@!vnneΛw|29Δ}QABeQՊTX,cUQI d+7vo~sSgܼ9zW{P7w,F,,8>H- q„vd;$:_):E6Zx1tbƠ1`FZ,!h"la=4)K]|Vi)` J&QK@kdNVdhE+MAxxLǬI RRf&aڢ8w)'w|'O@.!z N%4kto7f":ˀMtDcw/\:#O $cΑڠi@|+^>8r/gTؿc311Z+~eN9SoT?Ftֈ Vj|6'ǠF!C1!˚*i߅Sb1e̮iQ,9wx:HbdiTmFSP%*M%mL&8$Xd4bT:31+ S;N;H*؏RX62k!j\dH#djM!W b?-*6tX}\[^--޽}HJ.w1a钮-QTF %і5MvPLv!W/i2b(@p[pqw?ȘqfẄ́𸎟1 U ߱϶m,I9 H KHf (p#M]Z%ӖzΆZ'<K]P )[p[dM?w.xȷK~aΘxIߢ,HqP 0+wx'x⷏ߘ?cVp>Y`J!v4i= l.lfHk ¸Kl ҬKm||1ɿu0>+Oq*GCóD-c&:Ws޽y3iĜ!-hdZi-Ô5cGIJcvY=VtE#ʥ{2j!C:KFx|͹vѶ GޔW t#'vgp>gg-m-׶'qvXl&x.90`3&u}Ϣ@B_xYaoCє vP:!K:ŷ7t-0ȄA. 1Ud#޴>beuy#}ͺGVmi^MHuw+ƆY{ eX="9 IDATI]zoHu VG|umml6A&;t-ߋLYC.Q(rU&|Z|_n%NJpT2eW'ZD\IcW8|#vW2|MkJ!^!w#M]d- nhtݪ҆$u&|"VEaZyܵθmr0fnJ Sd2"V(x*j'x'~;6}\]] ...8::~F7AYE&ѢQOGUR qMcZ#̑6/QD(I;r3DWbzL7.3&ꌶZ{-@y@~P@~`qNL?`8R& u ^_^eMxԢ:z9ZSR-=ҥ|=F*V~fMq[e;Yx=d>-̢rU<=pp˫^ f8=v$iB>j77!gΡsÉ{͉rJjMCͫ)&^J~+^-6}ug{&Yohѳ &uxƗϸPrdX4A 9Sƃ);D$V_QJ{rvy.0p&!fxPܫGܦ'K\zz<S&~doJZ g P kĪ006($t T\ 1e1}vWvàѭ爪aU]1$]FhJV5&q1-9 Րw J >+:l$8Pn8!-[pЎCn.;Cwl:v}YoE9OYѱ}L)UaoSn ^W>7t?#~m LZÔ=_{ٶ\6#"vnźUnO [|M ]bys;wfy7ѥuQf'Hc[&8z[!_x;.c'&`G7A7TJ%:Y1&?ўR{35#uBP,!['+>_YOW ]/OJEU.j!tXSL:<)hK=J;j^Vkh퓾t_ >3dNga#_ݡ*rmf]/~}|= R*fhʯWA>|O ? ?|zFk{N.w9ǝ7Ă1QXO__p?oPb&~찿pL1 en48=bN'bnrw9׎9͑g-voO`xMɰG,<"(<GWt\Z[j;HJ9^#iAxѺ-jI䁁h[}9/nKb[thT:l!dKȎX{BbMx=Ia7#)G'Ǽ=eeҽӟ|=0>v\-pápm8`55fǎﰗMhZr u`i `-?:.Y5?)3GߑIwS)efhPTHlQo4l7Aw=`Vլo}ַeb|!̜/|O_˫5on+cQuprcѓ6|O_H} ^8xӻ]OW|ZV atX!ogIA* -#d*&))VmrP5/7:5y'f{:ٞNlcʭl3A[դCB-;}s4mAK҄NURe]͐4>QpBw50/甹//x7߅˿ooX-W__t __QPc{Yk4]P ή*]ϰv.)w :@AujAz^MSIA#FP&IW Ucֺl.KT@- n}VKZ')is+ye;S&GjGDKl3q3DBH`SnD]zL[,!jDj'; Ī sΚ>J0N!)kKa%ِ%V^y̭sMNQI,x^Ԇv+=nfXNDmtWsԡ 6 rMAQÕ~q 7 [lvO(wrG^3掑:1^B@-v79xa-Q53 mTST}ӨlA H0J\P@4 B#cY>ѥ.T;CvZHCHMAWkL@7*TA Z(%jjʡ*hX[k4è=<٠i%ȡj0=nhs0jkn(4 A',w]ΰo1+(} 9T呎y1y!pVԊFҺIБ5#:暑qωq-2Cgd1:lғkzrM $E*@j\[%oaX\WԱΚ;;/DlPL͔䚓-k4 O7:ubpК;4Th%{Z0ꔞѧcVrȲ.dXKOS&&ܖ,1hB]֓ qd/YUK(sƌ,-pAP°=-Qe`RrZ=#VlnMx%`}PBoizhjK eR%:e%:Ue ,x8Xwxcr~]3醠;2xx_ſ[ק*?K&tV'cHcﴥ=uXwtrC.-wмsΝsLTԣ1 ΐ 5UJHVV'vpvHvmSeJ ;xmIr OD555mpqq[Dw2T(4 xCܳs+hz5A_TAHGטiAm7mA) Qn~Bl{^nTsxrEo7dV>q0+y?#nnc :~" Y7t-3؛_0 9Ղ3qK{zQ5g; y5[\ܖdX~YqͣsҀhىHɝ&TYKŮs+(Ɵ0=c9(9JHbP[4T #t CCP;lNzǼQ'ՊP+e[1+sLb;Vn8VF 8Fi(~iKU]JRs:# h =ȫ0AtZ[( ZP[Z!i5plkc2}eYaJFJ% Z ՑF}jRT&e_<^c)kGb9$M:NuR rbi =}Hu-]tNTetټ23Top)j d:9XEJL+3c\kO}E*UnҨV?X|J+,g.wg&<تס4!P! ku1ނN&_FM#b@dKKz8 ݣ5ɚ j-g[NgwTW<|=f}]%z݉sfqʫu)&&cMlY4A+4 $, ޖFEXlp˙yE۰tF̬#oQ[-Ow ڹ«'̞J{ϙ#'#3mg5?O_2QiCꀹ2`'BB}OԡZzկ; /089 <-fbM[wLAjUS4Tt٤SJC~YfxyvjϮ_r%G]ywBxt53BeN7oiKzZPUԟD MGGAϒx!T@kQ܃SXS$- v{l1V4:kPgp.{t:P pR<1IO\P#7XZʱV9F=PNNeԡB[K,5,9U?P) VH*>Muna;ﱝ{<_'/ #N~i M]Ait$C90FSuvkg[V]m97)23\d_.ZcyghA=^+]UBr& 'w蛒ͪYdKr#a="hN4DE1$k{bا̢1ٛ1wGDq3.0ϞWA:b,MY{#y~|MnB' jMC Nsko/8S9կ!X;k" ,Lgb=A2j0=b9>IiuHo{IEYNGۯhR5=u(Gh*,=x~uf|rբmoT,M!CĠ&/,@6;i*i;XKPZu)KҠR ]JP:efDVE$ՠ6 (+E}UvAO0]MȷvsN=ҽNva`6]-T ~m$/ ad$=E5j[0LR&n=vo n:_RaDHG@Q"Q5?[5dNKhv7MQ6|kiԾB Z] U$U$Հl8;JD8-h5D4 *3jOmr m%h- , L;ri aYXy{c&Ii[$o{Hǀr<<+n7/_T:eGhT1BYEU%̰ -81ܠ AUQguDFvIv~. :d/0G(jq!SZxǙ}ͬ;z1ڜp-&DT4EWhPD- Ŏcx$^s,oPXFChw#∅>$\MyҾk(m@ݒÒ#n3 ̶ fß5x [!o8կ9 o8_Z.711jސi0S긛v{2l8v}? $)=#YĺOj4$g5ѾX,.[WKuzXS1^%yvcOI2:RZԕ¼11[ xѠ* b0j抡`"t=s9bj1θ'(uW38[.X5ɲ&BHũQMEVhq@@A%A:;r$ٵ+HWZDN --*-l]֝b2ød}MZ$GRyG5Ti:4 vϦh{-Ra1t#h*\l*PEnRen6yP&Ha?Vjĵb=Q".H[y6&9]⌾ O0'{3fqi:-N`9(LބBc$,y"_r5^KWwnѓ(ѕnvcsU;sOEkIxrpݜp]pzҫ\{P]J -g;Kzlpr}hdd=7<_xXy=VÒ|*v Ɩ]]dķJ?A*vZ d&H`IvH,U1`NMۊ d.8xZgxnkl#³+{ųw/y~S8!Mj%?uCk(njVZTM(KmW Ǘ"5 ËR6ŕ)JPnx+%#P-  {SrOP񪘝~_[%dY'ɀM҇EhNozXJ jgvc%2P7Ny' hHEF MvBM֨6켐w#Vj|]0)#qG([Z3ޭ!:W4SN>%nl>foxH3VU,UՔ8=FUNvS^bV%1nqb3tc۫=6h*`51VVzK -%PĵR9~&C$-٢A5-5.8sӮi\SVXneXjAƾE]UK:sn-w1`m к;!,ZVU(yHDZi1nR. f1n>?; l%-"(uEhu S0 S8nK-zu./9MFO.۷3eB n-C+7\XM($:5c*2Y=])+ K)8 <7+ aҟ4+&R6uYhB A*2F$-j$w5FT+`uǼPR+WjݠVp ӮP|Ie" R8MNs/9((B=?ajr^yQe1QEڕXÜ0Yk6YkEb'6EP&b @]ID@5Bo))6k#\*WAWsD+)I:Dҧ* d2zTY5\,6 6 5a`B5HlX?tm p^fHBKӠl(iRv nr L-1VĚX,vGLߝp >E$a|^J4F2V }$aDwecvzw^wTaLP a<5 JEVZp$t$ P3\uG7[pTްxe!AKtEw*47C1Zp yx?XG"5(N9q„AEbۥKQؽr?S^_)I#7zEMwz_# IۗGj0 {/DS$}˓MM vo oMV$_7dkIna ~$cE8M8@}Tb1yqT%m.P%ʇ2ZÐWcP++yɮ l P]}V+Ш ԦJ[;ioХ<2i48+82f|@Q$-mKW՗dYf]pa{vEȷ7_}ߥQCt_2 %SCz֊ NkA?㪺#? WzAn ^_2X=Iuw"gVU1XF}g̽5fʄyuDx>6-l m!"s6y)7cQH9,V/.xx_W(f8AB`ٓIݦˇ-z4Or,xYh+d_<48oB81e̋٘c1ŘZ6RR˖V¶y_ף1َ:l2-+q+H1ݨhb*P3ķ)u )M9ƶk!@*ԕF@kȤE FML'\L'8`#sHƚG[YWnEvne-r u9ei+&j+&z$<ѹ:Ζg-yj&#^2)ם>θZ]VOx,irdtY{=aۄgk߭qʒ~(:& X_xMuDN0Kkb΍}up bYzivYzTԶB+TBArJ4]4ņ͖fܨ/9`ĞE 5 OW(D,\:SՌ+N=_޳PLʈ=&!&U!KHON>;рc{c/p͂}cQyQwZ7||t|gׯ& n\V Wg vG]-xKo;23`.(4JӨ ũΓ+$רfXty{~-b.9]bLE*MR*U_îID%Z$y~ /o5jFime3M!:ì,떁92s*٧Sa SBPQ=G)Ԩw:ܠY[Y vYgkΎtPůQokJ;hOU(Oo_HGEHWh`Pi]yNܭqռzcn Nv̏XoWBj{va4[<6s(69s͎#OW|"8ulκl.۳.]ؿ b*_eti#H|}t5?_V,/7G̣1jo6$ZE\klr1dZhDʈ2"҇)ӳWxveYz)wrF۠P$8m8g1=~snsYxtt4ngg? N)Cu7ovNOy׿?1:$-=ҙGq4e-8w)|y4xmǙ+GR8/"-_&RKij.+J顷uP078mK-,C6g={oOGo9Uo}}xD"<ï}/y1FP=W\V&*cnm4 mK[9ğo sk2׆DOuٞv|#`A@ӓ<ӓzMɅE9H'EƯ~4LMz̓D* -W;~o¯/JӨ5ZݧljF7=k]g|5ALoLtg .@SF8t7]575qO<O<FmE&^īUݼKI֠^ K N<4.|HQnF͈9%Rsh>` 0`_\%Q}ʽ`jEqV`u3,5#!vK -Cd(Vdؼ/O ☜1 #TsB>h=v+[F}VkTB5ZԎDSeYVx/ t!AwKq&rιsE2{K%{IDdihn$[`-OQ ́B)T8-РUZ!om6`!GLCA9kOt5V!KY .OBȾTIe6Kο8&Q5 #q`#eLp) tL1eE:iJ^PYk%M|%,Sbާ!y$(i0ޟ~SQcum&7,IݟQr's-z]K`>.iQȻ#c jP&a$ _-[ĸ3Kf̙lsZ0 + \sa$nj$vtG?9ĺK:$M;$r;T{>mklq)C7տ"QjU [Upliy6cᒯ-Ȗ9埡gUYԧZ=NqX sU`JGM 1bXTC6U(|OԵΨ^CʡAԪNR'%toր 4 NIwy/=I4E(-r:S0;0fΘcTD}~Vq٪_ZGpK m??c\*{{wW BnD[8Ǭ8k&/7?!!3s^P԰8S)G#lEhKDX=o $Iqkb4"t|[z'覟ߴ~hYBZ,GCސوhAkDQd56]ºǶ衄-G)ws]m}]s(0,0DuQԖ@h{47~)0A;s%f9D]J{^?y˥Dѫ7 vt*hpBKK.rZ5zP B t {aeDxz=K.|^1{NiDE&5fQ).6G{WP>~˫OO_.xAznk6`fQ%&T0`=ƛ1+J-T꾺9v/Vp~3\jO% ֛>"g&zS38X0,q IT8$e>82_H6]X2`7~p\]S̶`^_?'x'~犟Q)i56ď>v ZdB_Gj٬E]k{&b+<%ԩ2/q/R E1`Tfnfdϛ_Uwsމ*,Ą%cr*k~u75Kt౛.ekPI)AX36wYSSfvǬ11?E/Ko}$~IXsZG`Z9=kP$BH"QӽskD\l8ZӸ_lEB8TA+BQa =X1h<>}\cO3@JʚTь _55gaJml*tf G¯_k%~ͿvwɛWAm+8M8rG8"8¤UE-F!m>vx9Wg\pEBϖx#cڽ٘sFJ3g5cc偑0FRS{60g]uBZDRp\2o>KJ^& IDAT ~ld".䲸n@UjW!fKd1F;%\!3-rӤlL֠,u!>fH6Zur&4XZEX񜄎q}b.D ih3xy _1 5R :W/PY y`!LRekvHL] 55mF$-v?c, [͘f 5CgŰdX.ɤU.|d*ahkt&m"G%PTICrhO|O':64tDw*tdMXES(R"-h{@@[ZChJj~gFCWn dL+t nR(6 +܇0}fUbf%F^D> '7MDWb)1F%VsNSEc.zFU&2"жHS̺B%lJ@2T~&1 ,0C+(NQt 12Z棸 F#*1Hju3]vԣNB@E߉H#u4\ְ(я*4* Y Qx'x?(AۅhQh ?Y|ϱB\@|'>jCuHt >'04J괊2TJECSKeˡ2e9sa;j$W>~Eu1΋S疁=IШA[4}X|SvU Dw @DV7TTJE @5"(ۚ0]¨K+Sa{aY: qT>q鑔>MͲO8k6ф*ܣ =^x0"d{gJP9:ۦ`9_|TM7~p&`%E46p=:x"Z+Ϯh{nŒ)#UvnAٳ &!PR/uyW\,>v=.18 )6z9) -. GC,.\ϸιܯNNxpK;RQ+Ҡu\t7[ ?hjZKt!CoHY%Xp`?o}Ŭ[c15~b zZh-J`%"cY\h"F}l.Iqxg'zDLCEHY&/'&K.O\F>E>AlyfUfc&8J BQHoMB|=?e\OVD|0R@q#lI;ůx|I 8Sb}jM[cųnUhynQeK]"zDteH[2hp FkѢl$ fZX3;({~!ל\s:T%kLUd)4վZFo%`!`.13&Z쫵CgBY+4Z28[2 BIWtfJsxqYkj3j`8%\$8H)RAidsFS XTp6x'7?D_ B6Y#dK #~ve'>t\?grsm<|F?#C ÿ5~K JiEo@BC%[Ŕ3nl?r>nG^?rzr'@!i{4a<#Խs].jd󇪤ՈB!u]jC8.o12dK[=,> 1` 13&!b:[riP=4*Thcy7Eȑ{W9!=}ĴJiCtgno{; >"}M@XFG  stgxcMMqpx%nwwxAnB>)57nn$⛿Ƒ ~%1ņ-镂I ΠUp=O<KZhQ򐖀\3a|둻푷Xj|/{?ݷl mD#FAPk֐5baH4"H 8YCژ6&;4NUMV7f?p9tC+X#?AD6.mr@kvIGJNAA^Z.4DLkFXU#zZH_)agl{c #VvY}U=U#mR!KAcT:a3VjN)+uH*$ ,EЪ R D J.Q:>f"Qr/b%Kt.Em"kS,$1eOcG=gVB;zP+#V?P \%xUq?wCpL{ԙKQ@Y1RѨ j);|6() 괠FרM&jt0JL0 Tтx+mQS Z]ǥh Ϗ0dI1#w_**Ђ*,a)9 #LېDW%Udt5{lM_[&h9%M "\$6' aP ;}J> ,̺Gʠ&\|czm!}}1[ۏ8,?hnEGGB}=qBY>sCv&4zGx?Ѵ*V;1˒є` #H2҉hY*CF/b[GI%PHkMgQnCU8M#*rj݌Vh {1Wz h*Q VzNjCe >!Smǰ Plh lM3h#ө]ը=)b_ݭKd"MUxfDfideN!yp&"*1M1nC/;;%GXͥH]v.49<OT$`{3rN 7Z$G,,P&h5mGRkL w)w) uҪKg'͘tik8~ƨ,Dc;tBkj\+e*iS=3xsrrss u'jr^|@s+,-j24*OghM=$!cL؈Z1IW+]fxʵK 'Χ;T4NѨSv5 .Il\6>UJhԮάw@G Ӓ<f]شcLĔCl1GL!}%p嬨wGtFdIJMKaiѵ3cGawv "wC1\\-oƩr>1) /'x'kd4&N H^?(cxLz{%^ !5/ogŸ\ ;D.$[Idqel:Ki*^uE92(GH,r 1' mv;xS&B7~+1Ư NQ|,*=hHPhIRw77AtD<"}p /OGKFgS&ejR$P>bfU#)>7Y{+qR(S`>+0˜fS,XBPXQhdQ~w7|/i}7WKh|p=%-,tp= "GڂQp=sŨZM䍍VY*hnęa-;<4Y%,+pNrNr[ٶ TR'}=j#]%[IYa?yK'l?éR*#lfƐO9oWU_7>*2UӦt5=M[1Qg5Xz=UǺcetV8jB{ o12W ykA}G\i׈Nt9xr^~,ųTFm5!g)[z>[D2W&ڧ~ɵx/y:E,15jUtu(_FKzL!K5ʌW|e@7_m*r3ڷkP[ϵuɋ)ޔhp]0_-yqB@=|AŐ]CQAğq&n#Yಟlk'x'Ogk6íf"TG+ZnA`NYo5l]둴Ʀ>M7g7e: M6Tv^bu3FUϱNMR!k 5cИe hv$ϜU[ZNuPuc(%=m)7\(WRG(-U2aaY)zD uMq/h%˲Z^:nʪF A f4À4fgʗt諕kuU690iٲ3\ss{׿J77)~悮 w$O!t &hwH4rB3F7[tT6kzxXiITI3.+zo!9R&>DuBTD5nȽs[ݞsys}Lbܘg(CNB?[1.L&*XQvLФ*k2A[A$v:,( G8|$RG$$zTN* 9\U{,itһ9d]Ѷe m&0c469C}hM;AuB5QFs\c 6^9Va'l!tC^h$$G)ǃ{N[ Rp<\F?=yGyl974q8MK5ZW/y؞0u&Nұ˧^˲b5lvżtO].G a[HYӍ65n?gsc>;|$C IDAT/>l$ 6&a`( ""; ϰc5f'd'lR*VKEiGש}:TmYJ 1}/[(cM= )~h>΄wsvLNq'qTNm|\ʵ|"0 c}Hƣظ[ugUXU3!FG-.>w%N]p9aQllϚ'v>pZ߲$}6q&uE8b9Z\}ܱ]ujl]%V;9| _3H7DŎ7ޛps* P"} c#]HDhtⓐEuƭ:v} Z3R#a#vvQ6:|wEsY@J!6YY4f*к2CV[@SNL+ssƛ%9.Gтm@퐻.G͜Z 0KE G0CmKa +%l11b/B GbC[!YѓjKOm1enLO_1v4~XОT˪|1lH\S|? RbYnE'5Z?;N;^ b,qN嘼.ym5@Z_O F)}Qs.|<=CZN MH8zFFϗ-A%$W[Ւ5>OVq;G1 'E' ܓgY,K ۦlkc!ۅCvC:J`\:V#G7]Ks'|_~MY\Ho"x '''9%+ z?A#<#Ō7 %qqd,Mnvg\oϹ}}zLw婅OH5+mWh+ 7Apζ\Www9Ț~gytE mFy ).T>48{,xU~_;.U T(SLmOLJӦQHJOƯEK(d; )nrJ3{gGqhN;^?NM ȗkdnn ک|0x}ao2ݝw}ԙ@8nhOҚK91-}g} ?~vΧ3 `F,<vOX&<+>,?&_&i|ַ@>h\%O\WqMgg x}w|mn 2Bdp> HC_9]U:&k|Β)wr\=Lhj o/7Q@*А`/y3bȜ9WcKoiC{ʕ~V.nc>4X@wN^ϹϹ]sࢽ+cj×G:Cbh.K֊ظܬι} R_~~)kBwOh91it_Tsup)3>Ίx5&:?4TAEsnpfp0TKgs>RౡÆCmM1ɕK# jiR4.yU>Mi9T9uWFXs4z{'DqL'Y!{+do쬐meXc6>q'kS_X4O/05F߬KuPO]fSlsB?_3y^d2c~1KOpbI-BхG#<ϗ;_?ǿlk<#(A%?q{wՏd_丿NH.MrRn ~ŵjAg Z`;9b̲*ƔC+T/($VOƕ刺fșEu h bxЏFi#ꕁ5+tW\?[~UzppFSNdD1o{.>k'ȕtuJXu 4֥-jۤRWS6$kŜ;o_K:ß{GKD!m6 /()9Cz$Շo=#k_O*|v?%n@zdhZDH-e4O/vWeC+hM@jCSSKB_c.=1)G8"szg%XWuE˰]>P%&Ʃ+4SG WhCNMhbKryyw)ӞY!ȕG~)LjjG Y2b@m+YiGì;16gpϩ{˻wiKޚG{&QL S{”֛!dz醞3[[//Xk}SX^(KXsRU1.*h> ZЎ\<]#Lт; 0VjŰ^,sO_0_agthK<,:i`4-#- #WJ+/^ S hIFu?yGy?[w9_c І&ߏ설 *ꥄjw5Du$RSq꓋S:R7x:eu3Lmd=pYhDow/x؝C\8<)q%B ؠ9965AcB%Y6=$w:-;hO/`zӢ9$ ={ΰS " ZvaRu*eP(t 0eҹC A!QADFvHa:wn*곲{=Vw>[n@;xUW\\|q5/{ Z0WG{Κ=g- gwW77 SN7|4֓r ,Ya55Vs8" /yk>#uFΔ:Xm}+JļJ Sq@ݘxmj%q1SCR'Rg/:L1^MWtڮF\yiȅ{Qa.[B9h&آ mJqLW Z ZTO F?JKZM9#ºea8/+jC#wm+D(ɅǺ.iE5b? 'UVuNen{AҨ]BXI8#t(LM̽kL;A1gLC97M b;!mzoPt) ʷh{:H֫ڂ +g:,Ԑ ɚ j5pT S5Um#zޥV0:' v') >5O(4ܴɰI56JsU_p^p+. G4ưtŰl?lEB{1D;:=jG72z@4$_y >yϘ6TXj#<#?c~a{_c%aODGi+BR"o[AR=O[ӚÖn5I,?T1ʰا$YBgqsvim%IC&xSNB7LvAq):,JӥJ4)˨TKTD%qѪE%"WRZsHs n䏼:yM݁k@_vڜs9jsƊyb?T_C ӣpI-h_4AXTM%> J06= 1񣔡 kV|Z{z5)NF~y{tgh]B-JaQf6ҢP.rȕK!]NթIidatY!e6bюY4#1FmN䌲u5IwK8Q@[cIkA(pUvF!K!^E4SxE+%Npq0.+\/r-!Z"mÅtronϦϭĶJ,%( 8R'N;q͜ԩ tHL1G܈sLI=6UI6}Dzޠ*3]*Ϣ:Uǥ4QO54SlX7SWgrQ5TA1"3da),(_`x”lA#ʃ3lr&5lrug_}va]ԇ.Co1%wДQ|R@4 !OG-Bi]o͋pv09PosXފDx, ؈;]b?"|qn;8xiUQC"r'7'˟Ec^7W AM55Ns=ϗ;|-!-"N97Ēgڏ. }\GV笺<rR:_g,p< Mیc5gGJl4S'-hDkP=2ɐ6pA=THEluL{eb5??o6g>aM8Cӧ5J)KԘo"y~bwD񑩎5ZMGi)MpH 5=fb qKr`[_Gٛ2~u?WАK\4+Ei45B K9u%﫯up>MvI^M7&܋#rABTaXġjt`GL_ՀW} H`U*b:;!bn3r{Ey7w8euYywg=VyG5~Ԧ@}C.)E+Zl/{*ivJ҄&"m@ Wi5Ԁg;ƒȬQ\hjjVBmy i@H~I3dKZ2j̦SP MbPe)DB*P07@"H AxSfΘXhFYl. 'v#:rGdI@DW[&noZ[BPWUeQW&umqpY}v5t⑱̆zT{ %5ZK!QjM~A7R+ 17xk<r.ܖgx"zx{B+,Z!]Ъv^1猓x]քqD~bsR-]$_x{v˪[s,&R;0;Ipp u.I8,\ゴ X+qC qG֔ S &m53SpSMuY8voDb-赤,C ouwC3Cvh \c&1P JR;+btQW7)[;tR>sUkS,[[t: 3O%b$s^Jb ̸ۯ0]m=)yP'$99hC+Ƀu'd Μbl;b;s6T*qs O+l$U>w)y0 &xED JKr#O7NMF Nވ;{;E9fX}VMLIXC5ξd^qlj+NÐË<)~)Z u4Xut1Ci3ԗ<>jtfuun\3X/W[{Rç2J˦kkK8⪹Cg\?_/Vt*c"VPyL?{B&<\-ht-v^? 4tF* FȖbR>kQYcȦp,,BCbТ=Gj ¢~0tD7j̲ırAf '܇휰 CԈ$=1[sge<GyG~eZ4kI}#~oj9DܡI|ȨujjjZW$[FK~DHk|#GLjBX[A:EF_5vo$DbK-MJ6I!YȻNm`u_T}% %4t?>Ѣ[!!q29ecwiN']4Ak$ySl=;h|=rzt"`? yr;z=by%ɮWhWMݣPUК:;.4CP6)]wKTP6Ƣڔ,ʧ.!KIWkRwp0~?__A..6Ls0#i0ZZ(\p^)y^:3ȟ;g6sWn!UnRgUfb%%>{'_1z5ՌiiUcq\ΘT*vP K B~XVAWnwt{7{yI\E+_o5ghsƜS3f[}@G#RN)l𝄞bb;>'oEl={'_?[~gk)G2r$g`nh 4i#y#5ڞF30(]µ(?`]ė/A{p\zK 'a« ]IKu[chnu=&X>m,(&Ģ2zAd[s֜,X&cʙG~9QTV3/`7syfBڠx1!yL0{f2J񞁶d,’qm~Gy䑟?[׵6<~O"-ÜTT%fwGtӈ }|:袦uLE4qkFT2h?,ִۯˬЋjUSUTNE3\sx{`h-pFSTjmQ [;/)܀ (ܔhVfIl@Y.+>ǺTEyxE,jH'NH#CC4dGnT )k|aRj(]#c$"B78 E:Mנtjۤlmev0K=J^uxf B (ʎNueG\OqD,b-fY4%1D t=ZQ`Bj4kBmgXFn(2cX{}V~?_&~ŻEe^ͶN%6DՎHo8[pzd5#7]ì;c}eWuqQ.kGjxZ"×)~msy=pۭ۬05/Bi# b:RƖ5T=*4ْhVpޢJ̮LxgL 7ӵa% 4"5Al1zL1bh_qEgdt-.Qᱥö:q[iTXF+s"ׄqUִJ'\rBCDXv 15&\'ܔL4"9q#}ɈYr$8Lt,"IvÓVmVFR9EU1>?!#2So9.)>&aPeH8Ե,. =I˰]3t-gkלnu1i)1̚rT\"S(ǿ4{|@F3)CB%mZ̪E*=m!T„7.URomО9mqo|>Mr{Ѿhf:b۠5-k F_ȫ<;LBυA[ ~`{>!GyG~l߹?6+qp%OO)K-uC{Pz5jعw7ޠ $b(#MET%W d=>#|̠;k\'al1ЗY Μ%i]oي.GP~5]y}Ofü3aMEeT]!l2e=.]GwY0xf y0L.ƴN RN)*FZn$w!tGdzdɲ+:"uU]`I -4+uWw:edwjvch|!,?m1Ed:{TYw1=\L?Ո}طH|P=|]g6ـ2Uo\5 %'=X%L2U璘>!5m_004ȱ p\ఘtL 2f΄)r9rraƂrUB\Ĕ|dtjPf]ܛ7iJI&%>S!ĘĆ~y9e~?f{ܙd KKΰ#ƌXKޣPpCFN 5 YH#89o8opS:8b1ekPuUvGq-v=vA#\5';N[N[ -EK4@@>?K0-qG{[Ɨ ;) ,.l&sМˉOXbnĆCP$uz'x_ Xw;jwͷ'OuKvߐ9Cű7g^? AkZYUJItƶYtن}BKػʰ|ˉ}Ϲvls3NToX?;,Ky۸~A1{h ޻/Q9R,`I S2!1:,%>C|<36|{~=?<|Cqgp?=%+/fb ?Z^Xx1|8b{!Oo鍷Y9P|)ؐx&[gwx )jHaˋ܂DZz7rMr 5Mg0d-/.?#ϥ݀RW(IRa_;TLe*TB#$$R8mk._H¦\h8ْ q_{J|ljp0KdBfb)f2{ai1I]bO#l[~C%7t# m%QLz3l7CB@c jYes>/8Rq 5%JYf7럹\q|gAYeͱW @6<.8Chi䖖XYuƈ#%N;b"PS~j+SmZF'sF's&{9##UI:I$ jSbN垕2sQQ79}}å~˷$-pG vT2!Q&颦"TH/Пh.pbz;ԻëBBe9A8P`B79ޛ fc/\ĥNzZ{'x/VIjm|&-xi.e /]q~q}qeJ˔F٪%tl76i\qk+Wtz= ѷAGM7+&P=rUg $=K~,aX9 _zu5<8JZhUVMETE!kĭMk%[:-WO︹`=y{#arֆgwz~밾zEHIEXsU"PU6j\3".7XqiAWкx4F̌19F5S4Hj4Jƅq+L RM:yFqLfg/z#2&L sJ&l&$^ J 9rNL*w6cNDKT6EJG2Vf\\7UPE\Pqc&a hv\ U-g.[ -1 _8w=OSJJtۊq z_\#kt69icY|/GJX]F}T:tZ ^|RUttw;&*U*PLطh(?{%V̫>OGt+[jѴysBr,G}VQWo֧ %x(Y%J^ ٍQ5G##y/vxOH'AyFJ$g&xϕ6z*P0M `%iQچrJ]jEY4qU\IJf^/ KF%fI/"R]4>?+bӡ)Ȣ4cY[=VR;OP wEv#RIHI&LSP!ϴ481*95}ƑĘ!Fq`6K&_.' [9n̝(1 &%11S͜bS4vՄf#PՆ׏  #6](UFK:lLiyL& 按5cp1].=•G8mgo9syq͋9ۊ:׈kU=>gthJ F֜tU]vj:H ‘R &M|C"LDgw.e9Q&Ҽn&-ֲ/]Ra[q=iz1ƄC0 8vR'-9wA]Q]'v'x'o/Wuïɔ.%0khrft>x`B(g:!ƠdDIQx)W*R~.%RѨ ֑i/dV&VXݍxHtK 5M$/L )dF& e=88N w.?_ ~愇+_-k+ rS3(P6z[-2A*tc/oihhͱDJTBR[ϲ2-O1|Ү݀G~վzVL5&d􂷟_6y*½ 9цAm7t fK٠6 Q)̐nř~`ކCg0s\S5v ]uGGRt$tT-6)Cus3{9c3*d6;4$y= ^=-Aw`jͫ_Khrv/S32 !LwHJ%U_6A-91 %9YV2=oGIzb*` p\ZdA:.;ƼZ\qS^2'fHrIJ__sK>/fxuq; ?|ˑHGl;:QH*raNn\;312//m t1uڹN?`[rS2H]jI-#:{""W5*dD׼2=_?:<G<.3rvd:0kt\$7gP}$Et-g9knߞswswK9ΜÀgw A)C.wQs\qvsIU|N75>g}8L9Ly}~wM`PRg*qGС>ess2 ]c`# |"tr e'L9!&SqBs&W6{aP^D=nF.J]6Slt#zS.L'LTs`AyVO27# 9CkFkD2}~O<O .w_ b"u] ڕ`w\d4A UJE)4D;4{>}T;TFkLe\)$Z&tBat͐nAH25Y|)?9'I̱&3 IDATq=o)ӂhӰʈO2}E[ VVtESz1ЭD)k %,։ ]ex̏Y#TD d-4REUsb"\1s+o2g{z5'W3N3&rE T)i]V PF:@_X&d򒟦_*uƑxG3g,#Ӏۛ+{ 4ۢR!TVy)5ZY}xDFHsk GsOi3qxV jfP/yUgD9 Su§3 +Qq\oWX>΀>YSdy=Kh6#uPZi\}~ehU'5ފooGIXr^ֿ̕51@*G5?P^v m)5)0Si'߉Ჾ66?yk4c_ib:~Rt7h K>l_nTszƎj??r6o#\..ZItX%cV3bAO_|ZԐX)VJv#&T1˔ݷeҝrlc2B0 F-ʸBXN+Et RO<O/V1KTW>q#OuVDXi +N)vcLrfIn6&aQdd¨SI?7L=Y9 砎6kʶTQj{A;3hQ)0ɠ,*f~,TM1?0,8=]1!EgHL,Y}ʢ$EkIKe)dL#0jąPK|l^rW96$H:@ە t,1o7V%ɣI4ߚ,17, k"{5N'f`9]-][NYg㔇p4,6HkM*K+y=G~͍|^s(X#>&/iw9KH}):[~1HQ)]e X׃O+ՈZwsɞX֙(U\UE٪vF^redo[0Nf8AHZ v8kGg, %%xCrxhuVu̠6X^ ]!:O?_3(V  Y#:`jXa}$z W0U.P yX#ɮ!'#ϯ,ș3tS2jF[֚ff{$ 8Dm>¦mw4*̤;CuI|a]i 'a: JR8E[F[a9ceF%^am)>dQ25G̰bs |pG!j~Vo4!}'=qmmu=\9W{m'ѫ>f@9m/A:q .+uHȄOTLȬ 8`O#UaWvإ>' FDv)kzcn:N`!M%<jvƘ9B(=xO<O<_/Xyw/PQ(bt4 K#!N #:[afkvFOK>Wl>K -1ۍ=sàZ2_yX]] u֤:sҒyM4K ,%u͗,iv,1/CИ__D'2Z/9?2 'xUw):Έeg}gͪ3 ,@{h%ʰ!TLfEL,wVv/Y}6QM#|HОH'>[VQlHbR EOem#sLl'cƚS1~ R]\&j2D3i>;N-;l.6bQQJa3gBWVc SͮS[cѸbjRѲkz|_~ Mc<;D\p}bp=lM䴭@RڂK#5ϧ8i@ BIV,&N[9:Y+.k.F҂v҉Nط]pι>oy"[S (Fm_ߔʕ+<-SdAqjAh[dƯN)|}'{GhZɸ] K06> 5YkKhtSg26pb1wAAd=P{SJTt'Kl߄8J+Q59}}ڔ-,E!l}#bդRerY#L-C'):V!5|Nӑp_+?zkƇ9=9e8mBpFCv]1{bJ|0 K pF@=iJ)G.eLP_(Tºq^ 䊅'?֑ 㯦X1DEG}㰨U4kl`.:dsf'(kTzIeTe8hT-Z}FAa#Vy^x(UO3>ICVPN1i+za7xG h61&.Y#s'x'+  ǃ)W5fjl>|?dlox1y7\;;.;.;n3Ԧdr]E1KnlZ#GҎ_-=.ʿ`Za]הiC* jKǯKǯmzW!kn3"R&lE0,8=2 #.yl ,hlQND ԊRՇvKR;VwC>ݽP$@I楄x)h@-X#J gASJ4]w(otCOrPՒҖҖX>sΏ(T4OH0sTjِ՘<>qxs9QNh2M "RШ0_{Ξ?0yHoUCdj&ʜиp $P%&ې7/FDR5Ëk5}6Τ %I[ľM T^w}3L#֫ɣ/v掎; 8cAT{0 by_c!2A"1l&6l TIIܛtľqdZRժ;v+Eiv{hRAJ͢~\A\{_N~ɣ<&M[2Ak 49ܼ{H3*WtHv$RUI%-5 pǍayԥrƋC[!#ev"]8a4HAԨjNAY)[`3,Ww<d̰kiTa61]iDQvI !85ժYCΊ[b&Ɩh A3hr KM[ʐLJmp=m!a9A]/yLNu\W)tT>r(aUϪ #X]㬂CdJS|ٞ2r\8׬.1ԖHJNr+.h)*,`HZ~‡KRiݤ9#Ԗp r'q_X0&ԕZ}!p]*K6*K!UM'l!;%kI; Wq9s&§ U6mzc9s#;5j'G34-Gj.P*A%}#|B'34 KC2[\35H*c}kZEXs8hkst/-϶0 B&f#ʌ~#nW9R} HS#=64HM^džAeOP҆2Ӱ L{Fϸ'x'o/W-JW:2 h~NčMNo;:;%Ɋ~@^6yg](g*$~).RaQe}p\pWDʦf4Y#&|>=h{3>-q}{Ez+9qoF-#fuzDLwLje;vNt}zA''_x9*^$[Z$KB1[tK:Ǝs3s^CPwSC#nԚTq)gn>css疑qA5 *U%etCFq1GT#{ܢ6%0\]9'R]B#t*D_ȫ H͗]aƷ9|mpʱh iC](ZDJUb1fq0h7mڔBƗ#.{f/SY ?^}+LG̸`<|d21̨MD5)T!Zb!C((VlyĻkĦRdZ>D),[<+5#^p͈,PΙ?fdisl_ws F0"rn̔?*F V/SՕYA28m=vtaQӀ43B|?kMM_ 8{E% YvA_ʻD;CtXj]vOw3j J_!Zt-G3hxԆgLc]r:묐 2%ikD2q_Gc^A,9KTQ{|n1LIЎI6i&lʦ;,? ~:%s,rIs8op'pS`rv!tDnAn}-h ^HS]hEf\>Jc^PPkP;hCHJBa(LJƊ owqOI##h1ro ^Q@ cp;W$1VQ\īg3<̯_O{lu,ݞr<3<__sv] @&JBhB̯֬-Aeꔦ!u!ST;4uY8<\4sL@S5r6ef!K(H>Okz]pT-R\=yr(3v"'Q :>-:09{={H>3@@<㥫,3,ԞIUMޔSbK8"(l¡H,r1`4%0Lra$zU-vȅ DR3-НݩН˩[YVT8= ZȊrLj;u*6Ya4D$3JӤE3slv6i"hvG3ò2LQe(D ,Ы ,( *[DPֈ "a"LČS` 8V.2ewjmBb"XtT;u nqˢ2pXxBknIZI@آ[%o]ҵv,hD*4M") %<#E~0RE/[#l @qՊK˭=Kq\O 8ǀ%PB2pHD*da&퐥.hE<8]"Zː;e``9V 4 HMG3j7` JM񹅹[$M:0H:ie-ѵ0YF#)}rp=8$dK| RXv9Ma;8 R<*Aj"SCxC0CE4?PGvtTR ꨃFtXc9jPҹ2t^83n:YЧF#gz(t-i#M2I)jtS!lPگ3<3^yx 585P/LT@.YR&JJtƢa=Xz(d^D׼ќ͓<*SuM> hZ>V@&^QАsi60&l,Q@W!u$t^L'b;kpv&9 ne'ړ5Ɇ0э ÐuB;#2y{!a|ۦW61N+;Hqi Z]b JЙ}~悃A]* K21Y6HI^9 ;|'aې>$C3WoOQ唑AeuEXĘicSct6Zt ɕBkZq>j -~|{WЉ:k:+zƊ=Y(`1'< ؃sF*ny┻fUm-E z^68BЫ F% K\,PCA쫀bLuևHlFYػ ľOA EX5mꚗ5r vuwrfP͂-vYHZzdM.mFS51Þ1'6)|&ŔI@Tn^m3Gv`½6aK>ݽ)CR&Wbka瓬kt!# QJm=LUA6H5,tMC6Zlm6O-\p;8Lh]Ra='6:q[rS5:#=-S$ -)gr*)Jބ:NwbhNȺ.!]E. ꥎ\K.jqDie/jѳN\؝2 2yGd?-'kGgLXJD24Y.E}gy_Z|?]Q[:0A^U^O-5VB߃BIŋ~k! . ./xFĢE IAIPuQ=C>w&^A2_8#s-?]ޏ|~b6GQJ9͔#=hF^ѫWQ%5=f\4ot>uvDTV0Gk~9:_%DԦAj$VS9$];-9=oAW̙E^Lm@w֠v &Dњ_`#G5X LmވGh&lM|ݢdSE:D:FTb9W`0=eOp j*֠&[JQ :1Ә1ť򣋪 <3g`87o sPW8TɌuc2.,54QS`ͨ~bT%jΕ|Ń:Gk~4b[(W&ebPLƽG\g&{ İ vVܤ'9ү,.=A{|?ur#ddis{won["Mƫ9#6Q !~*bB=fd>*!$7dEؗ!d7E,a93VDx GS/:SګՎh7Ưlqk%;ⰍmP IylꈽIT^8Y/ןl%]%Srͦ/y/D8dl.{c3Oyŧ?ӟ^^w)M0L/ً(ҡUg;%u)6IYvKi-#S&qYyi>.?Sy8zg8eNIgtɀY>>Z?' 䜓<"H`'\Y/5 YXh9XUItEUi_%FTv4 lrg`uUkTҦ*,&guvNOx.##bM"q.?:yG אָ0xbS[KmRY ?`'j謶TATR.42 .[.$!26Ԑ$sn## .]@vLG@:إJie%YX;M[K)I rcZ^=:bQ;Lw}t73T Z i,ِl S&uQ&ybUJ"u<%tLP e,wz9AA9hv404@C" S+87hY[+>J$z@*}ݼv4~Y9F3,# Fn=ygy3Z㷹zru꾍;=ʵI/lJiRIQ)2ja/ت}Ta[C,&%њh3Z1_jĤF$]ҢLʲYZRh6;#scs8r9T6=o BV1RB$\^BfԳQ] z͡𛪀pa{?iI|=MX= Z!v'uyӹ$-\R'zϢX xz状3{8ZJEY96V^j@h^ɾrb;=[8NASKK*]ϥu)+MƚROŐy0$9wAEϛ393FOP($,rDsj^.K<w 7G~JgQc#17ol.ׯ[jߥmnqTsN!M'"'Nۤm:k'bY;[)R,kN# $[,eJvXɈ4sR`C˛]ަhYB,(kz5=Q/| *hMN~z|||챘٪-2͒<T7|R%Be$*'3<3WWk7NQmu.<ԅGv>5:ՍNUTE, ԶKHlʊ*d+X}VG͂50p0˒7KNO&3D+\" xF̼139OvPRP&e3[<nc*[蓂Η Zٚ13Ɵ[ Cݴt>CŚt  ڧTeۢniaʠ;epŅ32ѹq{fQH5'-2[ OXZ<>OsJe Oxwǯxa(Y!6[ZQ!*.>pqvً;.>"s6)&mѼkT!X< 8{3&%GA͎gQ#kN} xm\Kk턝/y Ѽufn X m@.mz5HŎ;BbBD<2"Ǧ6cz{QTC-YTdIG mAfZ6ژ{1a##$vwv_߶Yd}EMȘ/9>b}9lK8,=]txz5u&zespP.^>mo?ӏRXVuiz嚞!(Xf84|Rz3{Z|7X|jetY'z5ˇ΍O\y]ञ2V^6 6cPY06p>a ؅/0l $:e~&Z+<`lBlA\C\S.S%-L7o =⦂[ 7CI5/W /靭IKRk {.]Vn+g7k&R=IYm'gpP=AՑo-J1^zW]K,2JС4 JdjǏ/Q}2)?5f.:j;J(öevDQ{gyW˯mo}w00a@@u ]YoUڡ)M,Gc45i…RC/ʦI4̴p7;GMhJ5לhX*bK275X1)F&)=p8皗\sƼ@_aSnsqac 5yt.d=2_)} zK{S_?&<ӵ-9BjUNO eS >KL<8g|A3y͙wE4^cZِٻ#n霧hR!d Gh}modjf{?*ˢχ["bǑK\D X.R $~0DS~^+HМ sP`U)r1wLF__Ҹ~EhJ?~ɕqN,H5yh= >ڿĘJ^s;ORg.oPr4J M3ԧIJa#b7pC.j18zkl;aQS>,euDlf쒈8ko7-BJjgO\sâkuDT_g?Zsb]w'`lTĆFG<] "P_!| DcG:@ ĤF ]44RuґN]FIo[t,p[lisZ;c)>n3~fؘ(qB܀I2@~e\JiA>YmVm<3<ߌ_ðtAP ZO}Y% NM>P urm4\@( ՞؅vĮQ&+Mv\6yt#X5VԺet-cJdl=BkG[е"A¢aPb!*v)0XSj]#P429P=9]%u]|! Mufhm~꽥v5ޫ7n{i,~ [  ڂp٘hK8d;k3 î? 䵃`ޜ9/_\28{"?342<%6.ɕM(b"$q RVު0Z3. ⎽ ՜% Ꭓa$LX$}feuYz=:gghH aX:=R@X'P$lSBj:ؠ<߲-;̋!?ʯdCݝަ as/ T`%߄3:4?4QFEgOD:֒ܰ95Ι2z9׷/yG([ek"$-E ᜾w8(?\G "缸Ծh}Rw-RƪsoH*T"Ӑt% :5֒^{IY>QF| K5VP:~Bp)f<`=0Tr:G/jtYV|XGt-*iUA74d[N!هlFm6^svi&.bEIIlT@/)n8D|ZYYEL>'maR&;,o St'_-UP ߞF<3ʵ3)t\39hSj.<.::$ZZReĶ "{ˑN) 1tҶB$6MXJJ`'B6"b%EJ뢴6 ʰ(L2ӐsA}%_u̽%Te{BQtlb"u}6OɈC zڒ7{fyE|ݦ2(6F ͩI8 6W2>_bc e݆NmpW g↧|~p]B=^=^ѵfL1־aJ K IDATuncnn15j\r*yS}$ma퓬|nS>^A{Ex@'0^>bqdkxvCLW'FeTjM$."ajE9uŗ6Orc=$mnJ~o 3&)JG<vG!ZTG^4g=-nN͢&ŘE>B۵Yn,6@uQ$6ZP>Y u jڤgL= l6|ソJ\;1\UHp(]n~6Q]$*7t5_o!.K[ޭ`F:a+|M)Ga}0M=NVtV] '<H^ .w>qGdYpҽgҝc$N'c@Y6\U`?͏0wGܓ)d;iygTy%ts 5 ʚS.j딄%*p7i{񞮷ctfD b醘ZM螁%7 7Snfzx ,X_* %(NIlK5o*|/CҺDYnGW>pM$0es T=C{{'<<1%AC:3<3^~ϰ Ѭ,AHmܬve˔"*.:(WU^PZȘxϗOHnò;`:,B[H"}3 fx[ Sj:trQ`/VkmLʦqJ5 T'5I s֧:MnꔙN5ר/lx1_x\ W߽pA=xĉ:oOHs"'A) u*@uP35~w??ֈoj0?hMY}V@Шwuvf|oG{sqK lr|K⋄09??Ɏd[^[kwq$wT"  11Y PJHL 9}4᭹uW ,d"+%I]&3Z߷ެ$Y9 f.dL%+-K$=|1yTn 64u'if/{ቘ7cfofsN/0Tź03tz!51&]ĴWeZWK1TGL gu]#/lFjtFTq0 т#qhhĿcXc-K<}ٓWVvj]6e1dؤCij_7OʹHR1~3t29aQxGg|7#}΍m<'ȺXH\UT7~ir3;O[' 7K>X_9;~$۰˫Oj"=֧]~J?_(Sb+J۸vߊ++o?3H{NKVc|{Ze .!)=edX,5ȱЌ< \OGF ę ZFb_nk)^4\$!G :%fGZH2$ 6[e';l.nJXWꄞ3=_>nanKmK|Bu.`\34l[mHjGmtB) ,X;]2!%\2#>"ݷB;ͪg#JTiBv*Zf)r|`JdIDgG6)mΦF+ZzOx?%l e2ĄL qSqS)zЀ6.De vD2PtAd{̝1L䘓slV.M, g ͟svN$Ǘ{=Lv3׼~OHZR4Nd{l.wՔm%ZMɰuQ뚱;:/pFoI:L8{>u$2'\g<7Ժ%jȲ3C@$ɉp`QOYԣpb CAr2loЌgT ۜp:eQ:wֈ]EwqObNw1x[]ϰb+#2Aנc<2h4}BgP wm{!,) A䲺yf/tɻ_t -W uf:%2p8PhO,>l1X0ba@$C/sv6n&2 _  @AB,,]̗&XOM'`=)q-Z'x~ 6~)KBj. 1R'R#Nc:7B5$j#%IߠtYO\LRP\E]Iv KQU=E?ǏYmt ;.UIFB0{k55A7:iw-fwDwIלN^xknG\ܜqq{ʛ'DK1XCB|!.%R* tD-k'93VՀ鳍jQ^:ŵɣ{^{?g^`7ʰ242YL|̹q5R"c&.1 )kՀe5dY 4A=0#Ah5zh)d?el!fø^rՎ>[zƖs }ɽBV4C PXvetk\;mмt32,=sNf@B@ҚN4Qw4ꮤH?oc9ec{s1ffph[[.QCZY#)kvf'}G~2fH8y|!ɽj6K9ܷ0}ER,39:%1'Ih!ulЕ[ZMC(%Di:PZPlQE@*0DE]lpQN+akU+l(\Z"Ė4)tRT}wګE-HR\4@5f'$>J^HpGopN@6@@NSt:-F[Ǎ<szuțSv4IYԵA;8DZhpGhfg'XBtQ}*FbFV QjZԄf1hz}J}1Lsc 2iNwHt]U +&fjϰ|_mfmV@ iYWz5C9JÜi=#6]" c:4D$Ua&T;ngl7I8/\C_; iRG3|;T_ &0.ѭͨP DT)ћj M'sˠڄKYH+BT0JĈ ֒%F<6.Dy>ָ%V~TOiEG,cLFEINIMPԃ o$NP$KY}!׫GY=Hb8ˆc$bYzCKRHFTIZ)k" S{KK XgoWsjS8-pg]T-B)w<<ǯm>:d && 0aW {սMuchm{h\aF5/?/! (`zɇO/yK|1sf}»]t>ܷ|~ƺ{@ifJRL5|'x'++8bOh-}b%>-(v[b;ex퓧.I"M]DtAh᪽3RZ25:$MTe4i?~=n?7<|!ib~m~'$Ͼg_xͰY":7 }LaY$Ox$OKƋy֫NIv` 7ô2L-!@ =6pH&%GٌhapGlDa#:ܨ#G$O\ö`f^"SEhTNj*EhFX7 !&G-GxQ|U!~Ἥ1&A P/$ZPcGni$م6bG60~[A_QjyU;9;>[Χ[sG8FVE8ybB2I[YlD_|݋~wp""a70Q^aPubL;i9砚s񲄎iBZ2eF[N ҫ3Β7< .5N NtH(\"f-R&TAԌ{'WyX^x~ƛm+' -Β4jZT-JI*]tQUEyYm]CR6.*pLˌĺԺf_~.;emIߎb  M IDATH͇D] $q\vzb7avs)/!!r#&$u{d.NlUhUvPt*Of-Z `4xw&_p6xU5y)F9!R!mfb{s& [˸<ʌ??f3>}ʟɟ4 ???cevXx;#Z,cv]k&h RL53qwj 7V76G.B1,Ex1+{1KF_7ԱƮf˨)&"_effiUfվbikÓ'k\z,ńꐩ2P%-"b#r2V֭bIZ~"Q6Uf?K2THA4F#%Bh"WȸA A-%S:zV`}QW,Ei3KƱ˸a^s0욾`&ZPAaڝb8[[j5f^bp6 "m!k t#4)Z&*3ZՖvhHhDg+ Jq~aT3-7vT9,Ikn]y.)R(iSu`jhlIb:HA.jAdUn 25dt[&;:3KϽ56O+ՠUBJ ⥏x#qe%=nۋpž~E5O͵7J"OmTQ`ݮpH5/ cPl˴sZ+vd T蛂k+F͂It+јi L>kN{oSO= ;c  c힢6)@5!\,Ub{UE/d@-u2$Ƥ,4(zSZ5]Kk\/esZmS a6HA7*L7I=mC[ T]!V>C,|2LJ3{ lI#5%0{5~ӷNyeP$e`a;걸18!Х , z)ѭ0kv90&DBX¦Ģ L*ߠu*BvJ쁢=Hni 2L-6f\M~Q3\=h<g+3~??3??oo;.//?~u~Ydi" :[[~H]i++:KQYVDI6Zm1O~J#<.DlAu%):ܢj  7r02=0m1TQ*[f"?.??%|tÎCny+Fr'ȱ",v~tEz 첉l!C4Þ8H%[9ԡ$[8VFi-L{c`{-=fp3ﰚ,wt#Qqs%=sR<Y7]V5AIԎ)g`K"&]Gϩ1Q-} Km:`>`:-'\p^06tNimy<3){ FQ)R{3b%t="#2qU{sUl>YpH7hC-t¦~Jl.c>I a4#.}͠q3veYNP1g :yE`-}r%Ma}ּŁv'ݐ[yHtOqsb2F, fk==xv?)ԚFTN$Ą,S DX i6K[M⎻!ٕد:QdtҐAa} U"F~Zc!=fYv@ٴ-oG∄Xi, %4]KaHAmr,tC4`Y9ahZ5S\FDU1׭SnZN;i >Ua-pp5ʱe6w]+ݔ5OsReٌXc͘"jscn_ݴ``WC\B1螂?p;jʒ$CvI(lQ}F)sb{MncĨA ъ7q>Wd.)KD.gWxWf雯~COnwOGG_bv_$5o%uR6u4";GC{k5֚V$ FP"V2r*rnse|3>ܢˊd5`s~'إ]vi0mrAPB <)bz]̽K>]cY4oo6qwC~~ڈ͸v!2| =%' )2i;CيeZx:z;hhy](MܥV:iJP}_; ח^??Oã5jCran{CE IC;.8 V6յ ӆX0 ,110gF*xga 7}U‘# 5-vcW{Xff5( ' 7!77nQSZs9gUwov.a~6Aiijid"C86(^ߋ{!^7BZUH hU)y}g,ˏB~V5Nb'Lby{ͩxͩCr1K$;KGG --͙sdj3~ O/yLs>VpV| i>Эrh>;b]YGm1(jc4%FSb6վ3/Ѫ.1ȑAS Vh5txde X,[C[ V#K+dD[n9n(W軆xby5eAےx#pҔN17,^bri}Kϋ4Hx9-y͐%DwIkF %QoזփJ( +6p얏/1G_q !pH5Wx~̺lڤ:i-G[j_,ҮЖCcơwKehEHVzKɈ>'^boTgL:)ǓG)A@ұt-ʖ6&\\Mc&xʋ=N]r'%K!s9F~ѐd"V FCg7<|G}\]]/n[_>AJ]$IZyJǪGWuI`:J'_ٰi+ξHɫh1=ՋwX^NRTЛ  HAQHAm +N7/WZJjM˻!?mcvUt1Qs7o8 +wgő7Y␭4†{A4mS%&Z`'?> 9|~3r3;ǷGyd^0tt-xybaqgz|Siitγ&B:Dtd>(Szu,\(Rf‹S&w/ӟȻBUχ>鳒(,re){*x)@SyZ_zo?aPdqI~s:~'|h-yHٮl}._y<|~O1(;Smjnr%۲GܭxunJRq1c\1iBF@Q:n2b /O uS}+#<_ M]n'E Pf]5/{o#[z=81GF7\3)V 땤vF   uð(RUu[ޜęg/"Yl SD|VmxYU&hF44Aݑ]Ҕds#X ( 0EJ,Q52]]`[Y*h5 BA.c g;P5Wn?׏iv- c }!gTԪCDzCuJadcp?[9e׺>1$DU..SyDtgIJ4]ө丂2"&5¶ KFK,yK5 ͜ZXmֽ6k\E%<2ˇ>܂I'^v]eC2U#2 j MŖy=s=Uwr^ufb1l,BT/,A!ûG;C} T6k T*.vD@L6-j "U"sqQPudv\Ӓטkb͗$͗'01FLjxlMC<{*ssuإZ{v<^Hs3zd&T(L෨SZU0 OS`%(7í^a 17S4B5nhkŀ>dxw':71>~mt[v7 A:.y0R~ƻfa# bT! !1ּ re~1+%;Y=fy'm+ox|1ЋMe!ϐ I-UrU6x!FLDLI8ܲY\Id%O_EMK:%f7FtHk\ |5x*)g;$ID\s)( pUXd3l}UJW֥CRHYJUduC$lbLXw.a S3-n]0v5f!\94kAj^UtrK%4l2D2rIgR.j5/j#nɑ89a3$TuP۵8~O!i1U5 a56XEkrRڧ n2;KPmM.Peb%(*曧x }s=5Q7Lk ]׿ggg<~嵇3)HOsFf]tXN׏tfqeyeq٥:bY[ct)4岇b"ڷwva,.9 ̉J*,-fyYކM{)^bǛ,fMբ$hta$]{AϙI9j`0m! v#"<',bH66_vXmTF*j&$5nzP )5$yrSUt?'=2I-net%@ib*U(m\ ٭ЕԹL4=h?]n/~IG_`1B&,.]*|Ϧ*T.CݠBa.0ED|7/9"zeڮJ\L&)ĝȚPhUKЎKΊLJ5ӋɅLu_j tAd9cE`";4 A[rOgjCHjr1v HǾs`SZAx3NY-֒/r.ꂲ.'І ezD"k6+)d4-uevaǘFLj\D;|s>EЧe)i9'gJNw][=s=Zs˿<~ۺ-A] ?Zg/JnRRSZ w||!NGy*.Օj. dJtY=$Fȣ[b;cq3qiniF˺< NM.}Ct(Й=lS;{׌G]ۺbO\/pnsr(N94Oコ1Rmd@$6gi)v\@.:/WCK~-n?W]^KYmB!sU&A~i&٥4g׋}bz? ~q{UoglfSd9{OϿ?ٰ߹_w}_K"ʘ+yuA++az$ [±Aӫܔ;V;L!]KdPC^S5ng;,^a_j|Y~ďCJ +F&ݘ<Ӊk.TujADHw2;9\2^ӻP qyEZ`1/:V  jqe ss&"ul_DvJ3Ja=kz?ȾRT*UG~[*dk-ѪwcXm6>w2Eh9LZ#$Jߪ Rܚ>Cj5 NдK2SVp#q03 9n21Lڧ@٪QQHdHlRbc!3 :nJ:;QnPs?9`u#mV/:$ * IDAT)s$>)?nO7$s=s=v??eZcrOO?W3+sX3QlXFBY,>̊g2:-g A] 2l-vRNfZrBDEZMU)$AQJQR*a2cfq bqF׸xC4+ڄ+*3\% k!L*ar4+y4MZPdTZܫP:9yGcQ}Tc9NʙnKp[ЬJʺtTKO Z AޠAi2O]bI\cfwk{o1Yя~ď~s#Rb{C] M]: *p%%Z!U,R(҆bGY/qCN1Vqqi:`Zv!g#MhED>c(XhzHa/UBffqUٸWKGat3ĺ!Y\i&5*м IHm1dSx#8O4a:C:UGgf Ǽ{>faJ j@.cVkPa* LgoFT3W=R )GSx]bS8*4=i* >ej pp8e߻w)g<|rR(bRy'XJ-"͊C,CJjH6'arY6~Ļ!lp[>N{.yC&(%<%`l_k]3tf޸Ѷ1ڪbRE%kE1KΫC.C^ލ6ݝ@9RtyBTڜg\1S̕>mkE[\s,N8'~Jxbr'4۝Ӊt^"Z!zC"42P*Ra=&bK\鴪 j{57M.}Tb7s 'v" U/H3l=9Ѵ+;vcF#J|lh6ئjorP'h^ K2 W.uC4ؼns|tBg|4)IEwOX\\){c EnƠeFRQ)F]\0u h $>x΃䌽P6 M""|bX,=n}68E4rly6jaR!#hPq nIYpyK08p!q.Fq5lS}Cc°?ap4h]m2odW.e=Y]t'!iujr=h=0Fz W 0r\{W+@n+q(u"LPA(6S&-Up9]쓮kn_0Dv޽{緔ڼ0vBOѳf)F0χ!`t̻;fؼduc utJS'1x^Xoh:ـOG:pq[05D=nNxc^zFaN4ƗTzl-.c st^]~ͧAeDٱPv,]iu}UczeKᨔJ4l^51wBjU& 6G^+R|R~U iizCv\xSYLjex"'7(?Yd?#KĴ1(jD0.$&g )Oz3_i-rWF8G>vѫ*Nri!Kݽ9~S+ 36vfXvȞ}ƴy|k)C?/?({S~{= F DK۰_\{3kW?a.R k3I(ULȕ+!)+|~ oo'D0SfՈ=-h"FJS(XX6Se@ \T$jn!^O3>:/{K/n?䫋缸}]X[]7ʖJtglJvyK6ꗂ ,.dRG-cuGl޽y̗/>aӴHuD35LWꞴNەDN!U(?5/HMdO'y_IB|ȭi~L,lJW+TBn(6y"Q,Rb )]v Yw5rq5~0>eȸ㣷حE)E.#k+Ov(Y]oX,&~,~8]XhbDxgwOF@'57˗=_{XZ;Qi['#Jq^` In۴Nv\}$#|{o * y-乂(+&BmRcUƚbܢ[meQ72U Hd'PQQH ,Q(2Q+`e256QqvzcY]fFKv3mJ%\6 \9`NUf#wX2ʁ܅EaXj4#LBvK@郲]R9'Sdnэz)j ϶CIrnyTԨfډ0f6̦HZB쎈Q-rY69` *!"ncӀm;ɄM3{ K*jʩjBH54$RVh$AQKt5"eQhYLE2jZކ5f`J)vN892f]O[17#XwXCn5-ݧ# jY&<ҶE9Rf+vkZ,(VH6.+\HӎX]R#Sj6t zIkMQ*a+#%)QH%2Rr#o/FJP\9`dNxc=j+CFaƣ#8PӒ8,D7Ek5La\A3q 3"%sG(Jt6s.+&)*i6=w{M㐎tRFd5Zce DDFR-!5BiaM"TęIoH Psdp\WM)@ Y])0ƔtT3!X"ƕ|J9IBf@ID1RѠfА:T:Uu!*iPRR nnRA] 4KͯP^M3iPªQZ$nЖM ̐ȑ43Ym,>mr@/P[-4sIiTBi˔BdLAUD$EcL%CL5ArԦD*kF jĪsx U&9ΊRQ}| y%a8 {HlhPs, Mp5}P^%(ڑGTI^ jt6G00% 1H6)W&r&8̤1)]߬9l8lyd\G\'C֢D9Z:;S#;```4VCfaRR#p 9iW#J(CBмHQm\Ъħ$gS<\~Esd ts:{E)dl'-^+T4B(WC(]eT1Ie,4)BY6uطX)b)c}3*a#˰c:!u1g )zzL]I0K/O.؋.ؑo)v z朑uÎ|˰ahj,9jbGc MK)d 4Z"u*D"5uR42YGJZCM5Q)!iuC& 99Rbi{6Kͺb%&ڶ.eI4٬0y%qʾvɼcX=\%//K%G\bXX}ֹ߬e5xK}.&\NYOHΣ9sQ" YTlhB4Q si>FR_*5nFxɡƛJCFdOW/+_"Kesbq>`sQx ![@aN^dZ%k Wp-\3ZYm}/ C#.7=n^hCr4Ҁ<`. iرo908d >?cDQAY!AE J_DX4mAu6e'%ɢ"hH0I0k!ד]^^Ո ɫVm>cA%]VJ55)P`3ǔ]&"F;j@o6uo$`vajī!^hװYLx|wk>y-(=dv#UquJk#|R ՞@r 5 `#>rÞsn}ŮtAG_~k2t T#ZCe³Kx6xXJ,c4?#&͈OP`GL՘풀1Sik>#hγ\)@S !a#d)';9$DQ*@WS%ФJ ŝFJ67'|n)Wqbrr*""Tkֆ9f bvK>~iCNG 6g<؜+8"ݦlG/U:͘0p99B[WѵCx r?Cs6ˊ.+aMi=6uM"\⁹MSE2SfoDsC? Os2 tR .VG, tORed(r:̩ r4h>5wݣ%_xNm@bhĶƵ="e&Vo6J|N_C4S ޟrɄer>BD.0'<3^9c'#NG\hyV&huN#j@rgfkzIO9]@} zLnUY /A UHKJrOa\a-{"BPSҐc3 {\ሔBR sG^gdI<㝑~7m^@>-YZKv-?ffOf_bO\6`JPD&pZ䆎v0~wʠ7ۦ`w\φhوv+@~*IG >~3=s=7JeQ[ѕEHBS2$B@4 Vad)j^ b)!bjT<3(SeM])4BSਈTkH:HJA2M G&JAoGX욷<.yjnsS=D%(+Hkt'a%^ITLm Sb)LzY\ǒ. z*Fh0z*_v,xO}v/9\$8)Ufk#x%{G2S Ѱ,-TB5R U B)u#.b>"Y$T)GFºn䒆RNTEf*Н5qCW-VEZ295$4J,$"yN}"9a-xݠ1DyŤAZ<Ϗjgi;mK X=u{[GKtƜ/ E,5ʕ8g1An +Zjtǝ=MeOSS(P{jVP 3s.%/^֯ELIj&Ϣ,hZlb8C 98onO܌aɎ[)#C#G(zck dwbk?_QqqV)YP?rcʼnJa*4ImJC=?!Jjy|3PEQMcx2>w:';cΘ9$ٚ$;E3LIIXqf^s^c)17bLxgkZ/E'Yi;(B 41=1Q#E5,4uLdn;!*gќlQP] ҆3qgnxٺD )bȖ&PD+t9';>+)TʱrR+lq)7qs8TH\B<|h[VuUM^kYI65J=K" ]+Q̒(`ԘH wFh508tGwpaWJA<[ &@Y!dB%^u`T0c旮=t ȤBP':亊g8JE:9y+BYUĩEp=>DD$Ԩ*խ 5A}=@3S"]d-oL?GRvVTB({g=Z4D6 1O2ƭsr#9cĜ"]z9 miL)zQgPkqZ;}fÄ́) &. Iv`]hyK\$&`[9WDR@"SA遥=gyc9RY=b^#@#G9]yh$ԩ K5TAs԰@*9iUJHbՔؓ*6@SZXp&.y">` !#uv6>ۺjp9CRN-gSq&4N=(ʭ sA5Sg ڤy>U@ UZP}οea?s'%߁"ب~mʃJ9ר.5*-&g=eWrݛpMO\"jT HP9JF%L#W,(.Eo_p\ 6Gx}꼁a(tZ1gڜW;mb#le: I'cN9ji3 Ȳ.bdPۂs"-Rm2BKJCngO}:6='.l X^ũdΗG.A5/\H, Y0ߜ<Ͼ|[>(O|z$XnM9f? 7{=<ddNxpO{SAT) ^0> G-t5=sEX3Wf?"vuw32*YKhIL讠wZCuַ48 Rv#=/ZG,4~ q^>:T4Uux_>e3݌_Xm&ۦǾrhڄEN*Ծ N,fSE  @CqH,Q qhsv2mx!D] P(ȺB+ Ԣ@- HJJ+־J. EWz5(1RQDT\PfÐC׷8ZH[bb')v6|}D-ʭjB3Mp.<~:cff1/8Kt=D3 DK Jh+|;JGp7PT\2g&Nl6%=kі2m'$) .^q=?'X4(cI4،[;C-DKQ}sk+h$ƭsŸ/B*,>K}Z% !P킶ҒՖvڄج˥KS6z o$ySw%+(6T|s}8f{# B1.41'Į3(.RWPZ%U![16ۨ.jhjNK+zڊg4Xp^iSwψ;&I$ϩq BZ'zcv&PM;P+$];b!2t;C(y Pɣ eN F7:<jririQ=ekdady1B$myWkQAFJj,->%KТ`%3(c}P{Tͷ2(eX`Y1[,HCpjɣWKK\'&FaIȩBP1U&978w߹޻ Λly쟻zn:yRXX1jTcsHޣɂ2[P7+_VYXNiǙH2"H2+'|" KP|,-atY'N.h9;\'b-i4}G|ctئvI^u^gͰbtb^Ӷwj; a9߯bb7 % #JD*v걜y; 5ԨBKW8ZĤ)@o{&N[ _vEY1bC2MBX5B&{IZ#KS^?Ja5cu&]G'w4;_UYnuةM"fbf" Z$TRR)JJ 5¾̾¾bbܳYٮ:Y_VD$N0H:Ə g=kvyct5Y!pI8chF[Yd}.W\=c>&ӊJԶpw3gaoMI5un@pB"kb:1t&.Ep@m(qIt[bR`n,%B/Cf-0A8Q~ţ\cQe8bU٨liӦhk+:#2~tǼ ^9vmvEt[`-@rCAǪa!5Ή턜Vjhf:r?2{L(j\XԽed6[ltl6x?Ub "dMjwv&PGCnܟv{̵G';v (Lќ h9+* @nfb P<ϔ+Q 2)ιdmEgl%I=3Anwޏz$&g uƶTޥb O So 7mV}ݡnrOkMAъNk/|,>%_WҹpȰhPcRP!H0 pYV}VyegjcMvU}9I@'GSyV!R8<-O?ZbS>P fIH7L5+HU}_>g͐CkLQ֌c;d.{A,#ֻ!QK-o/(*Ӽq(8!?HnuU fOk&<<~u`:갢5."b3B*ir/#sLM,|q%g-rŰX1WYl552>}wSWO8FF(GehNJG3>3^_dTMc|+~z_{o_`Ȍxd첖]VzD \¯k4:ZVw)ZgG By`c/Gf,-ۄKN)ѝݎIm=\# 7]AԾO-HG< /* )yRCJѣ~Q8+P6%ES!kh$}1%>{>,Q%UP69V ~cO%wM^m,+h"Ő)w3mJcԼ>#mcgDI4 mk7Dz‡Q=wǠDEoy{'*~*Uh:$^ŝW0 ."N='='=F345Gr0GT{@%!YZ,!ҮN:>xxK~/] aX=&eQK"Ǯ#*EJ(ҐJш2ZC'iԴ97x콚}b P 4U{f:?a3Jx>pW 1:'7 % s]\\6zX2E;R8c`cQrL3W(v1\JnjؗPghiqmn3 \uNq?Q [ VK `Dmn3S #Qz;C<|%΁缾⼼$F0̵!71Sf)6 [dPdIEjsSMt^ p E10%~AZd%:-c9b". L3mw7 ĆaRZITɜ"t K9? B)xLo'ܿ9evdDL;:ac_X{`mc}:Uyz2>'nb;mLmڞ^{%گI.#ak,;8͐iy}9a_ȼB-+$ZݟsvKFNF&T E!z"s_%2Ļ=Oĭw_w +GޞSӳk&Oo9r7Oت- VIW %%^ 2@tAiCu=Yla9x#B΍kY7\|Oyo>l)v^`;-vUCe=͈æI^kTBRKA%$mV<]hp(3eEdQ6ٕM -t7 *JAF@=|yo_ "!l"fO-4ѢB2bƈCXek2>6o 9*kZ(@Crs;?f}w9|YCQCӚ/ķW<=b7OAy6zv|(R@yFH"F#Mn=1JQD1nNh}3~_/e*dY9n1naX:ia"tJKUg$?_|_~uɋ;ps,{(eQ,KĪ&k{접gQU()s9~v,荷<_bC2p^tq+ID1IU@Q?l_y}>'tJT 4 BR #Nxw|1]|y뚿o_ Ocܤs޼Uw|>l cXv.'|L Xd61"j5d7s@41ӂa"Kus뚁sn)J cuV@[lq2#75Rg(ےÇҩS+p6ף?P1cP3H7.N9GW3=r5O71~hquS望?+-j%;^>Oyǧ̗#R#՛ Tf34PG 2W9%cY%( HdSF^*p:& @"sf]?`Ë; %x4>elRUBSN#dE5 k`Ll.J+SbR_tXs/okږmDo{x,?[no8DsUn\ԢM͍M4`QfYC9eHIUH#jX bڳH&EC TTBIQ(f Q$%$BP\z+J jQ 1ycPi{z+h؋56P`(@WJl5f*"Ԡ E)AS2p㰻j:5qҝq}$1f g3 QS[P{:fDɝ7a6mpn'W$IhZE85I}e$PjҒ( iUX] cHU}DeX2kMKOF50rU)&v9 )qfԏ!l-fr}=<:?2}ndF=+.U`BS D)QҭZEf< l0rP5bO-Mqh[,`ѕ8g$GhITJSuY+FdA(aM3=pZށPePTP-F*s҆MZ0PZ+ʩw>ڲ&G$$&t CsZSn &zXV!iҬYkcwXgfXZ}RN(GbV8S =~۠h;;0"T\0)(Ғ*H A0 nlt]VҧaN HVdE犎ܢ+.~GMÏ<@jK01f/lE`rM'6HA(*T+ EE}UR(̂l#W Ē w82=xx?7 _ UeK/L)"7Ըٟs{[ [ʶa_,Zg o/"V[hMXVHK1}jqiElFRUx*D$ I]eU\A8fuL3?ħ]k-rG AQk.ǭ &6`dlx.?|ǺTP6IbUHRQ1j!yb' SxOal-XK״-=DRMQ$\Y\ݞS*o(^AH#{7%D{^QLQ1} )V:+0}bmkO:oi=]6ۺŶnSIBn$!]Մ'?v<)PNޣ9,گk DDb=v_(+Y#ЀõZ{ؤ̖ `}*FFSzuuѺ 'h ^~G6n]>"^  lW)u.e]g҂ł2K:VDy(&밪,mjB tr>ko}1QnpRm)Xыi[t'Sm`fvIxkr_0\٠}j:+kcai1:,1V%SBRN$,dԾ}QNUqUZjcv19=G<" ,NkFTzM*W  v5캇$IZDM~"areq~y=44PdG'ıד|52d6@|ofy 9pn9rXRi7~٣J U!q vUsr??nrowY-Go'7TzB&o:.~#$:`1ޖ3a0~ƈs ,VQY%I i"uR󌶟RuVN 7L~,COd*KtȽ'?W|u ׍hS)Ќ(`&ƨZڄ IW hʩzzt$Ft_ _b4.A*%/'}W1iV[q,m0V/@Mx 22izLsrs"R/ /_Ȩ[ר[+qlZJM7:m-Sxg6Nb'fa(r(uN(Řv}+AHZ#5jZ [9tRlU Mtc_l)jV(j(yYA֨ZlQ[k[F$KF%CqGxmA@騤m 3FRl֢ATԝT@&s@K +Ʊ2O#g}c\7w3KCS:9V7͜Qsș@澉`FS"CURt;Ŵ":ĩ:+f9[DvaNOQ`Z Tԕ!^:N>^:d&^b߰QjRY*:1"7JAH+]k)j3'WT6OrP* #f4Ь(f" #G ,݉1ԘI=mLl5*B I=M5ÍcE|ȗяûOߢj9U="dtww 'v VIj+lXI*m:2% ez`L0HfJvHqi,, IdJCefՋL?}MS]O)4JXw%ء55JgZ4!vcrvLW-@JK"B+S*GKeajP*(-L3F6JʥL\N8i] E9RQ9S[ nk[K)v*Jc[xwҕNϝo+j,ۨAՐ6 }M-iKf8; H6gcd9Wۧ$fbe)=pܾ8(Uj@D6rT?EtOESV.ϛMkh||<3I[c>8g<8Ď$g)Nݒ+mfk:TD<i+!VGeē6dqhoffIhI̖=fw=fw]QND|7O\D%pBH\q{WD.镅6,.yu<>O1O1l# aT L=%HےFoػwa_^?؞lmL|p琨.(.N+[Oys5*;56Rd?G)S"?:ǫW%~\|sGְ5  g|\s5?gQ-OY=uҮXJ2dsknq_mWmtc1OxMzx7!O wޯxY[L;&o]o\]VIeb4 pnTKPPKy2I&=o}~~44F[;;ʌĺ&-l<,Ƽqjj|طi[{|ϗ#%,Qj  zsR]sZ]sR_SS~ŷMbOᒿuzB,.JPPՂBTDTiچ/;|1_Y (u@G`0L9\;.|@mF-J!G8ʆ~y}o]5o矓>L'#gH-͠` R1Co,:0?52HWuj%[Wƻo< ^%Xxbpyߔ@VNl>t·?a9/?m01i6oZlb?$2ݫ+V+][)&ba 5en-_"I"K?|UBġe? Dtg;[ƚkroo ԈFJ*6eUNQԔbGOIޡ3l¸95\ji *e*Lzx^lZn1 N X>gTQ(C߂'d TE'&!@IJ+gfKAQi%HRE5uIUҲZd_BU7U> ^x^x?_scʴ"|+) c(X=_.4mנ#~B YEWm $7b%1(ĪF;ɰN"چBn?WuܬX-MP@a vn7XJ\wɐxC2$54Bϡ̹RN(=bD%1n;vZYMrvllbŕT]w6jBja^p*P+BlRO  AEtgS%D! ;;;RA~z,퇗 x_*AvArX`5"aua"yiYS j3:Ω:.Ph{%:[KgLax1AV(VˑF%Y 4(v LPeEBHԶR$jkop2<-S-Sҵjtm[ acPYt~bm)^n?QK]0kWHzIR K y#Ҩ4v[ ,w]n\+$>lOހ:1Q3c玺%".0NOe~ƃ3 eXDm\[Gk2YǘdɆDFsEwkjD3LY}FЉIc~R12,-vCH_gIrLTHq0JH:AP e%!2(Zbk!~gMGt5k67MXYF`^{^!oJۉ٥.mSFQ2cNh` _5T%GUry"" oU-mc,;̃.h,RrkPG5Qaґ挔 C㎑L؂  Yfo7>p7d [AZlJٖ # Ǎ/nZH#5]F@rp8l嘭 _P SP~Z5"4t4BG{1E#X,V&k &76atYQe<hpDjMʒkM3N ń~>0@ޢMJ63^/Zؗ1wUKろ8F3 ysyO#'B&SS#ruRY!$*F2Zƌ#cU&W-֌9auS^+uM64ٹҹD[){-2O}o=޶I2T"e3g7|5z嘫c*9(Ube mg]T$~4P.y%2k5y~dh|b})d$TٟO _x^x/SN!a>Tg\eS7+~zo+~_*~b^S2NNjRA 6(Qnk4-4Nt;w}}{ۚM `C`YF{DK[DNBM3po}>?|'AM?jAHTD+̺j0r>g2Ǜ-C5 "5*6%gZ :|ϛy^pgŧۗ"&+ꏜri}ſSs6e)JHl>QdțTırǙq_;‰t?Lt=3w}WNY"M D#HRBPTU(Lʮ>Doy-C#tD*o On <ⲓ]avOݞp;?%lni4V ?]OaG?t˜,Jr%?!pq/7L=!j5uCPȔ'Չ՟>\+~Ƅ _'|{c2-,ȷ&O˽ /$\gITzP[Z3C rB?AGikHuKnԩ(;Tӊf2鲝Z(\XCMÄ:,I P&2ISED-! *[-K&A岫\v 1v8;*AUЬ/YCD@"iD!Sks6g<,,.]K/3UWd:&]=?g?J_+p^í=Osi6dqW ıEZD2m(8VނjV 62uABˊ6*% cn4IRB*Dھ:B+TtQ4TGS*$D]VXs>R2ow{(*.Z6Ź+U3b*bifR2+ŵqWl(j[Uu#}&~?>r={Ĵ;SwdT&E k&Ť#* MrU(^^%ᜳ(*ju(I2YfZ<\mW몉 pP4\'Z[3m@-J""aI6BlNuZGwĥ K(f2׏xܸ % =mSwH|"Xg4 {O)*lЧ2eT@B ;m)OI-ǘfL)qmA&tM~Q||\rcY`9Ư7liH斥d6Y|Z&k% UV!\a ,fsP̂eϧ8o&PyhɷoOYOm2\:n0QAшI^<”yZǯR* ZЉd`XmflФ: yp{i1 _k\9" f(0 AJRIYdEX؍5`k,`C0}?aknU) 4Xf%@ T TZ3 ɮ.esO]M}h_ /¿_slwPݘ`){'72.ҰD)RXMLa&}TY='VʙD,QQ(.*# k ﳱ;]nxr,:kS2&Sh .;<F]@Ƚg|z̻m6 :lJڏ_K5͜6mn͘1Oۅt9ËGO {Rn#CUՇN=pCoP% J>)Eai&2 XzH{fM7TYgĉn'8YWyG#.lwP\ VCV4y#8OdD kFQCg[|O0p]+[J2Ӹy:`9nYZ)kH)dSxjmdD dDRı ?mV^صG-p j]C "`<oA)i`2 'Fڏ4/a<9&LE$-ng.ۅv S >g΃92 g,tiwȢ`uۄMtqLgfz;Ķf7'ɐ AbmPgC'ĦIG8lm*Mml;|lٖM'iKV>Rn>StlP)SvEQjDJZAyCJ<Ts$u㘵7T%D%SNe{n_ / \~N؇hg+Z3LkkAz)~P@]CB"Dh U&X|6J"%P5 V!uQ+Dc{! >AQb7z{>}B%4rIvwU,B]ʫ;>o~kox+ސ '1a=+,߽ #+zz %iQY"2"C Žx,q;34gv؄~9d KKsX=c֫.Հ!O-{viv\9g,o{LУ ;'+^_T%v^%N0}?r/[1OO?H{3>e/X>Ggo-_^8?hKVW{M!*LQ*McMSuGooWyw*R>u(.eB`w71&}{b}CXgAE;X[mtkޚ%bV7YcN=fC? &6[l$?M"'o(lnkE<ȿuQ-K=g,6ǚ2nl0p-4%BD`Kȶz*~+p^4݌؝D_6ߞtg515A#eo#|QRR9&m:k$>7{'}ˢ4וƝ [wZw CÊ19959w[mHZ4yI\ddOrȄv[(5y2tX[M99/ `CSoMS!?u@kX~A.l#VG#RЍ Q4ɜ_8m}[q88dC여dWZ;f;\{C|@o?g^3q"&΃] &K2tmTᱴNȭ{ԟoToo[M+BÃ|Gyb`43Z+g+ZK'3 MGi1qRQ).A%I@$6T6´0YW>G-H^PY"F4H N8Pq`3c7CV]-n;,קxN8P(-(4뼋D%V IÆۤ6k͚l$ 'Et[P(5EE6klPQՈ~8V kS؎D4z߱8Ch'cE]YE8+?B]̣l.;1 Wd~LF{VWP1RU$sIEEdAD7RTA r &p ̇T`FK,RZ/ђW;) TKtbr<# BZnFٱ1WTp IDATiӄNES Tl$a&fL#1G;st0G7TnLEEIII!y xyGy/u/_1\˱{9S`U|YR'\-Z$Tct1^_tAAlm#d lJn$Hᵅac 1n<1[ȝ.di"*,ֻzevar#p-N1'05jCz{¼^j¢!' 2ژQ,v\y0IL#zK(x*)꒥h{,eݣVruʇ٪AyUSXtcj7H(mځ}đFЈUUIԣ^s+ʱOPiÌVk ON>İǔ0d4>?'(UӡlM [WXb")pZA6@t;K1Orkڬiʺ7f!uh C*WmT*A7gPaSƠ"|eS[X'qIq[zbhOKVtv 撮g.q9yȮkurhr#ƗG: u|v$ʚk^5Mv45M#څ)(]:.sz첀tN}{lS.\Ga^)4$>SHH HrHr,n8fg0?3_CюnX0'&$PV]iGlj`rr(~{1`*Zcy;Y vaH6MҮ&9פ_i*$&Cq(و#VsZ ́sq\cRKx yE4LC6OnRpӪQY1Q0LWk۱fܢ8̇Syg/9k]q^#S#똸 bȎ 6}#<#%ۯO))]3\%"d37oj&N\MP'abxX܅I2j=XIX %\1>~Iɳ% gX>s&caS!k"T_H{m,%ފN#\YaY;Hӂvr<4jVq\c[{+LcGmXoڔ¤왔*䩁8NUW:O<׷ZT`ydQTW%U&Yi: s0FT߻|O_`$o9o]p0 "Wo3饦\LQNy"0^jEJkؿ߸q\RRĕfzc>>8%ma*F#ov:.Ճz/&<3/91n(EXT.fW8hzsbwn5kD̿$f8Xf]>f&2Bvf;=hÄn{ɑ7 ~5qEEg Xw>¢-jdž tSd! W=",pH}5-F{֔à _M;5d5 ϲ{əuŹ}I܅##tx@l6}s&$d⣗ZDyɒٜ1tS+NeuoSXV-qVT .sI5>T,6Z*Ѝ=PdIbU}_ UܫmM 6 ~=77r2syExBVXT$(G"Bx>[AdkP;d5-sQs̫rBsɔ˦9 Xg!,`r6(h@~>G³2~'#'o*LM=4~s҈7aVDpZMxs Y< xx˨;_odMlsNMxab )_xo+~ڮ5˚Y>sV0gKOw<#<߂_󃄣[TxңM hHfMs28^TyA2Z ӂlc i -Hd5ܗRa6jPa+󊮛b:v T]<adI)%ؿN;'''^^WxsEIqg1U6$ `JH TVSP&pa2$xDumbwYlDq,a'g)FWel]fGO*<jDXJ2V^A=RfWQN2C$#Kٔ4\E|wɎFTlr$YZw]~ЅJlBmhhhhQ19nCj.졌.pֻ&x ܪyR1݊paMK}"d lC}L#j$"L]!`5J:%@Rz&gQzX3ܟ4RHdS-6iM&OltM tCP63E(G`6K,`b锎N vJ3{jEE|(z}pZ!%@Ý [BZ 4z`.!j aB&K6 Ɇ&ÚeR͈ііᖐ\˴ͪ#瞡sйcMsTsFLxHgNpψ{Fj []0 is^4*l2JLYQEBԸv[m6c[.qGV``a;siۗnQDv(Z.E!q!Ӄ!:4ĢKĢ,il 464.h,)R߫;>Ic/_[(6/yr`@ġBk8Q#CݐyH3 MRe(jd=aMФv$S9-x͑Ftg8UtlkkgS `tGdfDm6q]҄PW6Ân#դC56Xf}nSuҵpƊf ,%|>)sCzdRKa3r?~zȤ{d[3:oilW[xm26;a 6Pͨ}:5)5~r(Km*eWG*qG.nDƄ@djJ:7MqG; PMa`cFqV"~%0CaO:ImZd LȥEKl"6deQ~:l50&ZEt1O' VRw.9hIQK첑-n ơX bĒ8dIJbx zvid0 wȷt9j.ԥz}^0ԕAUTI B:5SccW#<#H~F)RJP-m6>L _^q}mt߷)IYE͛dK5`S6v,cCW8s֜VߞEx9:#-Z#U+DKeo*@}0~7{~ZdP^kxd6qS ?f)Ƈ;_ꈣ-M+bLD+Ɂ3UGh(#";ܰ}+zz{GdfN-׈BTNFJ )A3AXI\8¥n; Rr+N7/ikΜPxu Lje?^gN='W3ɻRd+:@M$Y8]QU!۸vf3k-aG(wri| [=m8zXIM#d\s5__${hD6@$oMT]h`2hy|\\r!?L:}$Sv7!ۀCH|QKZiN Oܳ0"s*#]!`R;22{LAL L~!_m8-4.ڐl7rP^۔:EۡsQB{42H0op7#6x 5PS|2;Sk] LԤLނa {cPy=#<~oʐDa>nB/$!ېùw _oHנl'PɉɁJ9$OX(h Ӟc{=VƏ寘Nz~w?Y?3歛a9nmmZ,&s}nCl#JeBVYEYV0#, Wb%a+a`l9 B!fwlز^2:`8`sӆK1-ƒ%@5$P Fzح sc53)Zmx*/p]dGUd7kλi{tMw CtȄ+J# -+ dhQ;mm[D&ItfT4-UE{,Gqѯ ei=g%)fLj%0#hǜ}W]cXbzHOy 1"PHW! 2P~D_rdyZ_,ޏy_+UA#UB0GK  Lw gug6P5 1ЈCl3"p`m/{h RbDCt*Dd@n^b !4RLQb`rjP6֥\bly^8685: t&PS`KVBC-dÂ60bx4Qژ'Pop̈́cz8{Gy/ ;"Z5V!ѪA 'EPhW̽!g-f6Q@i! F9`NfܹG5(.VW\~>ߤ0 JSQ  5zk6!z+Q[]&!ߤēmK ,5ιݙ5]?M nlv.Ҭ 9 !x[TDcjf{ˉ+*w- +yE4/Zs R<13N *ة TH9Wꘉ GSN_ÙsVy\L\ml,`>ӾWPɠA:hu|jjVI~Pt-QcI@o%Ä`$tԚvȕ<1хɶlQ6ԊFkakN6m=D TS}XD'SrIFNLF W\ȌX-{Թ&l ZܟV>e4Փ:"qڝaIN:-L;2.Mӯ0(!ybosgcl]Mf~٦MNXCʡWԵdt2K̢{&n6~[?C& +d7X?_SyG t95%&;gL2t1~̟SDA6gl' v"xBhk5vvaqCLlnZ̧C"ՠn`+5(q"!RAn9Vw}6Eš:鰭[YUDLiL 74ί3OIhC.ғvaWNMJy@T :AI}&C6W|NNx?axT*1kba:)yww•4P7$I}7}M3 |Rxg^rkcožR\RB` ukRԷ*2RVw)6aSJ̥.v+'%^&N K껂tc9H" _' _o鿊-Uƴ,_ ?y.6~[Y] )f!^AŊ5kEd=]ĕ A"yW{WPXX_X,EXzV6T6EP)/OC;Qz& >&X]~J^K cXPq>dnpqC&*8,zѮX}Aegit\l=6W.[jgRE6U;0z]|nZ+DŃlME/>i4O7L883:CC| v%Dw $z Hlp:k.h{-^Uzeuvrl7kNU!0bCŖnsH03L/<(Jgx}veH|+HƂx,v><-h4JvY]`l<̓%]=c{i.a@90 tƄ=;<3akٚ&3mPȅF,4`f YVeIZ33 IDATsqs;QZKZ&|IN0ٌ"^ZXVW=6is= /m4\)X(ҥKj'ۺijX,yy ih`, tFKtI]@\+?pfHVos* fx_1,O՝tCQugXRMk:ҚI=6\_\%(`F79GX ul'[:,ϨwYb*ZD-l;9&R)z ,L 9UI۬. A`z`kN {obma֢X坤jq9%ܖ7%֓9nN;s#<#SN b1~jsnFg}  bE2@D =P U(]1d3. ߱4ˢ*K:ACa-&~_&~kQMN')MfPMtmjWKBsOkZ٘^Mc32?85eRˊjX+Hkߊ.y^-CMv>`ja4_W<~%?;lqDBR {I"ǒKYĬԣrL:cXxQ]0*х@ 4le/(--,=Ȣ7?.oqrpq7h ϟ~ወ[y̭<86:fңtYkXvND,c_XEEL<]q9^9!ۼm~Wf{g_ [-_˟xy5!9S_W^ !}'>D^(+{)!CM [[Zi͢6pr̓Ƃ;:FuDTf:2ydc=kh6Vj~r;>П2l,{O|8n.;5=dJ=3?&|}7-pau@]D\;ML#~̾_# O<~%=Z'@ Ǘj;XPdkM1`T<4sV&ʖȩªL}h5GF !(aS 5LIZyGSCPN5ґ60=1&m{T;#hyu FP#h4HZtGa4L%85pO{cA+F{z6 AELƳNSxyoؿɂ1>Xz,)x &ƤޘEnqs|Judj[^!f@t; XS. iM5fiYcebP&ڗҖOy8kid ݌E7eXcU@\e*}8x3WEMZX/ MW)$Ů*®+6 A) ~L{tOOxVLZ|X!;a -Lt ,t ځN5)-*An7G]c+A6sxLåtL~Y*E_4֌ӈKsy{GAZMєQ9`8%ZdMبBa6{|U1vKbg&hMKS蔮Efāvg_6>U%6kIN8͘ѫ9(j(/BFEKӆZԞNgXX@"t(**rbZ-K'0Lz5RSM+$'aLؖCA$0Y7_FAuL$ Owg!d&SfڂL;1h/p)tȏՄ:ӗ } yq₻I˝IɎ+qRa&I#\)W!c) gup  ƪ 0T\s*S'1}b'1}rSR-qsb&}%6 >I76hb-wۀmNv?eaFLnY+DV109jyrEr͋Y`0`6rȮ}0۟E;J7!&t)45@;jPGB.Ed:#Ox{=K(szPPi1i3e`lɌ뿢:wgsO;1Wb_o.[zZy` ({-'.'Dw#Sw[1UiRUnS%.]cкݼ>]sufc[㣄qOEBO$"A$1 >Y}y>Ӯ$ZЭ$$q;ojӆ:Lw.Q z{=_B]IH|'̹d0Jh7.חC~9f`-918i-4-yz ~7Q>tŴ8#潈0N嘻ERjɖ4fcDNAO,;n}G,yg~=ܤ>7^/wTXʤ¤R&u:;>cIHg;TX&X|f-uMJIʬ:C5tsAX^N9C[42arA!?\TG+}0l$:sGFAE`{)1)}\Ý9_xXZ\KfڒҩM2pih>4h bhej;owAAbO 61 '!ʠ>N{ל0iK#iq]aW%.h,hL M!Fm{K)q)J"w)hI#4hrBr͑]Mt6iS.ů2,G BSh^zڎ_x\kX|OS{ASԮ:X%= R5H|4cpMaYFΚc[#6%>Wy9`5F B4EF4Qm#p KZc b,gۥ] -fgysjzkC:-y1y__'̰agl퐭(F.43̾/Oʿ}guMx_"/6=1e_xyTVt4>wZq}_fr ~~>,ig89Nc9zԋwx |TŮH[.[1_LOXaA]TE)#)8TX3 i{β{r2k90&\gn<2.6 b!kVIJ Y! {ZM;԰Sy@0dAYhlW?_|_qw|yr%cRm :|81=O'>-8 z1 qˌNkd.q81nd@7({m@,nDHs#"tѰ?gygW+%|68jŐQ`9Ҡ:]f*b:`*"e&eĘ*"~ס[Ќ*T@ #op(], ámFaj(A@r=p-0@Nuj;Pvh,6*jQRP6RХĔ(AЧE1"e–cDL==J,RBi::CI>ڣZTIkV `C]Xu]NT(jC6 34h1hHZ`xIa?0[FACS6tYN)9w JIaܦB߁hrAQە˦)6u9ozf?H||K%5m^74Jq3,YjA[&W.rд^:{N;f? B  f,N!:hШA% jaɀVӰ&\r"LrL! vO}p( r L8R*dQLaFvSأI@-6A ,Z6f!'ܐ|hEy_[#2 +rMɠEn0V&į$kI$͉ؗmfKN/=yaD~p4E"N xK""QR"z !h 꽅zEǣ6/pVgɕUFDiF4ى1Sާp.XsvBBdSP'ek%Ұr #Sfb#:!p 8!\XUc X50ks3CmSn RY^谨BLiF"|2W|X.`ٜ3"O2^Y(OP&ePYubt :jۡh\' D^)Zљ2LFԪ ĞN:ygw!^XTɾ(A"lggyg~T)`rK9`,P MH=6K^K0k?]~Dӳe-[UCnde0o݄ҳ^ 86ƀ !exz%Vɔ|81ٖFIThT%"/0')^}>괆N;IߛLbL8D)naIp(TH 6:5u0p &ţ``Q`S`IG KV0J;|jj?{7[\a)Fƚssyu*tB z"foHR}H՘TR&Q`ZG{^13O+ ڙ;ulf :Tȅ^챵?ql]<.CY?sL^Y= ]2ϡG|>:RWޢy(( r;7C6rF YY!=/uyd>du<᾿E5i}? ,a^+_(6׏#\=P2@>gm]X;G` ?D!>N78ۇ)ۚō6@ ' 4Ai *Y>zrDv? #n9\\#+%^R?Qr#K-;ǀݣGP?Ԟ 3u![|қĘYFӉ>=4a) L'lԗ#vNMq?[:Q Ggl#zFJI.\pv+h[a)RZ4y*75Z1a"fjDL備`.[xbG'NX3'i4vi8o"}upS6e#6EhZ!)Ca#?D2$b~?~,ToJډI)_]ڽkGZ PAun9c7sJɘd:"bl} H,r"&ӣ76DGOcG,g/}Vҵm+0?m|L3=zX}}5'7I,ZVHqSu X &,ńRZz_p2%q,~ZΑWs}ή~ɫcg?K϶n g;>d^Y&l#NQ+rް\ϏիKN':Q>E4n@ Xyu̺{-a^oMLg{~3?4v(JtG:ԁA;K -G5\%!xF_.9;}ûw6Uv<>j0OKO T)V6y5tq{WF8p~'p'[I®!4!U{ۣz|՜o6;=*DT-OeZYXE=8Yx%QEm9QݔrOwXH10F1FHê1ݪfGbۤM2an{iry_" Ij{H,Pce1m|@KST8`mgG'vqٕO>uEM{[P-RDY=4{gy晿^wh!10w ^G)4GIty߮L8 m\cL<Ңt+jUb^me72187o0;!Cm%v}N3y6xatHmD *nY9]";Y1W{jàICWh<хGqWgOC1 IDATBOؔ誥g#GQN T@vEsoT%+LK,XA&"Fe2X!%\E.J }2`a@bGOqwbJZy9DSa)Q%.dc:{|w%! zEIOČݨY7#Ol"]4w! ۠l0mdL3RޖitMvZH%$Zb%Hk47ɓZ8~/z5mi>"[ 2,𤷸X<%{#1 F+[u;HI9m,ñSGNE!ygJ'TXG$`2.؛gK Chf;R#ڝA{cj5f JrATˆtYLQ0-t0-l#̷ՖK.pdm~ۘZnL7hh sJ˟z4`tc,O\# @5}z.+L0+L"\R+r~*QyC75o>Gfhri Jj] @&}3<3~`JFgkFg+gk|s0i5Pz30&5ҠZ jal7=4ZӮYOݎ-^4hnC,ߺ3Lffm9hNxZyXB6ݐB7a LΞO`b2cQX3vջJ2諜nOwGg>x[y*d{hQFVz佒ݺ$А=ҠO4I(4/'b>x|tOkC!툶LRI7/^)q#]l1hDxW 3(0(Q 1BS~4P(y0>4=|>VJlNӔlh"|Ĩa;GQZ䬳 :4'xesr|p(!9~D+{6Upe=ngyg~60sP1zgy{#n?_Y=zU*!]yKԨ6dz;[v[НutPT Vc`L~crCa+FָKچ)w7<=S*ۄB]@o1.y1 H}Z#:d}詜n=m~FF{EzR^+ ;)âB(Ÿ0ju J:I̸/~_M([ =%_-M ~X~byZHNBOOy{bJZGиVȏ0\q0N7Ow}VNKFjP4$$;~ߍ^bˈSؤ7 㮡mGuCGk@O/؋>Kv'!y@tkJ:T1 961t'X}AWHZڝNhJJ$%U\cz ao ǿ]LW>WR}J&lrirn~*d f%YAP8EM8vITG;E5&( @WwP[L2z^`jzQޠܹ[̓KhIjTjC^~bLk!I=&&̓I`" IQF:f+ _O|+YXkIFL&8rPɀ17R-ę8+.)Jl.<mlb0q1oߣ_$)TdFRTCsjA"QJza=_;嫣o=5~l6;OVr[zg 0 􉂀Ql-76{q]u`$ ִ 2;A3d¡%)&&&迖/OxPNvSƂ&)SWwl>jQ,YAZ/!30:mPj@1~37[&_If(*>7|A߃#2c}gyg~bF1 _]?2-h^Y ?|T-Ƹr[O:*ڱA9u`Q)ZwBĊQĠb$ -='BL@B*҅?y/]&ťŦ1Ilz&%mƨ]c9AX\whg5xCxa -\D@ ZP''XȠ3)\0p=OkYS8~Q<tOn+:z%"c",ZƢ4]"3:8e]5ƤT tJ -_98jm`EDఛfHѫw]DOEaK+d- ɿsc\!A;V芃^!5:f^iiBiJ %^*柵e'cl);&V#c:{Hӽ\dϹygy~lr?o'z)Z7{K$Qݒjc} nyrr^R]M纸g qD0Z ͼ6H]/4OLOF.0LauWZ 7}Q=6bi;L!7&sE>Ԙo;w{I t{k C92Cjj$9& oƇPlBi}OD t8=ԵIaSJ jmFk򱉈W}acШFdr} HȔЫ\IDoq5^gȾg/>YHCgs5R)L$.DF3̬V?)ѿ;y%䕱@6es>۰%1Iϡt4֝ Bh!#"c;S=WHr\0X,x1bơ}A82Ymym 1Hh۔EjEt7 [v/:ZR>P}:zU#6xxb3o?_ul;Mܥ4 Q®Yا|oZz[kOZ}zȻp 7})-Vt>[vhZfa}=R*AV*js~v󳏜q}w/mhAs=`53NyHyLF.ŴBM iJ$ȗ5⥱OoXd]EIºLA&N$8N=,r,r$wp}+:{ڑy ?3Iwu/TroȂ!-o=/{jLSkX8-C9eSg;lA& 5`r˧c^<ce)fy7<5$x6Ii=-Nщh8frN%3)t9T#0L0Cmezc$Ķ*0FEO>i8; ^?#{,:vjz$OƏBc`P`!Qxn;Jpw ,lDTvu:1)|YTܠlre퍟7~E6ى&;[:+'[4rtcn3"8/C;RĖH%m03%sdfTFNW z0N]`:$3*ORHUZo3&c 2IB`VQ3PDuP5~ ڼ=eW4;#m1$9[6 rK,rڎ^7ssÈ7x=y XNzxiКqѿYC:$~S0ycބϦu,iW-/ny􎳳E"4mg\Sn1Q1:"JC0q3TCe)ҫD&0[&UzC< X|ø0] C {|v]{D-hyGA6~7?1?)7G\3^@ew-uE MQHՒ&r2Z1;e|d{SIȑs.юj[ilDHDz\ddM&gR{g{prx+fo#fDqSQIߤ TF)ޭ[bGSpIUR7=^%_r^}I9g|c[<;X7:|4.*A$`py':WW9W9i23rPPĵ#ʆɪ7C K`ž.v^jAz[~^~O׏ +C}CL\8g6oY@\b/20ft4yt55RWWDim{6n{6˰t3nSs3Q:eݮMU(!aCkvɺ!vmfz}XgHqȹ}Ë)-Q bG1ތ+~&*N Fy-o8 eq8϶߽_'ql&u,bۡZ#Ɗks_nkQEIyA%7QZB2' &ē)ˍBd5Cn{?pܞܙ{>7Mv#7%Q{Gyͦ>Y}N0(#u+ıp-q)US#L!>CtI|g+l9rPӪve¢bMPv I6u܄ԅ̄B&݀ *I+:b5P[|{MP F80 zc0t, ?bRUʕ] ՑF|hr;[ YVL~=dv"i?V: U9DAuygWg<ZTF;ǼV#BPa [NF5_tYM%fI D DO['lymuRhF)5D֦Yw=,ìb*Ƭ67!SKp҄& ԈNj 6XwD.yn[Tݖw1Ubmj֣.SSQbK>9fp><!ޔvxMgwgslzKw@j7 ZT>NpVPT PШ+ O :ĮKt )< W$8" L,08++ifM%Q@f@\4%mohS`be~FtUPbVJ* KDG-/J. ENt0$R"|.u$JS@6*j]@ľ$hy8>U'Hl Z^m8*=WFXC"aXp6@ |-f]RX3 IDATIIKmɛI׈F1h| > %4mR7 )RtwNxC6H&z_MiY>/E s^xXa [[7M*,rdfwQ#zE]X?`V{C)8"- Gئt$ A62_}vj$&IlarBLZT QQ&XEYDXEDf!|@q@hxZExlL1)F0CF~A[q4&H Wy=#<.?Xw{E>Tg"АBG`<9}}KX׳Ms۬ re}ʢ.5fRI֍NU6im6R9|= cJdJAko R"A[GR P&gB8t9r9r5.]ȗ!׿<` M*ŝep)KӐg Y|8uhw6f5_fWj`7وIxפVYEyDR9, KKݨ(.LmJVJtY=f`\8$fj3f;3g@ͮh2 wZ@_xZ>|W'Fore$ )R*RCgG10(:Sj$be1{L!ٚMZ;hKzbI%jć%UqMxCn|۴aU ='L#o=J l2&VFXjS'8u%1Hx>r\3*&M$ (]A)Q؏| 5*J 2Cv|*爭YD,i$4 (E Aa+li-24_M6uޡp Je[O!oe-Vz wׁ~1phsvObc1Bipd{'< L ' Cq!ja>I{qaYmfbȔOԈeCبnJ+vg-=>Vx͑ 8nсcuȄ8I=.؟;@*z-&#CnCri1>)Ŏ|Y}A1Ó ?)tWڗW'\le>#<7rK`xW<|1m}ޯ-+^;W_qwL٤Xdts y7_/:bb2). mVtyPGͼT:<֜\q63UoM/lN}P2A OS԰.`:%`+N|s=px1/ Ă#jM!~3JN%4JVaR _#B$Cb$)3Ot{ ED-~[i)ލY<}>N983ٲbQZ=SBS)jO7p5]lhs]G,f1̂ҙ=O@ EID<|처vUA}V+%)s,>Os?znkRa:gsfw#W%RtKk={n.v)A{g}}w%ka6Kx km; ^ I(]ʒV؍Ӓ.D; quP%.Ғ 5:}ə6wBEMmA0oRx +~INACNƾ[ְ=wɩC_ؤEYĩ&l N'R.af[!cjc9IbT:$,3D*dZ~Sf CvD1gИoI[cw1G9+ꎤ0 "Y8@ ga$9b6aͶ|ݦHH4`N9hOH?&a)}6EEY4(>Q8Hec=10HD$& 2鐷mvӊ;mJIH daʌبZ:qߥu0pglS_W9c`ZTDZJ%+zMEVI lve(#<#?)@PH iT(;$KVXT rLFQ~ F5(EJ"*MC9c9 n и1.GD>8=yTK6k6Q)(c{9EP B%jU!e})ۥb4.=6KSs V1% ;8.0)1ڥ;X2j/9𖴭 SeLKD!0XH #A*tY[im T3jCR& E4Ōj^TAgnM֗D<]]9# 5U5ȬYK2y{ 4:1ª fՐUe賚X/GTdݏ~඄i  ?iɂOslJ:'=a.wc??yو"䱤hm5MDŽf'?C)̀愲e6\θθON.UidM)s:jtN&yPo"sB^R}&7ZtNv-Pn aBZ5=mIn}}ݸ-^&y^F Z C}ל<:Ɗ#4)I~'2K$Y,#,l} {d̩sC92Hp؊&n/812yN{l>3>:gl-ZU6y{ >p0G>GWDCPn|4֨&2ٟZIjj!QR^CCejA [$Fåsԣs\9Ȝ,6H674?q)qU*,j,bbՔWN5)+.QyCF&<<#<k4'GBFcPd#joTGPE`R~B{Q!_ tX[j"vHeIŭ}ʆ1 瘸كOgO>;| T6V1DK;$Mل6?sH>W7EZ1g Er{{6ۍB2}&`ߋ8y*xsGl-~q5 HcΘ[{7ڈD#1~߈ rKj[T a834IW!ԤQe=vE5Ⱥ@&!СpZ qL{DYh-vOKv-- iO(&Rƚysb.TDJɎ&/y/ Z$IwJR,.i 얔meMJ$> t 'gcvM S!߽~ o^TZdB;r"G ߩFv蝴#t\S Q8'=n6{[ hֈVޡOvr[ z/^]N<[;LE1.jd[…I2'.dR/"\-FhZM[IHa:>F6m( w\~rV^c Wʆ mr*~~rI0Pt@4bS#5E"G^R" Els)-8rO\S-Oߢ5ߟꜛM5c/IJ1ç.nj.ǴlI+_WK'?+Bd#<#?@4~u]gg_5J)??AJ D5f81_ /rl7X1]hz4@oX1(,nHYݬIhflTh/u(tD:U\0s\3en[ S8!;&oC&,;CŤlfX"1а\!Jݜe' dE6GLُ&V: *) ]"m\:ZQI5jfIC&~Q(Z"1MԚ@'搖YPTꆢ^ {Y$S`3s3q70͛_B mT%P@UIitC}4L uIRʡMp "V tF7ف ITqSJcߑW8Fm)%E,IW>ۅAMH6a*dj_'T4\q0nP@+] &9c#9)iuBHo1 0sVSѬ|6@[8luB4'GK6Өχ)tpI2MD&4ƴw9]E{!{,ޕ T1@GyGJu͟o_Tm ,鋄0fAfdITl2:j<µLϏ[.2\/u1ŒpIOJ[MFبSnmh6w8S""OR6V5+{kD7̳(EkW"}>ˇ>ڡkvɓ?!IqYVf@ ]dgXvXG9"TAAE|1z)֧5Wĉ)svQ"YF=çɭw}ls[lJEMFԹAج>F l'p|@ؐ,"w,c}b=l*Vբ7grq4Tɥ{`7%VM=(kES\^:#E}HRQ{>&D@85 MG| .;>bKpG9( )K!C z*@JMhVkFxI"!l[-mv4yw>0$\LLdmNuB#O$闄MHcwd͌35w<vyQ|VAE&F. RlIDJ% I~\2+')wi*)0 E2Z&w{E?~53[d IHH(w_<ϳ"T)'bW<)zx T5P ϟyIM!uwmS~l@ xc;;o>l2y)$R.%սT~ش&Ey0,[ןP'FhXDĝ8((% *|薍*O2U$NGz}T*TV'R`kR$ 4d{B6:֕Ů {{B0;֙./@qB&RK#>5/lB!15oƍL6dƏό3 &M U$E)(Sà ᥒ,k؊ϕLIj&mkQtG|O/6^22<ŴNCv^Z+{ |0*v/IDmU*Q%O+?h)Y( l%e4KRp*u+[lE$}?&uChÖ3Rr: L8ŵ=jcoukaoqk*M/znjN%ѪyCePj2;m(;- l*"P뇚*lɱ!p8*ع6{lT ZiafYۻLbsGjMnj>wS&BhFmM8ұkqA-"S/"3ZDB0Ѣn*=`hIV?~5 jE)(55ğQ^_z\A $+ =S'>3'ɏתjnr?sZ"NkWLu m{lݓHٞn|ZGMOmxlfh6I+JW t^M׵$:ЙnI.~TkFB,={ЦwUm׮w>$8 )j)9'([9?nHI$I+oJ%pEpDHӢUr[N o6NlH&lsR5=t ݧn[;YCvTFMT\;T92Ө2 UEiV){h&TGўV"}Fuf)/u] iI )TI8B\$UN*! u0" h^*YZ+Wqe[cXUBeo]K`1D,*qC%TE%VAqMU^-mOV);Hs/I/EwbagfD5] iaZXQLSMuv&&\4@x?tT Bxjb5$*$(*;qI\lKغz!bI_\Zfq=?h )u!a0 -"$Ʀ)$ejbb ^ٮ8~Z$'#s/YI{b/!oߧ{[mQpVK$CKw[Ԗ*łotZ[+5@bfS. P2j2¸F)ŗ+pG2j-%b` B&]AiDU;aDv 3Ej ⊫ETmI&~"n;ؓ=.hMW8HtbGHI LԺz_gE(}UYl/W;Uw2[|J H/41q $InZP b5VF2$YˊBj+`)@KZK`U tQ=%8 ;IBMnzZܱTbG+]YN+Оg;H$H5' "V_1[8$WNP7gjw%LT(g):q !" 0|&j_Jv%\py)Ż#D*(-M0L奢c*&A9Rh-'ߦ6U1 ]BɄCq.aw>>+DbJSC$zj04w6!RqBc!?BP:_r*+>IɩTSz }{ݻヒa[oiӦqꩧ3f` ƾ}=B2dƍk4s:v{+*X~6Ϯ]ta}ݘI^^]t?޷o_>c;B5rBqj`tڕ0`!B!BYL4McҤIL4ǎj?qXo-:0e:uH6ŋY`6m-͛Yh۷o'55QFqUWI[O?}:cǎeݺuٓGyٸq#!I[?svZƎ[ٔ<6> rrrxiˣcq`Yc'm+dp%~7ndر$''ٸq뤰i&:wK.|߭w&z>.\y^,]ɓ'ӡCv;W\qE}Tddd(J H[Eѷo# BBB :>lk?i[!'.;_UU?XOٮ]1cSN%)) k㑶<6W^y%˖-#PSSʕ+93ic -[FVV mP?~ҶB!N'ZO-Bee%1iwpWM6I[#G2x`t]sy>y^z%:uĴiiˣu|SҶB!NJK.y3UeG<)95b Vo?xc{w1 )bB!~4MN~| !h V8%{e줩'_WO!B!F?!B!k1~6I7P!YɽR!DSk;oۦBqRqB!DchOndB!Bq?!B!O!B!~$B!B_8IB!N?!B!;a_0j5vTG?';iO!B_۹/659~٪z%t҅.\IY4޽{:Y^[nMKm1ɮ|HLnqB!√UO-TmA=&Lb&>}ׅ+93f4Nk%oc$.p+ц;YH.]XVcӻwx|W}K4.gx&Iу=JVI kOĽo|Ȃ7?#>%ٚMwKףGF1iпĘaƇ̻y,^{ƏddK\)M/oxF۩ZhB۩Mrd:>22/)fo?k ޴L:z_qp=vyB!BAJ~3(/pY&Iu֍.7ńW{bܶmrt3_W&G r\xΩ{+~rCZ]W_cAyAtzoSo.LCj;uN_l"-t8 RkH%JBY8ظq#@Ouu5+VmV7OL2e귯ӧK'B!v8;]}\7x'!=J0ĥ99gxX͙CjvrWֺv?;7ǂa}e[,Ă Řkҋ 6;;Vn` | OK5dˌ6J<˭{>=|-sdܲ ̞xcs4LL@Œ? T>T<'$ӥ/Vp#p(+Uz0öm(..FU[ܙhi2ZRm 'o6sӹ袋p:hW\Azzzؼu/OOU0LoSI.oK0P5 0 P0-(l~{Z6tU/B!NKJ>gVpiV$y<].J*N#9.^FK7y,دw p[1`on|sxKF dΨθ̞pY2޷gs.㙴"E7g /77CyGXr>_P $.μ1u& kxKô5Н 67W6ZF/^sGp3 Xo 8˗(crrrXr>W]|S.ck ݅zgu_eY[7Zˬ~]iX򷴐Cz2af 3ѧOte]< 3Aóݺpǟ0wwqf qfM1gH&,lP|>`lAWB!hΚEůԋp%l˻\0iw>)))nE!B'dԩ&' s]^;F&5b,?oݙWPbc ek3'caО~ 'U1*~rzu}̽q@87so<}͕L^:3^ s}3+~of*|jXGLܖbrZ*I˪Zz$bDuaQҒZXy o`K@ͮ ok :CSױ2M>ٳgj t9 [%))M=/o. ]3p=LejQb4qcKoiQ+B! O$}~1 VNogDǎPU8\.^^>;R%FghЄ/UN} S ތu\2e :%oYv=ʴ xu <^g2W=4ugu8q{%w]x&Z}tOY3f>_oz>Oՠ1~m`a`CЈUTj`UPUw̥/?n*q.NeciDuiF :`5ABgݜwy gt>=~4Į]]zv\#=_?f=ܡ=Bŗ7W<sq1@͌U;04SUUT0Mݺ3 LEH[_9D70H؂D@}#ETy2I@VZnut\n_ @.rWcTmq~[?^IEiZDuoJ0&uuuQ@(B!?-4K:\[pt©Gbb" _\=rhFm[Ec^%>#sބg :z'7,yba֢W9zhlbA=F2k3OORu؜kӹ#{3q΋|hqWf-z#/p "0{q/o}!ox/&->x<&%tOSQ9SQcf*(Ջ,@Wb_21Li: LLLBQ+ji(ͩF T{*YZ_(۰b]-}>_~%iii~v׿fS)6NqB'~iT?/bYB]0MBT70 =c:FTo`!B M~|U>N?? 7RUUEΝٸ>CCU)x̎;{G ͥ>X5;܉7'źջa֝zcf =E+~guT=>Ĝ!=ų K5HT){$PFHM.0O7 D7M¦I(%q嘖E0:C'(q_)T~VDN7GyrT>ChJ^no,w1L,+T(ufIDu(5,tG!ByռS v!^/^XQX6q9$zl߅נXrrrX4F aB^[lulx߁ꦙ_/<,꒾9Cz0jA>sG%Sw GAP0LXQp:b_Q:.ζH6zB!q'weͺ㜎2#i a(>b̢5$O90 |7ˁjviT:5$%B7DiO$Νڂibᐎiiu@i*Qr$܎R>˝{siŒ.pkX[weD3 bpu[5B!4/zpAQ(XQ̨6ɵTӔq^r2doFX@ް^-fΐ;On]מ|7|R;8Gᆅ2Do,^S֋~}%}O4,Fu*Wo{]$3([WΰL4BS2ܴNʢ׎]k~@zz:לw*~?~EQoO?4Lw^.r\Dǎٹs'AIh<5Kݣ7(B!Nf²0~(f?X2n rW]-._ǒy3)^{OC+~_gxJrtg y>ܻ|/SkxƁ$ XQVnux珜+TnßK'c3w>?8/n(B!ɬY%~B$aۿauZVIi_v"F"r(??V]T.Kn}/`Xnfۛ)|þ*~/[;'qsX2n .gMѪ٥6Q ۸'n睋AۭG!BY%~z#~]n,I1dP}w|ޞl}.??)cFw"9ZM1:IB!DC)/zT ʊ)X}zB!΁,k!e(X~6B!Ɓ_BojUЅBHO!TB !6 !B!/$~B!B wT]=_x>G֯>=B1yA!/Q%~pF&B!'tB!B_8IB! ՞8BqG;^!8+/֮@mwB!BK2[ywz4z"cB!BH!UzG:Uk'$0!B! W^_U9SnzG\s;q !B!8N.)&!B!>AzDIENDB`traitsui-4.1.0/docs/source/tutorials/traits_ui_scientific_app.rst0000644000175100001440000013273611674463545026447 0ustar ischnellusers00000000000000.. _writing-a-graphical-application-for-scientific-programming-using-traitsui: =========================================================================== Writing a graphical application for scientific programming using TraitsUI 4 =========================================================================== **A step by step guide for a non-programmer** .. |date| date:: :Author: Gael Varoquaux :Date: |date| :License: BSD Building interactive Graphical User Interfaces (GUIs) is a hard problem, especially for somebody who has not had training in IT. TraitsUI is a python module that provides a great answer to this problem. I have found that I am incredibly productive when creating graphical application using traitsUI. However I had to learn a few new concepts and would like to lay them down together in order to make it easier for others to follow my footsteps. This document is intended to help a non-programmer to use traits and traitsUI to write an interactive graphical application. The reader is assumed to have some basic python scripting knowledge (see ref [#]_ for a basic introduction). Knowledge of numpy/scipy [#]_ helps understanding the data processing aspects of the examples, but may not be paramount. Some examples rely on matplotlib [#]_ . This document is **not** a replacement for user manuals and references of the different packages (traitsUI [#]_, scipy, matplotlib). It provides a "cookbook" approach, and not a reference. This tutorial provides step-by-step guide to building a medium-size application. The example chosen is an application used to do control of a camera, analysis of the retrieved data and display of the results. This tutorial focuses on building the general structure and flow-control of the application, and on the aspects specific to traitsUI programming. Interfacing with the hardware or processing the data is left aside. The tutorial progressively introduces the tools used, and in the end presents the skeleton of a real application that has been developed for real-time controlling of an experiment, monitoring through a camera, and processing the data. The tutorial goes into more and more intricate details that are necessary to build the final application. Each section is in itself independent of the following ones. The complete beginner trying to use this as an introduction should not expect to understand all the details in a first pass. The author's experience while working on several projects in various physics labs is that code tends to be created in an 'organic' way, by different people with various levels of qualification in computer development, and that it rapidly decays to a disorganized and hard-to-maintain code base. This tutorial tries to prevent this by building an application shaped for modularity and readability. From objects to dialogs using traitsUI -------------------------------------- Creating user interfaces directly through a toolkit is a time-consuming process. It is also a process that does not integrate well in the scientific-computing work-flow, as, during the elaboration of algorithms and data-flow, the objects that are represented in the GUI are likely to change often. Visual computing, where the programmer creates first a graphical interface and then writes the callbacks of the graphical objects, gives rise to a slow development cycle, as the work-flow is centered on the GUI, and not on the code. TraitsUI provides a beautiful answer to this problem by building graphical representations of an object. Traits and TraitsUI have their own manuals (`http://code.enthought.com/traits/ `_) and the reader is encouraged to refer to these for more information. We will use TraitsUI for *all* our GUIs. This forces us to store all the data and parameters in objects, which is good programming style. The GUI thus reflects the structure of the code, which makes it easier to understand and extend. In this section we will focus on creating dialogs that allow the user to input parameters graphically in the program. Object-oriented programming ``````````````````````````` Software engineering is a difficult field. As programs, grow they become harder and harder to grasp for the developer. This problem is not new and has sometimes been know as the "tar pit". Many attempts have been made to mitigate the difficulties. Most often they consist in finding useful abstractions that allow the developer to manipulate larger ideas, rather than their software implementation. Code re-use is paramount for good software development. It reduces the number of code-lines required to read and understand and allows to identify large operations in the code. Functions and procedures have been invented to avoid copy-and-pasting code, and hide the low-level details of an operation. Object-oriented programming allows yet more modularity and abstraction. Objects, attributes and methods ::::::::::::::::::::::::::::::: Suppose you want your program to manipulate geometric objects. You can teach the computer that a point is a set of 3 numbers, you can teach it how to rotate that point along a given axis. Now you want to use spheres too. With a bit more work your program has functions to create points, spheres, etc. It knows how to rotate them, to mirror them, to scale them. So in pure procedural programming you will have procedures to rotate, scale, mirror, each one of your objects. If you want to rotate an object you will first have to find its type, then apply the right procedure to rotate it. Object-oriented programming introduces a new abstraction: the `object`. It consists of both data (our 3 numbers, in the case of a point), and procedures that use and modify this data (e.g., rotations). The data entries are called "`attributes`" of the object and the procedures "`methods`". Thus with object oriented programming an object "knows" how to be rotated. A point object could be implemented in python with: `code snippet #0 <../_static/code_block0.py>`_ .. code-block:: python from numpy import cos, sin class Point(object): """ 3D Point objects """ x = 0. y = 0. z = 0. def rotate_z(self, theta): """ rotate the point around the Z axis """ xtemp = cos(theta) * self.x + sin(theta) * self.y ytemp = -sin(theta) * self.x + cos(theta) * self.y self.x = xtemp self.y = ytemp This code creates a *Point* class. Points objects can be created as `instances` of the Point class: .. code-block:: python >>> from numpy import pi >>> p = Point() >>> p.x = 1 >>> p.rotate_z(pi) >>> p.x -1.0 >>> p.y 1.2246467991473532e-16 When manipulating objects, the developer does not need to know the internal details of their procedures. As long as the object has a *rotate* method, the developer knows how to rotate it. **Note**: Beginners often use objects as structures: entities with several data fields useful to pass data around in a program. Objects are much more then that: they have methods. They are 'active' data structures that know how to modify themselves. Part of the point of object-oriented programming is that the object is responsible for modifying itself through its methods. The object therefore takes care of its internal logic and the consistency between its attributes. In python, dictionaries make great structures and are more suited for such a use than objects. Classes and inheritance ::::::::::::::::::::::: Suppose you have already created a *Point* class that tells your program what a point is, but that you also want some points to have a color. Instead of copy-and-pasting the *Point* class and adding a color attribute, you can define a new class *ColoredPoint* that inherits all of the *Point* class's methods and attributes: .. code-block:: python class ColoredPoint(Point): """ Colored 3D point """ color = "white" You do not have to implement rotation for the *ColoredPoint* class as it has been inherited from the *Point* class. This is one of the huge gains of object-oriented programming: objects are organized in classes and sub-classes, and method to manipulate objects are derived from the objects parent-ship: a *ColoredPoint* is only a special case of *Point*. This proves very handy on large projects. **Note**: To stress the differences between classes and their instances (objects), classes are usually named with capital letters, and objects only with lower case letters. An object and its representation ```````````````````````````````` Objects are code entities that can be easily pictured by the developer. The `TraitsUI` python module allows the user to edit objects attributes with dialogs that form a graphical representation of the object. In our example application, each process or experimental device is represented in the code as an object. These objects all inherit from the *HasTraits*, class which supports creating graphical representations of attributes. To be able to build the dialog, the *HasTraits* class enforces that the types of all the attributes are specified in the class definition. The *HasTraits* objects have a *configure_traits()* method that brings up a dialog to edit the objects' attributes specified in its class definition. Here we define a camera object (which, in our real world example, is a camera interfaced to python through the ctypes [#]_ module), and show how to open a dialog to edit its properties : `code snippet #1 <../_static/code_block1.py>`_ .. code-block:: python from traits.api import * from traitsui.api import * class Camera(HasTraits): """ Camera object """ gain = Enum(1, 2, 3, desc="the gain index of the camera", label="gain", ) exposure = CInt(10, desc="the exposure time, in ms", label="Exposure", ) def capture(self): """ Captures an image on the camera and returns it """ print "capturing an image at %i ms exposure, gain: %i" % ( self.exposure, self.gain ) if __name__ == "__main__": camera = Camera() camera.configure_traits() camera.capture() The *camera.configure_traits()* call in the above example opens a dialog that allows the user to modify the camera object's attributes: .. image:: images/code_block1.png This dialog forms a graphical representation of our camera object. We will see that it can be embedded in GUI panels to build more complex GUIs that allow us to control many objects. We will build our application around objects and their graphical representation, as this mapping of the code to the GUI helps the developer to understand the code. Displaying several objects in the same panel ```````````````````````````````````````````` We now know how to build a dialog from objects. If we want to build a complex application we are likely to have several objects, for instance one corresponding to the camera we want to control, and one describing the experiment that the camera monitors. We do not want to have to open a new dialog per object: this would force us to describe the GUI in terms of graphical objects, and not structural objects. We want the GUI to be a natural representation of our objects, and we want the Traits module to take care of that. The solution is to create a container object, that has as attributes the objects we want to represent. Playing with the `View` attribute of the object, we can control how the representation generated by Traits looks like (see the TraitsUI manual): `code snippet #2 <../_static/container.py>`_ .. code-block:: python from traits.api import * from traitsui.api import * class Camera(HasTraits): gain = Enum(1, 2, 3, ) exposure = CInt(10, label="Exposure", ) class TextDisplay(HasTraits): string = String() view= View( Item('string', show_label=False, springy=True, style='custom' )) class Container(HasTraits): camera = Instance(Camera) display = Instance(TextDisplay) view = View( Item('camera', style='custom', show_label=False, ), Item('display', style='custom', show_label=False, ), ) container = Container(camera=Camera(), display=TextDisplay()) container.configure_traits() The call to *configure_traits()* creates the following dialog, with the representation of the *Camera* object created is the last example on top, and the *Display* object below it: .. image:: images/container.png The *View* attribute of the *container* object has been tweaked to get the representation we are interested in: traitsUI is told to display the *camera* item with a *'custom'* style, which instructs it to display the representation of the object inside the current panel. The *'show_label'* argument is set to *False* as we do not want the name of the displayed object ('camera', for instance) to appear in the dialog. See the traitsUI manual for more details on this powerful feature. The *camera* and *display* objects are created during the call to the creator of the *container* object, and passed as its attributes immediately: *"container = Container(camera=Camera(), display=TextDisplay())"* Writing a "graphical script" ```````````````````````````` If you want to create an application that has a very linear flow, popping up dialogs when user input is required, like a "setup wizard" often used to install programs, you already have all the tools to do it. You can use object oriented programming to write your program, and call the objects *configure_traits* method each time you need user input. This might be an easy way to modify an existing script to make it more user friendly. ____ The following section will focus on making interactive programs, where the user uses the graphical interface to interact with it in a continuous way. From graphical to interactive ----------------------------- In an interactive application, the program responds to user interaction. This requires a slight paradigm shift in our programming methods. Object-oriented GUIs and event loops ```````````````````````````````````` In a GUI application, the order in which the different parts of the program are executed is imposed by the user, unlike in a numerical algorithm, for instance, where the developer chooses the order of execution of his program. An event loop allows the programmer to develop an application in which each user action triggers an event, by stacking the user created events on a queue, and processing them in the order in which the appeared. A complex GUI is made of a large numbers of graphical elements, called widgets (e.g., text boxes, check boxes, buttons, menus). Each of these widgets has specific behaviors associated with user interaction (modifying the content of a text box, clicking on a button, opening a menu). It is natural to use objects to represent the widgets, with their behavior being set in the object's methods. Dialogs populated with widgets are automatically created by `traitsUI` in the *configure_traits()* call. `traitsUI` allow the developer to not worry about widgets, but to deal only with objects and their attributes. This is a fabulous gain as the widgets no longer appear in the code, but only the attributes they are associated to. A *HasTraits* object has an *edit_traits()* method that creates a graphical panel to edit its attributes. This method creates and returns the panel, but does not start its event loop. The panel is not yet "alive", unlike with the *configure_traits()* method. Traits uses the wxWidget toolkit by default to create its widget. They can be turned live and displayed by starting a wx application, and its main loop (ie event loop in wx speech). `code snippet #3 <../_static/event_loop.py>`_ .. code-block:: python from traits.api import * import wx class Counter(HasTraits): value = Int() Counter().edit_traits() wx.PySimpleApp().MainLoop() The *Counter().edit_traits()* line creates a counter object and its representation, a dialog with one integer represented. However it does not display it until a wx application is created, and its main loop is started. Usually it is not necessary to create the wx application yourself, and to start its main loop, traits will do all this for you when the *.configure_traits()* method is called. Reactive programming ```````````````````` When the event loop is started, the program flow is no longer simply controlled by the code: the control is passed on to the event loop, and it processes events, until the user closes the GUI, and the event loop returns to the code. Interactions with objects generate events, and these events can be associated to callbacks, ie functions or methods processing the event. In a GUI, callbacks created by user-generated events are placed on an "event stack". The event loop processes each call on the event queue one after the other, thus emptying the event queue. The flow of the program is still sequential (two code blocks never run at the same time in an event loop), but the execution order is chosen by the user, and not by the developer. Defining callbacks for the modification of an attribute `foo` of a `HasTraits` object can be done be creating a method called `_foo_changed()`. Here is an example of a dialog with two textboxes, `input` and `output`. Each time `input` is modified, is content is duplicated to output. `code snippet #4 <../_static/echo_box.py>`_ .. code-block:: python from traits.api import * class EchoBox(HasTraits): input = Str() output = Str() def _input_changed(self): self.output = self.input EchoBox().configure_traits() Events that do not correspond to a modification of an attribute can be generated with a *Button* traits. The callback is then called *_foo_fired()*. Here is an example of an interactive `traitsUI` application using a button: `code snippet #5 <../_static/interactive.py>`_ .. code-block:: python from traits.api import * from traitsui.api import View, Item, ButtonEditor class Counter(HasTraits): value = Int() add_one = Button() def _add_one_fired(self): self.value +=1 view = View('value', Item('add_one', show_label=False )) Counter().configure_traits() Clicking on the button adds the *_add_one_fired()* method to the event queue, and this method gets executed as soon as the GUI is ready to handle it. Most of the time that is almost immediately. .. image:: images/interactive.png This programming pattern is called `reactive programming`: the objects react to the changes made to their attributes. In complex programs where the order of execution is hard to figure out, and bound to change, like some interactive data processing application, this pattern is extremely efficient. ____ Using *Button* traits and a clever set of objects interacting with each others, complex interactive applications can be built. These applications are governed by the events generated by the user, in contrast to script-like applications (batch programming). Executing a long operation in the event loop blocks the reactions of the user-interface, as other events callbacks are not processed as long as the long operation is not finished. In the next section we will see how we can execute several operations in the same time. Breaking the flow in multiple threads ------------------------------------- What are threads ? `````````````````` A standard python program executes in a sequential way. Consider the following code snippet : .. code-block:: python do_a() do_b() do_c() *do_b()* is not called until *do_a()* is finished. Even in event loops everything is sequential. In some situation this can be very limiting. Suppose we want to capture an image from a camera and that it is a very lengthy operation. Suppose also that no other operation in our program requires the capture to be complete. We would like to have a different "timeline" in which the camera capture instructions can happen in a sequential way, while the rest of the program continues in parallel. Threads are the solution to this problem: a thread is a portion of a program that can run concurrently with other portions of the program. Programming with threads is difficult as instructions are no longer executed in the order they are specified and the output of a program can vary from a run to another, depending on subtle timing issues. These problems are known as "race conditions" and to minimize them you should avoid accessing the same objects in different threads. Indeed if two different threads are modifying the same object at the same time, unexpected things can happen. Threads in python ````````````````` In python a thread can be implemented with a *Thread* object, from the threading [#]_ module. To create your own execution thread, subclass the *Thread* object and put the code that you want to run in a separate thread in its *run* method. You can start your thread using its *start* method: `code snippet #6 <../_static/thread_example.py>`_ .. code-block:: python from threading import Thread from time import sleep class MyThread(Thread): def run(self): sleep(2) print "MyThread done" my_thread = MyThread() my_thread.start() print "Main thread done" The above code yields the following output:: Main thread done MyThread done Getting threads and the GUI event loop to play nice ``````````````````````````````````````````````````` Suppose you have a long-running job in a TraitsUI application. If you implement this job as an event placed on the event loop stack, it is going to freeze the event loop while running, and thus freeze the UI, as events will accumulate on the stack, but will not be processed as long as the long-running job is not done (remember, the event loop is sequential). To keep the UI responsive, a thread is the natural answer. Most likely you will want to display the results of your long-running job on the GUI. However, as usual with threads, one has to be careful not to trigger race-conditions. Naively manipulating the GUI objects in your thread will lead to race conditions, and unpredictable crash: suppose the GUI was repainting itself (due to a window move, for instance) when you modify it. In a wxPython application, if you start a thread, GUI event will still be processed by the GUI event loop. To avoid collisions between your thread and the event loop, the proper way of modifying a GUI object is to insert the modifications in the event loop, using the *GUI.invoke_later()* call. That way the GUI will apply your instructions when it has time. Recent versions of the TraitsUI module (post October 2006) propagate the changes you make to a *HasTraits* object to its representation in a thread-safe way. However it is important to have in mind that modifying an object with a graphical representation is likely to trigger race-conditions as it might be modified by the graphical toolkit while you are accessing it. Here is an example of code inserting the modification to traits objects by hand in the event loop: `code snippet #7 <../_static/traits_thread.py>`_ .. code-block:: python from threading import Thread from time import sleep from traits.api import * from traitsui.api import View, Item, ButtonEditor class TextDisplay(HasTraits): string = String() view= View( Item('string',show_label=False, springy=True, style='custom' )) class CaptureThread(Thread): def run(self): self.display.string = 'Camera started\n' + self.display.string n_img = 0 while not self.wants_abort: sleep(.5) n_img += 1 self.display.string = '%d image captured\n' % n_img \ + self.display.string self.display.string = 'Camera stopped\n' + self.display.string class Camera(HasTraits): start_stop_capture = Button() display = Instance(TextDisplay) capture_thread = Instance(CaptureThread) view = View( Item('start_stop_capture', show_label=False )) def _start_stop_capture_fired(self): if self.capture_thread and self.capture_thread.isAlive(): self.capture_thread.wants_abort = True else: self.capture_thread = CaptureThread() self.capture_thread.wants_abort = False self.capture_thread.display = self.display self.capture_thread.start() class MainWindow(HasTraits): display = Instance(TextDisplay, ()) camera = Instance(Camera) def _camera_default(self): return Camera(display=self.display) view = View('display', 'camera', style="custom", resizable=True) if __name__ == '__main__': MainWindow().configure_traits() This creates an application with a button that starts or stop a continuous camera acquisition loop. .. image:: images/traits_thread.png When the "Start stop capture" button is pressed the *_start_stop_capture_fired* method is called. It checks to see if a *CaptureThread* is running or not. If none is running, it starts a new one. If one is running, it sets its *wants_abort* attribute to true. The thread checks every half a second to see if its attribute *wants_abort* has been set to true. If this is the case, it aborts. This is a simple way of ending the thread through a GUI event. ____ Using different threads lets the operations avoid blocking the user interface, while also staying responsive to other events. In the real-world application that serves as the basis of this tutorial, there are 2 threads and a GUI event loop. The first thread is an acquisition loop, during which the program loops, waiting for a image to be captured on the camera (the camera is controlled by external signals). Once the image is captured and transfered to the computer, the acquisition thread saves it to the disk and spawns a thread to process the data, then returns to waiting for new data while the processing thread processes the data. Once the processing thread is done, it displays its results (by inserting the display events in the GUI event loop) and dies. The acquisition thread refuses to spawn a new processing thread if there still is one running. This makes sure that data is never lost, no matter how long the processing might be. There are thus up to 3 set of instructions running concurrently: the GUI event loop, responding to user-generated events, the acquisition loop, responding to hardware-generated events, and the processing jobs, doing the numerical intensive work. In the next section we are going to see how to add a home-made element to traits, in order to add new possibilities to our application. Extending TraitsUI: Adding a matplotlib figure to our application ----------------------------------------------------------------- This section gives a few guidelines on how to build your own traits editor. A traits editor is the view associated with a trait that allows the user to graphically edit its value. We can twist a bit the notion and simply use it to graphically represent the attribute. This section involves a bit of `wxPython` code that may be hard to understand if you do not know `wxPython`, but it will bring a lot of power and flexibility to how you use traits. The reason it appears in this tutorial is that I wanted to insert a matplotlib in my `traitsUI` application. It is not necessary to fully understand the code of this section to be able to read on. I should stress that there already exists a plotting module that provides traits editors for plotting, and that is very well integrated with traits: chaco [#]_. Making a `traits` editor from a MatPlotLib plot ``````````````````````````````````````````````` To use traits, the developer does not need to know its internals. However traits does not provide an editor for every need. If we want to insert a powerful tool for plotting we have to get our hands a bit dirty and create our own traits editor. This involves some `wxPython` coding, as we need to translate a `wxPython` object to a traits editor by providing the corresponding API (i.e. the standard way of building a `traits` editor), so that the `traits` framework will know how to create the editor. Traits editor are created by an editor factory that instantiates an editor class and passes it the object that the editor represents in its *value* attribute. It calls the editor *init()* method to create the *wx* widget. Here we create a wx figure canvas from a matplotlib figure using the matplotlib wx backend. Instead of displaying this widget, we set its control as the *control* attribute of the editor. TraitsUI takes care of displaying and positioning the editor. `code snippet #8 <../_static/mpl_figure_editor.py>`_ .. code-block:: python import wx import matplotlib # We want matplotlib to use a wxPython backend matplotlib.use('WXAgg') from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas from matplotlib.figure import Figure from matplotlib.backends.backend_wx import NavigationToolbar2Wx from traits.api import Any, Instance from traitsui.wx.editor import Editor from traitsui.wx.basic_editor_factory import BasicEditorFactory class _MPLFigureEditor(Editor): scrollable = True def init(self, parent): self.control = self._create_canvas(parent) self.set_tooltip() def update_editor(self): pass def _create_canvas(self, parent): """ Create the MPL canvas. """ # The panel lets us add additional controls. panel = wx.Panel(parent, -1, style=wx.CLIP_CHILDREN) sizer = wx.BoxSizer(wx.VERTICAL) panel.SetSizer(sizer) # matplotlib commands to create a canvas mpl_control = FigureCanvas(panel, -1, self.value) sizer.Add(mpl_control, 1, wx.LEFT | wx.TOP | wx.GROW) toolbar = NavigationToolbar2Wx(mpl_control) sizer.Add(toolbar, 0, wx.EXPAND) self.value.canvas.SetMinSize((10,10)) return panel class MPLFigureEditor(BasicEditorFactory): klass = _MPLFigureEditor if __name__ == "__main__": # Create a window to demo the editor from traits.api import HasTraits from traitsui.api import View, Item from numpy import sin, cos, linspace, pi class Test(HasTraits): figure = Instance(Figure, ()) view = View(Item('figure', editor=MPLFigureEditor(), show_label=False), width=400, height=300, resizable=True) def __init__(self): super(Test, self).__init__() axes = self.figure.add_subplot(111) t = linspace(0, 2*pi, 200) axes.plot(sin(t)*(1+0.5*cos(11*t)), cos(t)*(1+0.5*cos(11*t))) Test().configure_traits() This code first creates a traitsUI editor for a matplotlib figure, and then a small dialog to illustrate how it works: .. image:: images/mpl_figure_editor.png The matplotlib figure traits editor created in the above example can be imported in a traitsUI application and combined with the power of traits. This editor allows to insert a matplotlib figure in a traitsUI dialog. It can be modified using reactive programming, as demonstrated in section 3 of this tutorial. However, once the dialog is up and running, you have to call *self.figure.canvas.draw()* to update the canvas if you made modifications to the figure. The matplotlib user guide [3]_ details how this object can be used for plotting. Putting it all together: a sample application --------------------------------------------- The real world problem that motivated the writing of this tutorial is an application that retrieves data from a camera, processes it and displays results and controls to the user. We now have all the tools to build such an application. This section gives the code of a skeleton of this application. This application actually controls a camera on a physics experiment (Bose-Einstein condensation), at the university of Toronto. The reason I am providing this code is to give an example to study of how a full-blown application can be built. This code can be found in the `tutorial's zip file `_ (it is the file `application.py`). * The camera will be built as an object. Its real attributes (exposure time, gain...) will be represented as the object's attributes, and exposed through traitsUI. * The continuous acquisition/processing/user-interaction will be handled by appropriate threads, as discussed in section 2.3. * The plotting of the results will be done through the MPLWidget object. The imports ``````````` The MPLFigureEditor is imported from the last example. .. code-block:: python from threading import Thread from time import sleep from traits.api import * from traitsui.api import View, Item, Group, HSplit, Handler from traitsui.menu import NoButtons from mpl_figure_editor import MPLFigureEditor from matplotlib.figure import Figure from scipy import * import wx User interface objects `````````````````````` These objects store information for the program to interact with the user via traitsUI. .. code-block:: python class Experiment(HasTraits): """ Object that contains the parameters that control the experiment, modified by the user. """ width = Float(30, label="Width", desc="width of the cloud") x = Float(50, label="X", desc="X position of the center") y = Float(50, label="Y", desc="Y position of the center") class Results(HasTraits): """ Object used to display the results. """ width = Float(30, label="Width", desc="width of the cloud") x = Float(50, label="X", desc="X position of the center") y = Float(50, label="Y", desc="Y position of the center") view = View( Item('width', style='readonly'), Item('x', style='readonly'), Item('y', style='readonly'), ) The camera object also is a real object, and not only a data structure: it has a method to acquire an image (or in our case simulate acquiring), using its attributes as parameters for the acquisition. .. code-block:: python class Camera(HasTraits): """ Camera objects. Implements both the camera parameters controls, and the picture acquisition. """ exposure = Float(1, label="Exposure", desc="exposure, in ms") gain = Enum(1, 2, 3, label="Gain", desc="gain") def acquire(self, experiment): X, Y = indices((100, 100)) Z = exp(-((X-experiment.x)**2+(Y-experiment.y)**2)/experiment.width**2) Z += 1-2*rand(100,100) Z *= self.exposure Z[Z>2] = 2 Z = Z**self.gain return(Z) Threads and flow control ```````````````````````` There are three threads in this application: * The GUI event loop, the only thread running at the start of the program. * The acquisition thread, started through the GUI. This thread is an infinite loop that waits for the camera to be triggered, retrieves the images, displays them, and spawns the processing thread for each image received. * The processing thread, started by the acquisition thread. This thread is responsible for the numerical intensive work of the application. It processes the data and displays the results. It dies when it is done. One processing thread runs per shot acquired on the camera, but to avoid accumulation of threads in the case that the processing takes longer than the time lapse between two images, the acquisition thread checks that the processing thread is done before spawning a new one. .. code-block:: python def process(image, results_obj): """ Function called to do the processing """ X, Y = indices(image.shape) x = sum(X*image)/sum(image) y = sum(Y*image)/sum(image) width = sqrt(abs(sum(((X-x)**2+(Y-y)**2)*image)/sum(image))) results_obj.x = x results_obj.y = y results_obj.width = width class AcquisitionThread(Thread): """ Acquisition loop. This is the worker thread that retrieves images from the camera, displays them, and spawns the processing job. """ wants_abort = False def process(self, image): """ Spawns the processing job. """ try: if self.processing_job.isAlive(): self.display("Processing too slow") return except AttributeError: pass self.processing_job = Thread(target=process, args=(image, self.results)) self.processing_job.start() def run(self): """ Runs the acquisition loop. """ self.display('Camera started') n_img = 0 while not self.wants_abort: n_img += 1 img =self.acquire(self.experiment) self.display('%d image captured' % n_img) self.image_show(img) self.process(img) sleep(1) self.display('Camera stopped') The GUI elements ```````````````` The GUI of this application is separated in two (and thus created by a sub-class of SplitApplicationWindow). On the left a plotting area, made of an MPL figure and its editor, displays the images acquired by the camera. On the right a panel hosts the TraitsUI representation of a ControlPanel object. This object is mainly a container for our other objects, but it also has an Button for starting or stopping the acquisition, and a string (represented by a textbox) to display information on the acquisition process. The view attribute is tweaked to produce a pleasant and usable dialog. Tabs are used to help the display to be light and clear. .. code-block:: python class ControlPanel(HasTraits): """ This object is the core of the traitsUI interface. Its view is the right panel of the application, and it hosts the method for interaction between the objects and the GUI. """ experiment = Instance(Experiment, ()) camera = Instance(Camera, ()) figure = Instance(Figure) results = Instance(Results, ()) start_stop_acquisition = Button("Start/Stop acquisition") results_string = String() acquisition_thread = Instance(AcquisitionThread) view = View(Group( Group( Item('start_stop_acquisition', show_label=False ), Item('results_string',show_label=False, springy=True, style='custom' ), label="Control", dock='tab',), Group( Group( Item('experiment', style='custom', show_label=False), label="Input",), Group( Item('results', style='custom', show_label=False), label="Results",), label='Experiment', dock="tab"), Item('camera', style='custom', show_label=False, dock="tab"), layout='tabbed'), ) def _start_stop_acquisition_fired(self): """ Callback of the "start stop acquisition" button. This starts the acquisition thread, or kills it. """ if self.acquisition_thread and self.acquisition_thread.isAlive(): self.acquisition_thread.wants_abort = True else: self.acquisition_thread = AcquisitionThread() self.acquisition_thread.display = self.add_line self.acquisition_thread.acquire = self.camera.acquire self.acquisition_thread.experiment = self.experiment self.acquisition_thread.image_show = self.image_show self.acquisition_thread.results = self.results self.acquisition_thread.start() def add_line(self, string): """ Adds a line to the textbox display. """ self.results_string = (string + "\n" + self.results_string)[0:1000] def image_show(self, image): """ Plots an image on the canvas in a thread safe way. """ self.figure.axes[0].images=[] self.figure.axes[0].imshow(image, aspect='auto') wx.CallAfter(self.figure.canvas.draw) class MainWindowHandler(Handler): def close(self, info, is_OK): if ( info.object.panel.acquisition_thread and info.object.panel.acquisition_thread.isAlive() ): info.object.panel.acquisition_thread.wants_abort = True while info.object.panel.acquisition_thread.isAlive(): sleep(0.1) wx.Yield() return True class MainWindow(HasTraits): """ The main window, here go the instructions to create and destroy the application. """ figure = Instance(Figure) panel = Instance(ControlPanel) def _figure_default(self): figure = Figure() figure.add_axes([0.05, 0.04, 0.9, 0.92]) return figure def _panel_default(self): return ControlPanel(figure=self.figure) view = View(HSplit(Item('figure', editor=MPLFigureEditor(), dock='vertical'), Item('panel', style="custom"), show_labels=False, ), resizable=True, height=0.75, width=0.75, handler=MainWindowHandler(), buttons=NoButtons) if __name__ == '__main__': MainWindow().configure_traits() When the acquisition loop is created and running, the mock camera object produces noisy gaussian images, and the processing code estimates the parameters of the gaussian. Here are screenshots of the three different tabs of the application: .. image:: images/application1.png .. image:: images/application2.png .. image:: images/application3.png ____ **Conclusion** I have summarized here all what most scientists need to learn in order to be able to start building applications with traitsUI. Using the traitsUI module to its full power requires you to move away from the procedural type of programming most scientists are used to, and think more in terms of objects and flow of information and control between them. I have found that this paradigm shift, although a bit hard, has been incredibly rewarding in terms of my own productivity and my ability to write compact and readable code. Good luck! ____ **Acknowledgments** I would like to thank the people on the enthought-dev mailing-list, especially Prabhu Ramachandran and David Morrill, for all the help they gave me, and Janet Swisher for reviewing this document. Big thanks go to enthought for developing the traits and traitsUI modules, and making them open-source. Finally the python, the numpy, and the matplotlib community deserve many thanks for both writing such great software, and being so helpful on the mailing lists. ____ **References** .. [#] python tutorial: `http://docs.python.org/tut/tut.html `_ .. [#] The scipy website: `http://www.scipy.org `_ .. [#] The matplotlib website: `http://matplotlib.sourceforge.net `_ .. [#] The traits and traitsUI user guide: `http://code.enthought.com/traits `_ .. [#] ctypes: `http://starship.python.net/crew/theller/ctypes/ `_ .. [#] threading: `http://docs.python.org/lib/module-threading.html `_ .. [#] chaco: `http://code.enthought.com/chaco/ `_ .. vim:spell:spelllang=en_us traitsui-4.1.0/docs/source/tutorials/code_snippets/0000755000175100001440000000000011674463545023475 5ustar ischnellusers00000000000000traitsui-4.1.0/docs/source/tutorials/code_snippets/mpl_figure_editor.py0000644000175100001440000000377111674463545027556 0ustar ischnellusers00000000000000 import wx import matplotlib # We want matplotlib to use a wxPython backend matplotlib.use('WXAgg') from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas from matplotlib.figure import Figure from matplotlib.backends.backend_wx import NavigationToolbar2Wx from traits.api import Any, Instance from traitsui.wx.editor import Editor from traitsui.wx.basic_editor_factory import BasicEditorFactory class _MPLFigureEditor(Editor): scrollable = True def init(self, parent): self.control = self._create_canvas(parent) self.set_tooltip() def update_editor(self): pass def _create_canvas(self, parent): """ Create the MPL canvas. """ # The panel lets us add additional controls. panel = wx.Panel(parent, -1, style=wx.CLIP_CHILDREN) sizer = wx.BoxSizer(wx.VERTICAL) panel.SetSizer(sizer) # matplotlib commands to create a canvas mpl_control = FigureCanvas(panel, -1, self.value) sizer.Add(mpl_control, 1, wx.LEFT | wx.TOP | wx.GROW) toolbar = NavigationToolbar2Wx(mpl_control) sizer.Add(toolbar, 0, wx.EXPAND) self.value.canvas.SetMinSize((10,10)) return panel class MPLFigureEditor(BasicEditorFactory): klass = _MPLFigureEditor if __name__ == "__main__": # Create a window to demo the editor from traits.api import HasTraits from traitsui.api import View, Item from numpy import sin, cos, linspace, pi class Test(HasTraits): figure = Instance(Figure, ()) view = View(Item('figure', editor=MPLFigureEditor(), show_label=False), width=400, height=300, resizable=True) def __init__(self): super(Test, self).__init__() axes = self.figure.add_subplot(111) t = linspace(0, 2*pi, 200) axes.plot(sin(t)*(1+0.5*cos(11*t)), cos(t)*(1+0.5*cos(11*t))) Test().configure_traits() traitsui-4.1.0/docs/source/tutorials/code_snippets/event_loop.py0000644000175100001440000000020711674463545026220 0ustar ischnellusers00000000000000from traits.api import * import wx class Counter(HasTraits): value = Int() Counter().edit_traits() wx.PySimpleApp().MainLoop() traitsui-4.1.0/docs/source/tutorials/code_snippets/interactive.py0000644000175100001440000000051211674463545026362 0ustar ischnellusers00000000000000from traits import * from pyface.api import GUI from traitsui import View, Item, ButtonEditor class Counter(HasTraits): value = Int() add_one = Button() def _add_one_fired(self): self.value +=1 view = View('value', Item('add_one', show_label=False )) Counter().edit_traits() GUI().start_event_loop() traitsui-4.1.0/docs/source/tutorials/code_snippets/code_block1.py0000644000175100001440000000110211674463545026206 0ustar ischnellusers00000000000000from traits.api import * from traitsui.api import * class Camera( HasTraits ): """ Camera object """ gain = Enum(1, 2, 3, desc="the gain index of the camera", label="gain", ) exposure = CInt(10, desc="the exposure time, in ms", label="Exposure", ) def capture(self): """ Captures an image on the camera and returns it """ print "capturing an image at %i ms exposure, gain: %i" % ( self.exposure, self.gain ) if __name__ == "__main__": camera = Camera() camera.configure_traits() camera.capture() traitsui-4.1.0/docs/source/tutorials/code_snippets/container.py0000644000175100001440000000133011674463545026026 0ustar ischnellusers00000000000000from traits.api import * from traitsui.api import * class Camera(HasTraits): """ Camera object """ gain = Enum(1, 2, 3, desc="the gain index of the camera", label="gain", ) exposure = CInt(10, desc="the exposure time, in ms", label="Exposure", ) class Display(HasTraits): string = String() view= View( Item('string', show_label=False, springy=True, style='custom' )) class Container(HasTraits): camera = Instance(Camera, ()) display = Instance(Display, ()) view = View( Item('camera', style='custom', show_label=False, ), Item('display', style='custom', show_label=False, ), ) Container().configure_traits() traitsui-4.1.0/docs/source/tutorials/code_snippets/thread_example.py0000644000175100001440000000032411674463545027030 0ustar ischnellusers00000000000000from threading import Thread from time import sleep class MyThread(Thread): def run(self): sleep(2) print "MyThread done" my_thread = MyThread() my_thread.start() print "Main thread done" traitsui-4.1.0/docs/source/tutorials/code_snippets/code_block0.py0000644000175100001440000000055011674463545026213 0ustar ischnellusers00000000000000from numpy import cos, sin class Point(object): """ 3D Points objects """ x = 0. y = 0. z = 0. def rotate_z(self, theta): """ rotate the point around the Z axis """ xtemp = cos(theta) * self.x + sin(theta) * self.y ytemp = -sin(theta) * self.x + cos(theta) * self.y self.x = xtemp self.y = ytemp traitsui-4.1.0/docs/source/tutorials/code_snippets/traits_thread.py0000644000175100001440000000273311674463545026711 0ustar ischnellusers00000000000000from threading import Thread from time import sleep from traits.api import * from traitsui.api import View, Item, ButtonEditor class TextDisplay(HasTraits): string = String() view= View( Item('string',show_label=False, springy=True, style='custom' )) class CaptureThread(Thread): def run(self): self.display.string = 'Camera started\n' + self.display.string n_img = 0 while not self.wants_abort: sleep(.5) n_img += 1 self.display.string = '%d image captured\n' % n_img \ + self.display.string self.display.string = 'Camera stopped\n' + self.display.string class Camera(HasTraits): start_stop_capture = Button() display = Instance(TextDisplay) capture_thread = Instance(CaptureThread) view = View( Item('start_stop_capture', show_label=False )) def _start_stop_capture_fired(self): if self.capture_thread and self.capture_thread.isAlive(): self.capture_thread.wants_abort = True else: self.capture_thread = CaptureThread() self.capture_thread.wants_abort = False self.capture_thread.display = self.display self.capture_thread.start() class MainWindow(HasTraits): display = Instance(TextDisplay, ()) camera = Instance(Camera) def _camera_default(self): return Camera(display=self.display) view = View('display', 'camera', style="custom", resizable=True) if __name__ == '__main__': MainWindow().configure_traits() traitsui-4.1.0/docs/source/tutorials/code_snippets/echo_box.py0000644000175100001440000000027111674463545025635 0ustar ischnellusers00000000000000from traits.api import * class EchoBox(HasTraits): input = Str() output = Str() def _input_changed(self): self.output = self.input EchoBox().configure_traits() traitsui-4.1.0/docs/source/tutorials/index.rst0000644000175100001440000000017711674463545022504 0ustar ischnellusers00000000000000TraitsUI 4 Tutorials =================================== .. toctree:: :maxdepth: 3 traits_ui_scientific_app.rst traitsui-4.1.0/docs/source/conf.py0000644000175100001440000001335011674463545020111 0ustar ischnellusers00000000000000# -*- coding: utf-8 -*- # # Traits documentation build configuration file, created by # sphinx-quickstart on Tue Jul 22 10:52:03 2008. # # This file is execfile()d with the current directory set to its containing dir. # # The contents of this file are pickled, so don't put values in the namespace # that aren't pickleable (module imports are okay, they're removed automatically). # # All configuration values have a default value; values that are commented out # serve to show the default value. import sys, os # If your extensions are in another directory, add it here. If the directory # is relative to the documentation root, use os.path.abspath to make it # absolute, like shown here. #sys.path.append(os.path.abspath('some/directory')) # General configuration # --------------------- # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = [] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The master toctree document. master_doc = 'index' # General substitutions. project = 'traitsui' copyright = '2008-2011, Enthought' # The default replacements for |version| and |release|, also used in various # other places throughout the built documents. # # Pull from the actual release number without imports d = {} execfile(os.path.join('..', '..', 'traitsui', '__init__.py'), d) version = release = d['__version__'] # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. today_fmt = '%B %d, %Y' # List of documents that shouldn't be included in the build. #unused_docs = [] # List of directories, relative to source directories, that shouldn't be searched # for source files. #exclude_dirs = [] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # Options for HTML output # ----------------------- # The style sheet to use for HTML and HTML Help pages. A file of that name # must exist either in Sphinx' static/ path, or in one of the custom paths # given in html_static_path. html_style = 'default.css' # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". html_title = "TraitsUI 4 User Manual" # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (within the static path) to place at the top of # the sidebar. html_logo = "e-logo-rev.png" # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. html_favicon = "et.ico" # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static', os.path.join('tutorials','code_snippets')] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. html_use_modindex = False # If false, no index is generated. #html_use_index = False # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, the reST sources are included in the HTML build as _sources/. #html_copy_source = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = '' # Output file base name for HTML help builder. htmlhelp_basename = 'Traitsuidoc' # Options for LaTeX output # ------------------------ # The paper size ('letter' or 'a4'). #latex_paper_size = 'letter' # The font size ('10pt', '11pt' or '12pt'). #latex_font_size = '10pt' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, document class [howto/manual]). latex_documents = [ ('index', 'TraitsUI.tex', 'TraitsUI 4 User Manual', 'Enthought, Inc.', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. # latex_logo = "enthought_logo.jpg" latex_logo = "e-logo-rev.png" # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # Additional stuff for the LaTeX preamble. #latex_preamble = '' # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_use_modindex = True traitsui-4.1.0/docs/source/index.rst0000644000175100001440000000037211674463545020453 0ustar ischnellusers00000000000000TraitsUI Documentation ============================================== .. toctree:: :maxdepth: 2 :glob: traitsui_user_manual/index tutorials/index Indices and tables ================== * :ref:`genindex` * :ref:`search` traitsui-4.1.0/docs/source/_templates/0000755000175100001440000000000011674463545020745 5ustar ischnellusers00000000000000traitsui-4.1.0/docs/source/_templates/search.html0000644000175100001440000000174511674463545023107 0ustar ischnellusers00000000000000{% extends "!search.html" %} {% block body %}

    Search

    Enter your search words into the box below and click search. Note that the search function automatically searches for all of the words. Pages containing some but not all of them won't appear in the result list.

    {% if search_performed %}

    Search Results

    {% if not search_results %}

    Your search did not match any results.

    {% endif %} {% endif %}
    {% endblock %} traitsui-4.1.0/docs/source/_templates/layout.html0000644000175100001440000000036311674463545023152 0ustar ischnellusers00000000000000{# Filename: .templates/layout.html #} {% extends '!layout.html' %} {% block relbaritems %} {% if current_page_name != 'index' %}
  • {{ title }}
  • {% endif %} {% endblock %} traitsui-4.1.0/docs/source/.static/0000755000175100001440000000000011674463545020155 5ustar ischnellusers00000000000000traitsui-4.1.0/docs/source/.static/e-logo-rev.png0000644000175100001440000000751111674463545022643 0ustar ischnellusers00000000000000PNG  IHDRoi*sRGB pHYs  tIMELIDATx]ktT>z\$m ȥ!TD jV|_CWph PT\"B$$6aIf9qfB%= By}; vo`!4ChVv[12 !HGiyg):QVd8SmsQAj2~~AH3qU:?!4[a6SRu ǎ7H'1"_Qq!JbBwx$I-S^QO>AO~( HAPU)=Ojjm+ v$~ئ"33zviJn[*.\v(/E1U`Ycֿ&y3g>=x$;GS@]d1YÓo"۾X6n8o2 ,c_܊U?y" "cdL5HfFj~}Q]H錩/Oxcq'~lӕ_ ţeW\| &cLMhdȶ9-՗ $ Θڳ9i˗>xa6>#E _h2$}앿"a\l߰0/"ޑҦ.*:UQyٕ~`:oYfxu? b)<̜>җ'rYgԾ6ngeSMkm>uv" Snhj ̌ry_ݚLM01@$(]vƏ{_{#&>4l|c.8~rK05bjԈm;14*:Ο3yK|ީT\> 8nd٤B]j맻]8#&[5TEUlu#u\/kk^6t=Zo`Ӌ-,R'*EP1#EQ DfsnlOYYYҨ!${G2yZ~\pN|olӋnϯBu-\$5˘TYgNR^\8gF{@|4Ņ0ov2֊^:j)D"zM En1]WfN@wǛ뿨k B|c!>8T'JԉaZxubOW~;c%dLynظedNSt~WX\f-pO',9UI21`xĥd  ,{ER"Z G 4PLq@$#15! G}\.-2kEfV=G15Q&ph!9Ce Cvj(# 5#GX:InHJZmڞU__(h݆' H7cHκ})"Db-&`i\eU?*YJ05 D S[GabDěrqEʪ9կm"4LwtGTدr{OPۿhj?:}"i b:/7yA@eK#$t13mj51K &^w !%PSSSֆlr{s^#w4DmQI S#3a@57Q; S#:į v4yR+A&P0j/))-&Z4S.[Z2d^!j8J01-j(T!05Q)"jԌ+@vpd"'4LuyC͉cv,@A1i_qLq|s4bvGz!U !KIQD1E3[1vI $00h6FL̙dnu˞?SScw\LGaʃcf-N]y/4u: c c PM18_h>4~h޽f l%&N^>?2=iC)9v!˜j>hN'N~(aİ}Wx+' u0?1sL _/>_nH ! x9zq@bzlLؘO_6Ac6~t=F&מc2\汋rh3.婓Jx`x^_>_mqKkj+-++Y.zw3TU+qܹ~M\_:pBI" D5 JcTubd!P%+~fz*EP]6R2;/uz] g,'Nd=C^n188D,dZ}W/)~ǎ/z~*0P]g*ݐ[{s]b76 $?`[퍘JTDDKŽ t "((}qqwZΦO11fZ XSXk71E~;{GbN#"k" r@4˗mrN"srLڀ?Vh?݁nw'?0l۶`bF4]2UU ;llgL bkx'ۄ&%QU#c*B{awE|DǶBhZ-f/wIENDB`traitsui-4.1.0/docs/source/.static/default.css0000644000175100001440000003231211674463545022314 0ustar ischnellusers00000000000000/** * Sphinx Doc Design */ body { font-family: 'Verdana', 'Helvetica', 'Arial', sans-serif; font-size: 100%; background-color: #333333; color: #000; margin: 0; padding: 0; } /* :::: LAYOUT :::: */ div.document { background-color: #24326e; } div.documentwrapper { float: left; width: 100%; } div.bodywrapper { margin: 0 0 0 230px; } div.body { background-color: white; padding: 0 20px 30px 20px; } div.sphinxsidebarwrapper { padding: 10px 5px 0 10px; } div.sphinxsidebar { float: left; width: 230px; margin-left: -100%; font-size: 90%; } p.logo { text-align: center; } div.clearer { clear: both; } div.footer { color: #fff; width: 100%; padding: 9px 0 9px 0; text-align: center; font-size: 75%; } div.footer a { color: #fff; text-decoration: underline; } div.related { background-color: #24326e; color: #fff; width: 100%; height: 30px; line-height: 30px; font-size: 90%; } div.related h3 { display: none; } div.related ul { margin: 0; padding: 0 0 0 10px; list-style: none; } div.related li { display: inline; } div.related li.right { float: right; margin-right: 5px; } div.related a { color: white; } /* ::: TOC :::: */ div.sphinxsidebar h3 { font-family: 'Verdana', 'Helvetica', 'Arial', sans-serif; color: #acafb3; font-size: 1.4em; font-weight: normal; margin: 0; padding: 0; } div.sphinxsidebar h4 { font-family: 'Verdana', 'Helvetica', 'Arial', sans-serif; color: #acafb3; font-size: 1.3em; font-weight: normal; margin: 5px 0 0 0; padding: 0; } div.sphinxsidebar p { color: white; } div.sphinxsidebar p.topless { margin: 5px 10px 10px 10px; } div.sphinxsidebar ul { margin: 10px; padding: 0; list-style: none; color: white; } div.sphinxsidebar ul ul, div.sphinxsidebar ul.want-points { margin-left: 20px; list-style: square; } div.sphinxsidebar ul ul { margin-top: 0; margin-bottom: 0; } div.sphinxsidebar a { color: #fff; } div.sphinxsidebar form { margin-top: 10px; } div.sphinxsidebar input { border: 1px solid #9bbde2; font-family: 'Verdana', 'Helvetica', 'Arial', sans-serif; font-size: 1em; } /* :::: MODULE CLOUD :::: */ div.modulecloud { margin: -5px 10px 5px 10px; padding: 10px; line-height: 160%; border: 1px solid #666666; background-color: #dddddd; } div.modulecloud a { padding: 0 5px 0 5px; } /* :::: SEARCH :::: */ ul.search { margin: 10px 0 0 20px; padding: 0; } ul.search li { padding: 5px 0 5px 20px; background-image: url(file.png); background-repeat: no-repeat; background-position: 0 7px; } ul.search li a { font-weight: bold; } ul.search li div.context { color: #666; margin: 2px 0 0 30px; text-align: left; } ul.keywordmatches li.goodmatch a { font-weight: bold; } /* :::: COMMON FORM STYLES :::: */ div.actions { padding: 5px 10px 5px 10px; border-top: 1px solid #598ec0; border-bottom: 1px solid #598ec0; background-color: #9bbde2; } form dl { color: #333; } form dt { clear: both; float: left; min-width: 110px; margin-right: 10px; padding-top: 2px; } input#homepage { display: none; } div.error { margin: 5px 20px 0 0; padding: 5px; border: 1px solid #db7d46; font-weight: bold; } /* :::: INLINE COMMENTS :::: */ div.inlinecomments { position: absolute; right: 20px; } div.inlinecomments a.bubble { display: block; float: right; background-image: url(style/comment.png); background-repeat: no-repeat; width: 25px; height: 25px; text-align: center; padding-top: 3px; font-size: 0.9em; line-height: 14px; font-weight: bold; color: black; } div.inlinecomments a.bubble span { display: none; } div.inlinecomments a.emptybubble { background-image: url(style/nocomment.png); } div.inlinecomments a.bubble:hover { background-image: url(style/hovercomment.png); text-decoration: none; color: #598ec0; } div.inlinecomments div.comments { float: right; margin: 25px 5px 0 0; max-width: 50em; min-width: 30em; border: 1px solid #598ec0; background-color: #9bbde2; z-index: 150; } div#comments { border: 1px solid #598ec0; margin-top: 20px; } div#comments div.nocomments { padding: 10px; font-weight: bold; } div.inlinecomments div.comments h3, div#comments h3 { margin: 0; padding: 0; background-color: #598ec0; color: white; border: none; padding: 3px; } div.inlinecomments div.comments div.actions { padding: 4px; margin: 0; border-top: none; } div#comments div.comment { margin: 10px; border: 1px solid #598ec0; } div.inlinecomments div.comment h4, div.commentwindow div.comment h4, div#comments div.comment h4 { margin: 10px 0 0 0; background-color: #2eabb0; color: white; border: none; padding: 1px 4px 1px 4px; } div#comments div.comment h4 { margin: 0; } div#comments div.comment h4 a { color: #9bbde2; } div.inlinecomments div.comment div.text, div.commentwindow div.comment div.text, div#comments div.comment div.text { margin: -5px 0 -5px 0; padding: 0 10px 0 10px; } div.inlinecomments div.comment div.meta, div.commentwindow div.comment div.meta, div#comments div.comment div.meta { text-align: right; padding: 2px 10px 2px 0; font-size: 95%; color: #598ec0; border-top: 1px solid #598ec0; background-color: #9bbde2; } div.commentwindow { position: absolute; width: 500px; border: 1px solid #598ec0; background-color: #9bbde2; display: none; z-index: 130; } div.commentwindow h3 { margin: 0; background-color: #598ec0; color: white; border: none; padding: 5px; font-size: 1.5em; cursor: pointer; } div.commentwindow div.actions { margin: 10px -10px 0 -10px; padding: 4px 10px 4px 10px; color: #598ec0; } div.commentwindow div.actions input { border: 1px solid #598ec0; background-color: white; color: #073d61; cursor: pointer; } div.commentwindow div.form { padding: 0 10px 0 10px; } div.commentwindow div.form input, div.commentwindow div.form textarea { border: 1px solid #598ec0; background-color: white; color: black; } div.commentwindow div.error { margin: 10px 5px 10px 5px; background-color: #fff2b0; display: none; } div.commentwindow div.form textarea { width: 99%; } div.commentwindow div.preview { margin: 10px 0 10px 0; background-color: ##9bbde2; padding: 0 1px 1px 25px; } div.commentwindow div.preview h4 { margin: 0 0 -5px -20px; padding: 4px 0 0 4px; color: white; font-size: 1.3em; } div.commentwindow div.preview div.comment { background-color: #f2fbfd; } div.commentwindow div.preview div.comment h4 { margin: 10px 0 0 0!important; padding: 1px 4px 1px 4px!important; font-size: 1.2em; } /* :::: SUGGEST CHANGES :::: */ div#suggest-changes-box input, div#suggest-changes-box textarea { border: 1px solid #666; background-color: white; color: black; } div#suggest-changes-box textarea { width: 99%; height: 400px; } /* :::: PREVIEW :::: */ div.preview { background-image: url(style/preview.png); padding: 0 20px 20px 20px; margin-bottom: 30px; } /* :::: INDEX PAGE :::: */ table.contentstable { width: 90%; } table.contentstable p.biglink { line-height: 150%; } a.biglink { font-size: 1.3em; } span.linkdescr { font-style: italic; padding-top: 5px; font-size: 90%; } /* :::: INDEX STYLES :::: */ table.indextable td { text-align: left; vertical-align: top; } table.indextable dl, table.indextable dd { margin-top: 0; margin-bottom: 0; } table.indextable tr.pcap { height: 10px; } table.indextable tr.cap { margin-top: 10px; background-color: #dddddd; } img.toggler { margin-right: 3px; margin-top: 3px; cursor: pointer; } form.pfform { margin: 10px 0 20px 0; } /* :::: GLOBAL STYLES :::: */ .docwarning { background-color: #fff2b0; padding: 10px; margin: 0 -20px 0 -20px; border-bottom: 1px solid #db7d46; } p.subhead { font-weight: bold; margin-top: 20px; } a { color: #24326e; text-decoration: none; } a:hover { text-decoration: underline; } div.body h1, div.body h2, div.body h3, div.body h4, div.body h5, div.body h6 { font-family: 'Verdana', 'Helvetica', 'Arial', sans-serif; background-color: #dddddd; font-weight: normal; color: #073d61; border-bottom: 1px solid #666; margin: 20px -20px 10px -20px; padding: 3px 0 3px 10px; } div.body h1 { margin-top: 0; font-size: 200%; } div.body h2 { font-size: 160%; } div.body h3 { font-size: 140%; } div.body h4 { font-size: 120%; } div.body h5 { font-size: 110%; } div.body h6 { font-size: 100%; } a.headerlink { color: #edaa1e; font-size: 0.8em; padding: 0 4px 0 4px; text-decoration: none; visibility: hidden; } h1:hover > a.headerlink, h2:hover > a.headerlink, h3:hover > a.headerlink, h4:hover > a.headerlink, h5:hover > a.headerlink, h6:hover > a.headerlink, dt:hover > a.headerlink { visibility: visible; } a.headerlink:hover { background-color: #edaa1e; color: white; } div.body p, div.body dd, div.body li { text-align: left; line-height: 130%; } div.body p.caption { text-align: inherit; } div.body td { text-align: left; } ul.fakelist { list-style: none; margin: 10px 0 10px 20px; padding: 0; } .field-list ul { padding-left: 1em; } .first { margin-top: 0 !important; } /* "Footnotes" heading */ p.rubric { margin-top: 30px; font-weight: bold; } /* "Topics" */ div.topic { background-color: #ddd; border: 1px solid #666; padding: 0 7px 0 7px; margin: 10px 0 10px 0; } p.topic-title { font-size: 1.1em; font-weight: bold; margin-top: 10px; } /* Admonitions */ div.admonition { margin-top: 10px; margin-bottom: 10px; padding: 7px; } div.admonition dt { font-weight: bold; } div.admonition dl { margin-bottom: 0; } div.admonition p { display: inline; } div.seealso { background-color: #fff2b0; border: 1px solid #edaa1e; } div.warning { background-color: #fff2b0; border: 1px solid ##db7d46; } div.note { background-color: #eee; border: 1px solid #666; } p.admonition-title { margin: 0px 10px 5px 0px; font-weight: bold; display: inline; } p.admonition-title:after { content: ":"; } div.body p.centered { text-align: center; margin-top: 25px; } table.docutils { border: 0; } table.docutils td, table.docutils th { padding: 1px 8px 1px 0; border-top: 0; border-left: 0; border-right: 0; border-bottom: 1px solid #a9a6a2; } table.field-list td, table.field-list th { border: 0 !important; } table.footnote td, table.footnote th { border: 0 !important; } .field-list ul { margin: 0; padding-left: 1em; } .field-list p { margin: 0; } dl { margin-bottom: 15px; clear: both; } dd p { margin-top: 0px; } dd ul, dd table { margin-bottom: 10px; } dd { margin-top: 3px; margin-bottom: 10px; margin-left: 30px; } .refcount { color: #24326e; } dt:target, .highlight { background-color: #edaa1e1; } dl.glossary dt { font-weight: bold; font-size: 1.1em; } th { text-align: left; padding-right: 5px; } pre { padding: 5px; background-color: #e6f3ff; color: #333; border: 1px solid #24326e; border-left: none; border-right: none; overflow: auto; } td.linenos pre { padding: 5px 0px; border: 0; background-color: transparent; color: #aaa; } table.highlighttable { margin-left: 0.5em; } table.highlighttable td { padding: 0 0.5em 0 0.5em; } tt { background-color: #ddd; padding: 0 1px 0 1px; font-size: 1.2em; } tt.descname { background-color: transparent; font-weight: bold; font-size: 1.2em; } tt.descclassname { background-color: transparent; } tt.xref, a tt { background-color: transparent; font-weight: bold; } .footnote:target { background-color: #fff2b0 } h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt { background-color: transparent; } .optional { font-size: 1.3em; } .versionmodified { font-style: italic; } form.comment { margin: 0; padding: 10px 30px 10px 30px; background-color: #ddd; } form.comment h3 { background-color: #598ec0; color: white; margin: -10px -30px 10px -30px; padding: 5px; font-size: 1.4em; } form.comment input, form.comment textarea { border: 1px solid #ddd; padding: 2px; font-family: 'Verdana', 'Helvetica', 'Arial', sans-serif; font-size: 100%; } form.comment input[type="text"] { width: 240px; } form.comment textarea { width: 100%; height: 200px; margin-bottom: 10px; } .system-message { background-color: #edaa1e; padding: 5px; border: 3px solid red; } /* :::: PRINT :::: */ @media print { div.document, div.documentwrapper, div.bodywrapper { margin: 0; width : 100%; } div.sphinxsidebar, div.related, div.footer, div#comments div.new-comment-box, #top-link { display: none; } } traitsui-4.1.0/docs/source/.static/et.ico0000644000175100001440000002362611674463545021272 0ustar ischnellusers00000000000000(f 00hvh F00( r5(H73iKD]ZZzols$jV4{H5Fg@Hg @' 9c]sE{c@Ec{bFQEPkG\ 1}m( @_-!p3%7)&[B<]VU~okWU#XW$iU$zu5{j6Yv1GWw"X f$I qJ QJ[JډJc4jJ5{J 1FJ qGI Q#W6 Q$j#XA${#h1IQ$j1< s4{A a5S Q}A\1J7|xp``?`8(0`W,"4(%p3%v>1IGF~QFja_~wtdFwG܆ h즋" ij""!zi"""!g""""ۆ"""""F얋""""""Gzޥ""""""Hi """"" ih s"""""  c"""""! R""""!|2"""!|{2""!|2"1"!5 y@y`"!""" 2""""G s"""""H b"""" i R""""!yR""""!qh2""""0i2""""GR"!z"""""hr"""r"""" """""FB""""#93"""""GB"""""62"""""hp"""""%""""" ht"""""#|"""""!"""""k """""""""""Y s"""""""""8 b"""""""&R"""""%2"""#|2"#k"Y?????( f-t1!j/#i1$n3$j2&r4&s4&s5&u5&]0'`1'^2'u5'v5'v6'x6';+(X2(_2(r4(u6(w7(x7(z7(y8(z8({8(P0)s7)z8){8)|9):*c5,i9-A1.R4.E3/W7/u=1x?2A97>;:{F:F?>{I>mH?DBAMDB~ODJHHOMLhSOQPPPQQSRRUTTaW\YXx_[c[]]]^^^b_^___dddpghhhmhkjijjjrksmnnnrpopppsssuttwwwyyy~{}}}t@4LhO\b$8PraKx_ *?VNdcpI 0M}Wfm:1n{|wFvu2!5yziAUSyxj?]GRryxj>E-BYyzk7l`, %3Jg~Z+DaT)9hzC&6Ooe" [q. *>;'#QX( <H/s=^( @m,6#>%D&K'O(R)P) Y+ q0!2%"`."8'#g1#4($l2%p3%q3%q4%0'&a0&r4&t5&u5&v5&e2'p4't4't5'u5'u6'v6'w6'x6'/)(r6(v6(x7(Y3)z8)v8*l6+2--m:-v;-w>1543Q93v@3lA7vC8;:9wF:><;N?<VA=?>>@??zK@AAAoJAFFF~SHbNIKKKnQKLLLrTMONNPNNZPQQQSRRVVUdXVXWWaWaX[ZZwa\d_^e^i_```iabbbedceedhhhphqh}mipijjjlkkplrlwmoooqpopppxqwrsssyvuwwwyyy{{}}}~~~ŻjjybO =iٙWa"HuihZ!.SWZ% 9bݫXxaBmnczq2 !*NwܐVr-% 3]wt\#%XzF' Dz:  EIv- N}I`')uHYH޾Hn65S|HJ' 9dH<%"DpHs0!.SDe(! ;g9pQ("GuM8b> .Uo0@m~1% KL  *Nwג7%%?4%% 3XжP& +_l,$ =g^/#AT($ ! 1>  )[4 #Ck,1{R(%+_f|xp``?`8(0`<5"=$H&/"S)m-*" -# X+ s0!b."o1"+%#h0#+%$l2$u3$p3%q3%q4%r4%+&&8)&V.&g2&r4&t4&t5&u5&.('O/'t5'u5'v5'u6'v6'q6(v7(y7(o7)}9),+*V2*g4*x9*:.,x;,/..70.C2.z=/211u=1l=2z@3666X?9:::}E:><<PB>~I>AAALAlKCODEEERFIIIUIUJKKK`OKMMMZPRRR\TS^TUUU_WaWYYYs_Zt`[`^^__^g_a``bbaccceeeofhggiiillksknmmpppxptsruuuxvxxxyyy}{y}z{{{|}}}~}~¿ȏՎV)IzEl~zEzEtgzE{=?bzEM+$0LqzE9!$ 8YzE5$CdzEc/$0LtzEW$$ :ZzEG$!Ce|?>$$0Ovo*R}u7$:Zc5 ?ac&!CeD $*JmN$$0R\%$ 4Rxf,! .eF <]v=)6u7!$EeږM'#(Tc-#0Ot׽a+ !AQ$# 8Yvh=$$6jB$ 1!!%Ty7!!!"A`&$6jQ&"%T@$Ay7!$6j`&!%SQ'$A?????traitsui-4.1.0/docs/source/.templates/0000755000175100001440000000000011674463545020664 5ustar ischnellusers00000000000000traitsui-4.1.0/docs/source/.templates/search.html0000644000175100001440000000174511674463545023026 0ustar ischnellusers00000000000000{% extends "!search.html" %} {% block body %}

    Search

    Enter your search words into the box below and click search. Note that the search function automatically searches for all of the words. Pages containing some but not all of them won't appear in the result list.

    {% if search_performed %}

    Search Results

    {% if not search_results %}

    Your search did not match any results.

    {% endif %} {% endif %}
    {% if search_results %}
      {% for href, caption, context in search_results %}
    • {{ caption }}
      {{ context|e }}
    • {% endfor %}
    {% endif %}
    {% endblock %} traitsui-4.1.0/docs/source/.templates/layout.html0000644000175100001440000000036311674463545023071 0ustar ischnellusers00000000000000{# Filename: .templates/layout.html #} {% extends '!layout.html' %} {% block relbaritems %} {% if current_page_name != 'index' %}
  • {{ title }}
  • {% endif %} {% endblock %} traitsui-4.1.0/docs/traitsuidocreadme.txt0000644000175100001440000000044711674463545021566 0ustar ischnellusers00000000000000Traits documentation files in this directory: Traits UI User Guide.doc Lyn Pierce's tutorial user guide for Traits UI Traits UI User Guide.pdf PDF version of Traits UI UG. traits_ui.ppt Slides from Dave Morrill's class on Traits UI traits_ui_slides.pdf PDF of Traits UI slides traitsui-4.1.0/docs/CHANGES.txt0000644000175100001440000000651711674463545017132 0ustar ischnellusers00000000000000Traits 3.5.1 (not yet released) =============================== Traits 3.5.0 (Oct 15, 2010) =========================== Enhancements ------------ * adding support for drop-down menu in Button traits, but only for qt backend * adding 'show_notebook_menu' option to ListEditor so that the user can right-click and show or hide the context menu (Qt) * added selection range traits to make it possible for users to replace selected text Fixes ----- * fixed null color editor to work with tuples * bug when opening a view with the ToolbarButton Traits 3.4.0 (May 26, 2010) =========================== Enhancements ------------ * adding new example to make testing rgb color editor easier Fixes ----- * fixed NumericColumn to not expect object to have model_selection attribute, and removed more dead theming code * fixed API bugs with the NumericColumn where its function signatures differed from its base class, but the calling code expected them to all be the same * fixed bug which was related to type name errors caused when running Sphinx * when using File(exists=True), be sure to validate the type of the value first before using os.path.isfile() Traits 3.3.0 (Feb 24, 2010) =========================== Enhancements ------------ The major enhancement this release is that the entire Traits package has been changed to use relative imports so that it can be installed as a sub-package inside another larger library or package. This was not previously possible, since the various modules inside Traits would import each other directly through "traits.[module]". Many thanks to Darren Dale for the patch. Fixes ----- There have been numerous minor bugfixes since the last release. The most notable ones are: * Many fixes involve making Traits UI more robust if wxPython is not installed on a system. In the past, we have been able to use Qt if it was also installed, but removing Wx would lead to a variety of little bugs in various places. We've squashed a number of these. We've also added better checks to make sure we're selecting the right toolkit at import and at runtime. * A nasty cyclic reference was discovered and eliminated in DelegatesTo traits. * The Undefined and Uninitialized Traits were made into true singletons. * Much of the inconsistent formatting across the entire Traits source has been eliminated and normalized (tabs/spaces, line endings). Traits 3.2.0 (July 15, 2009) ============================ Enhancements ------------ * Implemented editable_labels attribute in the TabularEditor for enabling editing of the labels (i.e. the first column) * Saving/restoring window positions works with multiple displays of different sizes * New ProgressEditor * Changed default colors for TableEditor * Added support for HTMLEditor for QT backend using QtWebKit * Improved support for opening links in external browser from HTMLEditor * Added support for TabularEditor for QT backend * Added support for marking up the CodeEditor, including adding squiggles and dimming lines * Added SearchEditor * Improved unicode support * Changed behavior of RangeEditor text box to not auto-set * Added support in RangeEditor for specifying the method to evaluate new values. * Add DefaultOverride editor factory courtesy Stéfan van der Walt * Removed sys.exit() call from SaveHandler.exit() Fixes ----- traitsui-4.1.0/docs/Pydoh_T3UMdoc_HOWTO.txt0000644000175100001440000000350111674463545021411 0ustar ischnellusers00000000000000How to Use Pydoh to Generate HTML from Word for the Traits User Manual ====================================================================== 1. In MS Word, choose File > Save As. 2. In the file dialog, select "Web Page, Filtered" as the file type, and save the file. 3. Run Pydoh with the generated HTML file as the input file. Use the following options: --css Traits3_UM_add.css -h 3 4. Do the following additional clean-up steps: a. Replace non-ASCII characters with HTML entities or ASCII characters: ========= ======== Non-ASCII Entity ========= ======== © · “ ” ‘ ’ … ``-`` ========= ======== b. In Traits3_UM.css, comment out **margin-top** for h1, h2, and h3. c. Find the styles that correspond to code examples; then comment out **margin-left** for those styles. d. In all HTML files, replace:: with:: e. In Traits3_UM_1.html, delete the Word-generated table of contents, which includes everything between::

    Table of Contents

    and::

    Index.......................................... 77

    f. In the last HTML file (currently Traits3_UM_75.html), delete the Word-generated index, which means everything between::

    Index

    and::

    @on_trait_change decorator, 29

    (in other words, the end of the index) traitsui-4.1.0/docs/traits_ui_slides.pdf0000644000175100001440000242260211674463545021361 0ustar ischnellusers00000000000000%PDF-1.4 %äüöß 2 0 obj <> stream xuRMk0 W\h*3h[ة[7F^'cI% Q߀F+]V:_$Yܟ,t_mTaI l-CGKDetS"L O5j4h5'p yψu2Wbհ3Cdds.2jǗ xa|uULTz1"t d瓯ɒk5,̀A23i'?1pHJ$YcNaLp@x @M%g"24!83l෿rި endstream endobj 3 0 obj 337 endobj 5 0 obj <> stream JFIFC     C   " P$ p  <7<V<^@ na71GYpy:Lm ax 67g_&Ab]Mk><0d&a;<^2yB]Z)h^>%mwv\lf.z~ezYOz|ϳKҲ} ^3w/`nvrw=O'>Ùs]MMylߙ^ƷK_v\ ܦ9jx/I;Ά;E!̲ΎS`Yvy^M^'8SWF6-,oGs[s&O[l[z}'qȊ ( (Ip:nK+@Gd* )wStݻgSfbMkcOYnsAC_4-\t#ws7lw]0;K8lsvSSڙvSmX޷ywrY=C;^=5Qos{mb-8 -nOuLJalH'ͼS&<H*(R =r 2wpΧ.rh~3?O?%eαb9VEqA@p푣0r G EU.eV"o FʘR';Ҟ_&?Oxͽk^LD-lŪ`keJZ'=d 9E4hA(  j#f~lf[[xʻ+M}ТQ-Lz?yq. n+`GL5(ekL7{7u-zK[+ (@l"l#l״j9EA #iy MvٷiڌYLWatF~qhRz?砜OK$@"#,WHǡ ɫhMʳ˷IVŵj+1HDjB0J "(@@MfO eadi^э{Fj9AThw+/ÞN}\R:j5 <͜'[$nn=#B9b;5 Bܪ=,鎒[/VìZym^Y j'F'u\u8pw2JV=2/.nRr]P7# 2$i^ѭr G4AP@͞`[^vzVrpiK)Kop9̝Lk:?<ͽNb#ׄD F2@#$Pd)f+>R&5"Y"P^P@9 xc2&H6EAPP74??qއ ԕaU5OIh^!K"ا!~r=/5yzsœ>sAP}|d\>?46 @PEDPPPQQSh#"匉00c\Z戊02B-R̕`q]AryQgvgk>yߡyɔ6Gџ[U4s[MGueD8ھ'bP_ ((  ((C$C"26>1s='!?:|\X:>_ RԔfJZFXRVvpI7h7>;:\<Ԃ5l[C>Bj'^ NC$'UlڣYog`{_@{ T4d+a[Rr@YΕK>թVaչٟL3t{ZQ (( ((8PQ*$dq1sA"*uz >_O"shOZaۣ<ƽ*Xev:Ի/1XS:D-o[\{\_stS츓7O7fx ecVZLm/^i2͏-K37kLˉ@P 轟 _])hkEqR̨߹Y;bfPf𢂢 (*(8G4a"9##c1hֹ"z'yо!/G0X56y#rt->6Oyy!D *^Eml]idKyXsxw׻'ֶ=^&sƽ|>TpGxxyvJ+CbF1hֹw\/ü1^7n2Eos;:6(mشP3y7|CJ"f?~>.t;Ŝ\z.vHh "(z/!0 ǽ˧~ii,빿Vǹ{q~B <}L_v)ϴf=̈WOMLyO==~O㥫o>- =myJ#2ƐppĖO{/{Q]zqLN{<,/AsKUbj6>q^~SfFX ',41wk`\<ɓQPswgV&h43 ڜYSe6t:67<:C/;ZvwRBܚbr:tnØ܎ oW/kqryuG/'qȔ/пQȴf(J" 瞇\EWő$Dt(PIi X"8=Zyz=[}O: : |Տ;=OAU d|żLV[5{΍}]åpyzyҍ@Q]N5j0M_Yzf:skʱ[_ М7XoLjfPhɪipdZD+]v&2A=.%V+mLaW5})szkK".d93s{ xJn8:+\/q/ryqrh[f[nhF[Udh6=c QDK'Ṝznq侑oB )&9cyܝ fWFl(^86kBo^tqPX(c1A@Tp*r 9 PAD4 NWw^g Lkw3bz->ۗO9va"(W"r8W{d#$#d+%4sMG9,yr t#cXbF jwawG{=8?yRshd9iN^N;D=[6XS˽ph ˕-B9#@QG****(4p* Kw=[IrE`R=+zeoGv*n(G99xdQG)$IFHI,rKE1,NKb!xUhVh4@A|EVizU.^5.ѼJDG] B=hҖNI^6z.{6'b>9ֳ^PG,b (**QQWEZXK:Bjj6$Ot.a+q{4r8QTQG{=x!$I4Sij94&Ę00 !zz)>RنWXeTUW#r< <GA{=#t"YBN\vBXi]WmavNL6шW5Ǐ7 A)<,OZr-X9 jlɊʇVd:$ÐL YJHFivWL kd^!H(Q½+, $!(##$"|!t YԮXBYiYXVmafY;3+w5C:u?**D*(UUG¹95ddd2a2qӶa$̓(׽+e 'Bi]XUecV;1V+0 ^9!hY+##"(9RGI"y4HO5yKV=Y8!12 "#03@$4P`AB%56CD&VSvKz$+ʾ8JVyŅd>2W"l uվ*XثQ)zuY[͵a܊5;=df&9 VUD",V =''I|^6XvՃ$Ë|ܩ_Gl\"f6W Ѳ_J>[I,}qO`Fb$$Td@n֖"Y-bҶ6[)j6ZVe=>ZChx6R_& N{%?kOay-_u^c(2 ؊VJQי&K^ieLg޹iub>L7'0JB܈e2O%[zI1"%/.CFvVֵ^g*>+953{ zߤds함QεL/FT8O]r6CۖogD" Ѝ4+DAP#DT8oR#M ӈ*:&&&h*N&hЭ8DAPqCDgƨ??ý}R9GF̖ +eJpJ&) o8]mZley:QF);J:يϵV,oHޫu?e|qLQE'܄)awk!w-H,::h+eSks\:cw;WOS-[+U`իSU͑~j=[g+*WY֣3 A R *wZDUZb:l,KGF&B&TK&rcݱWRE1C~[r71LF"_~((p J _$ewgV3VĽ:Ig%߬v5dLk譋1.[oނC&[5[_5lwDmӵuh;wi:%z(L^Lz%}~t2zXHrr h̅#ylllVIhW P+n;$aOX{!1iQG!Bc!k¥ϺۿѣF4hѣF5*ݛzJ\b~ŠIǡBۨ4 &g5(n8 rɮ^_Vyczt-w"1]YŠM !ˮdP"rZ}y|ԍ$zꩪ(\C]S/1yH:Y9 o7F18QK/8xTxNUSߎܮyOxR0L x/Nmw6c|;=+Y*cE5z61]ޖ:exwc XQLlGzI*W,,diBZڧwO=~H2MlKZuA;:l-j^JM0$.jԻl3ѣ]j152u`8G~uNɺ"o'bωшgHM_\%F]w>_;UsШmgAl8ٮ#bMLyfXن.R m,mbA{*eO~VkW6!qf2ueZJ&Ō}dǘ,V3.kF?hqW2-M?FGȎeC4=լIWj&-4bBT$'PQw>[?8N'Gq4q8N'[q4q8N'_Ƒ23)R͙-Ϗ%ixK'oe4hыOJHq=pJ"/_BR##Yy_(nfF"cX1.ܵ;XeNyFJT%lDB£?Q~j= -SFt7 ҾDNEUr!f~N^SU%BT%'_?T%-ܒ}ڔdTf*xc ɺ;%i&:BQE_w(SW&BNʞ3_Z9[׭']diIIIQyRH.+])V5.đB$$>5HY¤𺼿TQE_ 4_Hfρʮ\un9bgf͛FQDb8J^U<_7 Ndi?zA9i Uв Lf9.XIG"J(^' 'iAfJ{< ("TV9;Z7H.Rr<$ Am~S軵tf&:AB#ѭD'l}J#*ۚ">cGgl<[Wy,48!?hcYsbϐZt/iYp8N"5~ޏ?QEQ~6 /gѭEcEFJtlMDSlq!6!oiNnh$dy_ER<_3G8& 2j6x5<\ӹYF-Ԑu7=Zv#F7}mIpopMA(*Mm+}R;YʩƤ#f+IԂ+&pFV:gETNl G!Uv&NsEc&/xvL܏}<,^4<-EQEX;*ߩ2)_qυMV ]$k[kn[tN8:fTYol߿ZFE>GcUd%H-Sʑ1?5EQEXVLl!/qp{ݑwGXS+)LunEH'S8=RkO gERNk%ON#.;\wiVe(?RJRE﹔m,w:=ۗzpӵ]>j,:4h׻њM+[db=܈wwBVrGvFףIc{/t^YN2|n#5(SvB 3)w#xy;]@UU<[Kݡ̚[)7CX^+UTQEQ~Ѷs>{l1Zı^Ԃb+wč5oydDV_'__U_eꤍ_KҝY![7ĔTlD#{ rbE `lDJ]K{RN`iCuhk10Ѣ~r,v/r9g3QEQEyA|fd;v*㣜oF9]?# (I i"?'A:}w4E(42ި'kt1/c`سх*Ǫ MPZ!PW9uU*;)~[`ޝ{,v̈́ʺ;qk/:v~Fvj1:;%q5O^7.}sf̫{J?UÅQESo]gfdXs+ݑ7$qv#[`=:ԁ\#zu):z"c^(fbrxRUs0!PBդ7 +,h>$%[^+rVw5JA(WQ4?U"hC23tl6@]媊[߁%+چ=ޙ=^Z_8QEQEcxE6꜏㰼eF[}5FHh# =ƶApWJZ_gBA% _QwLP54DS޾*͜Cđ vU6U.cTQD7<{+ybN. -PZqy&F(CVB)Ϋ ^^ ((m#3/-'eΟEF- =/He"ý._Jt?!LP.ȋ?ĖNvjh3Usx;'qQ49_`O>:te =GddpOp9M6r6HAAA( y O1X3BxESաȳ- HHeWXBa /Nn,ɒz:(*6r9b}{zHWO3 rofD۔ӱi!(N bO}AAQE~ټS|hmRgqK"bw,sy!!_Eb#%'._ZQiMuy;'*prJQ)U5h:m&f+V$Q'Y}lM'9f   *(/n304$w|^4All|;!QHdCXR /H>9R2çKfMy |G3v(qaeAAAUEQTQM`|U<2pN'[˲AAk6-{qTz)"WBDV"pCR2x/OX(cBzcuc&:;x;fІՅAAAATUE_z:Ҋ/E/ >{_ (D   }X[U0r;n'1u!]Qډ]##G(l؊T_Դ-<(hѣFS#l;ÿy,n%ys9w_   ߫O0AdDb *lXvwf1 kPh<(4hѣFhMr0P\k=iw    W thj$p&*uxCFahڱ4DD6lٳf͛6lU ꄄ` /ѣF4hѣFb9j-tgc=fF{6#$;h#H   }\Rjr25aK岻6lٳfG#9ERʉꄄh"‹z4hѣF4hѣF4hѣF4h'Ru   Vq{6lٳf͛6lٳf͜  'XwC;'P"wؖĶwljh49!qIBT#_ "AЈhѣF4hѣF4hѣBFGsO^ (UAADAD4hѣF&4hѣF4hTAP_>; rK?C`tyUh)GoE2T'f:)Kc118,lQ% F ^:LE6IԘ)1[f[v,;NwwCnCdFX;} cc#h/ADDADAѣF4hѣF4hѣB* K:WC s#rz7,՞l fg+NYHӣXlx~+7q汘faQ6WWG+ZLwhc˒LlPWL]"NwC;NADADAD4hѣF4hѣF4* * (PCw ^os s-㨒ۖw2đٕ[!VL59;d`mkdr"\#t " " "4hѣGF4hѣBB* (RMA>s6    " "!F4hѣF4hTAPTQETAA?AAAADAD 4hѣF4hѣB* * (  7!1@A 2Q"0Pa#3q4`$BCRp?zO?3N%Uj6X]A*S \yҲ]AjbV6Djjx{G}LSŲwOU#>mʯ߷)6JdQ[ǪQ.w+v+*%:[+Cʕ;o*alB5{RXݠRb;Uw&Q_Co(@Tk2mE4`"SF/hT@i"Ne][@)Bk &4eD9RP ;JhK*7{GVWM~ҥ2H.SN313SPh^Q[kkfIf VT/=@U}b*W ( !j7Ay{j= CXg* Q,6Tv ~Qg%}wi++]&+6a7@-4头+ ٻE骋Iw8лK+2hI߮'SqnFM(zZ+K< Veif2ۘ%׼K7epzm_xZ/rôJmQQBߨu?mtx=C$¶%C OQc0"İ3Kx ü Y6|%~8iSc0L]lM#cIO0{b#UcUf9al=1KJ!_*e&aƂZS}%*)GIZY;B)6ߩэ]O ض11\k 3+&Q{˟5?WT]"33t2L=]=: P_DՖ؃2 ny`N+-/05Z[M]Q A~#hA(ʏ^j;;!|]Y>d~Pm/̀w˔ۤ%<)3q5ҏ a[am#`ϺSv1aPBo:$ ǖGBDѧN=_h4;oŇa ASߐۡ#q+U^wo>ҏʿ|s-șy~Gnunxʖ#+0?\J ,b (Pep6@:`gĞ$eiaqo'; Q,26ݦO{5H8 <5CLs漼Oe|?o_&"LjF/tɍ5%N jgq)&./@-qVL64IVz Yib,a# ]`N(]e0-[ :N~>eC}f2#]\U3,8/E83x55)Oi?$ r?yiKo/6!}^((G%&Q5!12@AQ "0P3a#Bq4R`p?~vO.^n,Һ s-.T9#}*m_C[^g#Ի۵hxXԛqĥSh[D= S^fpI*"A}JfWqiY<Ǡ 7YQ55u!L}5)NmMC)ѧ|QjRx@OPܦKPz @j14TA?+U3K%cL^qq*Ӑ\VU'j4pu5o~V 35u ksH-cې` @!j/Gh9ܭ@Py],cM>$nrf3IENcOKo=mۘD'=5U2[)E޳1 a"'Y\@Py.S rN&(O/x\ '~f =eLیZbGp V8 6KZ{5h[W`o6~us"OIuTM `'GIe{ Oʎgb<VٓF9 6E`a  izvJ.Bd;>t2y~Sʹf#1~eQ+wXIq}iapw\'#0#!`a_#v])Zm ^|kvWC[A.ѺM(𱚍s?*2|?m=]J|S<j|kvWsWOͿbbbbc.tdD?,&,+9Tc2@O=7b]wJm!siM W4;6M6V?= ۪myy'9cVf6Ͱ>ffAoSN8@jX"t0O)/#Om6X(l;)_]~ؽL]s6/w+;@51)Hm Ʈb6}"q6M6ud0N͋FGI=BSbԔPA(8si3\ɫ,SGZPhNrR`U " I=RG>zH =dFmMt]r&P!O&HmU_$›MzNVO,IHC1ikNSk 1xCwoM):rL{pTB#(՛)L39̋. sOT/dġֳeCj͊I>0XM c T0L H $m0kahmدtۀNsQGVV:ǡq7;či#IJgtT ʳX"<]6ڜ͙&ŸǶUάj5 ;Nϊ *ZC-U!6q1zQ⭗E>WŇb(,9Igi )BǂǴՕʼ9Ֆ25WzkRW:Qc;aNBwXMS'p)IjHl2U`ȏL\9+lNkZJ׋-'z, ~ *x=6NaUWU=!ޫ|XU%Lz{d.񤂖ݽQ?sgB29Du XLtCD|># s(^ZTt3Ŀꎈdr soqܚրU 4df.TkS6lM&B PF~(ۆNj귂*3zEXpuUHM{HɢjZ,13.hRt&LL&0]*tU :1hφ؂wPFfEZ-b6'6g,+5M*3g!l7ZH|yv eeU CKDS0|4Q4n7!]ͭV8 dcQ\d-,&vn;à9B ^XqU8Q "ydívFM/h3F@X~>yVLԧbc%m$\H2ySZD*S2RSJv+Lg\R]Ta#T7I;f*]vb99Mn$>9 xz؞@2?>}auC}Ȕ \un`0^EњZH%Z i$IhK9F7(sX3'4:  Τp 1{r,ƘNUQֲEv^mLm=*ث,e" 1>B9ϊ1ǂdVG=ҨMM^eRF)<\.Q`Ɖ̗8p"V-6z48Ed &#TǾ R!D!׸HkɊe1%c- F > mr6=n*8 X&=|3`=UT<!q2kp?L&l ։6{Nn2Mn;3X~70ⶫL|9:)ũs 8L6as; uZ^Ok`")Mڏ926>-i]ڍU!P˷ou( '$4mw;*<ȵVFg8n`NV s>"JDH|Tp֓/Jv"9:pyv sQEZ?(HlB׆0%JF4&V϶[{+V kT?n%Bk4Z PX~ɽ: h.͜H%Jtj΃ޢR(MNsTX(.PCa`|ӚvќʂgL*{'FAt73s* ے?"X26 ۔Z+hiXRLvMEpv(t/ֹ@G5'> %X2$>w30ߑ5.rW<ȇ@21xL{>͚eZTa%8&BQˤT*A(p`BCf ֖+UMflӄ:])+J5C4B2Thq"ߤ5JIA26kMVR5h1M^C 72j7 ҍ .ܩxQ( smCp2BvSMSim(!Q*^$^JB{KY %C[5auXWo9ygT랊=Pv5gj0t QT)>wh?@2}Z;)Mn%>,SYVnUhW7`2kVxd-x(B%Aeڬoa Ė&ߕb:&J1cnl8PޛOS6m UZk}{7s[ Jei1? 6Mݛq? u.iOveUצ)`mE·❝$ҰMؕR[҆ћx-l2xZw\nhp]}%g{wS g;(QQ3CX;(Y!%nZLZ3a܋x$c&d߫z$j8fn9FB{w$[5)V @r:+%:,C79s=*g'q9nC< d11ܮɁ\kٿEZ"72l@ l ,̊Z2hVu<hMZ PX+, RlUv)MfFNcB9D/d#̫b;\ 2kѝ [T$w%TTg75w(QZ-Y?N9Wg'RIoE [EQ&b,]cngpxM¥6G6bB`1AJtl\{$\TC  )r 'pB%uخZJB̑xfV"N+[R%+SdG0Ч@9TŇHt;^y6'5>zE %5g%FD-^y>7Aah RwŽi5"XÙR oyF h#>Fk!iQ;iQeV#U-Z4~6-prgZ<27-VEBъB歩-:+' O7ЫVBq}{.\: J7Tg8dh^2@wD2:7!P@v䳨G\; n3RoH;q MQ݃J'6;S'~g`ω6V'i^ȶ񩰍*$xqM\z+\;ZO'԰ۃBOR"v!LI)YNe^-r 7V%̸NBjmZO':bJ,YqZF|%ԍh\Qvef>`t1!o8q6iv_U̇ãVxX{Z&dV8)|ˈŶl_%c*֕-ҢAcJl23 xMBRjfhO2QG ŭcq*#OщTqTHhU̇0=5kk욛kAv0bKP1fU+T*Ly:&O 0dhdž;U #}Z5lhG5E{e+V|zrBge(,Fc$_h7rU +7pPRh.;*hfX!M! vϱ۴]%|kEo&CU\ E~Dڨa0r.+{Id51G6M(G]%_"Ѝ l^ƿtY7QG3 \Yv#e6NYeb SrKk55\0FT0&FDm_>+JJZZxثnR4ta@R-vNbH86"c.U]P4~W8GK>PyR-çA^5=(Qe},*;,/2iMHjg`7(樏i#I J*P`C>V^/vD:u\bT$p>(_,#a"0Gr87=@ ^QgO(PfAMB.)-)?&KU]bZ]& a; |͑* Y8*s(q~'rR"W%o)ׯRڇY9n)[Н?ņn]J[#|^wybZSF+̂e!bJ5iWf9Im;y*#WCn.Tdg(VEM.jȇ^¶ i!v39lSD!8$%=S )yBeL<pZnKF+kBeZPC?)T}7)zTG% UQlRЪܟO<9oЩB8t!U_7 rtZڥNf ZU?ˊtEnXTv^)60, C(B njB`~'o@Q|aaR_)ODqV.:i1N;Ԗգ#xLd1?i{?B` m(9pq=j,QnX"ⴴ l6}q׭0eZ$."k)tF5UPz^U~nd jh vt7J]'wS*b+Z/ʼ̌a~X_/sD;~;pQݿ#x5nZϰ #b gmrvG9DmF~J4k2 -X%Sx VRSuB RCo TM 8/SI4W*|(z Yjm%DVÈm-*Z֞ 1%R݄'}S!#NVA[kslT?$Cs=Ff%>f>^xF `q pw\0}6Bp^h;Zw+s/3" Lc:vނ'djK됏GhMYsW~ Uv(U )#}ɹ9+ǞK%ܵUG,1⭎R;1{(b,~_?ׁweߢ2a׈DY殉?%|\2aaV;&,!k| lF?ԅ"!sKݴt{7O$&2xQ#Dهw74 9PlhΐR1s<10oO;D(Ck27{X]?hsP84hz)6,!B۪m%9;ID"nPgm6#P/AHޙ \3[:q!WL@ߍߗ|clj7qGf_t%~k{y+0kE;Rj*9{2^ϢVTG~^)ә:lQ*<z(RlO r,O1 ;DqN):{!;h9Xd9ګ1HO N$GU m: y8םq3ڋ0)h 69:H5aͲ ]~MU`F2B"sx'fg^V-Uj|\VX9^|C[ΏMOq:t-j cG<'ҋ o3@d6ns0GVwV3p' O2ЯدSnk翇Q]. q.K=CZm|GwqiD~VQ /{4(|ɶQ!k~a^wA0&T H4fMʳW7iOx0q+G%4$VH,A|荶utgp r@o'y &p=;}&%^f(5+\ю;5mG83$&֩PMC@1n7)# =q jr(pοeȓzi*io\òWXUgyt1H25O䪛\ٸg ܤ.RV N>UII?}\Qcda =؏icmr=ë0 #;ǞqHT<INq qC+JxqHgL=] H\%C97{zM=Z7Rw}sm[7G zR.oVj+:V+qJzZ[>BO|%d7쏊G[c{Զڵ~wrr[|֯j`ɯGһ߼?C/?%Xs1~oX^UZ.̽_HED3c{-kmF+\}g<At|O [M~+^6,pc̶J#d?@b[DhXmtqWr*4~t +4NCkLFˊe"FsG`GhԦq&FȜJ8CF#B}3{l\G]L8PRFm:5!(Ol' j %QhBhᆼ[j娏ĆuEܨVi4ꌉƌFQbF8g4Wlz) wPbQh ʼn2k[S]J CF($B/:!i9͕韱ѨuvQrڵ.?肘k,$64HdtG¥UB %Ҟcyq Q;Hj<(qйV.Qy2N}t?EʰbCRa`Xmܝ4w(0uw(L{jh *e #Ԑ+sz"By.#v5 I64xBqt(uRcREW>P dNr )5Kl>J;; +/өWdex¨=syCyUrhTg.F3i++!1AQa q0@P`?!gПC/UH"גW8Tw\fLZYd%gĒq%DΟk1671鬚GBVD#FSm~cB!?V. AOY. mz|Z ԹъRw +bƛIXŢ, PzOG L%;cc$ei"TݎcRT/ndaʆ{F4ZI4Vb'09,pm?CJ8$/BAY{r`1~>dMy"b!1CEyeDÚQ2!(d la̡# (6]A"{i.%"cb8_>)"&,a)ԆfsQX"MI *zRJQo"|g]ܺ+>ټԵib`'2 .sn)k\ȥmSA ռ!O6/DKqSc59^S*̂-ՆfPYd;3ocWQȢ“؋ 24oS&N J%*ۊ̮JW:n=\ΆFO$NO6?k _{|>b.KXr%IQ1BKEdȑ#d-^QTG:N$]^luŸ;*ƢC&E)Whm2JQ;IZ;Eʲ܅mCpGj!ol)h&&lA< ?~b5\B$pb DӑGvM\HؓXGVjToD%'H8B5veRR5٥Bc5;vEe _d57D?JWɂRBWh!lRvÉ؞uQt0еgk5{#xdLy|`A$^U~PS,O pEDB܊(F%ZGwK_ TY7&Ovb8S=0,AdR&ߍ'8ER%jVx*($LQJQT8}QDm"niK:@Z 1l$e4P̮FbBU4>k)OQ_(UYA.IdM- tX0J6~3:6r2YRJ"t!:K;QP$JE@#"5]$ϰvG]tT2m9͌U&>we@NLP}BCNJ6SFlNJlr^mBHDm (АH|d]$*%#J<#R:EV&Qhrb3cJ2( z VV7LkpBRH&U1AaAAaApAAAAAFAcFGR%$%ya6Q FMqJ*LMlBцAIvw)l{iX\S-ѷ@ذ 6*U 'QAQd7QJE5pT<ֲ҅䴛|ēؼ,eVEp܎Fq̕.\`֑5A;>Gv*D^ZtsgN4q‰)HnC9 ՊUd?S3IYT9r67ҳVٱ:#TꖫT!ulȍ*S~GNߑ|[L?{@fJ:ImȍlإdZ3Qk42$cKͽ.Sz䙠%J@Qu,6/nsBIFS7$ӠbtM|;!H+. ·>nq“<_&ytdoGI;!i&hzUvc=H"jRDyQ GI?b!6r/oHeBYެx2eŐkԽaiHôvi_J{.&5Yڿ\ʡ{XΨvZ,|w *!$ 8؟Q_mv F,b2K/!lߡ6jZakO?z-D"< ff*ٙk'J+"ɡeW _J Uo0T:5z0lVYEd_/q+\§fK 1rRtE3dI*<(3m "^JcLikXrf#dyfIzQDDN<j7"oݔY!G* J"sZϝ Q:Gjj6&\TW} ̝̚ŅdL _:ՓEi2E2Ђ@B엕݊ nYs!H @=']4_A3-T1c+$d.~dfrVU}T]F^0׏Q׫~WEcF*:٫GH;i ֖JG&răzVY,dmVfIEBSD:m"q$*I-[I@Tq<$K&ɿl2ldn9!=aqR+ CI+ZMtT$P!: -B"S 0 ` R?#@h#Zl!40:mscѫqHL9K%BZTn?*F֣‚\;Fȃ2 CgHS-$]!su, ;|J[yhPh%KZw\BDՑWn%Z.]eCeD`ק>J"0)CRv|6M 0RgJoLd%n))zYBZC}Z?'@=Fde(RG.۠Bnka\MIg(w S6PJF)7hUo/)fO -$5< D4444@|jT$W)Q>)%e6,59z2KdJSyEtIڅZ% Kw='[\J AU09~cCCCCCA!)--\afOVߝ"N3O)&BP hRrwe%5cQ#9H,f$dr;92IKvHWy SR~AXf8# X1G x> ,%55#dhd[b-GRT1RgHT y Y6R׵5\SL(u>&J{NLNL3^pW*_ЃCcҪwͲd[UcB:y2TT"DMs_N)RqLx ~.p l(: 9)ǗMhhhhcxs%K-I(Jajxe2ꎭsbwͷ&E?In0( eHDU_i˔$gH0r DX#lωCe%Kw|g0A1| x)=.͉ SDo|ܴ͢,P#8(vTJ,)bhC_l. DX:J^_J(CԸ]Z[WQ-ݧG.xO#A cNj KV̗Q`'US#DHrD6m8T]Q1An-ƞ~Priإ. sbI* "aSJdr&<]Cb#ԏB8#1W_!PF4٩mvīWeSHΤzA$&\i-it[F4| `Ky$5TUl-a !U|,kWpG z>1c /eڌV UŮQέh>WB[J)$3'+!1b$nsCU (5g~IJ}%B8kV%%: ,-T>i}ɞ1OUBM95KSd gEFIo#6U _Gq:2}5%~M"Hiz=5o`<0]zUBY.ű QNF>41!6XZgb\Jur:HNȖ=݆`+9jц;E~J$]n ʂ,7jl+,if/ؗ *GQ>XIV"Z]y տffmW$co؃+5Q<#Uew&u|:$+?U, W ?@.8B8c<Ώ94[@?!Җ򰘡K=DF F8J £r|Ɔ6f&x`'*C|?CwAM2+G,΢yy.1\DCq:D])uc99g}fmFE݇֎z."j#I5: X9w ӵEVCī3qqx0"?ccKs4>oM> * ޫOvr&cBn6b届PƦj }8xIA)2 <3qc=![ ܑ%51tFg#I~e6h߁gu|/g,#pAp1{g0 ق*yanI,pcOVi2 ?kqm0M!LBcI0nU]= VEKr2p3rՋ߂B\cǃd;ST_8/Z*.XZjZڪBaJHso .-BRecCQfiX*9 4A/DCY2#AeUBF T=Be:2YCx9HHK1cnj=wO df3)ۃf?'Дt~ˀ5"BPe='#r.ܴ KC񙶆 $P&2H-cwƧvI!Lm̉E`I#y^ !!!!,G1cީuZ/R3rgY;Մx1Z;[p؝KEfp J ?A# :eE &NjٵdOstQS9&r/\*4E;UHQ.ᐂCVW!!!!. 1clStIb۲3*m᷂rf]Sƶy Ii+_S..ڬ}uQfj[mjQ+s"tcQ !KF zKlۙ1Z 6[eA ]^\1> eZ PCm@ qce_G5oՔLDɛli>k^px\PD$$$$$$$$$(&1cwEQn.6n*89Dv ?z^DBĕyf<ia1ᛙP7c< q"Z3Φ˚ʦ j3+mfLrFgJ"^;wz/$՝DwM}z7^8Ԥ"xaǩbyi!LȖD74 黝k~=fgq'cNj+ls&hߢo_qH@scruS,,Ee%_e$SY FM/2 Ah@g|hυR_Y K'u2c[.e)o .TbȿO3[ y܂$"o8 X9HHh`땭{I.z5CtAlUqRGkۺh9V>.bMTI C 뛻 O;a㉺ JyڕI/ $$eבI|_Uyۏ.膰BQEL c Ï$y'DϯVO(Qr*G!pd)RE*pADaxkyzS™-:}hOٚ uLe ҇tMy|kZﱐ+K\yoN|ޮ}ǭCw,*_tuQ#bH\ТFK1-4/5ST^XeZۊBp#)Bd!!!!!!!!!!!QEc3GJ(&Vs!y8Dt >p咇!Mℨ = ):-Qhqpm=lZ/ᑽKF\Nq~$F5Sp;u9r44!fIwl1҇a%wRp,n6[,a/jNZh̐AU/ cUsѼ'mlzrP]nۇG-~%̫wbRł0gb$N iAE1cǕGޥd?3<)'b7$5{ %tJgWS$d[+RJYؚRE'df\d.Ejpc pcj/:+qbOBZSЃ|0sw5 IDd|b?bQ9Ԉ"pku+(bYS.Koi /cTC-))iD%OIE/wvĪ|!I A$;GC^nVlF6d-"4%f?Mׅ 8'Rrʻ)Uû <{S 9/ʥgвUWg*"xN)S)2+j54ڈ9q*&QDξQVis!= yhFrj+)4(݇Nk}b7 c- -}/K+=O%@jOȃxF|5gӚ#"l! A( B5?2j18S;P>,vORERd*n n HMfl]H9{ty@n]lnqYv-s7@KCm\@"KsPT+ &!l8I$%3Ac}e6 v/TS~bSca/բ=Y(v'1B$&֢#X\ʛj, xhv!IFBBgwE:1t4Sv-dYq>/{;9 AR $t\d3u"{Owu mA}H_nWۀ>8 BKw#"W&5HkCMͫBgO͓W3M=FR}0? `Y)s`ӝ6+m4221%.5h$I$IB`AAE\il 1'#DD)UR5 QCST0rXhJ_㝉N lOSc+^^i>V P!B" (T 0NJR19|"d`GVEs F 6lc"xO)c 9%0e 89zj9E96^ ZfCt%A1.| #K"[NK%uhbP\B QEa2GK?dVVǝ.D8aPr(c -2yz0F1AA 0Ä؂TnZq F;on*JU-~D.8 !B QE^x߂N;ri #$BVأ&NX&u8|C߁=  !! :HHk!1&_ 7)gQJ>$ c`!BAQE\[c?SO>F*,{&7z>Pr |QcAA$$ 8;DLz_Y{'77%Vrr6\1İB, 8EEQE ȫA"It 67W G% J1^AA@jMVbY VƖ, -Qb!^$ccjD\WUD_]c4N%0|MU= [Ixk QG!^1 kF#ϫZA+xBj )z-aAAAAAaHQGsI$'p %!  dY1+$+2p [%Z"XKp|*= " %@n3 ̩#^A ! ccd<9.Qہ5I$6"!kB]Rpir-EA$A z   HA-Ak}AAp!B>z֞{Đ;B'/ ؇sɍι, "1e# HAzHn^6 c6~?Зw_#6k_;GAAAb!X7<;{!me+ *i%NI$==eY ѐj$y^"%$$$$$$ ,@AG!`X'#TGI^ Q#OO X.$AA~ 1AG!b.1HT 0\ jɠޠHHHHHHHHAAEznQUɏ)o4fg"no9rxoDFy\B$$ '*(+ Ye| iU̦~[-M_1!WCYJͻ\N+;BʶĢ5WRFqK&UiZF](Ҝ9k=&i +U W>AOr,a7!jY ng4 (P6E ԩነ" dN37B&UJ(d3H;Cg6fL ӿQ&!P H1&$ElJԜa!BBAODQQXk,ЃCCCCC>XW4WQͺ(nS%HZ mD5*)WjҘ[-61hE2Hްբ/36@;Z?tͷFs 寯A2[bwg!rPQWco^"ƪ搪*f \ҝegkrDnL]KL~ ۔nɮLy &>o I B  z@*(5YeYaA*?9Dv Wdo${1̅p$4^0TCV0{D扎{$6j*%RԤPOtT;~ߍH*$.p*gЩpHr!Mw2ao;nIy)FJ5k Inx<|SIB, '+, CC  CǃBaq {{{{{6|Co vmXsofN*@6B1ҁ }F`NHPcZL} ["ok掺8m2`j`([瀞o04[$<[ۆ1[Į/!a {{{ノ#V /ﮒ"I4{e:i{J 0ˬ/黎b½h@e}~\[+sB{{{Lzݛɬチ AA[)uM۬h (f[Q3zE$#J<6Z{, |90H,N B ӯ )miJ qK{ᄏ9ネ${i$#Xf mcJ E[Mm/˥ h,G>c>9 yh8*,e3 *{j-ntNL0Zmk&)"OX07 .)eTb"$c 럭.`vh[䦻᮹E,A =,G ᄎ-TN% "(xL kI@:Z8w@ 1o:ezl{h# b3 `OɧE/7; i`;P]8K.%ۖS(h( e `N9J Jɥʂ/\e  쮨"Khh 4 'A R *"t(LnQlh%Ȧ LȢ C8;kOtYR:^UzF-t*%ɠr ! (/9ol6(5AsbJdH*RJ4߰&{ j*=tR3I2[+>~ w€KpS6?fHJm[;{8 CJ$c`0dc #:"{Ki`[&nd,##訒'{Bbihi!(KP$8e(j'דv? a:mx"(K82L<ь<"Go+i:He8)"ۡ8p4>%{/-檺)#ڠ0N,EqB rǎke*I9:$nhgI{:a0 (qB駦kj(膚邫7 jJ/*pE!,˭#m`rr~^q Za" 厉J&'jeK6+ルk%+zm m*fl.-!1A@Qaq 0P`p?`7O\t [oph׹ ۗo A[J]CFqWQroURv- .(2#&Vcx֧oo ]X$Z "-aG8#@jP :\n>IPI35YXƦ* UOWw"T3<4m^C0>RXBB=w ,5 OHt2^Rʅ7~T{C,B1CX7in@)[p.ï􇺥hJUf-a=HqDt¿Q,v@ߘD2q %,1X= 4.dT ejV f`F\Hb01} ϱqm[, (-CX0~?fyTZrKn TS2u̮1T:y]etq]6Yy v4u\V6 KC+_YA+U]*X6dCC,tS{F :{J,HLD:xklJ6˅jߌo@nS uz^jZ;/3fn6V xEVnd7DgAמLeSyK6U9Rq?! Rp?T%2!nGZD\5w6:uk[t;k#׆Ō[]jhq%S/o՘C5YuX'Y]fKkы^MhZ10Ƈ.bx0Zi1&^hHEJYNefe9u*I? gF|A<Zch:b`! aMr~d'!߼m@h3;ҢfWCwNhVվǫIKtiR7KL,Ge:bAro\Y+xj %Jv#ʺpZb`W%J++'2.$jS_Y/˗BhS_=r`X˻j]KT-tSUf,|l}e՝LC1U:h*˗4d1"NPqDeЁن_xqSZGNvSIc$$d:H |*RRo-Y#ȥ'8!;o1.1jX_CujWIrjnpo._ȡWn<Uy|M1E@tthO}@;th Zx!5G_ZY+nuz>&][bK?U5gzDEOYni޲՝uY %Q$#= Qa.\P4}ߥAoRLp`r3G |-+T`ꆿQBE9Fi/f߫;}>_ƫ/"=HZ^\4r;.AM&cD`U'D ێUR {cCv?1]5Dx.\| QZCBQ k HƱZ;DټcEdCyf t(sPAܣ?eBWOhW>`!Hݖ[ӧwpĩxv9 0&/ KrX1H/.cUNV^ZtMP+D<=NW   Խ(3(9ư J&5( 8vP,!1AQaq @0P`p?WEZǼlWUSzW-[:b6VHVs1MNVj 5/>u@Lto4t*Ÿ+azEŽ{ȄVrOj^x.Ӄwщ FjR+ ˭ U踌*%rЖwb˛49fê6p͹Uo>Z]r] sH/0`:{ xU/^QKӪ^=Zҧg͞py)Q(WԭoЭ\H ^pA!UM;ݎ@M Le:5kF<5+F*Qi}/[j  B䈭(h ^p0#usMlvEULU-ցPPUqyvZrƐCYt=h#^v~B[z5ܔm{"[aوиϗFYE6 ?1zi,PjQSm HѼp:z}Zr /'KKmWkT@u}eڶ:ϼ Ze;U_=7ݛNj=!TwϿ /s 0X4 @I֕eC9dN6vP\Δ(s.)J VE P:5L> B;" :^X-~1Mchk'IՙjμyOuF(ĸKB"r(LӔ-3z_Y(ƍPnծrDnXaͷSFUXQIw&P2ݛ)H( QO]GP71Hwݤ_{!j 0"jy"=h!S"^k6D \w՗sjzQZP c|,tme ,t@`jX_XSP4,ʣ3(@vѼT УѸVS}mE] V>(hoxa"遃Ϧ44| ^w 7b y&0-O :#]`U xM66!dtYyJeq랇+6[i8usxC4%}hX Jޫ3Z_KDeJkyTiJ>5Q;z@GA`m^Z k}mS;/iDrίApE Y=1Z)tʕ˗/0-9QL/1.[)|Y |>2`mcС/~V?{`u*U w:.ud|W|4th/c-6hx4jꊍZ0e";-EĹs)[c_^*SKѸH@Xif~H Dy5TCc֦3)׏|Yr4_N'/>M|ڨL-Ǫ&b3GfA#JWW =hC-xȵ.\g;3PoBՁ:IhɼHt%Ɵ%w|Ds+p798\)9&+a=};?ط+ T P5D4P R>}g}FjEAGۙ85S3ԦQ{ĦUvu1CTS}g(]!&__C7+4b޻C1 j:K6X#3¥N/ଠ˴˵.>~a ds3%sRSЈΡK3S) RrAQ .|݂&j!b=R:~ cojPW01 xVy?!]%0HC{XtD-柄L}]/%g=ʌPV?'DAhXG#* D(7@ fx [gBZqF- 4 yc%6u*T^ 1cZJ #irrbZEJ*T$GUޣ`s{yHH/2JqCUԣ>] *|4jߨ% w$]'c:Ⱦ% 0AD ߰Ԥm4$Z߱ 2r/H+xԩR}OR#"#a J".7fo & TKY`gZ,rr,!1AQaq 0@P`p?`Y,}?}C < zCX%+Rdh}8K>݀T -]8zEr26@TCHX,$s7<V,I+Peh:Nyq*a:h͠wa̪kF[ c\GsCᛴU$":c(aAJ6A8+rc)tkߴ=?Gye,\/@AUP]apl箥pi܂aqibijN0 *>d_} UzHeo Xl7 l_}+G1fd`)x!,JsJ-$Y|ʼn!?q-XSѽ0u(ݿt8'2:M{bai> YYdr˴}WAO?Z&nxgqJI)ʍ:^{c/ c%kag"^ IclNHZ`aE@ Ce":E@k; =H$i6Q}jYEVٝR,"4Ơ Zbhz &A\0C+= .9:{7lx g-X(Ȅ;r~%>ϱ*&nHLSp[ξqL!f%5rW^T/ɧYC$%ͥeVdt<+IJR=q%wa`QUYn& enya 6Pub`"!N2>nIr~{&5\GR2 \?a Û/BZU1YbAMȻ YY]Γz/#v^<@Is gH/is^A@_Vi5f)Z*YjbKfܣg Rw$A+򇼫A;Sp?lu㴩+AxhZ}Uئu_y*Cٖ]U֟EկQ{к gQVϾVs(4i}S]pаW,٫vnU.R] o~!'a}ɉßOOLg"v+ rEGEg?-p%0uXp"huUx9t.|W:: \sY􇀕F1c8-YϮfhHU.KCs* 򒐘&KLډn[0C8lk-ľD™Zjz{khV;{)drFBc}3 N|w+RS֫2Et %/=}riG:J5_y]Nx9z JA#*XFmT]U]bÓCg+s rjrYp`y".d\IXק11Ȍ_L lf/܎W%@M7BWQo]$ YO=ab*DFs!~Qxp+A(* k/{PR@ 2!Ha'ZߓO+N(xR-H97L.(߀OZ݃g5N6ReGQEt0]2ZCuo?i:s,_1V]_Ae08 '|kPԑ[L]0Q;Qκec[ JP^E9+Rt҅ gFf2*ٮck sdmOe^:>]>6hjDX"_(=_oX`ʘmLHjQm_ (d||B>hG59_?3Snowp 'fG\`=/9EC9^bu{SY/;Q0;pJ4Luצ8AJVC]YIb7*# l\A)C7#0RKrG]cD+%p9RS&FE-9 Et214E"eH/iCGDPD*~Q/*Q+IN Mxie` DG @JL%i)%J8GG.88QA2OG|:cszx&=L<.].9K@B@sruĪ㟂fFQ{̀/!ٴ%RHŹtiǓM9Q7uf!}Q@MYxwx/0T->N['/2[ݔ4V|D`Z_l,7םYn>C/^ba+ Ů Sjl>*<Š|ךQT;3_}D>]z?ĵy폫g6}j=@UavUk, W$sAXj\1oU۫*aMG0 3KE94fQO:GҥlEEa5ϱ\_"Cec#Z,Uiig>(Tn>=DU7f|V?Ԅ*8W}\\Qmw&\͏IJoRJq w~L:14Bѳ6i9(СXpYS`ٕU9b=/Ԭeq< LPoËb> ^V_aKE$Gcş[FuuAn3In,UYvEWI^%{{}B7 (Cguj4}HVݶe@hx'@-"G fC(_敋n BU?#8ge9y*6їm1J9@JtMJryJh)5c'r5@2o4n]ҡe|QG^H.N/DӖ{,%S_{jcC rQWry=2OLJDJwBHtM@ &*Nwwܜ]idNj7fU8\rz%>s@%M(I R\m <H2~J]ුRah{̽s*s('*{o6}cdY,|Ϣd=c%Ĩ%&Ohܜx^_(안GTvܴFT>޽R/w`@}T y'y/w /6{SO毬1ae)PCz̏s.IRͰZ#hi!J݁[Ы|Z߬f C\s4Wu5 e\XS^#I,VWX\iWj."F2_q@zBe ]>şbϱgGaxH_PUU7dl5D\tN~(͗,>2M hL&󯘽&Rdjq }0) KXuu)봁ktrK1t{EjKcQ~::*vC_l?HDW`6/!eG/5{Y*mAݎe^ ( PtLm:q*XVWDl- mfd7Eb$nyhud]Xn5Vi9ݹ. t[Q5T<h,PT ң{c9㔦زō=*Xw^GwuAN6ۻ]+_`eIAT)NkbQ`~eC~ʛ3RcM2)vZ *letGV_Co@/|L9Fcv% >tT0&鴨;5 VeTtcBE`;L\5U W9;%HӔ( uQ"Gq#N5teltb51:H;r<כ *7 D`]G㋍3z%E"Kv.ʩl^+!cҟZІi̾tYe6M\}؈EO>+C0<H"Y!ۏr{xx.p CAp4pmUI:g*ZF rb(l#r(:h r&R뚬_mtwaPCHayx wPY1K~%zÌ.E݄Q wftӉO)̹t+r(LNMci[+BSDY~CWt.^l%AcmC|4 @p8iӁYw?hі_Yr02a U:u^jrX2}3)}:GVc{hǻPPkjYTr,J:"|;l+V !l|ONG:Icw`Y|=RWAcϵBmz'X~ øk&M,݅OF:JoM A_vY]P!EJm]q v'h*% @p?[Ŵ|~ fr~'%K7M)=45h FmBxRX?Xk8zŜjLg_:jD˱ 㺟QxXXSoۧWoQjH3ӂJ0K.'ɳ4lFxir/@P.@p8S.7m4m}Zhщs$ d>p}p{DV-(d=JR\̿S@0"AV,sUa7rOYeղfy*0yp!p1XǕFbD"N+qrT"%~㶇^~Ib+)2ۛȲxtſW*D&ITb 24ܺ %s/_Y\ c1Y_54$kwp>Dyo2 x#+jV11]P4_XMX2'E:LYt@Q@r%+ N哟o0u!-z* eJ@3X_VXu *%*/$(\2 Je*[e`C@m D{ݯHA0fgk\ jK|Q T. !TQEqcnM 1.õUQ-^SKM`?RBt2zU} isGuɣ<@ F/@uaE RhLx{q~kjJ *58(s.-t? * +炊LÀ#oF:xYI u؟ 9er]+n4]Um &EL "2;bTyf1A>/qSr\"s70]u =beXјXY rz>+"z'W\(0Xs0m @0?4OFW.p \!C(8u.Y/I1*7g AF=&T'U\VSSzŗ@Wx;;323J5 B1E;ߪQʕ\:f 9c\-˥#M:i"66%XU]_&U_peLj*t*<ؼ._X_g@jT@\>"8:ŎBNV^ uYA/5G\@嶤;ߘԊ<ާ+"՝V]>`E`w+3Q&IV[d7"ȑV:HNow\M8qa0 ѯqAJλn`   6zQohȷnyc3XZiU5e}>xUh#ϒ,U㤵) ]/̡kp'DKf HFi)Ha2 !262ԳPsJU,(E/jἦ $sy`^p8E9wO74p+@ owm4p:c?K>JeQ|?^m,Ⱦj.B wJ-+UM]K QbXa+zp#hxpQt |2 #i)vGEz .k9!!iCs!͠mmg  bLBY.ZK:ٖ*$^)uA.qW,h*Y ڗ9V ĠG*8r2Orp @P*#  IjuIf4EPUvSߣ2N`?iKǝtsT/hv{'B+8 MUw 2#=njpK{@2z%B: {DzSbG!x}:g5H~b{i#화nzRQyzuF-:+кݢ# 1E#dhhkg$(:$z% wC!̱E~6E ^hpȂ|3%.̮RwbR|3  @p}`T34A p:SdE V2Mw c]$v\ӯ9 ?]MZSh'Eq98#^ ̹[/4yԭ\kn?TS(Q X88(n#`c*,h|)osOM|BlK;!,}gg>WzwH9mi=JֿD^"'$Sg %늦w:;CO@#&{oz1Ԋ;`(@CP \j   d h0?)~a[1Ŕ3 ,ose\k&][/ Sk'cPMfjP+" Dv)Z۫/ei7OVCf&[O3nKY-QtYYv8qJNI0[tdjDK\#̪mT5g_io a&bgcB̰+rFj=;X;.u}!TCw6pQ(J%b|Y|h@#M{KtLyA(S4J @* @}{!NPRbexGLsv+}4k߯o08@[ѯrE*nՈlC#p_J1*RV$AQ0a9C~ PQ^Ӕ(MBnT|D2O1^Cl,u)r~Rakx=B݀<,U4X>lfCz,Gr6XhFa"͟Zr⒀hF{8H=`!,s={Ӥ s0޻/=0)Ë%gCB 16k/ 3@ 'Eˣ^h]|1#A c4M8NY~| =w7( q#)&g0EcN?+J  {U/ EbP `nE(nY{x D!-xg![)EOهH,k0Ta:xj Ą 6>bW¸ęq>EP"Wޡ!zP۶.KWOtnx%. ު #SsIbPjye_ (fa鯠-i7lߎSF;mtD{|h5eՐ3$.|Gױ_ (P0LyF !/հCۈsrc^BLj o<"s(>0R/DeqL>k)7p:lGjRV6E|֌(B(|柌FvC9*5̵/E-}KQ-߉s J)߯Y,M, r" %7GXQ)뺆=ോ%YH uLw.ki,=R>>%q|v*3tzVEn>eW8;0 >&2 \w())ަ5_7\/i+[̚= #Slcfʀн &M.!s+g~]  l0 U T1aynLdn|~>mC IӜ 啿(drVgIzU=;0`@q%PC->`EGc Q_Qh_fWmk#Qh(uX=5.NbbeLߒ+_CR siH߷F 9(ұY[uk(BtsP(yhƘN|ǷdlQ/nwm9$-5nǽk OM_X-VOϐ_IJaR?jX$0v=Ɇn)>"rN>I}AZ_V0m};?pR±*T%n*Hhr">RʹZ6Y07Ɉۃ^r}~l*oܺ<#n (O mt'.[(߮zBnlj6@: d-?QϹkAwuMzOGH鐂 -/ *y@xi+ &;GeTpBҔKl w NQA+f>O[ܶr1͆:V+<=S(1N[\?ߵVOѲhŲ[1?̵3_07sQeбֈ#me~HסE+_8J`"p)oiSvGߴJliԩGœWs!'nsfA+blP>XmM'o\L Kwj*8C# فkG=+y5f@ĈXyBѭ.^% &ਓ-#IQ_b d+02VO`}z%~@Y̧> P+V\jAAy?Cco@/XkS[߸n u~⑅=JBǦP ݇]2,Tṵe7|bs:ɏMQ2- ۏ!};Ƒ^W|Ym{`}]1To:.xTMyY_@ҥU6$OTr҆|MR,'#`v;NsNRnTW-MMe ;?rɉ-DJuϣv8M=״K9+ϙ#UcJ\`$*A:3<'Q 0^( ÂbYW*l5\{JyQ@TRYbe8Vϩn p`P OGO]}໲|+6f\f]YCK._j 0[W-ɱۮ#Sp_au5=GiTk&[@RE^J|O" K̻6-21JIuJ){},ur^OIɛ,4$z(kS1 9HfDk.BwOIb嫢;52#x qa??vUyc1̸K=slH3@W}=ЪvkXCjtb&90$oy[6 4{3=nY[W#4ast:2@01Srk*N_pwKXfh~dT{~?t"9Y>4I]}$#|NQCOK\u+-U|b>%+K9LjZqj:;LL703+:8,Źdb"(Rѵ~ٸI -%1NvT+C}tf&T ~)aI^UgThgjy1@ KD^j6JzgȆ#QTT9~ 1w3Ϸ(OPc?$Xg #Ps XTu{ŃC 4/Ai]Gu9qbys̡Rcz]YLViW (qQG,ټZ;͓ e/|4pA=:9zmSXPx}Zj[v$ܼ z:C1t<.9B?<'okdn-ʮwd!PX Q<唢ȓQ۵{x" ޚ~QH7U h yL >*zFz[[sP0Tf+7#%K,* “  yvb([@ucfN냩|SPz0n9n,n'v jpۧ%?P/!/Jf*Z\m#p~ *̽Tū" ~9KjXq:B\.%-y,$09^%{;Ke&= @ a ª/w&a6{TqL21LfG c)L_v .[D-{Ȋ6.]T=O u0MZ%fXZg6V#c65|bT ak"]!Y[~5٤ "}PE!@qy(eI E>idA`1Bb.^fW@L߄tmph@ p.g/xB8(ŵ͹[{ K%,I9B*(`Ws!g6K1/s)4q}2}>&Yݬf0f?&n)b= ;ebrk Lzښ? jvtX#SU~4{D2` QQFA1O435]7YH $ ׈_* C : 1\-VĞQj1vuc /]X)+~gxj4]f{\}LSxJ=ݎӀ͒KG* (E*^>)6}T-WJ`W8SF$/ z,pinbgN"I]tzLQF"31j3VcTH<.mSțufr8 \p@A 0A 5./"X/>`/&_xE= ϒ.0滹2)z%yf_Sj幗s,缟d,,<0a(Vs}p#ǀN s!d&Wgtj2$GӒY .fZ hȴ( U");JQ@A0A4C 0} ܍9JxɎ(K:eT!B5:d2[\oX3L0\L.o7fm̱w˟ 8Vh&*W ʬ+@*2  h!5SP`Mcs6"j}#yL Q Sϕ9cO2O\HA0A 05Jp#n(jmp@k%\.]|K?S>+2Rw^ښ#.lfHg)|6My3 '\ wƟ _@B y؄`狏.'$sQb~/(@ 0 0A 0CuMSW QEZnbQǼ"Ȧ +JY;;3e˪YSG q)&zoK^mwq`a7M 2T@ I$>1l-~9ef dEŨn ]T;Np* & b!Pa dy}pa Es|7pxT  !qA(IǴW@Q^5qL. b}x(l[/fZe.mA0͸pjpfVan,ukh_` J\">WJ,Q4ѯMWsMv%DK黅3>ac 1g--^7x|p@ >T(W$I8]WC)aWsc!8 =)olϘVz5i~fuFYaꞮC <Xf:Mg/,<Ÿkj[)u,'+(b m:q]c Q8z)NwzfWߙo/xKP9?,;<;`W@}vöIC,~QaYa @ >98&Br\ŸkoSH1aYeo~_Hxy?3;yY \*;aYeY+ 0 Cp8mqEX8-M-QbзLLr0eYeXeM-nJR&|.# A;!xag6ExVa.S˜iqQSGVd[oRaSta^dž,#xY8X8B{w9 @8UNpNI{c={<HV84EqE|'-&eHg?r)̔WCHA}^x Xc`f:!*+K<=͠T5APAdG?g;;<f0v>^}Da*$p]+KfZyqi Mq2AM>ڠId?GB9X',tK?37Dm"y &,B ?"(FgU0~_1edEJUv{0vgb1s(00 &fCfx `@FYp]osYd9"Fs!(/ICSi\..騢ki0e~&8i'';xF:ʂaORw (`u /7n)5A 0UaPN}*3ߥ@ ^i8]a0KJwY8;OS,Z 0ckҵ>3dJ[V!t.)b-Ua,4Dlo!rX/m3zt[xr&oaa4N4  SM5'c\/qUtJGQJo-ȁW#:US7@ $MR~[Yr-F̵jlFb9Ry0h8iH'rntׄMwͦiCϤ\ L `L%SFcVc:+/pA(_M/cvc{'gOӇQ(Ob 2TJXUdRS-Pb5jKWwXN)`u#"pia!̼JlG>ҩ邌k9Ǎ)١bA=:&{& `{-0CfvGd ƅݲRBNƩ #-P(.xҶPWND|6 ,]US sʄ SbS ޘiˋԭ;- #U -/\tzp]>r Wj<[a3@sCVybKpAhxp{;\`8olbjv@*T=7UfVrVqxsuU1Aܧ+^/qj.GL <``UsSᮍսE출2AdU; .͡<`P K,$8CR)UTVRk(@p( T"4T[/WJE>E0T[%וC5R2ڀy n= 3BpPҦё[$`0 #0 ,Q꯯61 !a_jx濨 gs T<kwt. C'66c s#Wk5QVX  snAC @ endstream endobj 4 0 obj <> stream JFIFC     C   Sj" UTYll,llʖellʜ[-e-e[-eelryYl6[-el[*[-ʋ-U-[-)( a-R/x::GxΎSxޓ:*/z'w:/|Ά/}΄۠ߎ/:K"yz yK9+I/gWdyKxvhyGs/s^qKלG^qK!ǤoyzAǤoyzAǤoyzAǤo v':4ͭgO6I<=$hͣO6I<=$hl::,$TRȒBY,,jJ2lY,N\edY,^3,Y,q%,K%9qK%ɮ2dgRY,Y,K%Œd$Y,TY,K,̀d_ߔ'Riޘ1qa]?|ߵ? qy_76_c~W:˱|.{tJ*YXK%%%d~? 23_0>f& &grDD !,@//K!,K,a,,ԄHMqH5KDԂK!RKB H*_>k)`23@5Xҹ+ҹ+ҹ+ҹ+ҹ+ҹ+ҹ+ҹ+ҹ+ҹ+ҹ+ҹ+ҹ+ҹ+ҹ+ҹ+ҹ+ҹ+ҹ+ҹ+ҹ+ҹ+ҹ+ҹ+ҹ+ҹ+ҹ+ҹ+ڹͫڹͫڱͫڱͫڱ+++++ΪΪΪΪ***ϪϪϪS4 fL)3@hT S4*fLЩ%#DhR4JFHѩ5#FhԍQ4j&DѨEHiM"Q4&DҨUJiT *P4@ҨUJiT?8888Ì8Ì88999#9C9C9c9999Ü99::#:C:c::::ì:;;;#;C;C;c;;;;ü;ü;;<<<#<#<#<#<#<#<#<#<#<#<#<#<#<#<#<#WjRH0 x`<0 x`<0 yrͬnn1)}+bC(J_#QXW8|1nag@QfH/l;eCe{' mwI(]7q8xITo/1_[rW8 3/s v|hJa[nB]h? Gg< ˃sВhk$o4ˈqJrڌhE]`vVgAkѴ{ a,ßի.!@nY F왩[ )#`~ |(%QJN*3T#0ͤC21C3O;-;-MqzOr[%q,n/Pի.!@v)d+8{oQ#sPnHԑ0Ga.'DQ#I|?~1b|Zqi4(Eă46}D۶Q F7f% \BփLvBSv1KXiAljӀqPQ&P#/?2 tVȾ+H4{B\lM]'y۬M3ڶZka3QQ$a/vg(7i+kFJkIy2o}C/a`-5=Lt !>~=`~(9YЉTFAmCUuTBLcI?>W0hB˙(B7b/ޣF4ŊN\rOU $e)* &&j3RͺV/dCd[B {+,?QD2RHi Dcfߐ8=D5[eaCGPPE׸]P]$ڷs?`mB4llmy?J | MT(J" %6LHׂC\BD vز}xaJEa읜!r!r!r!r!r,!1AQa 0@qP`ѱ?!qю`! C!psGpAXbŋ,Xbŋ,Xbŋ,Xbŋ,Xbŋ,Xbŋ,X0 …RJ.L"ŪTB5˗ 5fϛ~ըPBzɕEt\4aXTVEQ_WEgQXWEqQ\TVElQ[VEtQ]WeEbQXW%EzQ^WEjQ_VEfQYl 129wFDeuWTdFuWuUwwwwwwwwwwwwwtdX1#۶(&b +^{^{^{^{^{D=AOYn7!j?p)]NG<x (Пc4 !$#|&0B#K,6#qױhK2CJʊ@qؔ O{|>zSiAa 4 !WAL'pb * H_Ad+H#tUS ˕^݌Cc$ L D232E] ,AH>L>ܯ\'I1" 2hme;qɾv#ǎ <&gf~UGec E#78ܰ;"D"\#4CE\}yǡ<\`~QβT#"&uT{G9BHy'*FB0CňI`X*V U`X*V U`X+e uHC W{ UkQ~$A @0%O[F<::y!m c |a0|:0c힨<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"dNKnxoCd}G@5"0 0 0 2 0 0 *JOw: >CZr%4$җ o#SWOCҖz; opC a8@8A7 /ރ'|+a !1Q@Aq0P?V:uut}]]]]XV1Ռuc뾂 / / / / / / / ^Ay AqPC.ce2e2s ?fs ?v ?~ _/C.Nk?~ x8 p6 k~`hXL R԰`lKhKnK5ZX6jX4ZX7zX7JX4JX6jX6jX6jX6jX6jX6jX6jX6jX6qeip?,,,, *UBBB"ߎWq"r˷n>뺳Bm\ypv\zEiv6T <~~QJIzTTBP..T*!QQQ|2/ |揖a#1?'3ɜMҨ*t!U UTTTBNG)aQ !1@Aq0?J*PBWB]*+A PQP] *EDQEDQEDQEDQEDQEDQE5kW %+)..%K).R\\ \W(Q] r5иBE=иE=и7E Ct. Ct. Ct. Ct. Ct. KtQE=Bmy?o#{7#C6<#S~F?qM MGɵy6Ky5{yoo#M-MMMMmMmMmMmMmMmMmY5M$976w_ɩɩɩɩ>8888?YR;9|P.s.KF{}Sc6Y}/yF5'矩v۹%#o5*Kï,|888&g~SbWj8sLHH$^ $u8882dɓ&L1(!1AQa q@P?G82D/LX0;2D`F#w`;0c僯c ;5X#D`> """"pzC?L;w#DD{`DD`hD`#"0#A;8Ќ0x&"#hc$FDGx"""#"0""8"!`wX<|Ou""0uDFh#`1uFQDF F @ @ @ @ @ @ |B >|^0pܻ1&"Xe:"EX b| @00H+p;C|B °RXJQBa|[ FXroEȹ̧_4&,-%Hh뀎 @HuL.t3:_ﻬg q.:WX l H:ѹD\g-G\X:;1nuꫯ+=Es4t߲Z׃OS) ~?OS) ~?OL9p,ˇpϾz3=L3?-LL3S3<=ϙ]&fa~8p _<-%=+AW.8<6rEE'Ck oG t5ˇÇÖg8;?+чm^swt='C QxB=BSG: o{U%-v-@<wz0h_->cXO}4.^9`!^c֒uBtv)^6:MA$CGߦ]G@hnb4: }W)wv~5΍:rO3*cx9@{[NHv4^2L&I'?/ƭpSg߬^y}NwƟ9ЦFڡA8[}R{@![^O(. oH"ʈO; y4ŷ:C MO"k\{loP/q9{+]t;ZڬjmqRG ][Q$- dy9YD[4ܰgNjwvwFNB65Ðu#qzGƎ2QODrɧ|/RgiBkiͦг[( j3 &o|>o&<3833333> stream xSKk0W3ɲ.C! ɥ3#{wٶ {Ѽ}3WQAO{z]ow q{I> hqOt5 ]>ՋߊP~\cZ=i7ѭ'5!_I݀+Lɮ4ED p]ff-:1%!s1~/؁7fR_: N-pXJ3ٰ f+l̇  0Iq&dؼτ.s.U b]ƤyR3DkۤwPZOD6<69FE8@^i_NhN!UOw:#?(S endstream endobj 8 0 obj 396 endobj 10 0 obj <> stream xTn0 +t.W$% -uElX/d^ݠY#$̟귱fgyPFd|n>ߘyTX]*0~'> stream xUK0W輐4,!7ڦlZ˖lDVFyvꏱfcqh}f>=_3~|mQ\?T7;zދQеE/99~alNuz#'ͬ;=wCguvol:~N5!*(Cn?OB> stream xTM0Wf$Y =,=MKٴt/ɲclcY'jiGgy|>=_(~^Wdwx|K.݋Q(tNF|9WV#.ᇩ6jG[5: qY([vG;#v>:Nmw4wdicQ9zӼ] rlPCQ}<}V5Ti\Aov.sS4O U6tbqjC%Y-r@rhI4Ua`ȸ MækmKTT%ŭvi{().c\ ݖe$鑔T;wɌ(-f@o~.ĬH䰖Kݤ- o}Rй Big% }'#Xyq|]CtkeGQ,o|S-e:[!,7H$M;zfp˜,Kf!M.A@^)j endstream endobj 17 0 obj 612 endobj 19 0 obj <> stream xTK0Wf$Cl =ڦ˲i^;IZLd1|ꗱmy}f>=~޾Wwx}ћ,vּW\5/śOsTp<ht- K4UGOImr>|0`ozj|oPSj J6VVw}Caq+P;^!wshk4#Cf7Y9Lrcdo >'c`D (#"Nө[ A/ pZ N܄z 6JM\*#w("f 3+Kq Iš"lG -9,t(Y؄{*" Q]o vvځd/ZkD!hRpwCSL4@JPMDnUl=> stream xVKk1 ϯ9K- vS۴lKs߯$[Iz2%}z{p3(m$iOgWN]Hc5gѻw?3.EIݑowev wn'ᮻ:t7|'uJL~`?&fޡp ~ɏcYI0fm N,0 +919)/e.L'TtlK<'+r0'ENzA*RSQJT!sO pt_#GNQ@"& $8a%ݺ=v!EH *RxQsMk2@xȫO2q=J `AO *RxQ ^f[?Wj#%R}@]HFP5Kk6:-E9/*y1RSYK<ГkOTKzMj{* D 9$K ygUW.-5-.ZJ;/(U/8aݑa"EQZKq@EXpQ,(ejᯈ޸rYMt$ӦZ'JJ&5hx**5xUTA/-Qͭ`/= ej)WÕ%NTԂt%7E8hSTr'othKX{_X(O Q=migfF ߂7,t*bla| B!RrzII^ A h:e} M0):hJUn^<c\ 4/?/ĭuCGC߸C endstream endobj 23 0 obj 852 endobj 25 0 obj <> stream xTMk@s|,-U JOiҿ,Eehvvy#CO!n@̊t-0#$t}.Wfӝvx)ţ_w},Rb؟ }8P}TUE=ƓX/ BlC M@HIB2گH,@¦\O!+`E)y0+0&/<k{έTv 58[RbЕ`:s/E^ W(?1+ {;َ*aCidV[ǭ9{'[\K;562r|h.; x'_tM]U9) unI*hAi435o^oHBv\.X*ӿHS#JybPhi#y_ B8* endstream endobj 26 0 obj 477 endobj 28 0 obj <> stream xVK0WF#ج7JOmR6-K~%dG684/}͌y _qvnijo٧?o?*p'w}u*dQ.4n|V Oce[d7xrkK:@'+c6 |[tϟA\[. $T^ aA# e"P҅ [C!b3dtmEb,:2W9&{PI| ˰"Hi{̷D/6ŤFib>C@ѺVe2u~O)'s|8g~vm-u/V&&i<-0]udQڜ0hFEiI!7r(E9jBe2Ȳ%2`NARާ{LB2ڱ n -j}n>nєhA "LHEƚB&[+xKCb$:Gqç)?m" VdGnb m$m8jD?Kuj07v wQ Zl_^BGrBMSb6_sJMI!FD%2PbāK'v/Ȭ^{X+irjAN9X|'#Z$~(^ YkXt򢸚rH5r* jtH3h6 2t[ӽ*^_Vn4+;;$r e/+ q,?3 endstream endobj 29 0 obj 771 endobj 31 0 obj <> stream xTMo0 W\H0M tvv Ea, E=>R6-7[~Qy+ryl$]5Hǽ~[|<T`XM_aÓԶg !<} f :`G6cg\n3bVՃX7c\6[_Oѱ|(ćP*S6 T!kvq@ɪՍ72LWVL6eX7ydă$i,Poڱ3lE _ "(pc^M3•ё#xIsLք|%rV\% @4MJ'C&M)m5N: 6B$4;,h 4^֔[)ITm BQB} 6\R\(njX8\#uf!(æHCHS~6$DNx#-c%f|KIB(Fqbi& ~.b endstream endobj 32 0 obj 512 endobj 34 0 obj <> stream xTM0W4#ú =,=MKٴt/VqB1Q4y[1,m5x^_OW +[;WЏ\݋Q(_ㇳ7HsaJF3}5#Nuz?UGbn=9߻΅~G+j#St=t,w>^Kaks6FXDlڅ8: Tmps ?wv#&…a4mW>r(u88):P밂 11dU)%dZz3\uJd(j +*dڅ@FrN7zvO߮oV cB8Z@q>BQ+0y(o9h̓ąvrjsiIdf-LHʨfX\ SeًT4^#RTV:j6#rIl79F/$t#;E|̓yZnd:%F8_|N.j@df2X-\ΒW ѰT*"SeCjԨP?B endstream endobj 35 0 obj 629 endobj 37 0 obj <> stream xTn0+x`$-Dq7zzjAܢҢNaKpcX6c<0_n̯ ^Vnk)TB_J_RW^Su5Ivn?6Z>ߏUCekgv7㱵ЍX(t4.#͎ Z:homͱEP4:~~wTT!waYـ4[v nysEC?MK1qO31erTE%V+А'e>e({?%JFt$T{ ZO5'agӉ\Z 5V= JhtMi\*Y*wVdQ-hH8F$B*u@ő~E+ âcZbY),s`*އXsS<f390=3 zppd@}~[\{/$sg/Mp"Q*js*E>@ٸtې t2@we&1oΥmh֊/zuQ^-eZ[`TՕ endstream endobj 38 0 obj 610 endobj 40 0 obj <> stream xTM0Wf$C@{ zXzji^;-uvGF=--kv5;x~|3̯ ?/ WY~?mFqGquZr-?\96'ZEMiKg_ޜ/x<'lxuAkC-@<}[vZ/an8[iާ;t;7ApȐq H|S: ccDytDiXD@=m-"i?e^KM 4L+KrF*dw&T jQ @I` uF.M52:'΍~0}#2V +e|У8~.)LJD&5@AjOۊAnXJ\1S'9ALl}S )'m')PkwQZ p%HX"zG? 26 ~bC-BʰlJRYr0auU曡K'+l򚷣ebC %=bp3DA9\7JˆV]&MP5hhS3` )"TLk:d=Aߦ@lBަS;%dyU[ڬ{  endstream endobj 41 0 obj 686 endobj 43 0 obj <> stream xVn0 +t.W% u-eCtX/Ql1CE(,[R$NkFkC|oJݩ+~ _{e2 SqdD[p{r Ea.A F V*?O67u]6ʛVYNK 8a&{~[nž6aRp(YVK/.)4UUW)/v ܎ҕ tCA$FmnbpcTY/(7W(RMy"w*t:dqf?RgF2GtdnL{.e#18c XaXŚҢr\d+rޱc*!@ )ad%E}`Sr2uUmW]T#WuJPGcY8ޱ06SWMy`D.i 1sJ~ L"ȲԸӢˬ,'m"'..WS=)% Kvln43V/,v)..be,+;kϨ\v7kםYرT:-.ܘ_+M"|[xxDzp7fBjNÒS"y;N)l2$i%|MJY1ǟi;Bou n1EzIxlc endstream endobj 44 0 obj 722 endobj 46 0 obj <> stream xTM0 W0YI'1@3i zXzj;-e{߯dى%ğ{l0;aCz'7{`ܹqG{4?e\8;36G^sհ[ښx|g~|+5Mf<6uv`y)QGSǰ 2AyxɣҶZt6(xD[ LY qc#KF#^Sً0F5VWc~R_U^' =vHGPACHt/${= YpTm\ڨ1MrtH&k}E7kd~#J($'ZBiGlUFd:Y::#_K5Fs|U+y&r}˙T\d!OJ6j*f5OJe!Q&r Yk4VRWr i&bC\\Rm=L(c.5\Cg/\A7j.)NMjiULfkiT|SVoJ 0ڎF( endstream endobj 47 0 obj 585 endobj 49 0 obj <> stream xUQ0 ~ϯAsd'1@sm`{+pne$N[ҧO[S6,Ok;߾OgFoU] _MW!Cl-QC׹εh珷91Mx"͜O4xn1XRX[@%4H#BLG~H]rS~|>Wq EӮ%$\SPu*NbDA SMSsBG0_PJ/ T 1.QTx%HfFm|?qR)q:YJ#5J1Qv8$Fy\f*&#VQ;&*j*n N@.]F{=Vm{í'v=xn{@+]ccS.nI_B۵BH"涇FZBqogk3y+.j]n0E;xCS^}@ީwjшΌI *->FrKQL*^c endstream endobj 50 0 obj 671 endobj 52 0 obj <> stream xTˊ@+ m?F %ǐ 8!~{FXWO-)~;p%4k|>޹:}܀] 4fc{tߋ˝@픤kq;?LE"U/$sKO?wSq6>If۞:l;:Xd-S _RG$wKg{AKx LI .aC* EHL|/Tj9@A3Gpӂ8! 9 HE@~]'sR*P $cHd: y&IjMϘK"Ep ׻A}vs[ ~5"WuRʋRTHR:=9 nP)lO7;23Rb~܈vX-׶x^fEv([~ԵJZ8~l3f[J 4犸 \Q{ܧha xumarS,$zڄѴ392fVG{v=s endstream endobj 53 0 obj 529 endobj 55 0 obj <> stream xRN0 +rFj8IJUu[%MqB]}l']@%{υOA@i@q<>+l;({T2p{vW:'?>8~[>hQ/zʝv-8͠B B(ZĈ(Fb . |,l M,L.|'4#*):>6R @qx:KDm #M, /bm'uE1`(sV}>\ [ ҿdDM}zN&Wt욣;1u6*C6S`0۔͙<4qZ%Uf8c_ƖY'6fcC1 I>7d2 [@j,vU]Eszze ]^/duiߝLy3QaVpLNGBXNMVYKFԹx1¤q*$V endstream endobj 56 0 obj 451 endobj 58 0 obj <> stream xXM9W9`Gn0 vo==%].K~T%uugD#˥ӫW%)R<߾tAGo\4h+C3ST;tlDOO=_?WepY]>wh`2P>C_-?фfp0=HB#Snky b]0Mģ뇃]L]Eh`bn?hNwcAv"!Ǯáh @`sW朿ĕi9v1^)g =7Dtƫ7GF Cr,=/bI sq' f <[Mb <a?FL$7Q ‘ 45Py΅P#i7PRL(3mό ,LHR$<@Q'!(3B5y: ~dD^ZTf3d'P(iDqҌa 5 ˠE9 S7"wA[ 30a`VB} ->hVBsk u9TvO˯֝0@G!2 DZZJYV'y!VTeY f8bE(2/;ejѢ M V(l:")` 7IJܒ^!CXˍ)>CZÄIs*B󰶦Gkռg<TԿ(hrxj髵rSVRü[:9CRg0U|o (%y ,3NؚUJ{iUO~}bTSSQ5EQPb+1zR:u5DTZer3?asj\?V z܈uXftN-+s8x%.4,MZ6%+ۭ;͔UJCr,Y|5EBRm%]^&\=U^;/K5˦ \!?xT9 _JU)ɽ*s `q`}R=ðb .C|A!xzJ ~E#?җ[&z9Wdeoݭt> stream xWM6WgH`Xk -`ۢȶh. )d5@-i~Ǜ7Zsߍiӻkӻ4m {mMGQ}_wȴL˦{5ZO] ~i_ipc|۽p3nw!ihw?ќ=M;aoy&qLOm {1b<oAGd . >og^ j'ChybN}q|:/\R7v5]_a!Qt nSSO T@-XpƱ‡ g7CðOh<},Ŕ]m6[PXE d^&>qI]c?r`C$iF=z*rܘ/ s)-ǔ-z{O Duk:"(etN ÔT5Zi)Nt )v $)-%s6էTödő{(GqX`Vu,+ 79Kb͆ p*jRץ&DCu^1cg͘ - U^PO1@1k5z&TzB+ G}H#"?HcבBN+^ecP|gpd/d/Ri@6C!VKS/:2,8v!Xf\N#SsuW؝+PWX"$6dL\fh.Bdܨqu]RȌyɨBC:jo8DWBWNWnU豪ףƂ*%O*YAݥ کټᜅ@{TT>(xwjiRѦWŠxfږufۄQ[ڏzo/Kk)sRBsk a+RSXۻ{LݏFN ܔcaZaR]3D_%oW-B_*V}'vj+)rN6􇾮Fx 0w|Fec3ZTťZf̴w jzs}10 w%DC!K,IC7K Q endstream endobj 62 0 obj 1168 endobj 64 0 obj <> stream xVn0 +t.W$ qۭ@enX/d+nbTQEz㣢[P_JGp~41&'#7-Ōߓ\(t\Nܿ{jȼ΍c[ΟV/9ʟzivyqq=;t7͸3L 'HSǃA;;".hh9b-NpOB#VctK{"<}N7c FVD^4b5̾ʃlx$t_#sFOr>Bh9"ߏv%XρA^Y`qz #2L.K#IAq ҡbLh6geC GhPY1MzNz\4B EkV) ߠu$$X{IԣEճ)B-$S* RgI 41v|Cis|+$!_rp-m`ik H$|skp\*ݿ񍶵T"sB<g,7_J`P LtgJ P-5B<0.WaD R%80saUƷ#9~dUL/kϻ~ aI*65\|e|B#"H1ЅBc<l}ܐ3[85OoR>^ ,Q?ş*Xp$ endstream endobj 65 0 obj 749 endobj 67 0 obj <> stream xWK8W*l0vwln {Xd.%J%w[KF󫯾*T{NQ#psZNѺGe==_wttS'Ӟmiz=~4u{Ծi/9_{?yz_fPLjI' -Z` PBaf6e&r"f_>Y`4M&d8앋Fr}J gS=^/#WLgl:Bdy=G;3jqo}aɋ_"jV7ѢJ\*.zHbI9'.Jib݆ ^ Q .DkJ et4Ҭm8D G(}c Jh؄Fud\0.m+І[©_C6g(dĀ(yP~ Z9oQ*V"cb@^Vjqz] *Xp5.D %JYRKT_լB-^SQjtJ5)pH<Hտ)эuS*)%.P<`@Cߧh .`g/z:#*޻D:CNBwUAZ>R~_JkNvP>.NMPlM_ Hfٯ/ m ]Lʨ(ьh--RR<*S0ccx[bJ0|QݔT$A溌0\*NfX9.sYWTe]SkPAѯ)C͑<-=8\ysGPx0xZ:0].Ί` `wzK|Mƫ\b 4^ou&4Eꃍl?H7 !L]?W.t- endstream endobj 68 0 obj 1054 endobj 70 0 obj <> stream xVMk0WXGI ư' =nKIZK~5&eYJJ?**zOg[U2~^VaKpD_\(.74-Ӧyz)n?r]>'s[ )_ۇnS?,#?ij.;S->uNY4:8UcOa5)^f 68W'uÝda:bL\ b 4)͞r֎ZNcFH-`''.ze%W^h&X.Y7ѥ8W9.xLzrB#!"Z@5n-hl2 mվa`q_ L!SV\s}dRJWj fX܆}mYVJ- !;S$ex>u9c=A3$2鋖|&F3]!dRaS)E]!8{/QlS q1rL?)7$.$L=Tzr  CF?Z5Čj')pV~]aHօŋ82:RFț63B1rQ β$Qj4>)$v5ݪ|VQ iM `P]L405y‰fQ r xabeȒ4Gݯ4vf)0ݨ~??M ޅVI2mH(U&fWټaVk|=]8yNB %ewd>0M1`gi$i# {U>SndF2^ K#oť$ TrX endstream endobj 71 0 obj 857 endobj 73 0 obj <> stream xXM6 W@")0$1àmbgIɲ%EǖE||4mm\u|a?l~|@??Px&^/wW}k޼}b:/9Ӽxt,}s~_7͋?tu>G{{㈴\oitO-Ӏ'px4J dg0³Hw&h^~ܮ.Xu9Fa**:i/ښ@Jt`/[Þ,' )61,|)L0Ḡhc9cR,ϑU#ڥ\+j ZJ<1 :7jaJ 9j hX8%XTtܨ;D{)fKZ Ɏ&$Q ט,1)ojqp0IiЂ MEu1A/ً*z&UAf<)Z hgAɅIySB"ojʢbAHh`(>jſ@iSGٿ`'NPԵ0asd9 8'#}ށc?;7yqwwz),ݢ a Y@ =g( +Pgu$[{({ќb4ÒFQyv2uyFT;314w-='_P/nEŰ(-]yJT|O).HqpxXڶ0y-9iE0K@YV?JH\B3AO6 $ endstream endobj 74 0 obj 1246 endobj 76 0 obj <> stream xVj0+\GO?]Bi)IKw4l K!43gΈ5[Y}`0]~d3-df;GtGegd_^/>s8~U墑k}oO#ܪ 꺦̞Gv1j&s#k4˰psaf|oZ|"+G[ђO_I<90Zr[>i=qۛ^)oR}EFQėtn5ңHXl;K"煄/niB^os8ُ'TnG8mC|+Փ\یm臦}OPy)j! z``"t BսR')j?"*.葨d4oqS蕖u!IEKeH:B1l%9q#:HE4d\qJk/r5E Cwʲr( $n } ezJr ~B4)nM(ч>#Դ8[[674OOmZ˦mM]I9'dR Al7{†P?[r[|GyN.ATEU6$⧤x? 3:KS@q}%@^T]aC .e o"WpY"ǽDu+z5: g;>iŕ ?M&O2_1 hgM[?pnƓ-UNtЧցUH*9 Q于ZH 8-,z@!? endstream endobj 77 0 obj 975 endobj 79 0 obj <> stream xXK6 W@$K6hoaӶӢiѽQ8A0FH~oo6{ }~E }T-"Do?fyEt$4 no3Csy۷0^ڜ.v>UG ‰U%rZr(Y{sNJѻz^pct~hwDhU4(ivN686;LCOep!5@59Y"Ф 2uE؏Gy3Y5Y$ؕײwaoQTLLa죊%ji˒Y\uzf62HKvJBIPkOX[dQ^ ]1S pEt u֡1Yrj'rhY.p::}6:Ԗ~pjρDQ{ RIJŒ;sWS|s #7ؓnz)]\ZyPKQ+5Z5LMDW_=vn+7Z95waus~.h"Y]O(WKa:[׏˘-Muz}r dUm _* endstream endobj 80 0 obj 1436 endobj 82 0 obj <> stream xWK6 W@"%[6zzvZ;-ޙCbV(Gr;hݸfhm_>5nom|Hm߯藶'R*_6x 慖麉t,7_w0^؜1xqgymcC;n۽-]7qe&. *c~Ec,:b8$ rD,Qpme(X^E5ǟy2xJE)"쪱^C|y^c;^q@\[E+VMaT:U5DNN| H!O[ϩuBih}vܘpb61Ag ϼ+ɘ*l+ieYdzQ5'{0\V)U󂢺IA*r?ѯV4_I2&TJJ>RdjAZkЃ)Nhлy3%J8S:&F_' "#Rk})~(`wKWkVn=Ji\3'~j'{/aӂӥf塿Z.[kȆv$ܦI.x L}yZ\Ɛ7TpOP| GyXWP̦w=]kBCem] z vw7 A0xuEe}޶bOߩ B+~MszYIM8.v oJbjK>3*œnbߔ*c_Jg[r!4 _%" TahC wwÌ$[I5Qfୖ̢ɦK/M endstream endobj 83 0 obj 1218 endobj 85 0 obj <> stream xXM6 W@"%dm=,zj;-K~)R-{n`-#"SCTGC}8~]*=|h}2c--e|xݳV:-:2 Xs~O'~xdG'w]Wq"43_(DZhb5bН @o6h( g+~*;cr \ka$h%|N5G(_"JXٙJ^3T$F?Feb|%H".?lHb/?A2vB+lں[ƂgT{TeSRr3mfx!ѷ0IrrqX€&XH]VkHb,I> stream xVMo0 W\  qۭ@enX/HY?02EQOR* ^о|/?ݕ (0B"OC3)Y\5Qx>myS>~]o˵S_~KH'[fػ~uL:‹a`:5>4vly88o i%[rNJ:|m|9#GjyrgkpӦ1U;tohBBUO(|o:P@rD[Qs^6p!& F@lҨDF2B^gh!@_=M(aE!gcd9i\(=SC9NNTD&|ԋ-!Mpo M,"S1Una;_oo"L:HV0+YHd sMZ-6yZ~.؜b]FK+Y 6W3RP>"A|B;x\urf;arRhƤFebDTX[]QajTU j 'k% f9&0Ou7[? 9#pf8Y.k]12Fu׵ǑFTZa^iœVaJaꥻF8+z꺄m$Z - AۛXf S/a 0D{wi7TL0\.(XYY[BK`eU"NN' 7> stream xTMo0 W\.?$ qS-flX/#);NS"ǧ@ e"cz^;@NNgr9=x#9;prNKr-R~|-`7t;PRY$SW` Q rՌċ ąvj`sPuk  aiR˩^-\ f6pMs4U]ZVgLpgoA& ,,@{KU){vpbQ u],H'Nz+Z8jnu~*#"FD-Ղ!95n>j_ݼMh7%\i`khxt3ec?uL X# ^nّ?|LIsej`iT$? J΢%ږvӨ>oҤ{YQbȂ rȝ>/+ endstream endobj 92 0 obj 486 endobj 94 0 obj <> stream xVM0Wf$Y1:مmZʦ{hF䯐J(x)izVgE}S?*P2&KWz}ґ)|ݫVȵlQx\w?3SXڨguDVΝz p .R@!&oxi n+qq BZV̀=>&#KdF8{%6'"|A ٱvBܦ89`9ר:+nD Z(31Aic'RJeͱq6b;SD[ Lj= yQNx!i)Sf`ǢSLVZ/96KǦnR|h [aD+Ḁ/t-$n !tgz"M7n`sg1L-t4_ 9s&QŠK|Ml)/ɷsHԩbJ)S6,v,"?5A٭\?ߤo^Ry endstream endobj 95 0 obj 777 endobj 97 0 obj <> stream xXKFW0ޮ~I##Hn 9,9%^%{ F2G=әmo<]}~pѠ?.}8}BXᄏ}УYG׽}^wo'럇v>EqH޾dOMO':5LprVLO6I󽵤Xz.*Xʅbo0YJ= KqRa,~~q 7] /xV|=;M,{.A6Ʉ&?P2!g!#8˹!bVf3r6Bjt Þ`.64zr6Xn0&~:*,撂4Z1U"…y+{̅]1ÈRȞKUw?ׇFW`K5iFN25Jn^$ծ!mtƯ̤g!"[cX#rMƝ +4lB(¥-z]#+#^57ks0uÂwΎs6GK2)>a(G!Z ~ap4¸MxI'?]]Yܸv{wXdP2up}y՞̰U; .Qpop8+;SXfjN8S, DK>0ק*UnSƫbsnj&[5FjWo4,C2Xt'N3eI~LX婜UУLֹ "]4;lUC,nmzF9?`{xEC? endstream endobj 98 0 obj 1562 endobj 100 0 obj <> stream xXKFW`oW$1$CKNI&!$d/W?gXYVW}UW2hӘfot ~k~>~߹hpێ_7.[}mؽ~G˰L/o?w?ǟn{p}s{=no6>eoC[{r4σ?BhN&hܰw<W+478ۗ{É:ZVwj4zޞغ %#L<;KhU4 /( ,B{8-̿x# ۊYxH؎Im1M<;V8r& iQhidz0A^=#EaCZ늩#tQ7`_-`iD-XIAv?d:PHD*.mABԕI,4]q N@/d,W+aTtL/Gك]vr?ȅ61AucXe phg54p|ָ֣AK.'֐E`qѵ5Lq͔pSZ0=d Ś,S[if+V[(J uU&g2xQ!S *C΂'I eAmh! a0onK*~M M3kB[d$ R)H9DQ""i[lo&yGl=BG@HVa+ۍ$B!c(4laqYJ*QWCZs5"RE3ˮI.W(BE^%)DNXucf8rȼ`lIeU-K9?Nm?35KV@zf[{|tߧ5ty0w('07 -xaw:7!$`84M,uVoToT!+uoTϋTμ*d^^ ^Jku CzW%NCjU'o^~;)Hʣ(}t 4D{ endstream endobj 101 0 obj 1351 endobj 103 0 obj <> stream xXMo6 ϯy)gmZK~)$2E>Oq';[x uK㏃o{;wGe2-eQv[]u6}Zo'pSm{zחp gwpv̀g燣)ӕnC2 GZ]{x'+zVbO; :)֢w7gđ-yt5 jOH> &r?F>@%J!6]vJv. Gj L9-D8$iwC(c=ڲb1bcv$_P7g[2هPNbrk,5wVo~Ǡ Oa%!"לkj_mc;]sBe ypmi }&\ԐѢώE`jz.E3f@^k. K.[b}7orshwĕ똛U~v_"~0j8F"?B`|Vx!زSюJ$uiwI rz9vZدB @ hۥ +> stream xWKk@ W3YҪՏZՍm~Ưwg j\iH-}ARݜp]uԻ=귇#=M}(_CuŎO7]IiwsQـQ۱r#nt{Zikb036e{>$CWԼdU]EXe76&lqb]va Z|b_^"^1(Mgkx/@; 7!艣ؙ}>f 202dI8Is?Y{tV{lwl"!9pFJ.'%Q0c;hep'gHqla{.SE]0V8O5E2)Z ,(֬vlARI1݊Ѯ6.lk\L:Ex!ل993qeڰ$ئ\ 'QNЭ`4 jRRa*0*(h`z!30!~1h ~h#@)<X$f)K cp#[Z\`+x™wG͒_3Geu&%[: 7 [7W:8Q И4&wԻ@Z 5}MQ|bk㚹0Wt(4omI:t6;۱^Rtrc:] 4Л2$F?P tIf6_ Vct#,tb> stream xXK6WfC^-n"ۢw^|H`.fdtn4!;;{{-͌R*?_^wz}..Y뮿u/4tk|}GCG|>ϓ?B}ػid.<Q'i_pGYT%EdK2M{S<yE`V?[s#y=#bQpM9=0P7n ыzKYqpo4˶ rZos8Bz`38#MBBLj~]$Lp{T*A|Qaؾ6*8T)|$b3"ZMETV_*~[ZǙ\- 68e@k@Vd6ƙt %9 q&c.:9OŋKJ(m&+Ԃ++$-: Zm*H0eC]"6PW>ĜBLl( )Sv7_q TZ9hH/np9<-w9F?ZT$o9g`0@E `ISPe3* 1GI &*=bשLֳT:p08>jslcId&ނAahѨ~C߰́ 0/llO )&FsrV9q G^T'=!|T:ݻ #42ӝ$u;Iv  k(sV@R bd3Xfvò`_)}\ \E*C7|6ʥ8mqKN%i jI[旳mT䛜uB8}do#p2JcWP@{ -a\*i (gv0Zj{>h˭j\@-A@껭TNSM˾6ax_Yۤk@oԢkIx0k{P]e=BR=| {N!G~K ίD!?j'[;7N.Cُ0BCy6%td$}I\;̭> stream xVM0W4,ao=ڦt/(<ͼydUOTAP,tIoڽ4{q{@a9kՖï򂏓xʔ/綼:Z\8Pds}Ռ@2Z9Aw8=Ni[^v29Ϡ%ᙏye[v%hb9Dnh_K4j'9w TA£ %M*yP 44SQ8n'N;%83czeRyBeir \F>,0xmS2 V%+@ W]`0u3ѧt;Zsl31Qta x8&g'+^x&>MRtQ c;*̑YM?Ee1rS.㟠bHI5[s!'0 kܣ;'2{"ߣVQ !l,_*Jml9$S)*ƣ,.Q[Cd-]앪b{(T dS "ϔc:"9 `ڬcDmEIYR(c!skF:Lh{P^5=Os~hnSY飉axMd[eيIo܎bh v6s4E*-S\\(n" Bj/" (JQ\cvFPE^vy9,EnRí endstream endobj 113 0 obj 814 endobj 115 0 obj <> stream xMk0:֙ч%15CR-ͥ3#ql1+x4zͣ<>}Qoԏ _O_+#il{Tߪ NIù}jSd+OnQF@sS ؍߫X%P.r}^tߚVn-Dຝi!Rw^|'ˍ,34~x)Fk(Hh4WSbƇ@ -4-'BxNtXs!vn 19qzS#IF$9s0?Yo1Px^!#v+G1ot̍0H#qw 3#z?Wz)s^3J,䧓Z:D>>Alpd-1M@g68Ne'ծDrِP }"뛋+HHb-w}m7X.y?/KJBZQOBq)CZӟ2?? endstream endobj 116 0 obj 594 endobj 118 0 obj <> stream xVMk0WXGcYhoBOmRҿ_iFGeZ^Y3z3ɢwIG+h_nzZVu/-swgž=ߪ皦i>T^t}Y?tdu}}z@Zkk.qrTq$q3qaO\/Ww䝟Pj<, "%D4b Lc@AF|'f|nݴJ(%-"ŕb Ýٌfarg9#0 8ܤ]]!Ucy$G0-L&+eMˁK:ʐۥFxxx&F"$T#!f CQ1;PS{@ojndr!rz&c75DLNUt'k6M42CKdOK\JpdҸ'll 8K;B$VB7рv$Mr*CrC n[Ǣ~ƒ 3nR&;&ec]$[q3D&@)S2ĈT2g3[ḳ9d™'ݱp"q'L˷b+˃7Ze eU ;ndg6VӔd&Voap}Yڰ]\Њ.hJgk/I9 UdM2ehY~[DjIc~dCԽ} 0*{NbM ˠNiC6f :M> endstream endobj 119 0 obj 828 endobj 121 0 obj <> stream xVKk@WهV#- [CmZJ\;}yL6jfo^ۭivSZC۷C~ow(wjh}?={m4/hZE~_N㇓i~wᱠֺ=~m|6etzk+XA+1Aʹj teeZ y]bS1 A2^َqr/Y\#Û'^2}L!JGCƃ*2Dp9TXcÐ-XvR(@uXW'Rcyl}BlX7{̡jhti̪0"{VSb\GX5x`xgWSlHc/Z y80<=E ܄r>&I>@yE2hCrلt8RD)ۥ4]݀Tje}leF'krNg'fiǒl8)݉cBULXXF sb-% nnC!pM ;,ܸZq >Z$p:amZW;"XHnf %^R{Q l^tфF6]Ĉ#1kMɡLFw(2>Kr`B7H9>wg̺筕\ҳxWjg"zS>HXx/smדMՓi>'W?^˼K?}f endstream endobj 122 0 obj 921 endobj 124 0 obj <> stream xWKk0We-CmZJ\;ږwhYUoyE-?RS/_wByVFs'3-^<ށkf#|~.=|p.+UcS{!Gq<?qn^E+ CWpez>kJ񉶓W& E= h;8IpBk?c(0u'"^ei鶛h\NF2djF#І`3.V+"iid3sECLcm ^ ^+m{Jɱn:[ u 6h b޲ɷf<@J9&2N^erR|2}3rIɩץ&q}6ٔ QXh>YՏښ8ր~3MMbQs+k;9Ied@dOӸ*ϐ}HŐDS%>[,sV~3kVqQB)j)hȎ*5q [bݸ(\-h2޼&@Q&3*gĘPIJ)U,IRZ<,&< )|$vE`qw$RFe f9 umI\p|<0X_Xqf -c"G-{rdNڦR6 *]2ye-r]頶OY[ai5uioͨ |}(Y:]#fR)k1(e98ėE>mx?(:2(Ag,bh&p(2Z~Qbn*l?F˘r_Oțk3Y +W)p W }XI @%] .c枀v^c͹&Nݠ> stream xWM6Wg%^m==EEs|"-Y(䐚ypl~mkM{04O? gc!׆蛶T#V_:ZՈ?6?oLӭZmo4ve00nnͳ8ʟbb> stream xUMk0WXG,aC{ ,PzJ4·$k+K4[M3 otWl [Cv_\KzкFCƞ)ۂ]|IBiA05{81#4 UfK E[tPQLY< ix4B!#YZj GfTtPŅ KhA/{v"[(6Q yr4W(*p=bEO4Aa!]%e/+ ˛- \p`_2UƃX_T/lnR\ga(Hv7R[]]PN<_}˘7 endstream endobj 131 0 obj 754 endobj 133 0 obj <> stream xTM0W`>" `@{ zXz6-eҽwf$Y-&b=ͼyPi~+P-kt~6y֘J?ћ,fNW9Q9y97V#-ǩugEhnty­]_f!Bl|@Fhو 1NbE*+S]@ Q||faca( s%:r'^;`eKrYCzZF| qȆg m`#({ å]#EంenX Aa]GӺ1oq>%ɕS1&taS {"Jӟ083H,"qQׁc8ݰ_՞殢])ŬxmWѥ %9.=04͒LC_%Ɗ\.$;ޘnS.yΝxW6л3{˳f|l͒7"[tv-OnSSSnQr9i+66҂лOBo7MwLs?rY,mǧO&<4s0?ҵ5ܾ.V#qsmf'#V#;藌Jg?%#5TG& endstream endobj 134 0 obj 668 endobj 136 0 obj <> stream xWK6WgA0CS۴(-K~AJ\I^;Yi|P6{UզF;QV6{xBoR)fr_꿪ȴ.?=W?9A@' mD!X*|܉/@C1%3tKL DhcށcɌP.QacC}f`_-6NJͺ%pՒđY&jը}k΁X[PIUN* pT>KS-8)= ]g6a!Aٔ׬%-+3G*2rSg嵮ShQ}qV{tذصcJ蠗x(܈x񖕄89ċ=4oX&Q'e,s#.`'ha(Ώ9BC̈́ONU1U |Rr7`FVGn9InI~bn~ ޠd\pO6ŧE > stream xYKoEϯ37Z)cD$!8 N@@D.ԳkfIz^KS:ԓ3:KYSI!7,bڻۥ.+_\+W}w4+DtzmХnc#@T[؀ )@ ;R/']CAe[3RN"4\"D.- `YUa,#6HA{lu4@4kJБEI8ΜwM=7#HPZ$7ޚ۳un{7_F"~-TzO¹mt*@I8'&jsQb#G gۿn])ݍe")-қnОp(bܳKsoP/]T]BJr6vӥoTX2Mrbbc m{zƩ$t-нЩsۡ tZJM|,]9~HgЊ1uPX]﹋Ј=Ɂ9lO5 Eg \P4:(fO%F;IDiS.;/5ğ?y|ֹiɫ4%C7Y$873օ $[&HEUj2mYi-P&IڎR#fJpVut\uȀn;w2\ LFUD…P6'\n߂i}jIάQ'/"?G@PhO/KnD6"_8Wt T@N7/H&يKmtWE!u53|(rGB8Q͹hqp[XYhc`-SuAZux^xu2X/:u{<ݧ~aüΖ Jm gT"Nī !lt  T::kO a8I,Zmw<ԡdb aO87:&iò禗A3Ve(DI5qFC5Ht[ӹ)98mudW9 d+_ϫ! I"Zt)XP(-4h7_ιX:5p,%\!c:;"G9MU~Qކ zf/*d8敏 欄$ PZĔΡ5o/;  _(èP- t5a.*|;c'H3PPE]eIu =2xd ˶- {&-Ft| 1O<5Bו&?:1e#T.-!$ w.(AW(koZ FK@:5T *@ٜښ_Zm$iO BըueY k{| =!aegb+:jK ٵ՜Ztf%H.B^Qc YeӔL_6Ek6+վfEYmO?' endstream endobj 140 0 obj 2063 endobj 142 0 obj <> stream xXKFW`mW$ؖ6CKNI&!$d/fXB0H_}UuɪF5GY }q0^_7.)[}i<|@r[&Oiq2:tko'eT0:\ogJJOfn:¨a:QyGz;tȉyQm7~ҴM4Ckc\vJPǣY 0} cxk70VsEDRs4rtp{.\durOQ3ݸĆiFZ-r?:cTL/'V\v)rKG#`kd#v^CXi`)a;\OiKX.Bq9 zqCcJs`l&‡%|[bY_']$ IL<1Z kfcp83ʊ:m&pKI!J4#Slju)W"ꈼNi .9” :pXluIb~ .1F {j3fAh:&*щu+fPVHqYXBuL2s6ф^Is2!Y=&TOAlJxd oB^T_TJR|*񴁬!<=d9㰆X5"hY)2BS4QjAc &rNGy/;A*~ҍcǖnms- 䢅`U:}}@Q؟F=C']i _RtlB_2$f8k~/JF҈<Ð{% ?'"՗@2v*}[O!T=ӻ ԐLEKݯ+kʈrM?,DrjuntY-9#F)ᔕdݫE| V?i961߅5zWV| F:B8)y>J2ajuL GD}IEvB3U_GBSls/e5E|qը+v@kOv. x)QTWUJp B PӛNo^{! jIfqɵ-E;l3} Ue;TwY0 endstream endobj 143 0 obj 1161 endobj 145 0 obj <> stream xUMo0 W\ H} uۭ@enX/#)R AS#[PJtݕހxM~O %7+G9^Q`N\yzKt5I]٪q05A'ۮkt|?jݴQrRoNc`3vKiц3[&u\˄ nNN\ui)*eYc Q 6 h'lxb g"OXWˋEzBV4"ctfI> stream xVn0 +t.Wd uۭ@enX/Q,n.i0(M>>>5/Nқxo\|Qnԏ T^V\~ U fvקݳSO9x<S[unvx5 z * N=tv3sXuXfnM)LhM%+oW 76%`62ag{e*=9u 0t 1G'A\̢jfqJ8bvIlW72i[Ѥ6E1V1 W)7 6$$ɀr_N@e -9Wi$`*3<^BФ̋Q`/\3BZ\/) J8ESc/ؚCՋ=}fRf~22a2Өqm*ur4͸ h[elX?6CGMq,2 x6t鮂hKNIkg{:0F 2xn, (pThÊw:e~"mFPR H_?IAƓ/޹%[w̖Y> stream xVn0 +|.`Wd q]ۭ@unX/eIDQd|||Z]~֪nTz8|+]KevOo"fMt~>>Wom=t| 5S}Ĺ[u(~=AU=F76ly .=fl̠R`kbdӛ6l"TC2DNGN6mގi{;įfC\~=ZX#mLq6QQ ɰk$㎖\nP3WS 3Ql3lSyl4gX{ EHVȖ܃Eӻ~f \pzn&hNۘG#I@w%*Yh ]Ck츶A9欪ɒ U01B:isF0صVZxM+mw+`f覬Yߩnx(y{>5fNTbBg,@ֳ͈)-N)ɺ,p),OI>SmO|@MS_(J=@,5j?JNUJŞKmUpZj1COttN {G(iKQM_זvߑ&~u@5@/ 0TM+ݺC{N]rJ%u*ipGiwH/o2 N&Vr3[,땙'ćj ךdf(y:%misWLEC;.> stream xVMk0WXG_#ٰ[`S۴w>$kֻN6bV͛7#ζ߭i7퇫gc[z5>{jh|<\kY#z>?5B߳$<ֺη/C{x;~4极SCJ]_>n֦qcfюu04Du<g;?n|6chA$OP|֭B7AZSm"؀1DVbӘÄLJ('+&vNJ+)c k^5d\KK{ӛNK+6Śͬ2[g,vPE SpyGgƼ~$Q^Qq<]7YMRuPgڋ6NjhWY*p!?2ἄx,v0dCY}^>ADJys)tݨ9;vqz,ӲRu.fΠv0ըC Rtj s>\مJ03ƼYڏjyޡB3a( D@Vp%ׯ*uxԥVbEdvN Wx1{|չ,|ljerrC9SN(@9I+ա'Zbq,tSAO+\E\FjrR~& á_kj*P|Ga`b1W'3TjlOHA} iTBOTsY‚%r塒)̼OH-@\"Ԭ+a8^\MFT{hvU{( rhC:sسgvMjv:_E endstream endobj 155 0 obj 885 endobj 157 0 obj <> stream xVKo0 W\ eNV Nݺah7![')6UTȏ)ԟjq U}Q?+P}lQP QѯȽ e鵺K=l~WS[nq?ݾz`G. Ξ{m! G:^h8ٸIZ=ZѤMY<4|Aqtl4S9VOYCPU((c6;V`,УGK`*GK9B;^p'hD Co;́@@qqk >!-Zny;9y2SQ2-رfÙ?)V5k&4?dE/V|=`\شEGPh]zfXheMOe?<Ybň(tC̖SۭbcD8xIJV(?),?l zxڤ\llHKͬ:9w'#(%'{cEڰAFXj˕z!/SNMeڜ7]!vI):'SJkX6v?J9vdL!e)pJʉ%=g_8}H]T%EOqA*yb1pMcaaf`WΒ>R8N%M-K| A ,Wu,]$绖_#R6KtlYەƶ3){agȫ?hg_e)(*[mq6|I/Ӳ:[*2HtqJjnyA[]dwIs(> endstream endobj 158 0 obj 854 endobj 160 0 obj <> stream xTK0Wf$YAo =,=mi^;mPLɼ3r uHLg ||Ʒg)d#[7sԪV'~5=yI?L&QY鳽?tyYgu)5$]{zrc!1bPSY|9J`+4&9JzĬ)\wdBib$GvGTJJ|><;7t.]U}V~%smj'S]/eQ<`N݉\|%́m#Y"!dS\U0áVE7$̭У` sبwC؅zRT7TA$%ʟs'LX C`NJQgPWK4q{3vW+3i-殉.@oA݈w* ʢeEjtl*&.z/\Bѝ׭Ü8cLc*^<:Fa+QVWbjѭG6 jz3o endstream endobj 161 0 obj 535 endobj 163 0 obj <> stream xWMo69*E `==u n\3,kR,,k{oHnBcG|W4]Gq~? 4rx@g<~LׯA[!{z;3~:t4'`+L9#~QJ;A^kGi᪈{zS tv'O-:,e>?ˌChbh”iZLFuw\L*BF^]>EaL%}ʫ#Dլ,J ;Uj3P_?k RÑRͮ@ga~2E'L QBvE=XrS) i݋[܋{E ffsY WRε.n|=M/#{Tɸ,5r3+A%#~KdLVzYWGBX\t.v)H*E&V,-T[@j6Ľ6%3RoAȰ DWFs}~P-~ r#梽ݩh nahlV/~5qcU붕I}gR^ʂI2>UC ?{s endstream endobj 164 0 obj 1085 endobj 166 0 obj <> stream xVIk0WGzl C<6-%ii.}6XNPG}oQn5[.}~i7ˏ =7}x bESyAѲ-l VCgk۞G<0t>\=~LfôӣWO;M1WOSg d6͠P1_VKttµ_VwꀅUWɉ.ӗ5ȬǍ2ƌU?pp2nY)B&6D 5osdD HmȐDB .#?*x9 ]_ot{#uR3upv +`bϴ ,$wwA^6,XLۼ!H8;%^QEL,.QR@!.fn$y5l0hR -IxKy$QLIS8".Cpj4U-cH)-:t4է̲n'$L""_O4^#t=-q2毋jܢjc\/%nojǦI:`'iO`auX܊a973 H;r^%m ziM$z\0SpQ?q"jo. +\+j F܍^]#Cݻ@ז $HF G1ޯ[ĻPQ/!x8B|}gb S D"erHAa4. RdIϳhOſ$+VcHe r,93NI: zEhfm Zh-Xߪ婵ĮWt0Tau-T8W&B?MlQ:j2VHӜl"ء):Mtݯ]hBcIط-ysެ0f!qf~Nd8Wcˉ4%JRP@bamK> cV}!n,jR0 ? 5 endstream endobj 167 0 obj 1004 endobj 169 0 obj <> stream xXKo6W輀K -ڦbEҿ _E;n # oy߻: =5Oݷt;ɽ+)(OZ^P}wv/9.;OtwLc]ގ ˗e†"n?IizT8#qG5=U?CyN`>xSx(JQʍ?_~ܲh2E)l:6M~8bh,40#ሴ Os܄ P4ԁSޖie%kFW` ++1$ ==0kyC⌥F UP@f1*cZ Ma-KM|ebr Ӊ}Y9Ehk 0ν#hǨ l(g1зy NM =BTqMA|kK0ޤ Ah Ylz /Z4밦@QykW|]!жP{ Z Tﭡәa JHVv"wf>WW`I9&nʩ&C'uTed}HS>S>83o"zH ׫p V*@48ױ9@7lhEivkJvde%)l\|TW> N%2YWՑ˶zYm0Զ+d_*IA?WȽ}f}8 IN5#mANfG~ܘ\2MO8JZ[hck(%@}` O ABWGIqaMÐc-EFJn ȍ> OqDOOB,Shj~z7a6;Qbr#te -*iWӏyAŎ;p/L_eBG>a􈸌a^ž>3e^4f-ȳU f!0@9x=T&>T5äeDfd^AJvwsRBiSs 7PSU%U:ad AXy 7A,w}sM7J))[i2 ^mV[KK̰J]) tv~;erZJ4sCO\J)2wᢓݳ-PН (Cχ#t]P]AHj-sehb3a5(v: j<'ꖰTl3-oo4IYjo**M+]FX2{#_ Sr/˛T{t~ endstream endobj 170 0 obj 1324 endobj 172 0 obj <> stream xXKo6W輀$ˊ@AOmb٢{)5 :S3_(XeIa\ ,.ỏQ]>S*AI;29i0N}Q)j 2/*XRKZ(3l_B-Fg3V>7N endstream endobj 173 0 obj 1321 endobj 175 0 obj <> stream x\ˎ%9nW($Pex/. +mcP׆g3o񐢨[ـ1YdxĐ(E7w >~ϯwv_ouͿF߿ݏ?=>Xrԡևx?~t}_|yaP^__\OC__Ǐ2?U5z$~?#eO?)v>>~ɳ'6޽zΤ4m7jqPAe OGz1_?K)>?Q?&Da;`DOG@=?he2O)| 9 #(J-bH~= ֻB^h-ʼnHA{e1I/,2&N>q̜!W_1 fqa~mOE1T^ZEy<~ޏr_oR'-w[n(OMG| #)'%.6$7NZ#F@(5_Ld.vIcw轳z'/etR6Mr礓6/1{8B9b ia-cnƟ[݇\n"nb*TpKn/>N3nP%ٷg Id<*J~07[Ư[y&j,*X/E颞y˿I͹kbG{ϯfͻtT. PcBiO&?7"! z`Єp$JlP. IH9Rġ%/dD@hF@2X:nY099[Mu#tbV<G}45 saA3q 7'5p%e:uZ'th"#Pͫ@5pH( Qv~pE* $*% kű;+එ1*9<4*mԢY'nTa?Zoژr Ǩ˃t3zoce +jǍE$ڙPxVh${5MA64+zEzP17鹥bQϬ'ެ^uwϙ5)FHӖh˦(СLu58ڀh$B&"=4[goVu|q38d6Sa-bXDE]}G\p8m!$C5QO"&SbT ?>쯩QnP![oOv>TOJ->֫?|eÏJ]4ϲcEfД=x"(ṥbQOmߪRiq=!z!Ol~upMAG*Wj3זl !zq30'Z;W4ӢC\bxվMA]&wqD.<_뮍eˠy߷UlzTcr_eQ=FF X:eQm9 bSd@b<4Z,6UiS׀ELZٹ_vq.%ܙhcΪQǷpF=LmkAHB!d=Y`ZI9k{i2Oc9N3 q4Wjϖ;TڼҼE()TUgbq ]-)5G֌2ЀFD - 46Tjm82),O13|Gq\C,qͷNZZTDCh5꺲n5ES Q`x3LrzIJ"itQϬޤAw`hG;R|3QևqbXZ%黩,IYϘ`v,IVVXrbt䊺,@wN6*# )CahD[-< t?|hr 9Ϣ[9sRz,Fc<+DE0T ) :pUJ)V)c:W.~vq}r: Uƾ'FtKem9<֘47=ߏʩwA ^vXu/Vc;])W5aE) gx8TW3d2ΰ!>WfDۇӺB !+Y|xKlԛ^Ѫ@upJ'[D9x J.Wk*Ͱاc )l9ePn{,E,UѓAz D|D9VBdӁ^5=Iю7F8Tb |[*mt{A?BXQS̥YʘfR19mK֜LL$M :%YsšqӲ'颢]t078Aa ͕6^\߾/ -e&$:cCJ{XuZ5SU&.QwLvݘh ?wJ?Xs0 "KT4CK7xv#?o6֧}奱Sӱ^M%vX+#2%.W9 k$YTV6}J3iUu?QK_nm4X37>ZMDE_Bk Bi hT~bQW.궐$.zl\6nᒁym˰&>D:bMgDIZ|HJ^U]+;aޣL఑ 0="6dKo0T8PG|KH,#55nLX'FØ-#5.&5v)ߨ7&ψBS%S Ô*8`pL8)#W1q-u6*6uTɷJ)i|^l,Fed]B|I'@1RӞeqlR"Y+t[zVJTc"ƹY]- CHiyA+I 521u׌!lC @R k-f+Ml|Z x74\̬Zp ݑc#ME9 \:ܬRӞ5s'hCLzNq#󢄑R c<8$^L҆ƷrJ_&*)5aZ4r U퐄6&Kb8z(&gwrm47K0/D'E"=niBRY. fx$/9@y_ɻIKJs3jIsH'asjx&s)œ+ϮDc7䕗;8/?<7L8J0#aռY<=<@ihwg9̹.^+KN3#ǐI3 pjf9i~pʢS clg\R SL$ ;"4$Kذeiv@;4<8NL}E$'Ix9-_\FhIDۙ.^ϢZ u,..)=V9tx;YrђrxD$}nb#ҫz8ѓ AV\}Q dSx UegheBNn|L)UKÐzdMRr4af/ 92NR7PU)q\Y,)2>˵L(rjBZB;[9q%y[} M(׉~ƹ 9[z`̪Jiwޥ+&TN򢑷pSNoSace~㟳E_^JKN0HT>+4˩ +A@ #6d[2SMju.ێ2ä@Sw| "Iaa?8 ~!UCO3TIeޛY|k$'D=^I8d4ݛe>^2 sB XyL\kzd5 jYuWq?wbqeJ Pb,Si 1/u|dy"{go@oJExYE%>iSט(Ϯ*䥨`gWs3T&B|RL"݈EJ$z`=cU 0,h?0PJ2(oxȽ?n#xM ]Ջ98WϏ<>| \+[ɡ/,mjx0ҟ &oLs9ƚ|&-i6zI,|ƪ̱ ccB.XoCPq>Ve1 Tkp^~7*X/ɱ(6kB%Y5ˋ uȀ,KzB8kI:cXW{sڳl@1kIYdɛ%6clWkfM4#ar^ É`f߬ƚ` WkMQ8\0X42zmJͦ(4!hdYkRIJ8/Do0&7kt~*,ɱ`ި nvO#^65._RCr6Q0±. w~YcdncѺ12 m?W0Xc=Kru>5„OQ{IXz%nK_, ݦe`o09=б2ax3_n7 endstream endobj 176 0 obj 6199 endobj 178 0 obj <> stream xV˪0+_ F U۴MW4I"F3gFclqjrk%~ʍ/C7-d V]:{>]Wņ7X l̞O8Wlz3VgO=]S_AϕGh,›MkAڝ칉qn)[ؽX\"{7Nu~aGH K;#9fX [*9{"Q>$|C! "gx.뉸IdSOD@a8 ˊAHX `n݊(I때 C@sV̵ vA]/ JuKe@--,݀-ՄQ)6Eû࢑yd"ȅ&b4T-<8Ap1l^r!u 5SzGGu׺#rhŚ5QtO'Q-ډKAB:YO&VQ?DXH/ ;JD׼d<~ULp[t7Ӄ~ǫwM om R3rXJX%@`+yH4XnKjm\-zU\_ endstream endobj 179 0 obj 691 endobj 181 0 obj <> stream xWM0Wl q@{[Pzj-e{Hvv)!#7oȢO-ꃀ[ܵ5xWd>/+ { `shT`iF#\ݿ6~t,l+U>?w;>X^㧣(vAE*.cA aFzMM_\%\jK0; \&?N oE?&C~)sZ8(?dJG oP$*o[xI恉<̒$nװa]!`d-0|&Q!Cpǖ>,|F!!Us]IS|WmĕҪ3a06 sLg -g,ϸA9l3 cCZx;<'Ʉ[:y/EUbuC¼L+Lo%eAO)̒J24z2" ׊Ţb MMV;hNX?8GиAZKjul!&CCYT,4LBQ[Nv )e,7Bv3nZr(Ò{:Шq-5/bL.nv~,s9`4ΡQsvv{ % l:' r;!Yt^E,nSbwGgژpYmM5Ȣgw՜8I>ѯNXtpa aˍfv,VhTPW(}#bb1_Rzwʒ|C9 l^(ik);nkʘ̬Y,g^.=PUpZ*^S+9JK2n2 9=s/x7P ~~wٷAҤ_JT endstream endobj 182 0 obj 935 endobj 184 0 obj <> stream xWK0Wf$Y1m!CmZnKҿH/!OmEtiЭZ{@>o? {mB_r_z]l:|}m?}S1ZNo㙮U{˯ti}ܕ1vG~Aoqh7 7H;a((ل[ޞGp!F?ڍ/.]'FSjLBΉH-;=SRwa9iX|i֕X#E@<$R@%AE,ڄ>.lK`^Ώp}Xun6{*sorGy;8tû$28$8 j/)fH9bӨB4̘ 6N-S".|=wX&Sn%Q@J,f2/ރD sfX173"cDHbRq&ZFPtr&9#f.x J!G1219^xs̚f,P8YW$Sbgي7:Ѭ` {8%M1<2}B肋s`k1MJuĉS=mU"a:MY(UƣPVV犛5&A\LҭK:f:>-C|}}KUIr(8Ff9Aq˗4w,u W0,Tfw3B7IDBM3sZq*9ǵEy~uKkN?A endstream endobj 185 0 obj 899 endobj 187 0 obj <> stream xVKk@ W\؍5O! =ڦ$-ͥi;$PN>IiWa&Oڏ_ ѮC&/^_/=?wY(<6WMn8ύG=mNmtܞ;r4'y_NMz?`Za:Qä~.| VEt6tIM?x;Rs!?}>xWY=tGW9;Bt?bC7_ewC+G<#e! +s K9){ZK}vQW8 !΍bZ^kO] eia+gDM\ɖc]`j[J/RWQ!Hx#cZY{ҶJ%gG0WAB]C%g̔۩B۬/yTz؅:OYTw3` kQԷռ4`o@jo| YE\Aljsw>HKT TR`#Td3 KlV*㕥E"H\u%Մ|[xUױ#E#5Ġ~ Rч) SM_̪B985zM?n@<Q%gȘq 86 f ƞ;ˡwAj\0gv;J8 _&LK(U[~LBfΑDD41"flm DUOMiH cNR1Į%U!TU-/Sx%TI%MOZXRcLJpÛ( o)9wb>ep$ĦǏ=(]o8_hx @+o}n`y²BZj~%%s8 l:Ҫb.S.=]#zdӘvoYo˵afBjgӊ?[GQ<4ꕸi3oGyi" f޼kxXC endstream endobj 188 0 obj 1020 endobj 190 0 obj <> stream x}RKk0 W\Hkɯ]ncmF{ߟ$'n(:jCjDޱr?\h/~{v3J]7'sMTsgHwz%yxWA(qNH!6A $ d!c2N2d|&uSDP/͍ҴُFk$Mkki%2vzo(' S-]3c!*RYmn"h&'p!aLj5ZV:a%vD*(1I7ĵ-&x tRctVB;}0KTWc|T_ם\b .h‰&[ΠڎgaV"_E|li?wgoQѿ endstream endobj 191 0 obj 393 endobj 192 0 obj <> stream x tTա~ܲگUT|U[@Q@%yD4A6OkZsYx{o}|hޥ 1\0%d=cg~yg-LC7νN=B~4ҪtfɔwW>􅫍sWhzh׆jGgHdbK&>x?vd4=G6>܆4<0{œow}մ%c`uMhF7N^!Uh,88'ǁo7b"BtyZێv {V땧x37-Y !kfeLs̎Wǝ~"+}Ѧhn4{NJr=$H'R[(ŽEj*c$ېue~}MOd43{3.}|]8`2VM=•W,}fmG[dzk+%GGEʇAδ"uN|{[5QEgzRZ{ڹY̼ZloUO}ʥu2WhRFkeGsH7 qӢ fՇTZ[N;Xr0kN"x &C+*ׁѮHc]5}sѢ/Wv.D[ʹEŖ{lPѮ; @W!ʤ?'Oj\x냃_OQ/cݛAw̌y}Fnȿ,hϵ1+Şx^ &_IkN}AILێdeh'F=?<]5߾963/$OMo$ؕ/ou㸡,aX/}&bnxx^#im,vkf_/v9ϪNZ5/&\Se IrQZ{v큣\,mph?E]>5sR[Ĵ%pɥuoՇȜni9 w̖;e"a*c|{N,#fʧ`jɸ473ݯ;K-wl7\Q jXrypw3CK8NO[i/W7>UWa9xǾXjpGHyU|zey[Zj{& $'233 oF}ٺM9nYugԥY=qH-Cr8IFڭd[̴=mUyG9 9p ɳ'-9,J^_/2yGIߓfWm6iF~:foԻh{D*ߖ2q1qKm_sE~K؝o >f;6c}S w;Lw>iDȧAs[z_z EA3ms xZ}i5N+{ۗHF{Dr-}MF{/s}k}'fJZ~DB~bM5bQ3/&O?hEW&:`܏f?c ;Xi>eŻm{6yA4~_Wsȵ)'[`peO! N\;NzgCvm2?wmvUl6ā75b;-9x7%OEh;kcAWmU5~k 3eQsEP귬h5w~".W:xnjy컹#+&~QTO@OLl5sFݝRhb=N`dC#NipR̓*aߓv5#Snms),lG;2[O\Ԗ]Jx7e/ڳ*iyYqX^C־O$ l9_piƢ9IGܘc}BEn|}{/*qtt[,p#-L}Oe A/vt~=U:f5sFU;gDݜk\Up﬋f mzfS4Ɓ/sn?+b-=Vlm$ra1>>EKv"- n؝]MoU?ji_O8~}eU3.6j/va픡άpJ]ʠ1߯n@KalCF{>mm<mmEm5%eCqC%]-={/oO vݷGr~Ճ;!7-|v!(ԲN*=lʯ+W6\hyfp=㌶1k=ٶwbw ]*w®,|a߮o<b؏7/>hհ^w.{'^xb'w^U+GE? *; HrʽJM9!5ju? xPz82iցQܶ0{Oҭ{kAN5ܺZ_[O?/#þ?ڎ(KQ}f=cD=o0m1yV]M1a|>*jj$(#WXUd)wcI$~* 5b οI &VAEMQ>au_ZQ[kJWWZrD\oEF{Lm;a${ύ/kG\I}X HLƈ/!oh@# ! ҇\ #QF^0G%nYwEHhG|@T#zO} 2`yDncN%4ڪbgy*m93̴ bu#??q ;Aݶ/z'zʹC]O}S༭#DmښYna0XYl]l˖5uZz;>==݌쳯Ⲹ%_2 #MSbX~koC.YtmFģ9c9#Gfyđe֡[%`09rOr:Imr7~wSK{bF;)9a"i?h=\1! s\};~ +6׭,- o}|kRjni[Ζ͇֜ٔk} Oc0 h6`hm]d[*rAiNq[$A״`0:+_К[/)Oyǔ(M޸hmUw?{|&}wSΦb-@;& Ch'nfh@|mmmmmmmmmmmt66Oq8h]ZZvo}dzQt5=fs&v3y<ѯ9w9"!@7D0hzmmmmmmmmЈd 85 Z  ! !v^1̲"]>be幾ws/wh@blwFg}ͶSqnEv53w-Xu3U22=3|Grswu'%%%%656djm3j7k*ߧ"d%2UsHtPPZ vnf-\E'CC<’hݵh~(3t"!G6dzQt5=m10D:CGeY%p#͚6"EFd=Z\=h^+wIGDm}[+$=m@gmmmmt>[6K'}8# ! !ڱUշWKgOx+.-qW}s~\!ڱX!S__Wmܾc67]|4]wy?:sއX_3Y暏vx5MM͍w7qǗ=N{ϯꆆ:qYe8>hDŽP4Bg}|->la䥇sCN%ayNaqsniׁ]鿌n!1۫>WUozjܯ6oiwo}U˕]#q>Oa!Q_J9/~n!4ynzn:9}юiEF5ŞV6y_s_.zQС>-8"׳UlUE J9cH}ͦ29QAUb~;2;GOOl[_by8{خVEzC 9gb>|h_*묆CWHF~xH}9w\P;Tgj.Pю 1X&e vY6DZn0)r=|_7X✯$R=Z[\g&:hīo3o/]/xΟyvVȑ#~>'d}?Eb9OH8r-g0ysn=p02Qw?.6/c5^[5Q՗# 2$s-az=Hs:ϳz0CxEh?]͵Vh?-%=5F/ ;#`|/, G9oG=jX1?-γo[Mo}Z[OXVTw͕syߖ(6+8.[OlV;bϗIh[ySiG0ޟƨd}sq%!GT?7m&g8/e+~ڵJ펏T: @O mߢHu>$h4ڏew<zG[g=`xzhhDg_;$B/nOMkoa=~#??ޟpLD;&:z_,* ^y0̴ ]H$ޟQkD/@CD;&:y>shDg_;/`M;"Fs Y.vtkھOaw nю^;s[ 9У6hhF6hhF6h]Ovii۽!# FhZ͙]tFlG;yXel.tCA #horhF6hhF6hhF6hhF6hhF6hhF6hhF6hhF6hhF6hhF6hhFhh@#G[ZVx Hp=2B6D7-޵&n"Ӟ鎙1'Mw]RRPRo( "A,6VJH}KAii~rm݅?\`*e+,8^y<%%vk.--p7D!(akGl]fϮE[;!xy,3/hf"G(i8DHhwxDr#rm:w D8~EB#tmmmmmmt6*6KѾND{" ! ! ! ! ! ! !1+k vOG`0b46f0 M Fhm D`h46f0F{kL2cdvQfIb`0f$bcD;Fho_Nt{-  fE3evU]o2]ju.ߞjFNHOm*aO ̴󳌬cla0p#\QAۘfm j YJhNb3m8,'DmښYna0G"F;L;d^aK$7UZp :Bk)vS.V؁[`0}?͞GsnFQhCE;hK\ VCh=Ev,nD<8v<z(G| !YY*ס[ 㑈z_NH ZFvH8xaGƎB #mA6hm`04Dh3 & CA{!CD ! ! ! ! ! ! ! ! ! ! ! !vA?AKJK{0ڥn7x<EWٳkn6gnwa?SНSsl.tCA #ݏ6mmmmmmmmmmm$b޼"h"v-3,.$\{[ZV/}l-AB+RD@_׃іuE[<`9&}ʌLUͷKdѮN7u^ř?$D$ߦ6gO4-PgA?4#o]EݖuLDžh;9OAii~/D[ܖ]=l96ֹ!jgvU[oK)7$($nw-ڥn\s;Zmk dzQt5=m1QW߃2>@dV3y㕬iHlQ.t5$6ڏ,@t-q,Dmqp>/whÑJm-G;QO !Hz9Σ z! ! ! ! ! ! ! ! ! ! ! ! ! ! ! W]s.OIbAܢTjzJhΰfޙ9]U۴La]˷9i--Szb2SnkJc/!GT6Y[B(v/}g;?c7qk[Oi(an-U 5WGt?IMV?;D:󶂎ZJ؛Gq4GRo"@%t}rɢh;7"yF_<z#7FbM[0'L$ #F;d-"pr{> stream xZM6 ϯ98dK600 Cz(zjn撿_iɡXd#DҞ 龞<`4/t?>.|׽sQE\߸M4qQ}O5wx=vO.Y>Nh)x`Ww1a=˰Y^.n_ӧpwzv|ަ%j 0>% DGX}P`t~.ZM#07`[;ksxb݊7# fsv DɤW!d8q'xl1I ӝ`bl|&:)Q+{hl_Gύ@JaCPgOr7oJ9%fny.\Rss?n%29Rb|\'rI}(% O٘( FO9u*hubƵ0o9;7JLUqS Ž|"Bsq#5cn\b#C5_b7'Ca1 ҮZ՟Odd\f:j#5=ytS$?rC(}1P} 9f֌y“Ze@&v 6=vSl#B%/!ӦpMhNPBz6]|8Lx2&l2HAeBy/nX8r:ٮP-@w-0f1D _ /Dκ- H--2Vn5lY8GjLlV=Dw` LSDJp=b(d3TfSgb" kwJ$[Dr-X- H%&T!j(BWꖋ R+g*De5Zr l(вNKRuJ}F%>L[ ND8 ,zy(bQi(p[ X@NJUBTb41mD)u*^R5aF3RGY$ە"@ȥǕ2$ZEm0.GC\|]9ƀ5YA.5QIj`ĸ\m`{ K-ǔ!RL 2^ImQdɤ-xN$cX^0S'QJ5aӸGYE#t *y%4D8-Ậߢ_G= ^ Pb/  MbP;eЗpQpfLI¥1+%k +|!i/CE?~޺)t_!܅{c@r~Q_#2L ]8vY᝺tI靺ԼH}<.UwSiĝz5M꾖 J rۆM*5eN endstream endobj 196 0 obj 2000 endobj 198 0 obj <> stream xVj0+tIڦ$-ͥьlD+Fћ7iZc 7N*@{a*M~E_藶d+~/G|G,NZx[=,VϭnY< _ru]6?jL uwV{;`k[]ls`& oXb.) {@Ea~.>e` `.E -nn4~3Nij"$%ɢ$K4͌qj1o=d1cMvĕPP3^>a1Ho i\F4W3)4>-IկH:]r3mɠ/.`JZ*Ym )AnRh)QyȌ(\5+M x"}7X TpP=nF@ٰ#69KUw]Nd@32l8:EЮY؋ޏ ָJ_8^ Z%qK?꺴ݪsg_nCֹLk(\.'5`c)ᎳxB~66T \bqRͪS5݃ >`twK,ct|XgFH/ثmf/PK/΁IXjy drރI bG endstream endobj 199 0 obj 725 endobj 201 0 obj <> stream xVKk@ WXg5,$ -C)mZJ\?-K3eӧOl4[:Mkt/W3;^ c2Ûi8?]K{{{^^Båy@/}WptjƝ<rܩ:=_eM.M]mSx`z_kZ/r3{j /mC(LlƄCN>| cSI0Kj㺞R#b\tb|,,Wcqgr)3fx@$_Or§HPBeO=ե8Uc:g.cwq2,ӅΉp ,1P-X)۩ Ŏ} 6p*qTTqjS3Sҝ:N,)ԫ]?t h weGwIbZ:1!?g'/##^@Džǎ9Vz|yFe>jĚc&};;sź.utTvPOT5 DWTS{ -4.;j*#b,(BG^a4a:3JcZx^8|p Vh`g^fjl7En2M&e LfWHj+z${1lB3 t$BFԹvVڭE\h9тja4m֚YÖ8+pʟ> stream xWKo0WgرE4J+q@P j/}WI{@zx<kvy,<W[ϙ 2oGlO[f3W[%yEL}.^y~7״LKBעerG f Ld枵r[)#`9L!>@z@ñiuō b̋6uI M΋ZA B҂w nOQ{CCfaah OEF{DK?K$teB_#.%ʄ Np iD˫+FAU 6 ̘Z#> stream x tT塨7pi=G[c- OD@(| Zy!jT) hSѮ1Đy{2L$Ξf&3o}k{?g2`,5Xh\[:"c^qXVnKnZrmE~4a.`&sNy9m^qWMsz2T\7re>㒒p?]:CIOUۏ'&и%nFjRW&Y. !"bAz yE.|gDjZᨼ*cF|NzSO^1ʈ[U+r/0\E4ӝ~g6c5YS );eEƅ_}6re5-2rAemoDDZG9ux{c*#{[ukUst ?v4qk' P:욼3.=xޏ+J?TmLP7_=֟깣Ϟ[ emSr6qZ>3IGj|~}ӟ6+wr_z=K[7n\_[^P~ǰ?Gb&n3j\LUc{Z(-܊O1[#kzݕ߯]yzEŔk78`pkʡpisբe{=x: ?fσٔ=Kq])Ku<}w^m}}13eyRfy`%V78Rܞvݜ3k~oWޙHϿSs|n|3(zw15Yt{#=k]{ͬ/.HNammCČ1=ܻ׸^=1VoMYyoȞSw\ўwu㪧wz ?R{ >i|fwT;ja(fٻbt?}RH-Z6'^7g٘yŪ瑤cg0P% ˌ?4 ٳOˡ?g-t#~0x9N]n5+V[nzˇǫ{ /nNW3w{XĒ +0@q}A,%6;q$8<\=_|{\m =/vߺЕ[1u.s9t;nW9ɞ_'r.Ϗ}$GhҐиFqO=RD;2ߏ?ŬsyF1u愿yb9y"n[Ě[Nι0}/~E3_άٱǵZPGwΖ5pqd:?ԣuWMrlܷ.2߽J꼸sW}+Y'_v#{>Fry|.z~J1J|n'v[8v|ی"6RxS} ޹w8Cmk#<,kA/Ĭ?IEj;dH)+nGz(\Uu: ;\CW߀Ƃ(`S& Oi٢\s{2lr-TϜoNp8aG|jLYU_}\\ܔ=6~n̅o諊=IzfO˞ˉ3o6{O{T_Zz w F]f sJԜ#fs+^6g^g)sjingw`ߩ>5$n8]123'/\1ݵzk͜{E{^5Ϭ[q?meϧyu==湝=tq'w^阕{n:`;[0jLbxϝhϟ^m+YK2e,huEw.{jce֜湔{WYޅtkS06wmP ZV EE/=nѹ\qUXK+oߒ$}?r{+{.ҭ>ݞtŮo>ncL1>|䇏y?}ͮѫ Gpul쒝fϯQ_/0$;(wn\$szfߚoO?[>{/^ğns5ط]wőebB4ČR`Lwd^O=vY^(2r\˦n|Ik-כӿfmhe*o.H~ŨksYSpMޱ+|cZ9g. )zhL~X>CݸcNAd_WOﳯ_2)^|;)rCQ\ l_y-s|: g5@fVͪ&+53'^5 K8X2ٹ\Mr_= ޫN88wL*WO8D=׋Z6v=vm׸9sjzg`ȟh/(hry_ޛsYgXG5',X଺g:Mp99k:sx\?itsu%*+Ʈ>>oTƼWNzz8ND!q;+y;/FQEO(˾U|i]vjɥ']W>ز)_. eޙKc0?TW{1O#`Q.<ɖ`yg_z~i1/L gc2W&ֳg}[1ʷ/:WZ|CX=W꿄HՕ*[3?8yn4h5˟pP8._IsX ҞmRi+68;f?3GH҃״+.l7uHŕȥb9ɘ(/WѸ: 3˘)[S)#p<5az~ˎP Ez.>cOKKPt sC\ļ-$LMMFy$LsQl֦h#%W1\V+*v9@z˒+͌;:b] sC竳cʸyQaz~z\)2׫K¿9@zT[1W+Uw|+Ls#@eO8Wχiϳ')@\k<E5yUX\ўWל{5 Q=w:.qz͹:"bT sQopKVǞ0=HWTvn&rz 0χ+qrUEg]Ӆ"桐_YRn|3WVs zܽ;ڱcl}W{_+.yUlkmlokh9z@GwwgwC]w+zns=HvM) =?z@9s=z@=z@9s=z@=z@9$ %$W'm)=z@9s=z@ =RCq2=H@9s=z@=z@s޿ 5$UIsA=z@9s=z@ =CR@{~2=H@9s=z@=zI $9@*z@=z@9s=zgO) ER=z@9s=z@ @9s=z@=z@9-z_,z z@9s=z@=z9 9s=z@=z@9s=z@=z@9s=z@=z@9s=z@=z@9s=z@=z@9s=z@=z@9s=z@ i=gDR=z@9s=z@=z޿ s=z@=z@9s=Hvs@=z@9s=z@Az8Yz29s=z@=z@9s=}>xk74 'sԡ;:ZC!0}:Zv\=--A1ӹ7Ls󎎖vss j075fb0=H?TEE[[1\<pY=yC3zd.K43p9wz/Ls~E2nz^Tv;vs1E\煅 sC V.h5Νo9@z.ZI\C9@zz.Z^"2n< /=H7= ݽ.2zkWsTzt \"Ӡ*OPzX=VO*?[=w;{ ]Q=--^h/zk_}}ExχsԢz.WU}u1](b Ŝ%%9@!z.9see`/y-ݻ?ڹ;}[>mm!z9""9""Q9"3NL3]zQ9"sDD=<Ҟ{eOk}\S1*1#~hEo"+؞uj ݁IVG0=&D;E #{ߦ~|.z.̷ZuR *}C M1yvww66AvI "blkmn Dx5=Ҟwvvtv#"bRhk >WzjڂvVlX.3V>cc[[s%꾚!./oXz{ f-j=칸yGɴ`Zj եm'r #7k|)655z}ܺ#d*z ss׬}#:12!gSruٳMW-y6EW ɲ1s6u$Ȕ2ۜemk//_}~iJ.-f-69l̍ckCL`qV'– b*ܶ:Rrs+Lٸ1mj9-q7{OsmEaLpd\ܺ#T5Xz=Sm|>TS7ݜ4vy^*v7N3#P!t;%Oa(@Ls\ϑjJjC^6 bӴt4q\]Y>Oz7ئD)l(utYM8G~q &"(66Ȝ @fh<ޘI5dǺ)Eds6 Co;\UAϭ;BL~]þ;&Smý1yju{̞& ~6H]pEc25J剑`]b{^qylu5Kk+pE`J.\hCθuIƶW=\[?=JO""@qd7lmu󀯲1Pr:;ۛ:;3ƮvČs|#؟؞#"bzJ#"A ""fϏ1=爈zH#"!=GDCz{BD2y2η "q9"bk\\e#"fQ9"szeOk}\S#V<{éQZ+Ɏ[XV>;Mp{`ſ?qz.v}m>= ĈĸH8;{H(ݷoWz.tٕbDb\wWmUOq|wDw= ŸHotk`wwW{kWcwƫ}WKr@;Z>1` QWyggGggvtk1uZ= ~g˖w<6V lkk5vؘBprCx?qL2ob7?9s#C|ŀ=W;Ksbx"׈Doy3w 5v57;-'fKwob8G9^zľ{[+Swcš:.v$OvGn5޶{C(9ON=*[[>ẁ}x堌77\s4lg}9W·#x+2D"=SWTh=cfx9ƘGg=O'A|pKٲ*U$NM)>^n]}5q46=^@}xwmc7Dͯcܴ62ib"EnNfÑk=]ϭWn5k&w[cxv>[ W2}mwY}toqp36:#'{`>&vz~֩2ou!;1Jt<+N֑Ob5! *EӦ&᪯oC}PO 1 Ɯmb(l7El1mg_}qsAJ4Uh`cwo7mNowv|j=76=>On2ao)Ij=o~A\rgW*KuwDwh=}LbDf~k/W2WU%{wnŸZB.;;d7`ڢ=; ϿRP^A[V~Yl}cyxGxWU*.E>_roh25ޡQ@uKholoH]]vG:;;BwD#"!=GDCzQ9"Z=7V$~̕NUq?}""";^o"(7I38as"W5-&<!q&A8)qK%$'!?T+O<%/1(gwP endstream endobj 207 0 obj 9666 endobj 209 0 obj <> stream xVߋ0 ~_,Nj/{{֍qؽߟ,ى&mo#qeI>ɟkPJiqt6_Շoi4靪8ЏM&,EE}ZĢϧɪ/L˃M_-`mTE=hnU4Gg4>mzfǏ`:h :y@,h@Fp,, ]ݫ{XwgJdftԿ͚NpX3h%2)@MDmy aj]=s==4'8$v5&¡\y9?.`&Xt|Jt('{ab׊]rk ˿$qҸ9'D2OqdA[#(v2>uX Cd.r鮵L(S?l2}SVcK\͂ B ys.\ͼH)Pq`'n'|Zߙ_@ߦfιLZ"3ijxq+Ò=ҷ ~X_`g endstream endobj 210 0 obj 760 endobj 212 0 obj <> stream xVKk0W/0 Bi)IKs<$Y7NSȊ4f曇d+0ƚҴEkW,[KrGb#ٌ*`7*ĿϏGov̑Trh~0~SqC7>cGw Ў% #B :B-+aZv"nPkp/ ^݅svt0xgi DFS+<;p7`= 䯓yU 6dŰI^\z(.STE4^檎0ʊ iN܌JuҹdV i ej&@얢ѴUCye( ~)=8.jH'ڬ4oJ YٽdTB\@z_ -:M)0xs3x̦d)HbT*%NwNa\,]`> DρhŭYUb#5*ijcԚS@&|-wRB/@^HbEG\l%urd΅^{]VB ' K^y^2ZCpJͨ61_+I5o5Đ*-B }Dn-]~so.$K.APrg(Vv,[R' 1JReRiˇcDH&]V5k7Ҫ>^ ^s?Z\~uZ`PR /JG endstream endobj 213 0 obj 794 endobj 215 0 obj <> stream xVKo@ +8GZ2OfҲliڦUj.3 в13_VAe0pOwJplKj?~"VOz.nMbRKuӟ1UjkW_zrPX݅Ͻ2uWp0 GՂH{x#hlϬ{eIvg@ g.@< q?/׏r6:f@z |H)=yD ,6FF9R:Ž'\`ȈR]H_w*Q`Jp9Ę3jtt9pdõp@Bf|cRL:qA@PFD qM{,s($vIhMC{F n|r0\MCKt'"$-PN Nngn_o&1h ݭQw4{FĜ )t6qѓ,Ap?WhĒc-wycB.f9MVeа X)1Ė\ga%G9}E[Sf{8.j;2,R|#noWjUPX䛖}EUSvh nlsi )->){]껩ui.Fx=T endstream endobj 216 0 obj 869 endobj 218 0 obj <> stream xWKo6W輀!)J c0CӶilѽw|IX$r8o2 ;?֐ێoGb-?U[iߗ_\sy~V q(,uM$3ϓ%D5SI 鎐Jxd}~PrUVQ)LD=ɺ27luz^x4ozR3i ] }8K 3h3NxD\_2UpiKmQRRqf)pzD }cMX6>ydj_BKQXhL<.O,HT(1Y]ILR 8ȴy+\Ѯ?8 ڃmxErGu*;IEU7~GGpHڀa:IS" b憧fwk#ȹ3< 66W'`Zbzm +30 x_-i|urN(#U/&>6U,`{?m?6L[PŅ:c}]nMKU^o:W܋ +>}1 ܵh 5cRcK:]bRŽc+1+g⹒gUoN95ߕӄעre税WKUUcUa_5 !Z^XK %{*Jhy?)f%g]XYfU;+5#W@FYɴ9v7KJc쭋Ue$Fk [h 99>z]1لcpouvUo7I슡""8nqܢaplV׳Dmz!5?74k endstream endobj 219 0 obj 1173 endobj 221 0 obj <> stream xYK6 ϯ9LDRd0Pf[ͥ|Hgvf7`.ZE~|?֎_#ʳMa>~%/o_{_{ìmڈOnyg="Puz{w_ZᴺU}T~mvBкFЭuZH:])e[YQWku+L4СɄAILﻵoSznS)8g q6% ^u QƼ^'L-h*:ހGgRG[,t&JQ88 sEw0o씱jÌ#Dž TPV9!5 Màdkج{})2K]_fpِ(l%)t |,@ \B[.ĮyC3D{(k-[!pJdɘPIzX-<`K~Yd8Pgx6~Kl!J1@oLȎ[#IY@:QX9(9Tg pʾ\ ny擛հDe954#.N&@D$ӌXiL\PC/"Iǐ̦h TD.KSX:z}lMBEaN5A<9$ugGvǧ4֢g.(`IX_ Q̪rRJRÐIP^jW !VHXlc_( jѲ>>x ^pmun4qhͫ¥3Zi@)|ʚҝHPۡD-ž_j\X JnPf0}Dr͢!5ܴ<Ͼ4.?*Yg&|U,|)n2^O"HbDnxcd[$ 7M>\P9j. FWF8 .s.P_Cghy_DAM + endstream endobj 222 0 obj 1229 endobj 224 0 obj <> stream xVM0We[CmZʦ%{Ȓ,'٤HhFzFoۜgC'5۷ۏFY~Wa^KGstyxl0BMƚMGE~5۩P|v풿 6Z6m^tdpܢI|Nf  imD74ܒF6/7_O Sk]N7` spbeoA&N0C^́"1ǁi(1Z'Ge\kV J u >o '4N +.)u+L)W P_bgRtqB#á YgUׇ=d Hvm :rjD.ShW ;,xYE$yu ƌuRFG9ʥ xjDz|b` 6W3elIA+\wQ(İm%1X L:a(+ s=,RqtXRE:Z)R\VO^g !ٗEl^iWdrP➝Vm9U#~-ܣH6}㥴+gp1ʔ endstream endobj 225 0 obj 643 endobj 226 0 obj <> stream x |xiyyUzyZZ/b5 B +"Aۏom}z}iǏUTV%@A$r%6Wȅ}g;3;{>f왳?3gx~ ZB>"g~"ЈǼdLJ"_#W= p+KZYIN270[,;cmMPW6CiuG UZR(2OUg~aJK[@/9kܿUrsٍo#@nC^Ss%3^YZag nxxިs*;N?+र'p8>rYw OŎ_io/n~.7K]ˇ]Ow=5ϵzَ4.nָ:z{YH_ N<2N/O~ᩓO35_e:ŧ3Q-&(f+'ng;:z+,c{kqN'8*K WNLLv!gϯj^W~1\+fؗN/z`n{?*z0xxNzfGiՎ앹ҪŕێUm)|v Dž0|ϰ<,ܹޖjy#{Ycs+fڗ6>rW;lb{wYckg^_6{rRWo`<'J(}o gZ+<{-QނohuS34'?r廟9x0q$y) ~rxsJ$i&qVt!eZV- T(y^?53oP9bFшZȬx9ьm'ٖ`Ԩ\ ᤲSxzzׂ)=xj͆1uӿs|w>7Tj|z0!_eNxn>ݑs:鯭>—|Z[>uO1}yvY̋xwgtyU,Nj9Կb}u*!g 8f](υn:+fs=>׹*ϑ/h Ly߳ϼ>W4L+?"[&:/#7JO?0b,<&SsůĿyflG<һ 96|Byy̜pco͜&g-ӊr6RoN_rIf.^w1Ϳby:gyk}4V A0YEuE}?}U]?\ycyn@9jW:]Ƚ6Ҋ. '1_U+J5׎ Q4ba/vL%“`~z OxHne<+a]ʊܿwٜX`,邓>w`~Ɵf;F$wȟ|\uߕp^8?裱|R=Cu5_#9ec㷇3x~S3Hoi`OÞ|1쁦9F,p<򑦑KG̝1r}K%gp؅2/ȼҗUG_-!J~gOaykQ}sp93íb}[XuVJPmu 0lECpZHub[R7eL}cm8ob&lwqtMӿFsWƉ?$Sx>3+<g^G#ʡg)g`l d~^xuaIubr_>u驩ל~XYcf}]ìkgi~}9ڳxۨU.t9o9G:F̃xf9y/}Oi`[MW=VW;//?b҅\qo_ǮZ[W\Bʛ輕>r@?&C- `n`\akv,~k6\/0]t>[ڑ>+/~٣:%$6Ի%s/@yyN"ǿG~F.~M=0"[I<(BjrDRxh,9=xҾ%̟=Hý?>з@]5vh,S[}p?--vo:un᫬ ӣ}59\cCdJ9Z3tje\xnJ鵯q9 n%;ǩƪ6i >| KN =)r,k_)s:8ac$'s_>yO`Ahd8 }}]==vgg"$rN9kkKsJCqNre]%_)]%gdj.'C;d8ω9[[ ++zӉx˼ a@1G9R ^1`νE;d8[Zr˜[ĸ]vyr&8k䬫58/H(, LaRT뙧P cπ,_nDYHWw/Ć/y6 C)<'V7)(ڕ5^svʱNRu J!JJb rxy+(yOLTD-LoϷSNp_'J'ь?!Ȱd99s8ySS9<с?Ts"\YF%m>47-s>gCϯxλ? -? 󼳳GS2 rwZ{B?- o=6@xx>Kyp\!"S_bƫDo:O0@49M'ݥsHrl`H:!RϻN8p΃߿i߾6xҍ'mg}~s.vtS˜`^epNv^;Mtv0SxAMjn:{پ3gCC pyJyxʦ}'x CŚihy,nCo.[CAŔ0s2E9wds8!p C)[9+BŔyNg{#xJ< 5W|NO{9Y( xJKds(F!b;u׽cnѓ62C 8G-4v!a>.2x͓׮uK-Xe!x]u923 t?4%e4sXhRyә첀09Uqߢj`G+n_J y~艁u? ܫߑZ:qjZy|PՊ < ey\=$O5<<׾σWL?;5a"F CɄ.[+_UW'ZCn~"(F痃dT9#ds(F!bPCŲsXyh7q9x&Jl!ȸ4xA)/.X9#ds(F!bPCϡ < X!(7SI}Q_cU{G=쿉sXqy)H&F(]NtwT 9/bp\: w d9Yσ w6qD{A_N)~V5L5%3xA<7OܶӖsHrMw^,WJ\Ԇ!ϝ$clB`[ (<;Om&t= M*'ph5ν9Y乑y I TW7s#k>xz';⳥BCŊJQds(F!bPCϡ < C1xA C5ߌhqRc shNT?>Pwʉ!fa SN-67(롡6Zo࠵tvJ,xA ߢ̿wbynT3^Qsސ3FSy57zg Y!(9!bPCϡ).!Ȩs(F!bPCϡ < C1xA+<טP59!蚳TNmǃ湍fDYj 7WNt!bœF}[W{>X= ;m7R/h,^T<dEEUȼ9/m@9~ Ufh]sX )\4|ϨHIXSFXyճ?/D$,V\sʾ-Gc[=jynu6!B5T14RxAx</7`\/9;s輊痃dT2kڜH's75ՁPT!bq'[[tePs C < /r;9sX 'Do>FQMr>qfz(sX睝Dw8jdR)L0xܔt<"xAxN3WWa\(BEjs2.<'9oڷ o%%==P9%"9pc0l#9}ځaN40 éaa85 0 Nx~( 0haS9 pjW~'?ߙ2./݇x0^:(%OΘ5­rXJFi^YqtOwsj"oK:gũsEy"zտo (L #N-T:ع)" [tS˭h͹PѓWks5MxEGw?z S\7?u~ E {;)ZěVwě2֌ot\3Mhk:oZ ?o8 Ϝ;s75ikmvM^7xܽqn;MyoopOOv5[[Jv+)p 7*v%5ߨ^[E7Qǫ#K6),lAVkYtSϷ==OGUo-SmfIx3T c0^Ɓ1RyƽMՖ@xuĨdS㕏w:LؑbO%d|Bze/gDZ^;a7rwwwt75;Mg,(!vJ߲!+%=O=CU@8n.[(<_vImj rK1V򼻸P/AFlyhA617^~+Gy&gZJcv+׀OsWW{{oz-{5[fuS1WWJI+)D¶@* oꩼ Xb ƫ74]vב*N\W -zo16WReQPBy]9RLs9;7 +,+};;Z.{m錗*O!ɰuY&oSv(}%[NQ6zCilW{ U;D8,i;t&śpB֋ǥt8 Y/x%%%䎎a 7񲠄[[oE$JeoQa[Cգ^% t@=!Qg޲\`T*> stream xVMk0W#d#wz(=ݖ$·,ɛu%2{YwFnVi{GWFlz~ nĐjFO{Pߛ .-fqݣS_ꈯ Ϊu{SM4G)*;pVxG$B 'xQ_$*^X'ؿz6`d/x0"$-[丈y[pT<]YJ%t QPi#+1J+ڪzLHq;65uT^ endstream endobj 230 0 obj 755 endobj 231 0 obj <> stream x xE;(*!"A$ `ܑ@ RQY*.P@ h\$!0} ߮#kgH}O?U=鷪ϴi31Č3ƼQlfN󎒙+Ԛceʷ.PYt/"r[s+ɅL`d`7>&y3FZ}R3 W nQiuֲO -Ym(睨7w+zd$/!W k[R 83R4dY풢!KF68DM$__7I D :3q,Kfخvx3Smr@̢<".nY5ͬ[:,@B-nĤ2(%G$?w$?"M@__ͼ2fn1Y |ȼ|^rq !|B@S3X9,,Odޑib,5M\# "UφD+Pr^)є4g*#C+H <Wʲ4 ?<%gh^k$.8⻴u)ʘUqOX=K[TQs O樺t.q! hU r~ Vp噺p:-%gʬu˽|-sHP,'PWQSzM=zk1 7?^ f,KcLCX4Ȳa%JE JDڥ&!o`僂[ -7fotaǾ5sUkVP˜f1=M$ϮY~!+c-]ۄAwshd4ok<Ú;Ky㔎<&dfEb:%0Qz Xnt u#Sû~l^Ҭ OuUVX6Y01]״Cc=Xe)M`+)/,F3Ko٭_뷘Q\5j r;P^06)w/7t=2PP7T4/P}4GrrTR/xlu{3ciLwX ,?NY̐eC^)K I MI%* C`3&\Tb𭤠#1C1׭uMՠZ {d,+Mݶ&wrEU Y1Ct#s̹.3g%;(2(vҀcßzz 2)˒E:h4.b}ziDLNq?Sò5>U|sSd<{Y,+xd7@9w>5!<}˲c=X~Y*C᲏Nª8+Ա}w@,G^{FAXsDE]FF0l@FY16?S}8G3]3g;gL]IbgTэ%,MŲ lk{?ܱ󊴛 ^3gYXMW6v@.C!񽃭Sy3)XVf* zzG /{N|)nKxՐDʲĦaK\X#6}E,{u>),s^Jgodֱɴ s(#ǒDCw?\kL4t29eRE%x Jh(@U3pSV,"_/^GyVw8oh>\aV布\p9sSvO.,9|9DD6 #+g |%F+cKWP \{\?Q[F-tPCKT+|T+g(('# g|J r'HĐX'r檾D.Q,/mn7ķ528`ur'=˰cPCE:M{d378Lr?ˤHr1a }\f3G`[`޹*׻L'MF7c<2Bb~SYS%V* х ,3uS,+MQz eU9eE=T(=fzΧjT<0Y~ۖTQj4d9 d.AA+wN/8AgjGe/}2NM{SGUõm!ϐKZZC#2wqGjCG (uz_r5G݃J4SްyM4B9E%K=:K7B|J5sNo>~G^tʲ d4-t}Vr5i7CW͂*fcM 4UVsj:LV|~,_3q䐜]6:*dx!&~>0@0?%8P{DSj݅͘( ]#ʌΥ>I ڻ~.}뙾o~xh"'9/ Yp{SSaEp|,,OP@Σut::}qX_艡Ό  1ߗi'.;_/ȸ̱ CXw"rYCܽ'Geo.{w8}:j8MiY?qn᪴WkM"Pj=7kY+g!DsQ,pVS5_^xYrL>ۯ۟|dyX61BYĸ6v:N6e;[a7Oi nAVE˱_hH=j61dy] "T?h5;`x@8CB`K~ž!0SN{_`&V&>f7lՑʼn੧;\\~LX=yR]qA4Y9n4Ӧ:f|#ss\9N9o U9@;kjwh`SVutOxD Xv,1OG ,C0vk-nr~2/ &P#[ l 0{ć$Fv;ɯȼ_My-1ucڴ2.ܽ̑Sz9ғz5qi[*a,W[RK&aCX6dK:6peY8")b3Qn='jL=o3Ŀ9aTxx8~C\:;2}&%Y&3Ls*]W>M_͸VkalmA w'Du{GWǎ?qxPǣ;=zz#A/;T_mbp{eYzXNX&KKyA \_bn=|?5Ə,_ mڅ[.)ReKy~JaT 6صXP+CV%:ͪfT|ʙ(X.eJ%YUL,% ^8bQ%4e'n6 5-v4J"t#CO jL ?'K) Y(H,'%a ,RQ%4-]egh"PB|сV%R(둍Ɍ%pqlkɝf%RQVS20ߖm(TeYJ,SOe)a2لeDY(TeYJ,SOe)1Le&Q42DY,߇PQ;&ZeK_j-X~,Q"VjĪ?b+B+AnV\(=e24GS Y'XajOEX.+cSSYdVr3򦌌9H-r}Krr2;v,kgǟ[7[F\O?,5|&.|O3sϣ+f˔eIC+| '~/DւB"kJ,La)ep>#{2ٿp<&;,7IcPS H/ݬL/_as8Zrc('\8n۽YNgq9Hp>Z ,YC.mUso..fֈ3U~h47, ;P_24~rzb`Kt%tfBpnx>OYcOc ,&WӧVJHի/!G[eY?^^nqZ~S08̙x}n u&bYoWC,kll_ A`K=u$:8 ucYv<ͲPl*v}{v XDŽxx>O};w_~>0'Y+>eRp__mۿ?f,Q, 䡸ԉ=t1JXfh|&5gI엃QHȗbk.,>"z,[F ';f kc-db:,T|_=960<_h_}!7oe{)^yK6cΚ_5oF0:, ލ/M;:BXpu-Mă+_>Wڰ~Q5Nݨ>^6Lȷ'Zt?3:, XQsiv`HX XF%MRL&c\Z~9+T@ƾ |2bsZ\`>4~E]xXԙ['"kNܨ>ވN1DKò?6k<.XPza22FX~1зn:iAA3 f-gږ6~Yj'Zo1,hECϷkW~$y,?$rŽE˓']11|xHkooАY /S%_o\_w U6|Zթ?W_hڳ$4`>oe~oX8ӄ1x.rf&ۻ7FDZqp䮮nj->ɆſKJz4FU|KS(> zaXMm>R ݵh^6?_ ;yWnƑg_(@bX`rv6/O R+*e38ȸLzNFeE\+gˈi @N{ͣ;)/w12y" Dރe~0m} _s fYZ(Re|,Ki}&EպE(TeYJ,SOe)'|0EͨQ' OiW0]oFY2ZIJ@1e!e* 28qӡ",RFY2̲A%f94'߳œذNNlddÅلi[PBR'}9ퟰuxUykd=|-/LͰ=25mYe+o[n:0YomB Z* y[|%9% y歑j R,죏$bƌi~?o,t~lT<].OS*3Yg~5Ajb#A7:z'=\R!{Dܰ4yk[a,7bΝqiTұFuznxP_Ml|VIwv:o!޲E+ Z၁ICR[6?viH<[9,dH= WWWC!8q{z!Y]w&$ dL7!AR?d,@I7/ɛ8v }5ٳqvP.Tұkg/&pTT &ܹ<,}>ӦCvt`NN,O }fc8[8дˋ/xӷ \5CmԸ6D=!OԨ#f>Xjj/H}BºmāڗI@keb!Zq7D?1e8? ZPI Ś 6e0)r +WjAO>ulVA?}dhZkϵ%yr]]N}vFxCRWW77=>DE4'K̛YY&fhi/{x 5«5566짟!Ї}uwdMG0b'N`j=5>6#"MhCׯ2={WKHm$@3#-=qj {oВiUoӉ2%iu3ofX}DKra! {)|hձ#jm^ ǟu΄dpb~0&Mѣ!YhiC48@^='}}qH9vR\#mE!Dmوga?ai(o:}S#.I3y}I21}|El1qbp+V*qlaMhfك`{&~j*e8j| NY?:v? >, /n=vZBIY9 6MHHoA? yY_5ebbwR Y&j{dy&Z21B45jFJXj2 HZFY2L2Le>Q42ČqpR%22DYʄEYګYtFB,Kiil,Kie*,Q'.,VLe>Q42DY,r2>Sv3Ԕk(%$~ Jˋ,ԩ5,2TEZڝȌX:EIj,KiePzpTPu;V^ʲfqCLߪ.(W^vr//2eY",ՂFZ]]-Vb(WA,Y/CFj-,+-.φr槶R4k`u(?/[aS^ʲf ,r*i*++.*QaʛmGʋsw82`Tb*q n0\y0;Gf6o5MŗŤ,Ki2T &]f2H 0nDYT,7X(&z2z$\S,Yv^RZa:;D! ߺ} ,uN%%,1[؝nU\w.ブ DW@3%2k`Y&SoA\ _iIxiOZXH1r+.4- $H5peŠR6CLZ^ʲf eVddga픗c%2k`٭ClUZfzWxy)R5ɑrQWP,ɩw槷R-rƽu=]z/.^<Q42DY(TL(TeYJ,SOe)y* p8YNnvX{U3 eY2c: ~ז:'2W7Zj:'2Nd\Ml7jjqP1扽p*KW6aw endstream endobj 232 0 obj 9286 endobj 234 0 obj <> stream xWKo8 W\` [P쩻EtW$$8D?~_j*JE*p-2e)gdEFcl0RhLLn,FvdI9 oRd6O22!Lnn*NPL:\% m~;6c'9)"v:G؎}M($>MI8QmL jG2XpM .(,s®Bq\,r6=C&(U7~q"Ĭ(qE`deDI2r b/Lj|0hk)/5!#CcH]![bq P1{.,2zAH#$񆱅6^&hSeD$#| 9mc( k[Ζd/+*JqY&~S /RJ7AډrEU5oC˶h3ĜHuKf) n&V;0.&Fռ 5`EIu`8G7O bU8|NoW8բ3vnW'OUd'=C7JLGfGc Ab˰%Gg@V!=w7VwXg:>-Ю8܋eD\91<_{?WJeZYp{i.ܽeor, endstream endobj 235 0 obj 1172 endobj 237 0 obj <> stream xXK6y*Il0~LCrhaiɲ$d/^~= tR_U}jwŸ^gg/?ߏ?){;wG1%/'T-E>f_3>NmA|o_G~xfC/[>k2*=tQ Q&=3݀?],MG3* W'9bǎ& V^ ]FMrkKh^׼w/09\e+>ʦX2V*wn|u0a\˧ŎhHW1];VhԎ/Ѣn xI`hld}D첫I>q AbRAt^txRlyLNdh@a:WdC3߿Q`,;i`Ie6~Q =eta,V᣼X$7Pfv,sƚ0kE=!bN$ګ+Ģr"a䊋$1r}HB[$ Uh1M6!O ̣xAMz.hQk ȴpwKķlIc2Q%փ$]Q@h57fT{C,&jG|uHWk=1u6G_Z2Hr&O/)6b"$yu|9"tAӇmO:LHZx˸ũ,& l VN {`W)I~I1>seyn*3 endstream endobj 238 0 obj 1375 endobj 240 0 obj <> stream xXK#7Wy^- LmCr00$%?Уn%L[J.ANu[C,=s}1B =?7n[>wo>j!|z|v_ .eX;]~>ql^pcsl^PTq.dy׽҃كW0lAH9 Y [W= ;6Ԡ®_?͐3 X>x @:, vgΞCˎ=p\xHõQ9 Kh2K@8@ % B4Ӽ#'K-lH뼂;zĄtM -G 19RLl hTJ9MIN.o\A֣#$ĦGpm븡"Dڊc2?04$hU2V}3 =0 f%}^Q=O3u*aW+ \:ڷj!G߳0f! af(x{R*߶*fE 9z*`@|HH'V nنQp-[B"Lzע(>|'q!V_ي޵"u˃ s$""(xYhtK"h%epahPlsBi| !>6c쇓T]_;phqDٍV=YtN>- D wB'W[ɬ3{Y``)v>?crYҢe'z*6EWfe\E8͚؆Ԍ̢kƂ:0wXg[YAS[Î@P@ OsvYRdttT4Ue! |܂%zI'!pȲ[EJI+ PrTA`\ٞٴjW1baxtO{XBY <  EQ-H0hƖ"[ WdJLWk@=]f!0;,ijUsV R s˒:c84eYT0!̥uw%>3FrxJTNCJfz~0q֬6=5L%L endstream endobj 241 0 obj 1220 endobj 243 0 obj <> stream xXM6W`T64q{6BNI&!$d/+$UI첐Ь+R}dVuw_lڸ'N+y?wviIkn׿g8-<cЫknux 9?l>Sx9/n{w1EO׼ X2,vf+! +ݎEѿ mdw@Η mJe/fr5Ʋ )d?PC..*v@3'MBoZKp ">uT"Dׯ*aXEa ( FP!0>`jB2sNHvFNtcw ¨9)/8ϓ' v*D?lF Q15G w STF@EP3rO6|xjY݈bM y\ GuඩťE$DRI L'S3]&@L&sHL!܊"2V툸u@Gw D!~,okEXXm2P?pRHu0f) &(w7JOb<|sĹdMY8y ٻq5Pvr 6N1j; JH/o%N!um6dk~*L,VBbҷЖ:r4%!lM=˲HR 3yaHXeA*IAR˅й[2»>,a9TUy%FϤ(Ȓ]X p*GX<&JL*{Uİ!a^dŀ oTipeGI 2̯ዌkK%!-P/ ob}=Jo; K؞4r:8%_d0I#N4zHJqBʨA$*Iߩnm`(/QinyF[3H˓QK=K9l-m+2;hoyƵ޳~^ha;:a]uytts+scye5$<.;&4*%3yQ7)͛ 9~&$ endstream endobj 244 0 obj 1347 endobj 246 0 obj <> stream xUK0Wf$Ɛ'@mR6-K~!Gg"='̿⯱fei[#|y2 0(\eIRF?R2vzogq~"*V%~^/7?H73o@{oNBUOQ'.Aiw~,_Ag[Y_agײnDB_}g+x|P(+Ǫ$"p"c=! qOq$j]c rGp#-zݤK%Upq{[s^چAJ9!vqnZ%Š5;q/5RM> stream xWKo0 W\ HI~IV N۲ah7Qdӯ= FRMOn ݻpe{fKCz/Y?/-QOWLX%>"_=|i t=r]UuGz<;B5 ߡakg }u)YX"򃬀E٠J9GQmY}>\KYֶh&9  Lq ҉!K&ZIoUYm`6@-+:"A7$؂dljΡ*DZH@Mqg R): #[xNglK:@X]NMtZ(+Z01@p9M/$KX+!: :a /b<OZ|n,vӉ\fK15(CǠx'{䶬6X;5 AbK9X;%Y xMii.oFڲ 4>*kI<(4?sUўӈq^#7zx5SI&K W6J {So iՠ  n⾡='j-&g]wv^q\o:T'K,N1b`*ZV64D2btix4,gQoW+u,ZCh@.^2̠CdGrwgZǩ#0:>ЧAM!FL_q0LeLvAo팪$^Es]' IݬTIQvU/q> stream xYK6W^e1lOCrh!dt%?U%enwgBvh#˥Tݼ1Nh|~5r4|@aI6¿޼|h?E_>Gs〭b_5; \?sL_"ε]0zqrTpA r|niFӌ?ŽrxPH &MfI'$Z>A5R|}MD%Zô:2"npPPy-x@;.!?7z ZcgBpPw0v d6i&!؆̤0J+8O&+'}'5{ps~_Ff^1օdqD\qaT/Z9OVWCT~ނɝmW:p޾ӭ~נa~{tpW8(]㲠w"Ԡr ta!k/;\4T-/u!U!!&w&*PBYOQIIrftSb5|F\@W"a[6R9ԂjFlhPUdC,8Y\rD(gs&Yae"dtEO~2C I5DBd)RףG't@}֜EuЉ$.S>= ME'RQ$*|iBI(zF̓;]Ŧu.lBHV:,^9+Xn]]jz D[)5oz]͉v'Hʋ#0{fS,]~X5(S1K5y#(ls :Ef_R+˟b92ƾWS4;l bfdlZjLZY洨E*T cn0"aiyq6aNa6RNGXdS +}md76Xy /[H 0-td-W`srΊ }πJuuQ2`ˮ}]v㴼>V{8~eG8\Іv{W)VZK8s74uy7nޣ5xF0u0~eVlhG[p&{l0آͯ{m> stream x XUU7pA[wFKk+1bM PQ@D$D U=׭ ؔ6__ӘLqL) ~(rk}>/9poukˊp'}g(sKb+* 5c>+\{B-5Ё"MM7n/_y,145Zh2ʗDp2@Gu|{e;ab X:l}-]O뭮u욶 Q@vZ Jz":^+D\z]f z]4lU2$ɱS'1Cɐ@Đ2ѱ~)2I0ew-\3ɅVse>i&AlAm[E`U*d0`UeS 療>i[Қ|Rڸf2* ,$(.4Zn6dI 3:.lI<ɠ}lDZ (ORV|V1%Y$hUJOL97mn=NSw!d<)TpuFe xD2_TjAS{YFI.4ꑈp@CJXX Md63o@?!j'\]QUnzsakn]6#F*J135KCՋOP>sL~ %^JxmRmӐeb)(i@"̀w!GrLzo=AN;Mײ^Zex>Uy~s~Sn"mV&}:ʄ8=Ic$k<ߙԐ>WtK5n>{/k7>Wƭ/ xPmqJ]k ]^ X-ZH ix)=Mߩ[Lo7vtiD+.oLf/dS?Q4`OK yֆ(I2'.ϭ=巾>ŭUlU <ޙq?O8v{Wkq+;(7.&nlVݮLo3n0R\nC.{vm&=Z>wZ8sE_.RJi -(=*9v䓂)or?4 =PDCn\y yђIY5K$M%-YuBpElhjȇ C?H Qg;U-ЕAoҐ[**0X+]]=K7$ot qA sҐڌkY7&GIGg=V/zP*^p_łOX!!II5x,(tvu]% :)wiDbowcwc)}fԇ<([aamv84&mtzrbdIe56q]ձ+=3Gn yw)2N# 9C_Iez5r`H +ʑf[M ;Ɔm2ZaHu]BI5Ksgu1*c.wGn|Ķ!ɹbh[H YKc6d}:wû7-=٤6;9Cgo5Qwles&>슷*6 ;l-A^q2@?!$u'MoL7Y[͎dRFw;j&wx͂!Y7r1jHʩ%)@d- F!s9OE~̐$7utyf{L-ѓvuCίGBX?O}C9w&('SeJg| v=Y,o3LmA2ebkgA[JįwuG"U&Τv)!'7$%jύ-Ix&~&vMm1{ԐJn$CxSaŦr|RpnF! ?x'h'QG}HVoNbRzh4 9F+'Y\XQ%N(slN$1.2A2e:d7\;ϗeh''f~Hm|F]v6+,ƴP6pIp>]M7yl_2Jrj@ IF!L[=lB}/IhȰ!j}Ԑ0F򏁋m\E80r:f)%w6-`s9^'&P29q)mWg:i~_~NBI(=Iq5ɡQ5kczLL6]jmY?ozG{ߵԐz.lHҙ7ww&sÞ./>튨#qe*M|hȽ:DOᇩ7|lӦQDISg\$ Za={z q21]JeZnlXBeX X*CdB+3o^:193uu+C3Kr/ם ʽ'ȐIrfCF#öy}71|-asKNf\%dtWV(5ZU5ʚoż!نL ›D5+o̺\4a[EEh;ޠQ{ڛ]>}[ e*6LKozQqGV0RwTyE!̤bz*ӈ$۾1-B]KOlX:јt'5W Qk®9wRCnjβ,Yb]K='46M>>Ґ#ޔu#YO2 㒥' J{zt[ trvbt{՞/#'|xu'OIN;麿s'N;rϡ; Uv42ddH>w&[O2\aspk6'x9FqF_㿤}nrzMU9M7CZ2 \WI4 ;k9dŻ{-wvJ5Ob; $rq+k5W.1N E|"}gR3uy|b)15VZ?W$"Y QZs@+x 248үZʅoC~#0,!=!1GߩA00` !-0` !-0` !-0` q!rR2Kh~'{^lvh ds VaeH9.5W08hLr IoB.CKv\2yXl_= v&magٲEKߢ}i))?pl۸ː6ΝލN}L;fкzsA-8l)a~ݩQ7ҭUίBvѶl)r1޳3{|b|-k7dh 9XCzB<ߐ8\r:rr %C,<{q=  !0$؃ wj`!!{`amȃŅF/7J )6ۻ!`j`H !0$`+~:cei-:""CGa߲q۸#c^\_// 3E Q UIغOm!pb қ:s!?%3yy}3lJչiZgC˗;[I*0$@T꠹4TXo$j83ŋ.^l\T_g:0W2$~>2hkknj4 q-0$}C4;ܚ]KHNLBZ(,RW.^i[[SSѤrhH'otfwK C 1ȁF5rfw0z$dۙ pϸrQWА}/8Uy)J\C[1cu%F*!2ҫŻ^o:2d_{zW.!)w:I;DVB,P_3aHz 3t"z) D;\.%u:!X_ &8:*P3R,v|G]/ 3h Ի푑ۋD krǝk8w]Fss]}V9А}Jۋ䓱a𻥯;q}aHC:\GnPVRS^ wsY.]@SSm]F>}UXBemH (qQ}%CN }\Hp."P%n"v7D;"X[khkGd9bXeYX_Z٬#rސ5gqi}yC^6}D4q-Od  6U]ic֤֔;4d+#"2#̆T֗ wlť!pf X44LMYJ60cǚqhP7ե1gÐ fZdj) ꢬ\!+W{y}aH|ȘOߏŕ  gN=~ԫI!pMjk]CG9)Gsx@[+wjm!y}a'Cw[/ ^^_e u-M /^G::ي/]lx{`jH<lC=`HdHfaE5P y޲dw8N*K~#w j:ut7?pOtt?QCްtޑ endstream endobj 256 0 obj 6655 endobj 254 0 obj <> stream x xSUڀoۿPtE\₲(Rl)ee- 㸍Ji_DPMF6&mӝ߹&Mo4%}{rss7$7o3aZGLW.,W̱H$^P`" eELa;Xa.@N ! ryHXfZN@ *}J\%!.c!G~0 s7gAq%Kx/\e"tAz s+t*cK{7c{s g SNR Џ6 Aރo1U*XU\YfxE楚h(岧JK Us"=X=lmqW|G΄F0*k/Qĝ_Sҭ"x-̠a?8Ɂo [h3~^TyjO6|ANuoԽ\qvbus1SK;M"n?Lpk O"oҫ6m,fsٵ ~%a0\¼Xl0+: ^" # Uv9T +jIJSgn2N_Wk__m^}yv|u,U 峑MCúD2LM3Ly&9Ys>d]^Z>ϬOTLT֖2q9n:~"{q}}N B*Hsy axo~K累,ּ8_2[&Vzj4Xb؊9"Ɯ!I"@OѯP+>_r8<I gIgJS9] *'?D+vEhRfn4 ~h8{YZ|nrIbXǠ=?oBhEG"qysJv\ڗ^묈rRK|LρEl~ÕxW$P98+Bmx' ~咉9Uz ?"h+%Fg+5X\_V쑃"gYETӫo6Pҳ0-lM◆}JSOcߏ hDZ1Yդ ˋy(E*MP{ᇙwWŌ/?zԷ)\VX]^/ފXҐ؜EFH"6qpт"`6/[t3%zbڈ>zn~~?6qVt'Eh7-վ<_I;ApwVM*zDE=3MDWtghvאp"a"䫛Es:0՟lpN7wy6ΝЧ,$ysuZ~"Sfw۬w90 A-b_ Az-1]Ëx`xciWĩg;2nw(fY}{#dFs#ڐMx&(BBr"8Klc΍WҬ0;nE4$UFs5?di28~n\t5:,ΰ?-`Iw {iΖӅm*& [fyV8fw[ʄ6Rgs}ւucp_ZH iTEY]7W|ڹY T{*.U[UѷU^8uGE-Њ"cf+a om 3P!Q%X5{fkѾINviEhy:fŌ 'C"UEQHZ eD"Zر.v`h,c3|||QM[ha6Nut&tĻ~ WMǬKRz)͗ ca=Dv ']lJMǼAv Ҩ}V Rs"!\O߫|VN rФĩcfX1N\hgܤA9 O >"&VKPt C[b:qqq /]JK@PB3uIf?;xFn̿'!מ#¡Pa-*t~TX~4lGV.|ia#ߦӁ9s-VS5\ Tfi+NƘ#Wl*cP, ?vaEzE i-'ICuQת&^u&RM|hT;[#7 Z ^Y yV xN7`~ЕTWV`m Inmp̒_Æ9&HyB|аOÖ@!z={ϯ.w:cyv//,uN{dm1[aEnhC V_}+OP.\}ལ|;zȾ?dt8~< 'sm̼L1u#afTG,hEcW3,) O"]F!V8b7ߥ"L@YF~ LD 7;-DZńNJf<*"RJZ[~yHStF/`h |dh9,QW Baƕ0ÿb|@#AD@E "Pt|q.T nAE "bT ." }Yo|vACE /ꃊX100)VTF*C$P" TH\ n[oIQWl^#ƧEE``\a*-L"g`A$d>qTnn\}qykE}8EaSW%ip'K"eյYk e@2$gʈ dKd \ yvMV˳\IV,Yj5MJ7EoF6*HtxWv4E)ҦCϓ Vmq9{)>< \kADZ@Ӟx5A]cMFFy_H)t|_cOp+,CYzH D] >_":QV vt\ R,gN6|w3E jA +biPREcoCO쁓_@P{{~gF~UŠrL\J/d9QwGU)]ήik>ߗY{JGLKFvVTrj{ C+Sk;gL?uu(AI_RmZ4zSVЋ47zMKܓZMLrOaMFFyQDַChB:/ ]6RO4)Ub1&2b"r-\anZ$[ӝ55FAV)J1ILGUK*o "\ŧEE =Ğ2oaLԷ;1 JLTWX)hAISH" S!e\Vi}QH)_ljAPU("p+bhT 4e؋M?6kJeU12^_r[v")c4 `$\ :/% Hk\EE =DQ~vhG?]%/(/,ĕ ,BN֑#PZ:닊@zR]֦}/0ĕ,W쬨Ԅ"p_u?c7^_D!&}II^kM F[McC/l=;65Z,զ/*AP@AP@D^̍RY**O; S}dܒ>;^lZN權"//Al-/}~x^\zeLOvGAw?Q endstream endobj 257 0 obj 7754 endobj 259 0 obj <> stream xWKo8W\.9$E0ر ۴(."%Q 058*O$H:Z}މҵDNJdd;~o;ǁ~<q[p>`/{#.;tQ%rܶ􀻇; )nNz^Uzjv'n>F)X>|C:ň6ŧ;^Ws,-O?K"M2J{%'0 .G7|H>Xڷj (kֺ @=g}૊_D@Rܐ8}Rc@N=#ptFѭ~sBT!sjD[[Qd"4 ^'Z8`Ǡ]3'9W[IK ׻4sU[ ܆́*emep}nM6CyȽQrKPIz}e"IJJPSS}|  g2+)]ocG/XC J6z"[0;کRI$:1CȒm,V~Z'ppY''hPMsu*~OvEW}LgZx$^/;s޷QÊQf]Ag$=׶&:M̂]wJ$`'Y;:˜M( 㢁@OkVnZ o4tmfj vA֋i*E Iͱ Kiln#E *1$Ñ^ַE( TAÞZx#KRfRC羄"$.RtsU+o)I|_ʈ~2.YV=WZ7̕EY_S_OZ'k\uLrf$a_3Mj/Q8Yh Qա5&z$QǸd5:7hhdzsj䳩$dSIfC JͰ,8f `~5]o<ykȽ 0 endstream endobj 260 0 obj 1132 endobj 261 0 obj <> stream x tU<}32 .cpA m"%aQ e1 *.O8hdq#BCHBe%;d!޺U՝N'UNUuv}mnڑsqܬ2J.,-#&nN,W |:e曁QI<@ ?A%*I2Ah*He yК!w)׿}ӛ=-Jx'm*)!̮ࢎsVN;=Rb%%YWQԫ=@_%$|k(,"q3HI0I2fQJ bt9taψKĥN t*UF+RZ:\'(D 6T)Rt'1'\.2[(p„v߃K%%dvA?QuW6t[&CMGwՒqE#~q;u ;riCJ)%eO^Do}ҥԖ̙QWY m;rnCr~@z5o>SQُ7׽J^MrK-/&/4O4oZ3ǘgX>r s&]kڝv_zA{ҳH/~.S?%/_be/xNrk >{{{--t0z 0nuY?rӨK-//9ɻ ߫{~cM++-XnS >f^;߸j!yzQeNӻ.K ĥ9hu)?7@a.í<&7l5>ƭUd}tzkW)aKFޥE?|vկڐly sV67,fX>=P`l霻s~ԥRKoХGK=~roIH)%in.}cE;Vy3q..=Դjf[k~- jZ3ߴrayl**[1>R"Jfy|mإT{H8_jwʕ.}Wj1;:;=K! ;_YTRcrlկ?EzxN\8|RyKfq<֑KL栗Mo;ϣT}̴$$$;&ҿw$?`Kޏ>ya1GcCamzgLa9nDI*wU3n*UQ5u}ԜK%ӷ]Izv*4HcmLK#w)y ->0uns p KY]j~~$QSlI ZE{CcGݒ7/Jp=]WN;͢KuMmHvBti U%jnI>?ulZūGl}AǶgK rGZeR|qJv9ZgbN) 8Hi&fT*ƛΧy̴fq,CʌnTTS{]#sեk:j7u)*)TwJ\꜎eZu^.m/Ҵn$O{Mww qimBdϰdف<#[`_tא#J&|mh s|S0.r6̯rΈ\ ˳n5$d)R5/}?նx15sO7kLI_6YRamY73^c|ƈ)#2J]Y̍-_: _~KWn ;{~ mrq .P{}6.fg'/%/5%^"F~KB]qΰ3E)ˌ#1_579Wx5|ŧ8!:fn\6[ßγ^tUa:%Giц'mZ=TiLXEԔpi㌫WWL`_uurn\)u_J\zm.,qiܥ^\2_J P&o`1_w .oYأn.LZXiz6Z=3DiBVDNNam^w}b3Qoa5YzX?|kƔĢUV.dZ̳G2^Q9*Kufnbԥ<.!ĥ j߷ Xn.Әx%|N63EEe}&.(,nNZ{95׼G±W[.>~ [SX'ga"6oX]0l_IVTc2sȊHòƕqV.дd9zwyC E .%ީRA.',l]wP{J2hȒOPw2 tPu En .z鋰E4Uayl^7lCz{Ҝ}{./v&z%o3FT:&f!C1], dHFMh&nCהϻ2Aò)׌2-әgN*vN}ɉq3oH]:jt~K!Bߺl뗍}>!c |a@r;[mPb+ܒ=ԱOT|oS̻<k^$RzB3]vC:ݼa0]D޽֙R-ͷͭm 3_7x6fko| vi: xuIFϑ+X0eTKKt'"MI,U5j=Zb.5LĽa_"@\z_c__֛W\&t)q3a˪>YMYfM**[c0aojZ\$/<:2Ɩ!zˏ]b{u~~/ g,gۼ#=߰YZl+ ڻ>$"_Y02q!~CcMf;2Z2'RsȰB2n@]:IFD]kR"ŭot \>hU¯8x`_IR!sF%>,s驨OOߖ$U:҄9es(OU9kdeܵWb.0c>\tJ\.e:.]>pE'=*R;:שN<Rz):5vrs}C'\4ړHݲQs;*;[[ r[/~/?ѿ˶!_D"K❷gysΛ|q}Uyo7Rɥ1tQvP2Vt2BS:axu(z),m;M}4F .|=>A[Uٵ{9d˗S/dr(d"0#?MUKNK/DD  ]Q%ӧKsBxr\<%#+M()2RRKaf2F~)ӬGTspIlNiYT]R<\*Ƈb9yD:.u1p)].)$CڞAuRϯ¥..ϥ5tn e'N_D8q*1xwT: JO $gR \6p)@sz x4Ҁ\ K>p). xKʥEX<ԥKwK@=p).K({NsRP\ K@=p)GR@nn@- 6~Roē.v]h\ 6:v*<}9YG۾nsuv%@s|7\ 4. KH˪.4^+R%Z#Dz&[P8}.$*t*M¥@s.4m.Mz)wSizM20w1ucFa+'Tmbo~BZ=)aBwjΑ*T c4Cn=90TK]2kO.5W=Ҟ?/[ \*W%ңFyJ*CiK>51E槧O %,KG'iB'aoX/2Z| jxix+Χo:wHdnquΗPmx 6~y{v٫p) xӥuݦ,DQ?O,\ ;EpӲtzJr:\ ƫ.Mʴ)J$"ƴd2cUȖ%]\$jANj.Lz%ʔ *YWĶ_ "xSFը=QL x3wٓKtMAŋ.I{}'VT"[ւ1> ]f[NkON|P/;jS"-kOx<1p) \ >p)  "OAP|zRP\ K@=p)win8\ .zݥ^?-/|[H?'e|kq0vKKR_\_BR"=..hR \ f$qRk7t\g q {^lݦ^-8i4'>7ZKs\R43:#ԭqH!Ge6NO!RƥtHh.MI̒6 fG:;-φqR_4-?bG([O+ZJ]\8e9vcR VPwNy:?$Mೡ.N>F#o t툖R^b^6b;@[.~R#R %|6\L v~/;)ZJJTKKG~qPB_.u=\{-n7gq!pLˉSqRKݖ47]{9lm/EI-φN۷8ml)r RlpR׊VPwSGD'OKͅ*|6ŵ;m{Xj l*NNrRTUB3*vY .ug^}I[ gZܐ@riWSR \ $6pC KKR_H]z \K%p/$8] \-/|[w)p). p).zRPHRP\ K@=p)GpR7J$nVݓK \3p).(\:(.FIR \ g+K>TZ(.}HBS~0].3X60e2K ?CĒR;Lj–OiV_@Bzh_t;zԫdWR(;} : |:FRڒ R_ {!4r Ӝε47":[WK -ε;45V4x [Z[yƆr'.n\¥x-lԖw91BA {RIS{4~ӖU2.UQ_~<6--.3n!$=*5;Q\';W:m9v4+$\;'|GFsٳ*SSR\UiUHE*\:h4\ [`nJ R +)st GūT__g=%fl|Vv"n/&R stTjF>CMTn.ZED9_d68qi?K6T Vr;ٸ]b iWwݥM}R? [C.30HGvdrydox\㹶3A^_R?p).cfN=\,^'w%ObvSKWn!z#toh%KI.U.ڴ~ o8WEEwQ~%}p}]u/荦 |Zph.V֥-Qdž;4 %jӅjRO ~.ZIkӸ|<>WW[#?/ endstream endobj 262 0 obj 8510 endobj 264 0 obj <> stream xVKo0Wq,EM+J*N@Agd[z@hę73߬lM{e6Xz_w ސco%1%U[yxEXyѵˏ^ lc]{| Lǯͱ@![{p0]h\a,'֍''zʑEʁʁX\vmo("كxm>CŒcdLYL( +p?bu7p|rSZI VK&KM}}4ފPz0@Ȯp9G?Txe> z*> " Pj)c;nsIOf0  bکA^yZɯ*RN=F %S)DT(sQ[= endstream endobj 265 0 obj 978 endobj 267 0 obj <> stream xXKFW`oW?eِ 9,9%%=$a4RuWWU_Q^[,^c |ugZvx~Zw6^?YJwol^x`4poQp}w^QCu{rTz0G+ {}T'$ OQ$$a+4ܰ7\hGi} jQÏB1*}p)FDav hDc+6:Ra [R­ GFLAV N\.: ;k/ɣ5+^:Yb+础ć2vX.9;d-W{'#|l,T+d1[⿾T݌ mB0RTEn)+||:|憈 A6S^as%jx~[px yR<5?׾Fu쳀3\ q"{`Q)'n9SG/ose ,5G`?Pl3f2SQr3\Q)*=}!ŵX XcBp D.Recf:t>Өk(YvIsEFG6ڽ;*M"N7*SiJ[ Xfs2U8%wCm C6QrWZYC t9 ~+xj\2yƱ)nG^Q:>Ŷ]8S5*AgVwk.x:wp E4mXEź"t7e0xXXxzeF|,P0ؔ!PT=Y|cx,@!^+^pe,vyș6*Ȋ(V@|s2odpf6o>;I֠2@]+,xBҒGNN1u3l cOCp>^9X(SI5c S]TR˭U.,_gFF5](NwY*~(ѵ^6ӕ¹/P-C_ZMl%Y,(B8"VjXhzja"[Q/ KY"4@K(uw(mUS[nF[|vh}im:$׳Sp) gYFpdrƑXYUOxUc M FKPPH|SN ^lO8Ȫ8~j˟=o/cOA]>r /'VjgfhouP5cTx.r0g֘K"Y-o3<>t*um4M endstream endobj 268 0 obj 1418 endobj 270 0 obj <> stream xVK@ WH3BSm)-K~5x,BxYFO4cxzϷ击ge}+lmH﵈ }+)~Kx#"Zܿ{ue|KygW[Gx.8]~Gzzl Ak>ak|YB,q,y/o@a "lT%geۜ[)GU۲t~۪fM x(.R=@$ATNd>")mZqbLF Dmo.4_34"o&pj | l֌a&1Ť_khTN^mNT^y,}iV^ay譥1v@µv* endstream endobj 271 0 obj 834 endobj 273 0 obj <> stream xɎ0y-H-M%T 1g&@ۖ`wƚeB{|)C%ۂ#4dų}6+"`Emŭ7暶c-`yv7ǛB{TtZoD)UyXl]@ck`c2BQ ^ -6 1*}<aYcG1딖%=xHet#vL d.(mV1"bT#ksg| `!߆PUKxF>'dB+A4W2Ξ?b0&> ֓G#{~ȈBLS՗DT Q gDZ-ډ^;X1*w4^F%R 0o5HUTEH>@ꩁ Y1ʐ1t(T8ei5i6&\Nj mfW `m75R-ļP$. cF5[:9)KeWUGaH9!&-ISA4K?VQ=E ȴjd]xJyt(qp0o\綧~Sk_$ #a`1@r/[Ow #vŖrOk''BJ 9[h{y}FVD'vZړs1uGXQno=;kjVi]rt1_Rd;հ;:\.Sr/ݨT_QJvPKts^x_>oj@Zi2BQ+=g\u\sF?k`ظTxe)# V DފފEt-۴ʉ%#7O{^s9'pr]/4 w.Ӻ?CG3cG` endstream endobj 274 0 obj 968 endobj 276 0 obj <> stream x tTEoס5O (0 Fp AbB0!$A0C3 w<,FDcHB;=+w}u.u{KBwI?ͽuVWWWw)L&1aY^3A̴KH3 9ERfOLYg"^*ܡjj2ҟEazvCn.fj`Qr hsFwM}hi6eS8e>7B ӖPI ^]H0Y0xrr H  xd(L=Ac[,&AH4`M'W :D1Q^ fE賦 a^YgmN]{ Zu_6WRw|ObO|W\#Y~.].%ӢJ )@)9j&8 ,yb(EÄ*6BR^DZZv鐢 A /afPq登A0=QŜ$*8T'JH\QAFtخU'l7j+mE,}lr` @w~mCs <2c@<ш%)rtFU6}[iI7Fµ k^ ,R/ })j*|TɔaQO$lQB0}xXA`@@2 a `aZk_݊חoI.s 6ׯK&N==acG$&h70{ |7^ee˷m*o^uCbf]k+&=P(qb${Bxʄ`x0]?m+>XWj $^[lH[3[4Sbpq93F{N0VgV^d}Ef}QLޥe!{:]&*z)}jH$*_[9rWѭ&ig$9 O<<#mѫCvׅ@TKkbmT0xkBkk=#0롲ѪGsGx^%A!RC?/Df,(x`ƀ-`Wf?Զ騮3Fsu;w!+S@ `Ye#T| .Jt<m\DI*ObtETTuFj>ع>oͪZt E=ȝ"2p2*:\g[%D ^"L/P:}D>Iī!rЭҮe&! gQ~ #g84n"FC< ѝPrj_|lS7Wcpկ2 U~ ޯd1Y1c^˖)AbqZŲ}E(Ո~Zȩq f!lh&o.t.OT`e9t#~<' 2W bO9--B>،rpG嫬>j)efI+#֙!%{Pe?E׊"+3VR9s /GtC*?GgͺW~zSɁa9L` !Z࡝aLo/6}̦6'rv'7nƉwr=K@8=GnHy&VI*%cY>mJ5/k?;]Z&[9#ّh \`OTNfLNƖb5<BNv,/:oiQ\~dF_aJi^1Y)!YS8E*@P 唡e,{^bC)AeO>&"1.=xH<C< m`{'?0Ig;ƽ0;:+ ļs])FCd$aѶAh.,aGAd}L !_ou:zQ)PCfWXG*{h}tm99 F-]Vs|'J-_Ȧ,[oԯ\6J;`(^&6P$P}V;Nx~ᣆ9`` >4ҋ\ ! `jYmNߵSp9A8]|,Y٘JP̕Od q_QWg?~R*_5׿teѣ5Q#4ô3ֆߦ4@5̾z ) Cb%H8KMx ^i'[?*ڪά2ʜt"dbŴfO{9SO'^-O1^G3Lf7 CE`/jN:c؂-A7ܡ~S Q_>r1czc;yL67mϑ>8Q!ɌaL&X=IxY+ =ʰ|nrЭL\nGyM*v')9i|!w6z* @U HB~D erzbSŃW*TVL@13kf_)T*(TnnA8´$-FEb6Pν+eiFo\A7Ŧ0ȋG=&0q\oJ7t^j0"9/Q#gХB 'rOr<|GY'fI~mkۇ/9 b;#RBFl}k1,hL@qrLOꂇ}*` U9>_Pz圪 TRpR yGMs&(DWFlf&G޸qAMA+!ͽ'nR_ ި@]O7&7h6M3_(>y ߷Ao(6 0eǪb D;;;@^|vS Ϡ$0fwP kiC.<(J w{Q/;hЀתˡUCKKsKK${[S|W$/< ~U>|^-2A|Q? Ҡ+ e6y󀻦ι*"C;BBv ?$C?ԙ xzk@CSykl:Qv3!/qGְH4^a y b@A/;hz}to}{kqRQHG'q^tР:|IdfQ 0Q4h@VTj@NSmDaQHvbyRWW<%3A;򈔼!![g]Uގ &9 <8hЀz<(kkALlXy0؛58zc}A-XG 3ܢ@}5Cg֤66T⡛Qow=?ݲ:^P`ŠWʛ_TT)kMUM5-MZ{QmmMy&/O҈R4h֖ښp3^rИ.> stream x xE;ɛ0ot=XT"x(1!B8C@bD0C>V]waU}|F¥"+LE95Oz23̐I뮩㗪Ꞧ1E I0"q3%ş LeY:p+26b 0(3l=|PAp@^jE&9%`e>{U{T|*ÆDß[[@:ZjvLMb:~*Q=2Rmh|x82a@<' |7 {͵;V_v»+;W-`VySǬ2qyAnKL@)oBV}ݴ/?.۴J?>%kޙKINz=d)>w/Z0OkZZ" ,2S03I1~IPoKxvts0>p3!S],0rg[?4~°.AbݻڷfkfhCS rgNxxJ& yxfb`73"TELϲ )j J6iz٦e.A1+gkGCU'(U5?/-5cB> C2UFD lEߔz}X]S$^[+,[v!I}˛3pe7]6A! # T ƃ 3K?]4v>|5 %{DBL|.ep/o|ln;* *6A{dn#Ԓ8A;V h VNY/Zdxi؈BGA·'2DC5 @a 烕|]ٳ|PVDeM2(_fW!DnM&3y6q ,2>VHi'>q/fYއf[CW O莨Zr2l۪Kx1tws5+:X|vLJ*:Ta+:.Ⱥ$D%B珃t|X9h"KAGS }䵡9S}?"FE>c/pHcZ3+")l;QjV Eǔr|O؉cﷲ(),I2h%S>eIa|Ր`|>߸.>|GR2v܇;2#E08/D>D >[b%O/w9uf_. v֬Ñ8k^6kaʄ15)#ކ z::g("<Yʼ겭|3WU~JU*kO^,&h"4 b:n]TS}0)L! ``1=2om99C~le?>W[';(2|fNn}&Oy\߽m NDd`&=~4v6:RgT C&J,ƇSlYOX\qH th`Ͳia_Ǝ-\_M4 ߥ<}'!@Z|M ͖B[{μ~<71Z21M<-IHއͼd16r ˟)ٹ`|&>K#tBkк HNk Ji]0lBƪ)<ZJQ4Y/^2Y!Mb?ݢ O[{M]W|RF>@c%^|8~S'Ǒ|l=pHhn):֌D f-IڼWpOgp)D dcvCWN>væЧyoL(#}g|4r*b*lzT/+yYf aj R|!{Y+~JH3}&9HG|-}Kc\zEŤI˘蕉C2'<3ၜWwKw_WFz|?npIC%Xɍd9o+lNqk*r3 ]F{ߍ绑ԀKy׏ܙl TxexN@X# UZhk3٠27 \1961&6zߦ `Mp8; WЃ5~ LG^/Q,_3;f_2E B"p>C_S(DAO}F>8Ն2Ph CG||MHs>JI-|x@}>lP*h8D_+ltb+% N!a~۽Q@G‽> !`Ҁq/9Շ?+P7.Cdm.F)Ye6ɂ/H.-'`tnHp).bv>(> m҃'6rBdJ.߶h`ʇ.[eN۝f;"ӰoYhõ])IKI`Uv rRfQ^Y:ჳqmWJ3>t34t-tćn'(tC_ ~GQ#e>Pz@!=@D>j߷;\lMJ6o.iOI&tJ_^oRH($|>PHz. f=!}^{ASzB^٬ ?]=v:C;V[A-#PbY]2^v!\^ z&ט`dWn؄yi9iY  fꃻ&Ȑ~4i~&>r\z :;tMSvI>>qe$Z0\g -O!ˠ,onII[\!xgW p=@>l 6o ƽ7a_Hh+=^ Qzb6}xے̢W.AcNgG.1X ד_d09>GqB_|m)3}AJ aĐc7!v/%jr'a=:a@j SE拥Z1̦KE}Zt: dH=Wn52j9p8tl'1z䷞8DmR#99EHOִ\ AO٭?*ZR.6:WgzX rכ6f58'ma;>XN'6G BsJ ]k ȱ>Bz09d@}pu^|)Bq:ݓL8r|)7zk^l:~ݑ9@?d8pᇴj35eLW?_#z4#ȐDuuԇJ7q'(=B,@!|G}P(b.Ufɇ&}pT\!BE BYU ;3=pN鍋P/]/\'|L4%k~;4j3.=|Se}Ɖ|)ܩ)AnK_o| oUh;yԫP닞0 hiizUv{|Qhrj* P>^߮X44՘* > >ty9>,5n@]]hԕ:ᶫoޖ-y=P_N|̫%o[OeHlc1OZWg2U>tlaiM6-YBn d6_vSX%n‘n*1UUzء]/x=dBH]_~{=n!g1 GitTVVG>tY[l;wk ?^߲uܚE%A-`}Hnԗx>>9KF`(P"Hw.1Zȁ]/ L!6xA퐹%l(%M}C%PSS!96"xa2[ɨ.(7ХڨoY'm!m(q\߮ ,)Ll"&{cPlY]%IL&SYyZַ]pHqmVXHT,>0&Sdo`7fsВL S@.2cs #I2ZtC*,KwSZjW**Z-7HZ_i¶SH8D!IeFFYЇח q_&. /lMA2VHZ߮ TVN};as6peЕJ)EweFѨ TAz6*Jx};ƥυҢ%7r`/*̼v5ȉP׷>Kqb7Rs3z;9gsN9z$8qc§j}\O5n<Ჿ_m׷冂in9U75V76*ov{C} :Ž>PH~([5l @|x-, {"!K&vw[H2[^V F|oQoD>ܳ}R(,L endstream endobj 278 0 obj 6633 endobj 280 0 obj <> stream xZKo697)`[==M"w|iEiN0%pg|ǦZCOu?ڨ>ѮG󆮏dC cd-ޟ7o8wgilukm=|jaBn߆D󮇽)Q~S1|Ger{)[voX)h ]Q" y^ קPW )5Ćܶ'HYm"Q]&SP!L&'12ܧ+>'*mQ] 2RFِb*mMK[$51U e]Eay IџM+#vvI % p.ȱpH>Yx:gh}rc_pgH)S >*gu=')f__[i2:}cyjy+P@*}ǫ`EpkW%h1QL ׶2UV3_FV,>Aőt3UirΈBG|2VT=v\pBځHЬ(x9g.wCj_%m" wk A8Jaɘ c%%9ojlLl2h7\K9U:\r|h!>T% xy  O Rb0O1KFHfrWg!J8JYѼ~c%Yck"-k]y |-G;E(eA/,:sPď90$:`J%J@Wx kc6Uf쾻}^o]ʓ<g}*Qb y#Bε9N2#(\Gs{ns=® *عzM6(Uz)([i6pOpb1@)?po> stream x |E; D킂"G0!@82 T@݇~Xu]aYܸ>~ZAPVuL/0/0 f\D** "'(,W+j!JA~At9M8Q0Q*&4h Ĭ6B[Bt! !, [!k{1XAXqicv/kY!hQ ykC.dQ-fj,5D3ڎCYe7JjEP5Z4kgOnU?1L7L=}XѤa_?40p{íyLd!Iࡓ?C{=l Jn^q` |~:+; .z]xhn Px2[ 6/_"7T,MF`3?k+/ hMnB=.zz<K$$D E+- Y 7nLSCÄJexCC5|aud,"b0A?"N2(p:=|a[3 l.jPBria Wwac^a[@3<F.x5I;țɡPJ<YHd[y򷓥. w`U||:KǣRn4m:%R"Vjnuʧ cC4?]x20DQ ضiaEQسv(d<ı3=i-&an8A)Hs}r\G}\x $؁gB3;uhς7A&6ghUPLnD$ʰМ88+z565B27 }Ez; vl cg ؁-ԾMU ą~r)/båCRkÒ.T33/*3J*)))(TCds*,))RoԜ!,FyFid噱^,f1%@Եybwqg^z]}:Wݔ|CԒ[2Yx l6dfɌ,Ҝa`D'xx]o Ax$ؠ}Ƕr;3dC$0"/~k}W:M./ n(8<ÃF6"]= <ߐ72z"|;ڕ vᓓzyfF}VK '=o$8$$߻}ȃ+@ H]?Zx_QFyFij6TnI*oy#偊偊偊偊ߍ7!&"s ]l|{+!I#=5.= _CAqTg 1`Mi' xH:X1&{qHuk~H;xj $p,X>÷9:>5l'&C&.pD ru1s O"Q.D w]ߨ:?qd <%Gnic01 ןXoxo'%V'&nSʾw돹%$R(p>ҁs]r:kO~rl^ ?P|ew9 ~l'z# (a=᫓m_g7Z(nԗpƣ6 C=bA3`(QZ(Ԥn9kbj"2= a~Mtb|$_k [h{҄5*Xv'7 l"͗<+lGx)8^/G~T7,|F+ԲEyp vrE;#!ȍdePS < ^V-cM/гןTzFiٝc#Rm`r^D`FuJ_W78 K_x䋎Q$ܰ>8I=+(ջKp")$Ԉ*U?|j\E^QćPz//'J ~#AW|בg=TY*R*R*R*R*RLE)TX+P@.ɾY(~3!! %/PBYoUAbәod ~gGyў7'8'?oo(uGm﷝ qY3qK[za5U1C<2?ʖ߶"qN ,YY̓?7kLU ,y8χ!z3q&1nLyݟljQDdȉ#04$+ARx~]IzuOySQXnmEiuuj(d-P֝u䫦Teyp4=p@u:;;Z!_u5 ϯ<@(X_[ Px~˗[Cmm-M 5:<('̪)Po2[#&fG.8FϪa P q6‘toP_m2T:ec < ,Jك:^45=-&UؾO/\ZCMui]MySrk6/{"n~r[C]%@^偊偊偊偊s 4St &JaWhcOfMGO$݇$/{)KQAq,d׳C^>F;7pnb0 endstream endobj 286 0 obj 8018 endobj 284 0 obj <> stream x xE;K]QD $&@8 !! ^U]yAָ\aB.1wfr_b޿9$ 5GUbH3-+`z6LZW$3Okd= X\$|#Z3 \gVx}Nӳ ZvV٘ijf hU'U2OXAȊ>:mwi=K_,-c""v i88O1:O{ @-%߬e\`WI )%+"z`HǐZoWD*p}t̜fP0 &8` `VTa5m`|g: S 82dUh^p^L^8.mL@J[֠A51 뙧y,oFXu4R3QLDô,R$,1b7 r[8%eu9h4C$j910`W[L-AcBa2:aq-PA(!Xl !%T go3jFwʂ'd1g pBitMa( d✱~z[m%w7nZ_K.,~RLfx@=,P1aDˆa%e'-46} 4гWz B{5 2@t{/|izo}[iZi|m%  ֥iWN,z,qdNl|2W@g'")J{6\ pM%7\o(}YWb1|!I,/4b&b|b+x*`|mY;~XMﮫ|sO+ .%^\`H[3S2]LTQ9S}h>4! zIfVZ3UsjN-ܙ 2 Y67>p1P9`B'Ux)W^J??Wfnuv4ʩYzُL[0xxR y"߄^;Cٿ>c |(nGt\E/ ,>m[s8AlP72ËBkGiD<&0㞊efKx-C+y1(>+h@a#{>jCPVC9u!o5qb9|HI|0l\d LO%Qػ+Y;,޼~mȇG mC&BB ftSޭ'>X/_I}U'&i} TV-ފH|l%_&ى>g{{ 'S@`\>A&A:" {4OݥGuO ɟ:dߨ[9p1]Q+ Ӟlwo`'"jX?uSee!tFnh{?NS4ag'>>N`lMaZHY/3t>嗿rU&|-m,B\yC9{(wwζ~%ly>0w~ua].(&fR+& M_0Tw6m젊 hØ"߻昜aAfzlh! ?lNt.|Tsm:([o<}OFбjZ2toȊQf26tͧL0 pWjA9LD !Q?\Ç bq3=lj |9g Wef}'C|#__k}†[%WM\ݍT*T/@Uj3BןUls^³c+5&=JVъZSi֥kti"զ:ìhr߅aB9RC>*|vktLP㇭ȓ9 ͻ l/j`~Cns>*6D{̧[y\qj)_7Ba#yrPba?}m3^p= wXe (R+Ё Q'GhWVЭeX~8waz~O.fl4oZXoCP <8\JXl+K,jiGEj)ZF> M"vp"XܐurxC'> )پ`ol|+PYaM7_ـǏBbtCGp>'F3{8{n'NFV]`>`Eb#gQ:9i<]1E!ʉc KL~@Tbu7\q_+o>xu}Ǿw;}Ǿw2nR@@JqT*M6R/hև4lᾄ]`Ljв~L`$;ޮB7ۜL|uNާĄsiүC ~(}m%)!cf:n).-A#EEF藌6,i?r(?1ܨp݅ǂ'00ݕ vLl !z/, fbq+AoYJ>/ ;ANp\s缬= K lد\2e$a:4&2g=I,$&?M[0R?~CAY@`D<oh4Coȇ?#aU[Pj{Ț>k:CrowpYY]DP앗7nشpԍ^>̇J.Kz,1lvx+khiߪ駍A3O1_ 7 %_H}J V["|pRcqd~M%UYSTуU&UM;{]' ΙxG_0_~č_pb8ոArzJʭXǵdP>  GW}y# ]ƈ{f tofTZΖeebF ̪ &smQHƖܨ2x^ Cܱ|K]SAC,ZIx7[||ze \a"cxWG^d~+7k | X F/2k'Z Ȑ0}&, ^@l ʰ~o|ۋTmУL;Ǎ*A#c P6}R!X%+l Ć_^_yJuh%0c_0B}) BB}>\G}%S(@!>b\}K>Qz}>@ d>P;&fwk;/D^!a"?ʭ}#2 }^uSm"Fr֫>|,-!&=fe1ɧ"zdpއ>Jj&eq\I2*(AnxȔ\ l!]4BNbocW=08`,Ha׺}U J'Ya-Uv2!X:Èڔ)dZݸVa1Ne|)x+|G/ԲtDWcb=m;Z w'+̨x vn !TaD{ύ:Ŀp~`;doӇ>AW,q>z|e @} @} л}>4(_ >PH@!|qכOD\bp Iƺu3AY(@!>PHYEB/Pzw]uӅ˾=gn?ٲ?M2KtCO܎1 էP^yXw5d_8wtQv DnOڎjpև;zPD)WZPqr'hM8Uؑߑ~F>@'>uM 2d] 0'u ?CxK6}]6!ۇnׅxj gp0[3MKGUٍ} @%vP.j  J%#tҝjLcgodW2!v}@bJgS>l1nn0Vzn^-)VN=fKn*a+6|g\TYQWNl(l[#܁z}Jta'T=xn;p\pzZZf{AhpSr>5ok>ÁV g}(|1t0cw6}p~ &!/w%V ډD0F8~N.qm&O`M3)Hyl M= ǟ\3 *v#ŪObF7!"á\ik%gyxjy֠l8]>x`I}F>A>PA$10lo>՚zn?mͯ7:z\;#sD.(cɖo3WVwTS  G t2 Ejtc@z7p7)@!>PH@!qCssDQήs&=:(wC}P($ ޤP(@!>PH@!>PH@!>PH@!QćHv0nÓ1 H*X:GO+S' YIe K%x \rqػ-JBSjΤ>:plQlMa-Z 6Jaz=r AmORmg1*05OQ̅=alI@G?>P@!>PH@>PH~8W>RJq`~p2pEğtOz,mK"nϻ]x?A.Y$'IxƕHS3"Ih5t &׆Ɠν|'BC>Ax4xJw@!>PH@!a".1L}`NēFH1dȘ=HvB KIʑ佬^G| _WʓJwft | 1F|BI%͑佬ވ2>6&nrfr'2 iw`|\:ap{Y>n8|&g&wr}(7-!Hg5wty h]{1AQz؜hNi㑺e]A3qn]n:(&ɝܚ?+#_¯kNnߙmL2DWo>PH@!>PH@ߗP($ BB}P($t>RoccwQb탅?P($} b@F}\e%@I !Sq ru؉<{χ$mfƥǾ49U+(W=w*K M;[~]~)Ε\Uعb?/ `C{/USUu~Ph-\ij|Vy~ʕ+W{--M uU:>O~󡹹T_Wk2*[=:z{xRA0By(8p?wX65V }B~s+sd(_>#]v >b]Vah-G%il1Vf~Q5rE=V| @Ԏ"o+>e*GCCMMs䃻m vD-k5!bP 7)@~Aسb K"1(a{rǒR__]]7hKf~! \ͤg1iT9ۣ(ȂQ\]jj5_ ă W1oJg^v[)>^'m'eنdzbq@==+GF=%Wmd2="G]ʬk.9Ze Kv)ۉ,F9@]]mdqPLԶ캼-Q\d(6FуfIS;L1Vsg2v@* bDgDžl$qKR&IS8&bQiQY*#D >tAs/hTk+.:(vϕ4k*)٤3@p.vgǾz?+J ._· iI Y|5<-W-k}̞́N~g:%=M&?ϯ>uyʮ/{-~_W},*m77U4\iAښ=q+WZj.y~Qx@!>PH[UDߙZlE*:_2<3CoЅ'~Is}%_"I=ەr#2YȮgy-M'R endstream endobj 287 0 obj 7796 endobj 283 0 obj <> stream x |E;oWPQDHTHLB@H !6vяkKx)rp,Ǫϧ`bHB@&g2NS=adߧ?NIoȘ!K@̜H*9%ə)%ېz&CBaHĂjA-$laL0 1@LA*("'(,W+j!JA~Ay fqii($r9$bas[u!o} x  Mq 1xm,sHf y.iC.$im!$Uu4ZX^`,<ğg +u  @,dIPzڈ9hAh,Xc? ! U̼*4&!"ΠCeN~h!!t/n+U/YTzNehdV.Dg!ms;1?9Y1B hdyƔRyP/C/$_]YSex jrʧgjFEJ(O_5kTIc_$`qfAýAi ;ՈH+I(.7~hn|ks 4{&k?սZJs˵eh7k6.R&UfΔFs,~JpW_^F4˚T*V-F̖_H@'A! KY 1g-76_]ZYn ˴ʧck'飷<8dpcq X:}`h8Həx$Smb [u^2A-[*dh[^ZZ; 3kN/ztF `<{ @R!$8+\-O0 ̃ hnE0CCysk۵/a<Zgeary4XXP/$B9BveF5u_ED>S_b|.S0.TJ_6hyy)ubS&ߧ|rL&SycO7#)M(j3䖔 _1Y,Yвi<>g/>GcI4|;o8ńhy'\K5m>uIeCvdsҶ Ĭ>t8K: >-Dr EeW\2ȅBg zÎiރ>ăA,\ 'k'k7iaB!M=Z3GBUڃq{T wF)GW}ai&ڇox0d:GYj'@"۾YfnXl?5>k;DkkiJ#C{JKAwI41eG'jޟ LJs_>nYiJK3 yKؔ2/qJ5[DPT,P>^B͆EgRaIj44 FGFY1{GoAF-fBs!;tQn@,i}?%K[6Ψ(1Jfd8l.ڽ|ֆJX3gP,;eʗMrOǩ% un(b.MS0B9o'=5xCă v,-@j$e<i U0UhtKqL'Z ]{ϮB5</%谕ᠬ^ Bwq%G N? Q52uNz}OhkWZ۵) ݈x2 P ؾL;(gkCr$9ݨH ez8}󰤓$G<6R/wap^æۤ<BLu:(]`Mhs$DFvP"׬ӴgvvR(Fd߷oZJH"Yw+OR|BfP굳4kb4"+g?w)C͸8ntsϾdΘg.uw;˟V=<抩7?o?O 9;l(k`Ia&BfZSk1v~v4*J7o$O&r0bCěEINrtB>J_VzriFB E3GVN&ym#ѤCu^MeZ]` ndC$&[W2h^HBZ0PkYan|-ЫLB#AQf\yN4{m;ڷCl1EB®p$!>qs3C^?f]m^1*VLef'7)TFX*R7P> @E@EJA~˃/hQ<0 2 $ ᕔ _nCpi!ab>{%&bÀ2r]sj+HߞpƢtnGɅyUf׶}U :fQ[\m7p i<<}ĺZ(x sÌ*`D5 'I̓t偊偊T?_OKc(TUOCh!X)W(fjQ(SܚS~,ʀ/<x0Յ2Jux>ñzx d*ʀ0POiggYx44_=΂Hw,ʃGjYR}kkC}/7O_ Qהlشmа}pIEy<ںKK9SUO@Y~_>.k@׮u67_uA/=}~/N'@Q{KscI~5A{<Z̦: {<6j 4  ʝqq;+Ch_>8FϪrww29F8 ϜM[ZA[㔇6g|lQ.ɢ=câ<;p 0/zX :F7EN1'yP,==' vWRN\;T_oxp dbW,^gYwqAyDž!BP X_RAHc*GeCrKFNUU;M!3_јc|*ҝq|PdA).|ԃLS@(c0azLu:Vu)nk)>2N^NFVn8. 9ebv!eqqexXW3=;r2uFFy kKh?DJ*C9 ΃*qPLsYA,X# MA FAuƃ""(72-AA֙K<꯻'U5ū_{ކ*(v=~L[-͆ N]~` s[sCr}]uYRZEuvzOč;uW_Wy lQH!\YEآTA!r< ;HG:@AQ4Q"/? L:%嬠܈/;p^b endstream endobj 288 0 obj 5884 endobj 282 0 obj <> stream x xE;K]EEAb#B@ r@ڇ|,.*E9TDX"&" s'"Gu0ɿ7_wMQUTV pc ĕp 3:.H?sf#7LVfL :iFXe)z9ȯCk:M# ]=euP B6ZgKco@LxrChN+!BCt)>%PrvP Vf!pqm!D `Že@  Ifi1I@ IR/kiMy+ WJ  ^Zn:|Jt, ,Г M Hi !h~mFnV 96U3,B˅BZ.*(}=S,fXA!n8| $19Zs*#u;@rS D4~tJbqEO(uA!'$2 >B %$+V8]V}킍fQѲ\I"h\yS8AB F#fj)E_:ÇV>dckiQŻ/6.K4<{6Z7k1 (0!ᡒ؁EnLx:?k[Й$ ݵp{> 9h`@ Ӑso ]/TKbkvlp]{+J+" ̯5eZlZ9͸|!-Nhn%3G߱oC}Z q2psWjUgYSt+E_={З !/r/sk܂|E%fk%&ֿL4L |vUmٰ떘|P¼f饙 K'S&融*6$k/t@P9ROsiܒA˳in|.ՌܢR4ۛ:RM.!NCOXJ(Sӊ`B'Un~ekS̯3l|aqdÒxEH 2I팡%Sɚ0hc7>d}y`VƒYP@B`3`&邽/Cw}KC+dDK'Y6l|dh>y,f\_7Z7+R;}v^We eO﫡|!ò]FB)luO>/V`Um/iEg;Lw Їx+f2anHl#Rx٤'=kߓN{B:֋ibJyJ7gCGqC'м-xߎ`ƺ.n0^s^SGCo47,nNnfvc .T_v젯YLE }h_a?gʹ>|P9 ~pm۪Z | \x]q=>V6|nL, Y;^;$ |MćGTC*BAʶ3S<fd>Xy_X6VK6U-)Fa_+*Se +z͎EEZbQp@n"^ =}Dr߭{?jco/}z@(@A M(%9m JȤ>Jb3m* y͢H1_]B'Vm#I$ϰZ>~B~Sj^<˗*Фo^[ŻCѳXPdݗ 4rυc>l|Q^{ه % >Lb\oZdeII1Ra'ܥ]{>h_ϻ VÒqǂft[f~X-PB"8*fo;_?W'pf!bxaf "t"ˑoL̈QZ3I6tڍ +!>ܑG,.(.òNB{1 ўiִ ?T0Jz- C!A/7 ~OҎWZǔ7+1WhHAEM·Lvw_y̪^ȡU&_SUX-1IUב>}hCD04/k0?\l5Mo{n gmF%(">\7lʡw @ N֐H-}JO:1xiU`8^Ei9≆%q 2n+_n4M'jCV&ofY奕(-/l-pʩE;0[."FZ}:U:h#1.+ Y-+ۂSY.@aͩz/?r"ScKe09Bfs1 f0HV$6pţn-nSc2,e\i74e%}͙aa !>@S%MN%>{}wzgy[uC^rHi7/+)>JdayI (sï&trvݬ]0}!3% 0O  La༇w U+hj Jm YkiG2a#'AQdi2lf^&RR:y+ V@l& 8W[c qXh=J+;2ADHJڊBHy\݆cޟz}{PA{Nns4 6D~ҧL|E XAYNzʹndF_(B2xzӂC}ʇX~0B-eGP/j,pB+wX>NdFЁ{ z7XᓮHp'jZ!P0lqDg"H[D!crb q;X?ftIgC^e:8oTy D(6GZ@x<_xm+ oׇ( WB.4A+4>/z=R7*4ŜXa\Ϲ>A (AaAɇ|(n}@(‚> ,ׇ?:x]\\!4}'p׵%ق>>jdgfi[}+Dr\͓oFF}!rnj';Շ?hH1m-l8;K:(d~C|of\.e;ᜰpІl:^Xbc !@kvٺlkt>8(8V~wXNP|+&+í^;/_"1lJ+$Tnnnq/= Q"NaJ LEϱƥ 7۴cV~7C}pH}_*ee‰7_ =SF_=pG,wN(- R+kڑpБpPLO72e.A$ f}^NmE\g٦eqÇ}@v7_(n}@(‚> ,‚> ,~\9V7|.j^!Wҭ ]9Wҭ7‚> ,"}@t_|`I7ŏ}G;oA{1T.8Kv Sߟl8piFc{Ӹ+@a;>taz2_,4\)%bO8^q, Hk?փ[O>tj!_~|h@M-====2I|JÊ>2ζcm:$ObE\@dzf}(L#pOg/Ё$s|!M>8FW|?Hem !11J iv|G3j\.ۯd15H7z?(X $8b{V'3Q|o@7IYrXBtu=D50H2n;-]Fw>r;I'3k~uáo 9RcŊ.t4==O߹>[M{5Z}E{7foI g)͠A QMVWn)<$ʀ {Nhuc>3W}|Cg- ő,L0a6 Zv(|/4?rTy"-rPCn(偞o胿/gZ{෺K&)L@2h|.> o"~   |nm6}Q]lʹnxĿAaADD       xŇH~0aǓ13";>ىSJUK>3eLjKΚiv6͠B6'9ܞ*{: ;%IIɌ )٥i'ge%]b, ^A=YIU+K:;Y\fV p,=o۩K`Rk[i/lE& }{꤈SUOqZBvQw ]j/m%o|>۟l냽މr/GPFV*߀> ,‚> ,‚> ,8݂> ‚> ,+r\|0 {CPv_Ky OtL>{4>E$[S䞞=(spȧKA<§>،}W;O^z||[!?]'"r Ы|:b }@d}@X}@X81P>\귊3>JxJ(ە8~e }Wy>l@x\BM~GJ;>}X/>JCqe||f5/<(&qYl5>Jn ع>.@Wć[/`;'X:;/G"q:O/.U^y샇?7zەGem]_8C9:ĕ>8:+q `?8 㣘6Q!J؁8O ?   !"‚> ,‚> ,""ab϶"=j`{C|a@QfcT%EuEyG}tHN.H]O>A 76 i-7|7ؤzxzI|uyR[l不!rTEZ:: ,/}p4=Ptt65A+{xz~/pV j!]5U%=Hg>HG$=iܒ}$< dؔs)4N|0p'-Ѹ}bɇMblF.S*!:zC"2a>6-zʪJIީNp!FU;g< {N"70!9룣ϺʜM\nQRiuizmE%*h?D TDz9@mmE6!'9룄̍Q|WO X,z֙$[Wܛx"1L^شqHn0.^M>y>%m/($Fh{Қ KΠ-reUo@Rd6+MNW+~@u\/;ć^ϞGG.T++󧴇3, =`!/3ɜ’s9*u}c_;ey%sJJ(왌}Ak => stream xZIoFW@ g dI@{ `iQ$-K~6 !)v8`oߛiwoo6ogOo7ϧ?6k ~?0x_s Lͯ~~yGۜiAsx;ּm[59oF[w!}W~ت}ӷzHoێXzOmf[m@]h{( j?5Em3[Tʁ+&Oۜ_L^bNb"PzߋwD]6s5N&?g^W_3Fɗ!Yh)ĵ%֣\BӲ !9;QJǬ(4-T~EaW*{s&!ſƏ2ߵg  j}~eZW;|u(LދB"Q>8#It!Sq6vƾTMJ=J҇I'a 5*% ީ*LO+{w^~dmȰޔGE&f-5s</@ˠF7RCY"VEXH ϝWaꟵ;屎}IqkoYF5ohDl88[\R~ԓzThaj@U JDN4h+0kɡ> +HտC?0O(xQa=/Ks((-0>ES?+p1s$Tm8R-aw2vשNpN+,vF,"f}~BcB il8o3 P|m6lf+NX?h g[thͶ+,ܨ5䵋CC&O_[P[Vp9O%8ȩ<zҬX:I YuF)V!*&8hU^1S6DbZyQ@|a2c ܒwH+볙Թvd*\g]Cb00ОiʬDdnLNc_Z7WY_n 3A Wum}RP4j\ńD0!YVW`BIe]?3 endstream endobj 292 0 obj 1772 endobj 294 0 obj <> stream xmRj0 +t.$d;nVv v;h6~$ Eyz{mkos 4%^_qA͸2o20߼&w݌n]B2K`""l{d10^Z>z7)Y.a&j\Qwp'()xWv`)!)r@P)=P;7KӁNUl~#OeF3b(C.;UE: bJ|rGqLfV#=X+<8u\ cūTv3~Oڦq?q܁ endstream endobj 295 0 obj 308 endobj 296 0 obj <> stream x `U՝/2(S;3Sӱv Z\nR ЦEMQA@8V$@ l/'-={/s}W qIs 9ʥ*_WIkv z׵#tmZQ v1!0iQMw*;9T"wTJVQ=[ b]W<<_^|?ސQZOLyM@Xb :D_/'mjF ~>bޤ1Vv٣Ķ]6>RS3ozB!F!b!3`l* `Np,?AzS^_|&GLi$HSō=rx9wOZ] 1`ֈ"ƈ8eS#u>n7Gopstc6bW3(4s05!M93? #hgb$ר{˟Smu7-ҲQ+mL.jO:ιU:7ͭ VZgAlUG0%MSl|w/<^5qwU?=턪n"T>r=):o~ZX@m̹>~tVzxcef̡i=8ٸ0hb Ћ.elA7кaUۇ[ֽlxqZ?Y7~ps̜T=o.ړ~;~TknuuUŶ}3y=w/8~ [aI6˪z'ZuZJU>QWVV[dմ_H).Uż!Ee;jɕW{ɹIۦNxWfEW}8|;&i"srkE҅SLLZpM~=uoWsy!i;iXsӜ=thչd|m9Fޓ?QGy{%NW-}Y\Ύϣt>XyڄsG_<~D\9K% *sx'673YGm]\w]S>{W޹MrT[v3xNunMZĹe.kAӭ]XE{γ`ٞ{ھ"o]2ۉ;?o$rm:r~Ċ~?A *4a7ޕ2sm&Bs:tެmD[y7j.az}YUO[6oWʻ9s5;ϺscnO΍X8JYp7[p93rRqnyDLH?)1ڏ]Zr{MݭA"?b-P޺]J>GтQzP=9HJܴSG=(qsc98<5qyLۯ\9I;'LN?LR#wo}w_F߭Lkvj+2Zە_s w@Yj{=\53寧;m~Nw}untJel=DIse|] }P$bB֌j(./be^f̮f(S |x$-[hJUMN2J` 7l$.J8N]"0=¨9強ք[$Rz|Uʩݝ?n52&po5$=!Mfj{yf<":y#];jgf_;ޚwjNߪ5w}ί~EܮwIחSt͍8oP;Gs*ss{/yݓ?wKVxM=)$ppX7f7U ءǻ nݎ]/s'H{A*rnT(ߴʫaz{OW$NRйdhݶtP5Q_m%ԹzVJ[[ߟ*۶z;[pRVlw:"~P^.gĹ!ͪ4Y|%Mw*My5oKbV 1b;|cԉ53۶iS;冺'{K'sݝ_ o|;7.ݹ}ܔ+u΍ɣ,wk>MqFm#Dq#A]DjjDl^AJŹ o~پW=gi0;DdJQ붫XDěQ݊k=S5qsI 4¦NU087:ž2m*]x-_w=Ӫ'zmvKqO]_7Lnnǚ w+wԹ4fޮ=;;j:F<˿xrA5_=TpY\߈8A'6q[`z}xF-WjJ5RSVw\yՎQOyծR:*ݪ:չZʄS2}OwF=}&wKQAk2^#~)ClNz2S 4.;)@mF֗Bh J0 3rVث+a#}p/mSLWԍOk~NNzߞ]qwn~@?_-uIw4w)ǛF>^;u˟|j4RV_L ejk#g)G Ncԭ{WX# JԂդߎU/qLu5J_k=[y'R\Ej4X&4!xqW~(c l&zo+ED{޷Xr×︦Wc*7V=vc'zj7U5F&\Yu㨳?lwFPvg'_v#mL.unrBsnĶ|)<#{/bgW<"OG>'sf?Ks[:p>8ŸcWKn?ǔ?0~}TMF\=K+~٩'mĝ3oĹFun<Fyoun[X\fWB;䉷򺢰Ob2o۾/'&|/9OۧnV-_?s˿37_S?}i ߠ.ss~ӡ-f_ d|K]eӧn9{r~Gu7_?k/?wwdҶىj5ƶ#oŷ.3|ӽV؜z1K_ RV7)_:~Glۨ0~UI]J+=NY9C]O*")7*D&"E9q#Aꥐ۲{ڤ;[閕jol3arnԼK7IOp[(테w9Ҥrj&8U b[]#Ni*7ñ*,BQ~^Wʞ8O|s:7żiV˰G #m{O\ĵDvb[/ s* `Zd!LK &s,_R870έ ؔmѻAAPDi %wnAEĹˉM’!έOj)-o[) *qvF xHymt3m?Da*02 Ei¹-[BXVa]9˶f);(8Qp膿-az̪k5V>XχR6ouڱ6^KU[m Уi:'( Fad fW8+vEA ;7WQ}ʗW,i;>ۘkZb*B >OAؕP3n>uDalq>KғO?m #摐aQ pdx[^?qnEn[v1giee}KO-wn[R!n{C"V#7/* ܼJV zgnq0anz~(4n=%ykO^OFadtMxH̛ϝ wPXχKun;ק [ܹ{F{Ya/ݧKo/oŠkG ^nڈJzJb9S5OQ>^DZp):ܹ0uh6 fn^/&P,T6vOc]Qzlv}&$ĵnӰ̬[{4n}ͻ-uʰX*1ބv֭N6BadX2<qn7:ʝdwX~YCIKnM/mO45BJӼNze&gH[,t$ɉJz']+-L@=IS#;k~s6\$s4Æ^:0B ìC˰q¬B˰d s6\adF-n8~gxk5fdLj)TY$lJ_bi=";ࣄgnN_pf;7";Eg쐿vCQ՗V+m6]k촫y1묽]VVJI|OgjGuSQz3'JɄ Yԩs M;) k);aT̰:2fOP_!02 j¹-ZA[f3#yc_#)ñcKcsZISwz ffbf5W#r+cs !Q[k[[k+A.xs7Oom=M"\rvXM$mZxO+?OjjMJ:, "4J뷵;$=ڢ>[=7T+bSf#(C7$HH0Iz"Cm,2a Ɋf[ӦWkjim,M[۸XJEeVmb- 3ix2Zl^H0]'~m[;jFadx3<mk[6##=GqnԹm&m:u&ܴU58H(skurD[uԟї3$m\ͬhn=ʁٟƓVauDfh>ZHѴ[piѾ[ glEJI ߦۖSZ2NY4bڵؔ:hZWK4@jTb{6)д[Y!b02,g [%ܞ_lm;ȑ|qc~GśҜu]/mj?=lvWK?iQZ FOނ87RCopn[ccc~57nqvt\(;j59]r)4l`T^v*}M plBd_QEiC:C^ڠ[ohMy5dy9f@hr"&ѐamڞz JKؚw/p d45ﺡXgݨ4S6܄PaT<#02 Y3<m dHvd9KiS7stzpnXχ6 Yaj>0asy}mlA8UiZ}'N FadxP2<m֢d7D;ù#ݹ9͹1չ!jL$ XEavQ [&wn51vGm#g$=Bg|Hj *kĦH:OX,ʬlצBADܞCo@0:=OU]|~5&i^9 NN FQ8 *s:͆7o~HU-";1ԜtUb'ӶiZJ~,6WUH2+efyseVUwVs4i7k=h5N(T?A lVS3dXo^'lzzUک*+ WzZ)eXZԛԊԆхUz^xs>}=E Fadx2<mw0 qƂD$_7텷-I.E; WRv]z7 *絛o~-G)cUOK˥ +-]j\lZK,vxS8uPeeP ]X&%L 1 Rtaa02, #fx E( mpܹ*ߥlj1ѡe7ݴPH/!;HS6 4S7oKZY 87mXZjh,-5ӟ -B̰yj02 #p2<8mG[TpV,q:%%](NEjZTA%^PɏNaD(&6|K>*uҬ \ƴi9*ѦESSρڭDk02 #pWޛҾW䗥/IaDhܹ9b% Z(Q^nZ^;vyi/}bwšѧ6NaxZB]^&*LFM2 #02}ȹe,{J-<\nnpk||ۛ'Q>`k,oԹZrL j;aNʅ6!ǹ?10U5qnA sV"t5VWrn鯏teěDٽZܽأ|jS…@ gRBnZ3@e6Tw(j1PQw sn7]-s0Ɩ*^%_!{^{^ɝfT~z,ohT[f|_*ӫJ|W;۝X[)/ZsHx[GGK[[SssmScMC}eeyl^5ԥұrI˒˔8r#rC}U4?~VhWKo-: aζU(-(6M=FFܪ*' OzSy'CaK#ݟ$(ɽĭɵUwȮ[[d׭m'nk|p]\%7!/ZV5{ tEҲS a+87 ׹eJ`&Bf٩[8WGwNj$=䊱rurOd׏[Nd7?y ^ /k*U2[ {lX^*p ޅؼA 'atnyn)˯޵@[W?]k9!QH={i\%87 ѹ]ޢ; 6|>ő~/m ׃Jܢ@!:7R ܶ繥>xV`6r5 (dBAPh1˹L5-SC{3N'8ޛוr'h7a=wt9kֿѶPt @,Dl[EC_qMgN;GG Ӿ=>knyoJ^_$m KXhضJߩR?1l̳}Z99M!-$uny]ֿx-uw/s2LNն|6Ƒ3^Ҏ5s۟+kn˥U_"pn 87 9+}ѷcNݕW#Lܹs~ aThKE9'(? #/2Nol+Qv֫AZj/vBun_s=d!2 ެ{vkg/^;ő,Wmnf .~ qw؂]O܈m#@"Ɋy#Dʹk͍84sȾ ܲW^ %X.u7g78VrMٓ(_][0ݵE 2袛W洇[)[AV|P&`)E]sۿZ[(gH0kGj?Ն/'F-)XjG Ĥ1>9"̼zBz{==]mŁ[#叞W/j(%SCP\sۛ P|:g'U{F6 w"LM'.έknQeXWvipn}ovJ==/]m3*?Sl~*O3g[\EcTapn[dVMR͛1SgLGMm|cC}n-mmM͵M5 EyRJ>/%/K/S#ϖ[ U=\YA[4 7wqn@ 2;.ŹT6ܨI6Lopn#=4vi{I^s(r(<鹂gOe8}/v$&&+W!no]z'U" R;#ҜYBǰ;7vS^byruR ]-s0>ܓuڗsV' l^<{t[zF[A^Fnl"d&%sKyut{H#>M+_'DvJvW?s3g01!AZ.EUcoֆUGx_ 7WKpvw(gJ!-4e)|c ]繥,zIn]%Hv} >WFm#},>7ZtknЇ) (?>O-`^<4 a"-5>`}ni/l>>%mݹC}nJ̆a^eJ>wKoc<Ķ8һ+sxACBpnb&GO;}کAf||kwn'mE=ֿf-, UAA2-[BXVa]9˶f)S ݹ@knLĶƉs[b ѢМB!ܴ>_s+ruü]pn@5kCb޼~44U?x7?WsH-^eXUctf/~/X~ #xN;^v,,hifniҤK'k:7W󳱔l) PL #18>E~Gz8ñ}Miκ..t ֋Z \6{Mvf;R{إҴ)9k:=ql[F~8!a~2pQښ۬EvoVswsGssscsC6wMFbm9.ST{[]9+a$ܦ'~ 9 g,H$ABu^xBFbm da$ܠAFbmm’ V"YA% #&6zf'mݶEХh872O nrJ_{?-j%:7Ҿ>VHK_-:-ҩ bZunQtMxH̛ϝM3SIjSs ,87  EXsUU5{]n_KmlQoNg"WpnAf+wmceGK3sKS&,ݞ^5??Ѧ2T %$ meB{XtpnAf+}^]p;ݾ^_so'roF-[Fųi[~=Ufhs PknDVP疙q8ؗHbOulN+i?CA5`Ԗ=68}Mx|*-q^>qMd?Мz[z $jk[6##=GqnԹm&m:u6ʹše-C[reAawnQ>M3lt땑Ə  bm-D=t3v0ױ# R79뺼_j"BYsfasnMLvwCi",Ksߜ5;bA AaVo ۴lGj#%˱]*M+ޘRq7❛~Vj?j*ݰ*OfuO(9$R9oݼ`--5MoD.8% h knh=*QppHwnNsnLunHu= Ě˹YwOms!ƥCzq?P6nzm$w hX knzzèvzj:!>3s^yY/Zx`ݜZ7eO|~umwY.2ֹYD'3] j$$heS疁cACȹ%έ_"[X]Qȹ>}TӖoeo^-QyE^XvQY>)jePYw7d0$5vɨ2Gsn+q48rW7;%WȞ䞗yr)[6T@O HOL wa%J::Zښkk++ˋg.}8^K_d_5Gn-Mz[jTP :ƀcDUU9 O\᳧r 2OI r¾Fz?IzQ{wM[k]Ȯ[Nxs#VTʀWK?)"-oZ@pn@5Y)LDL0;uKx$G|\1V.N.q'~57#! 1;,OEWw(?pn knyn)˯޵@[W?]k9!QH='DsD@ (?>O-`^<4h8H iEֹ]GC_> s P4ܠ!!87  EPAAlm a[I+v,FҦHOmx BQS_ܢv͍68qn W 08Ǎ{97].j,g-g$e ګ}XA͊sZέ~܊\0oaE8q}yrwd6e$b+[?$nÄcfb0! fkCb޼~4lD.ƹi>mُsŋմ?Y6hm_1lxaU9^.k=fg(KrnKOV۪8nTHв. 򴈺̹!ޝ Mo; /AP knZr'/;_{434Pi[K[z|m>ް[Fb8+okncpɾb!97MV"54e_! .7XlŜ[" n=k͘M3s{+ څ5+e1KzfU8or:w.6?0)P/p~,AŬbs-h 2s9I[RJܬO-yU.6"wiWK+funywݏ%?{ntdLC2z fym%ÎÎŹeR継84ZJΪQ#|:qnWK1tu֗O(Ѱk:0b (knK7-ms9:>pl(xS;~W6 M4q rKL/ sC!pk?AA'j dHvd9KiS7stzpnOW%^x`֬WTcIxA"j֢d7D;ù#ݹ9͹1չ!jLvg[s P57[==ހPauzj;=5vOyԹk"=a%87  EXs/|7~a"gA$Hn o[ ]  (a AAP(XV4ܠArn@dsz[j’ V"Y`y蒵h87`H0@-j܈mpn"R\sK<>O[-sH-],saӌ}3xCX]9 ,87 ښUU5{]n_KmlQ%<&N ɉŪaX[s[r'/;_{434Pi[K[z|m),Cua RB"?mOLLL`+tz!}z$L0sknsSy}ttz}=˗Ψe`45ݒ~ ,ad-ZA[f3#yc_#=t>ձ9k ՀGS%Z2&Ggunbmmk[6##=GqnԹm&m:u6 >MY37avA=t3v0ױ# R79뺼_,N8s39=87͹5V"ZE!QIцFֿPPXAj'F5"6_h&F M 5,"bkBH+-4a)jZHtEB 4AsdE  b7^P 4R".D#R:Z8`΅:RCVLH&Q}^(B(ݯ))5kNQXiZ^IB5Qo? O "UܢVo ۴lGj#%˱]*M+ޘRq7?M~jA*ؔƼsD-%PeCCkZ'lK4ju,n7ך+iՔ漂PѻeވmPʾyFU E,uXsjۢPAj ,xVFjN5(gPԜujiZN16`)bAa R*FiBB-9"ӄZC7JQmU)P[N)( <`+UL&* ')ou0bJFFR!\ 6<%^#j*\:<^qkn'۽Y% i΍ NWgܵ[.bX$C(*):H5}ti_s+ruü][gAAѮqnQtMxH̛ϝM3 )s7Z l -iǁV83e܀ݩQC=R^m]madض 2 #}Q_s[ʰ֧8^.k=fg ![>mO/Ujh|ڱ؅l'i$cmL׫ |^EE)_^̧xLlcMjm5`>qqcWZ;CϸbI/KO>ڞ;2 GBF #ђX_sS_y}ttz}=k~(1c Ms_ -9o҇ldX)sxʗ w=eߣR2eϭyPIo-XnVwr.GX;s p UGQg!v)[Kxz| n=?02 #^s %Z:gF!Ǿ,G{|csZIS ; -. n&VZ\Dp^Woyet/ +{k5zQ[k#7k(F*UL N4&?E}4z"BkɊ'o s;oFC#_sV>:HQ[&unslmM\- aAmY-Ppnܹ0uh6 f5M]Xtd3F7a%e6S,m 2a_Ω36;ݖSNBXghg8ĵnMmw•; 6TD+4lYNcVS!SShwwù;16{Mvf;R{إҴ)9k:=q87IiOLH&%N]!Xaέ|/[|֡~F]̽J_hP}Qz_Y6jce; C+"2tTۮEDJi;ЧѮVρ|L6{D&L?~rk3ϣCIx2h2%SOfx2&R3uoر+CrDǑC"O X5vTiʝ+JhzV2/oX%@a=NZ[1N7KgJi?+Zz4ROHWvѕ.dDuhbظ >KP&6vڄU##Eڄ!XD L=wφ׭a^F k#ի#&V2gp?⛺z}lK '.'v͚'G8z$adFÑa; s57hܹՈ:رo۞g;vH!"dQJZܼt8=4z9>'Mx'l[ A  sD){UJ~Y9iFH[eeeUUeU%UՑo֯ZPE$IPm*ij7:*{JT*T*k;Q*ު@2J-,(Ө0M-kVF§ǤtN47Lr< s)?J*6qej*yuU^ūV =V}T bVMyUjSLG[T#Tiͅ = '[3w0 2 #px2<$_<=lB8!έU|EdץB/y_ǼBҴriøq0XMMRX,vxS8uPeecNS2)p }"3Dad'2l>ðg8rWIKE܆gE;2]핲CV->즛bJH/vmKR-V-G4A ;RS@M3,@B ^ "ÆnsnN?v[R1w_z竑vY&RY9 +IzL;*s+q8Β .QJ"-P*/Q[(Yzs["h`>%I:iV.Qc KF hSR˩ĩ@Y"VTdFadxHgx1ik|xoڭ5XvxzYGcL,_v*s+&r8)J\ 82Qzc*h͵CסwU^ZދCkOGӡ l"`jg)MOUdFadxfx@9dtrn+/^C ,Z+_9Iϯ-"[h$!AYKKrѢj\J+*>`4#uħ"*έV"YjH"SD{)RMQEB"CUu|CO)C-=N 2 #02l8un ]@-ܞx3,/{ejr+r²cM Zʞɜ},#eAܹOvcY"H,i ΚtNx9 ΚƶZ9qWx1 bmΩS0 k߿CÐv@vCZF Ȱ̑adX ZԹuwKF9 scwUJ)ٿB&$w͓;'ͨNY޲ knJc Kbtbg  j[GGK[[SssmScMC}eeyl^5ԥұrI˒˔8r#rC}U4?~֠97ԅ PA1c:pέYx =[yHZ;4IҋܻKnLܚ\{\uE.EvvƇɹiO]-˫0HYb8FA[AACC 2rwd|t0e!3-A[ʫs߻EirX:'-'Pg ^͸fCAZ0`bss+amz9dRw 繥,zIn]%Hv} >WFm#}%oWԛJp #B}[tg'8r-a|Pi?p(aܮh~xgfPpn@ ca$ڜ6sH9lm a[I+v,FҦHO 2(DF@c8܈mp$- ٹ@B-Dέ~܊\0o#87 !5!1o^?wn6͌e9xaU9^.k=fǕ¼ 2[knW$ۼerf斦*M:X=tkziK/~~M3Rvy:xUum/^ٓ{#e9Ŝ[" n=k͘M3#,LPzjQg76e_fR:!qZeUƓė?g?2 ~`un9ΌC}Y -i%Mrn'μ*KunY'gf\o՞Q[~=B-D{m+fvdv(-:Ĺw6PΦRԨ^{ƍ.ZwnVgꘟ\-,V[[C{yZ^ -{yv73AiC‰3[s{~f%`c!GAoJsuy`׏e$3!h2q ZgK_mLT|-C7x,9^modHp9 !f/@iَlGJcTV1x>gM'n^禯= fT0k+P;}Ŀx >MxX†Mv} !۬EvoVswsGssscsC6w QpoȹY`s=pH==ހPauzj;=5vOyԹk"=G:Mj*g .j)!MĹ%-5߉_nD΂ I7ݴ޶t׹iHMµQ;{ l9w(2sxg9ܠ"87 !M!,y+`.œe"'87 !mqm[EDpn@B-D΍>s{ĹaޢGpn@B-5kCb޼~4lO>^~o(=g2[ZʰƜykr׵^M3껄$É!91U CŹxN;^v,,hifniҤK'4S X2D~ MY37Mpn@6ܞ_lm;ȑ|qc~GśҜu]/cuY'Mչ[hsH95{Mvf;R{إҴ)9k:=q맦{ĚM)[P܈c*m[hkn'۽Y% i΍ NWgܵ:O(D"=M .܊Ěs ]F]SjO&sp#B\s>/L,H  qM{m{KAF͹ALpn@64Thsn!j’ V"Y`y(rsH9܈mpn"("sH9%:7Ҿ>VHOfa$ڜ[knK$ļyܹi4c'$|ɺpn 87 Ds QWV՘s;w}-]ً߳iF{ v8OCPa$ڜ[knW$ۼerf斦*M:X=tkziK/~~M3śe-#AJHVʄzF< @:`km-D1֧[{|3l?{3j2,MJ5CC߂s a ~1B97|K 2s9Ii%M^g(/Omٳ oܘA! (%BԼ׶maGaGz2sL~gunliKgše-C[r:[8@?Xchsn!ɖضg8w|Z)Y]?V3fZi+sXhDEs# FO$R?ֿ/o֪Ux˗iXIHHxgL@Ds Qo ۴lGj#%˱]*M+ޘRq7❛ݢ ^0EiQ;HCpnC}919Q99﩮].L={ ϤSnk9DO'6۬EvoVswsGssscsC6w Qpn^մN pT硘w$M'3mNN;&N8mR[ (v޶NIr_Ǐ v['[;7@l?\60-/IϞݳyٳg} :ڳ?{U~5;w\^w4sikiʭTu ϧVnfK'^?JKI^΅rj/@8?7poŁ\;u_zAȶ7qถp½Gv\w ?iкKSnդu֬Y7`K_k+eҤIޗsyg_z%qw_\q%DB܌Z\s}w̛0!F'>ז°CD>1"f{փC[kl۰W+5;Ӕ[5n9so4 EZSS4… ,h?iĉrw۷Onjj={G/~!o0W_mZiW^i?\Q+70(7pٲڶeHE}PۺU ˭/-x1-%|wz_W|/t'ǎM{W׿?oyΝ+G?#NLz-#I?-s9?aiqUr۾}??=nKOEzKG͟$:'Jr?oo<ՑnjOޝy lO{^+Z fWI:!J<.d޽tMNח>q":#Yٞ})scq{ny`hDEmOj'Gye]3'-f|J6?,wx._PǨA4,Rm"t?(\{آ[W(H(7˯[3T,_oo>Z* 8ڝb8Ծ]=ށqJO_|3MO|~-;SF4 5͝4gNM>/mOܝ~r߄/=8QOhQ…R[7g~x*,%KVl?Ho?o{,q7=U۷?U/֎Z\s{U"ga7G: :#1C{GFg |D|ۍ ׯ.\6{exw>zfi9Q_:1/# h ܟe09vdIq{֎z2}^Y;] @p߹in>6]s`hAM^Jr4._7?xw.r["Zne/uG0Mvw_sssFN mۨ>L,N7}/oe˒%O8#>}Ϟ=R[bB"J͟?B֨eȆSw֗_/v:,^'ą3fҥn96nM%oiYekZ=zҠg(/7-f%j3[9+?Er [5BPolaA r[_OCv .1R^/%ߎ#Bqc-8N?4.n5{9s}u J㌕rrc~MMlؚ)Z-.թ\݊9ZEh,tcLž/"Znk[Ĩ_mookYe-˓-okyu͑%kS;]XEl9dQy@(5O&}{ f[A=xZ6>nVn>yxߵ[lniҤ*]{dqūS=Rn5?ICV  g\k海WzV9W^LmܪI*1j^p@oL'/ vꃿzIArP V=rVQ+7knOn”y4d0~r(܇Rv\nU矇JZAdT !"nVn> .PnJZ§fN~Gy]A 1_rVQ+7kn"r\@ b=ÕJZD.7Koqm(/o!@?rM 凞ܞ~ir3t5YT@ q,7LnZUkC׎u><^1GKC4jsmj2m;vm޺q[-+n}cCkZ/Mxk\Ii-^e>4cC C4jnd~vyzߵ+C]{}-YuɺǓ_g 9r-.9}~DDrܼz96nM%oiYekZ=z`PpL$[K|' 冈Q+7<ĿiNˆrۨRQnRZ_.-reʰ\Qn%C!""hLO/l{{[˺--nYlyc]˫k,Y}rN)Pg*9[1(G&1\K""F .,]eM-MҵG7Y:uo`c喬3!u]]Mh+Ph/rArS= P=z1.VpMzrMG377M-^zyMCzܔxǏaTK1 "G 87p z^R=FР"e_ʬя\nOn”y4d0~r(܇S൥0\Pn2փ/eǀ .7 [K1 "rPn2փ/eǀG ~5׍H$FL}ռe*"~2C59aۦsϝrCĸHrTn ?fغ%QndtrCDtr唧Lz[~->vh_mӚ)7 A Sr[ip*yc7+JO6v^f+wZVa[n^#1ܫ~dL94Tk=b1.Rn[&Ҥ6˔V Ң\dJ)Z?piT ;ZkZƟhq"dt.75(V ")cinG-yʴ-l)9+l#1MmAd,܂΢X)7D(9}o7csN`&rsYG_2a9YlERn)7PNym_rὉS<0.Z½T2[c2`_s+"E Sr3I\)Qt~g[N;[rs}[c2`zoY+冈qr唽ȽhiYn--qALr5NHy1>Rn>*RzZHr(H2kc@D#ʡ"e_ʬя(r|)V>DD?Rn-RzZHr(H2kc@D#ʡ"e_ʬя('@YpUя('@}6գvEmƥߘ2k?8@9FXO_ʬUr.7v:~b=Rf(7P)c=Rf(7P)c=Rf(7PNr~1Em8aGd{ϝ)Mo~r~{vE']EGo%m_i \CYĭaw{!EH )΍S~G$%xaM ݜ, V9핹|JW0]xLኮP ..(7( [&Y3&EfpEmf-%W4xې1 Pn0M N#^G TO˒G\%k1_g+9wN鴞Ӵ1w+_{HwYd޿Q;>fe5?iy4w[ԓq!n8ރL@\@9[.%#-q\ԋ%BX fY:}}J(hLWܯF(\nm _H[2nyv֡l8߃N r@rSnهrm)SXkǒ51 [iYn}`y\=ז.^V) Y rv70qrhi'cz`ᗛzm{JMuT\UrNtH@@rNvJbޗ}鈧t1}BvF>/WZ 3ݛô&fG:-ӴZ^W굞0x߆c-j|)G r@rJ-79Tfp:)ceΐ TXj0[kOYQܯG F _s ܌xRSf^n;EZXh Sr-.,ѩ7cwy^x5=<(t4i>m>{he ffXh B->ElKNVk+#pÑb1No999[V1  FeZئ5 f+M}\O-NYr>'c}_OQlE )r9J1g i(7PN(fznX~"äB]s/q+r3w~ܬ c:hZڴ]`q~m.>o_ *! BO|`.H(r/p]Uʡ"yp CEX>09k#(r|`sG(7P)b=T Pn&gU/(7Pkn"փLuʡ"E5 CEX>09k#(r|`sG(7P)b=T Pn>qi `&.u"XePUPnM~X>=ix?ҙXgZjnZ2rL'b^&ͧgݏ7|DJǍ + ]nknA'b;v,gq;\P * Ο?9,s<[VfznYk{Qd閿br3Uqi#);̼P^ϝs"`أiM~hӌ;zޒ^[갋)7(7P~)"1a/H(rtz؈]Uʡ"yp CEX>09k#(r|`sG(7P)b=T Pn&gU/(7PN孹 c-3珟?wLv3er ʡ|Br(7Pn '(r ʡ|Br(7Pn '(r ʡ|Br(7Pn '(r  Pn&erCDD Q 冈ZݞܠLPn!JAYCr^u""bR   RDDܠPn!JAYCrB!""(erCDD Q 冈 1D)7(+""bRnPV(7DDܠPn!JAYC4SnG7/ܠPn!JAYCrrGDD W "˓/77!TD @r(CPne(7  CAP6r=˭&̥I PnefF4#J+|z%ꒅgNDa]ssl͜k0kqr&/͉{8gr-[  "QFYeO>i.m3]~urEeɫ,GK3vIkxڥL.7s-ۄ-r('&6Sܲ'P56uI-<Dȕ[~M'WqEgB)칂qin[ z[n TXn <y*12]S+|""b%y™˗\z2:0p|JWtՋW\jRnqrCDDD"""b\"冈goo]2""""ȶ/m>>åhIKGKSK|7]^MW|ԻWU9xﱾ&.qZ} 2.̝PT:v%qjԛnaI*)Sj%@J1괚ܩ}Y;oh""""b08 endstream endobj 297 0 obj 35279 endobj 299 0 obj <> stream xYK6W`>EkHn aSmdSl.$k07b'ۿVwNh _o~~id_ht'`sgR^yz̋gj~njoM{~ϟy E//7^qjԃtQwj4ߚAtD1DawnTTDƥ@DD :Im^E#hr,J %/-_L4lmd:(Đ5'fZgI,N;IA@LTFfhC|d2o#{zvGTjL:rX?ՁV5'?O9i֕B\3I W}Sjp$DJ uCCbldiv\b7k\hRP†И%9`CBi5XIC%dGjMߡj} >?eHPv(5RJ:kfnGKsߩyVlk%48c(6 7R|k_`q=ň0tV(r>+XtZTߊ1~WZ M~)!0e?6񔉤]cEI7zu}XQSee{Ve. ~5)hLvRA]DTZ)!LۙX5$2 >6#e~!"W-+A&KZX AtQB]I^ 0)~}*mOj^oYVߤ&JoTgYBCYCVY(Z)V2Z0IJ-" HUi b[+~0r羧H2Wr%#v&uWQW!iv1[}Z^(Cx{VIo+xoiY,53Eme?s.XvZO$~O-ߦյvku*όSQTˣ + ]EBcNc4C҅ko+dc̵+FQ_L|ghczsZ?.oEjaFοR*ZK[Ls+-BtJ%q* ᗺF541hbi7=t|,:%pUz|3ӽU>h}ba8bV]H{(>?D}F}igGڢ,^ ӥߛ^JB-֛ۑ=zh endstream endobj 300 0 obj 1300 endobj 301 0 obj <> stream x tU+d`q{¨#Ab"F vdSI \O@|BYTDQ!!! e%;֭7:^=ӧ꺝U]r8XApq3SEb2a?F/؅ǭl;-3P t̴[~1qVq,NSd\0A쩕)tQ'}7]1y/W7W070|#2&!MySiK}Пy^OI^Kk^׿ Vh ]hrmy5TBS軼f #4}!DWq)7LGOӣR'xahxkpM^ [z/i轰6b^0Nx\|UGOy+#L-vR*f ҅ Uh'}Os`*),\OV2WD/7Ͱ0%HdbFbP -`ܔCp$}G+?g;^%'KhWSR~g\ Qi͕mNfEӅcLvҜ͇DvLރ NѬ3Sk;nN,Z􎵵g/̳jIJ0//PٓqesGG%bL(ᖂ˘|wMn :|n᦭?v{[5[_:ӕpw|>48gk>Z{Z֪RcEVϵc[5Ӻr%%ѼѲyM1]4H~/3hTϞF0?g_>/\bAN_:?> /XEA7VA.M/Qvw }^?x+\Y2,e!)oa'l3-'Ɨ=[<̱|vo;~!Wٮ=uGBJD+hFgLq[:t7cwAH 6.W!9H gm3oUmxk/=e33˧XM4/g^2=X:{xѴ3zwy';}#+Y9ӺlyIBScƔ^:~*C 'ߙ5/_|7S}ǾFd{>XQIzW;+~GѶ96NURQwP\`d"7]%)ⵔ7]KIiw+%n/tGV'ߩdݔRq'UZ|g? *ˮ\5Ybucho EeODθW}%C&ޖ0|5C׿+O4˾S/_ߧ{OLD%%ߝעFqM?N~dY1yn >NyY֔)ഷʞpcɸߗ$ .J[|*=}Vw]M4WT}*՛a~:Ƨϧ:^F> jҼ|.My]RjwltZ1si ڶgUgR?1Җ: s,lNЧleP:J~_챃[w|'eIG2\wڒ+ j\mVgN ԯ̆cQpTQ7hANG#<{@XIݤE&jgcz],=*~2fW줺F/-L45MlE7$Lú{&VN=3Ӻb%e;f#l鷙'dN9Zsu%ym dϓx}F/ۘ+Py0/no{$T}9:~gؿKC V:5,ZĞ~5Av]&o%7|՜.쏺2#'WlbC\-_5|*i{*2q֧XWL==պ|eiSnzu W[.uΘ՟>~C2T6q"xX/o"<(*5X 6~x~ /C}b瑳$n>Rbn a&^3D{THOWξ9lQNWL]U&K0Y'Zf֟#ʞ$O ӭ'[R&/kmS%^eMl앧|]̔1)hf^SLD eGcp{ߣ5mqwFk!RQ]L*{2yMqɴ@Kkv?yXy~;-SЯ0O]g휖fwCQ?Gysؗ!>mHΉ6/,`Yʾ!‘y{om=2 I2{MQN=]w[P*v{{M;{ \"aM,Lic8V|9OfZ(eY*V Z5Fv3[)շFMrd7Kq2{ [{e:fŷs68}x` me_[2޲?hYuqϹ]U~Z.?5_0Imܺ??#įsYY.IʅBBV=Tb5Pn^$qbI[cnޛV{Ro[ ٵ/lzǨ[~tL݊u ڵF}l|mWe?40g+rU=ĝ?>y/ǻxIjq~{8Br}c/z:'[>[χtد?a6ˡv_qۣ҆IΛ#Q:Ej^Y4bG YYΡѾ+|h .! tv̧+|Nw=Atي ڶ3W]ʏk'~7_$Ș"y^1nz0AS #PxN_ԛ 'Gӈ>&Ě"2z=Pn&PaH(U+cp>lD̨|h^BJ=n}51E+0 nwLzҞ K  {;`;`;AWps͇x!| q8 W߇&yA_Aw8yak91Rw˦Mwߑ O#1o{%&S:Ig/={̂䘑ksm*4R&Riz(ͪt[,zU^(ՕL]qFyzWLI[)H X9}-&mMD;i#%_rrг:zC^J^b ܴ$_( Seܒ,,H.Iݷ5wwm[8ʗ|G>=dY9NNmd/6ܦ|wZߑ /1|ۊ=z/wf_{vei4{n'sud屽̃|G<Z^ޜ{]EڑWi<[i\~5K,䥎󐞕]y$ӳ+{lw^'-ֿ;{Oߑ OޓwpAw1N;'Ap5;`;A=  k6w|8O6$k@HL|B&t;~ w |8w|8wC( \e\ A<ǫ;c,':ռ?~m(PH8ffy0U޿9A%E y7T>V.A.{6Gr;Hm΁6b6+]q٥@}At^WߝWI|CݯTGG<4*Z%hHxy\V)Z}:ByԮA}_V۾,[|0p:*?+#H'헦3 9M!hC=,4},Lf^Dkw#HP6}Ncdﻳ;NoKovC?¾#@ M:;C@&;Cdm /|w A4>ڲx;cVfJI/5o?X9]z~ϵ{=\@Owj0zv=H8<^r|8w|8wC(O8BM 000| 00 j߻@/ w'w$T;bw'|-|IO||#|Y3rP;Ѵ\&؟ʧJ5WLI[)'~rZ`ϓ[+M_ښR<. Ҕ- #nMKuW0=U&X-‚49˾k:xVw`KdY9NNu{x,}7MԒǠc{^|;ߩ iNꧦJ68|Gދ,Ҏ/yuH7]r 1^9۝I vo#Hh$ t찶˗/x;;bwluZEb 1nvf"""绺/VMm9w$wc*tB /᳸ߕߒ6 {:%Yۉ{T!Rd -n}T?| Du^Nh;̝n}<!J~m~ssBy?#|b;v}Vw81N;|Gū%u5T#Jy !="Wu7痘rm GSu7ssuJͅ8__jqygk}ҕy^}ZuW/l1ߑ |t7.28ѽ#=/g_e 7J;[A=6FsNweّ |;ntq$}Be|gH{AEw$$߁Hw81N{@Zwqq] GbpwAt1N;|G}?#\!|HHw81%t +_J\?U{k}4]s]YӾ"^R^ӗ:c(Cw֗R1j ;gZrUM%\t2X]Η֩З:Q ߯ u;GH WJX-2>(;nuݗ:Qc]/"^Lai ˸KW܉KĨ1N{]KQ)75Z=ݚƗ:Q]=-yb/VTAwIyKȁ=qٹ ;l1N|}T|Hw81N{@Z;Auׯ w|8w|8w{| a׫=0od# p8(<] s;`;-vkvY3G 9?vʻPsJvQ ޮ困!;'ROO_#L &eVI゚_GnΑrƆ𠺪ZDB{_K[~0ϙم6j >u^ΝOK=]8mj z .U:?M*7x{;v.vh@Ni Z]5Uo/|v.ol;W]N:W]dwۿ˷ϟo k-^|7N{Cw۷`hSSH}XW{Vko^zwٗm;}[ҭA;xKqwOBi+IMkkϕW؊~ W[_g_'uf++Ojia[9ntrQSx!M;rΝ[F ){{ӗW{F>Z5A{ij[N?ۿ.7|z})_sWv;핷odN6򥻨d_Tp~oUUWYl^}R{4J.WSƧfg?~ {wupԧ{X绲!fIMɵqqkOǺc4DmmeUZvƋ]mKxB}ݗ(N q*S{;֮x^V3zwX^Ә#'kOJO!v]FɵRaƺXįoJ;WYYazeLYSmdM^ؔrاyZUůU|nL9`u"Cxh.Ch{_)hba K7=wRZW(PNؔXw}{iBQh NtM7t|W0^Q^j.9w{^[NyxPSm+ ߽oFk/++,fa ] v9kWW|s/"/g L_=Y|6&BZ‚ӧwG]=;󧰼ދK<bӢ>bG_8dgmg])kPavJ#]h[NK? -4477UwTTZj7;܍6u7k9_w 000oM|Ifn}"B%~~gl':ft~Qt.n,^}{:zYٵkǟ?z]|&/7GKT endstream endobj 302 0 obj 8504 endobj 304 0 obj <> stream xUMk0W\XG3,az=MKIZK~Ceoi1h>{36 ߵyחw j~^U5d\D?2R_;rjO{zO*PX/L{WGuw%Q~sB%{`pe|{+e?P ?`ˁq6;.;JCf˚k59KE.EYd*F. 兇{32)0JrÉsśiu+HFh *mB4YrI+H,̬%LDv E ]åK 1tT&)-:AHVr$*搎U vκPXP#ʋ5+SJH_HO:¶b#lCotdT2N%jRFlKŬLJ,[q&VhRKb#u=֟;]@V\܄N$;pEb됌`,_X 2%IҔ}і, Y( ecx0K鐕Tȡԇ9bIe}[!i?W~8Z3ҳ(#c16 I*3aU%뢰݁.$~?p?ˆB۝ry{"կty9ҧmzlLI ycfPUGBP@{H1mյ]G_R]eԖ]48u@gSB*%/ a;8r^d*7j=t_` endstream endobj 305 0 obj 825 endobj 307 0 obj <> stream xXM6 W@$K6` âmEӢ{߯(R%;q`æ(CVݩn­x-^s}mg r;~ A,%I[SPMI>n_kxϷۂ>Kmw{o^nh(qaH:ܽ}> q{UD$fRA *}K{`nO2.?~\ɚ,Ø (\C_-2!գspRG=QBxH|`܀ ~=ӡ΢䀶9^(ԩp#S4`F X"X/=SpMZT|'>t VRI#s%"Mlf}d[kOQ,8DiYH«Y-f yI.(ЫTjH\C`cAdCJi` X-̜`b P%w2U ᕕGOpJ?,êO9aX$bTY/'%)}l%#z%A`;ie,\ڪv ._X-O+Y4V d9WoQw9,OF[Du.Ɖ)B0)FL[*D)uĢquZݧU`M 鳱:gLD\O?xzU.]TUV,B7"r;cA=Ti"'ꔸ6e񆢦@T(&{4O-=C,+ءͺE[T/\>!F$C/elg>S[#_F]*3lT,劵k/EY endstream endobj 308 0 obj 1440 endobj 310 0 obj <> stream xuRj0 +t.$di0v֍l$;Mh1$=’Ϝ@Q+Vנ&vIN ?} endstream endobj 311 0 obj 338 endobj 312 0 obj <> stream x}Ǚ7@ Kp{'$t\ow+k3+ l/.{w^Yk(!{׶,5#ɔ7$%J"iREZJ^I(r_{z]-or)}?x G{_67籽R|.y䞈7/]4aC.A!17=;E)>A0 t:}܂nA!}_W/_җ=ٶmu]׵.7KA6P;}vء ySxr']wq +?9c/2AW[P.ڑGԮ=/|{ zxߞ=G߸㎕Sf'ONa.z>{ٙ3_=t-15739=wyM#[ԥ S fg@?-EM=ٮ_=xMA?^WO 0XpccsG_:e\}xk?~&t6lA!V/E5ܾ}{x㳝Wetii.^{-o/Rԧ>.'3{-BuOXLkcb:sx\}C!-i+_Wp4ze_VWCo_7VnmeǎEcc7׿u뮻n`Bя~EO;\ַV' vbW8 X6A?~UWrAy\jL AA=Ag 6"f:5V~K/^|qv.Їz-07~qfV,S-e 4:uA9PfL@Gߜ{~iA1>vl}.ǟge={/ϟ'xC/?k?{صo7g9WsOϸ'쟯6=ё'"~,o枤# ۶BAm>u?9q;j:,v6ө^6y6l[[/jr!tz ڃ;5O]?^_uf+lP 矟-,,TΙe#[Ϟz[;tgo{uKo3gfo}kPSf6N^O?БKq޺+qو>!eAqb׶mβ{j˚ɮSJS۱M>A9B-&+Y?<:ĻL̴MS  lk6jf UΎ F,fAן$cù2M] p>9so̗ A; }s:~p١}n[ajΆ=$__+4]p5믿!m;/%AS-D+Z_ZԴRN`dGfD~r)FSBM/>3e Yknc7ܰ(P]\btAf/5tO\ٙ3_SW<T&. tYfǮ;ɭr7|+g]O\<9/#ħ>?_|;V8ߞoX[mǖv%Yg" %Z'߬%m5v_sʺg'ba#U=\ҝ A;_7uP?447@oփ%)}3MXB^)Aߙ->A׊&slS23OX?uߙ}oo8#o|~6;zt쳳??ptƵ^Z?~%oԩHV~?5];?/~zk_Zg*\ AfN>*O'!ݞL{0 ApϻW 5惇2Aw{ʲ|%8'Ae]q`s+[[ ]fML7 \亢A5_fo}_vllR0A?yrƹ3o{ֿ׮ģd,<-z}^믿|6Z2.O;MW 8gN'+O& c#v)yp2Oyz'.9?k3.kk|eK<}5:mmeBJ%ǍS׋]N)Ssu.fՁ9?.lc^%̮Wٿ<糛׿С>NqvX9~yy>pcw)~~3/{|[?>?̓k;&~X:t0hp[bY7t6!0X7ɯ?|0u8΃6d&x;t%\A~xc퉋?kO'IKLͿv'?PA\!0 [{}{߹zʞ{l9S^zwA\!0( >p[#!{|J<D?zQ *i-8=U0|}QwU.]CvzQ *4zC Π%zA7 zQ zA  n+JAq `t\Ė/|9)P' j :?w; zp{/cpP`Aze 8 L0P B@ (*oc@ .&:m\fo 8S;hNLֵnۮ=DZ'Fۯ%zO`NJ׷ -O:q4UtSJ\}K=pB wOӲ"eUEH!^r tS:(cr:`! z_V69ȃ']B~s)=Iw{k?X1䏆@kRoB聠`nOI.ɓrL|ٙ!O_+O61>%SO ?)dt7qCXsϽ! v~瀇JpQD4ulGJH7~SBKLw-`Z$o]k٤V鵊b_|ECvU}X]R#>CDҙB F,ȁT:y!SwXJ 61w );w-X=StK/E\/IVJfe-ot2Z z_!2™ `džԤBVyNq)u?D,];Bi}'[(N+ *|FS~)DӤ-OH;A)DJUw(jQTߚ TQ7v=zNANw2Ѣ8y#O1y6;h d[P_}{ )zg dm7h=AoV@˯DhtQv1BE:Ȉkk\Sw{^sneJV_86]K#A'(eH# L>aySTI;Pğ1|j Z)&ϛ/y߆wG=خRP1e*gMu(4}bٔ2m˫{l=dZK*|J:MWM1Ui4Gԍ>wG;تRQ[(5P`@3~SB! Kb᣻)86篟;R{P@ЃA(`=uft }=^('c G2w&(L^)p@ `@Ѓ3#x; wAgg Z}{;&x; Vuzpo}"D@  =,8 zX q&(_0Aշ^mK:t^cB.˷Ojn'E-oz:]0m" ͣ]tn=zY'׫~ JM$=64gF7AD̰q)rWr{ݮ ǭlfnUKQx˝90N 3l Jӫ3}~d;?(|&OM=<|Vw2G1}-Rkѥ2ߢ8,#z8'(jڽOxэs^[:!,A04H E+Z֙XYCp!)1w1M}nIzhLߚTe.ӤUWP8HvڽJw!yYUh.tIT/̅t|3E3: |И.bTi,pXe&г ^K+ҷEzrœ]AsjR+:E08Ƕ4aznDM6GW硘4X3wƙ|CEU\tuEQΪnsA@1ӝ'm~}%iѣn[/&2^dL.ORƤ5+:C0ݺ8F|Jδ;u#t;I'韰ō6)⦼ZZ>Yv_+$W lyU Jе3+BܠfȭhiAJ51֐=k~ )K@qU:#tw@Иta&T6U$>͂YQX^-&AI:{<]ʞLjKZiWkvZ%eoNݠʧ#tlu+.8+IC߱A0 ;(N^tMt"5zt[ c'YonMZ*,dРӮեsQY UkTV2|Nk=&Nf-P嗫o攥Չ1U~^j|mMl=t`,Pk+:E00Qo".5[":z鋣~\+8)͝[:z]z(N貄g.n=AϿ8homjX"݁nVJ$XwNYi.BSʽ 6 'D#ºm&MSޜ_Q}XL,tV&U /zH-,e#jIz>}@W ݈*{]ݥ+̩&G:Ț~)νg@2ONÁ 8_0;bxZXZA }"X aոjkQK s_V2gG q LӶcA.mvc B`s@' 8 L0P aOp@ `tX6#x; wAgg Z}c,v C}gyD0)"܇р`Azzh@0@g a4 `@Ѓ3C0L0P *o[X?t z8 =D8޲ u+u7?'@mA}H{/`{8f=[A!UEd5`6aa?DA{Rz7ewa8c0Ű05}eiەˇG_ɏ.="|&O>Lvp~a)ɵX/s'pc~L5Յ"a]<Ņ⯭Jo5E+04*.MUm :>̓Y͹S^.1`n$m R_;wp7?'@JY E27 ɁCAc%RYa[rPwZlsY܄@-)i,&Aa"P*J/'DSz آփ1T:r\O ?!-/@$-h%RkX $!dfF=)>/zɺ|o~N.[KPZZ)ڙKd 0宖!k| yR?}ީ~If1 ~ZЋRT>4&-̪; 2 ztXs?3dpw7?':usrnuW͂]AGBXOW u]w7?'@#A4K$-ߡQɬ9M]]=i(c'AIf#,P*ƖB/j}iL9nb R/a{,uv'wD.SD-ifu[.V݁nVJ$'M+ױ^J84k܄:KT,Soy9AeVO-1L$w@ ;sRָ CF鍨}4)4ڗ`z[ˤ}|@Ѓ3zـWM}f˸ / <,v~D!ڌM6KS/!l@{p ͂:n`nMQ/+NA-Cew> Q/wBpWzzh@0@g a4 ` :;тzg>PYP @6Zgu  g Gp= @6Zgu  g Gp= @6Zgu  g Gp= @6Zgu  g Gp= @6Zgu  {v{ -Hzzb"ũ;ww >m61BL,`,;sAammEӋ9.k;L][G_z/`{:;%iP6ɬ-OЙsn "8uXe$m]ͳ)GZ4JXAzg=LJIEhUö^W!qLLA4$̛Kz.D3RB^Cd^F"eNW;:u*ЭStE'.05)caQ`|vZ;SVaqrʽ֢8c"-GZSR"[an `Ǥzuc'YonMVjEZqD6ku\uBBArjeh]uj=&Nf-P嗻8]ݡ%e+{XzģSХtMy.}WZНfKz-*)c*gZ2~&i~> m17ƘXKgx":zub\[nF~4/=ҸFS*ou8AgV{ZWAϿ8homjab;*wC_߾BYUrlM+]yWŹʽҹ9S]o_G]L]|ԠV=FpД*.[=)BJm0j4]*w{V1,8ٴt容Jeq|*w{]ݥ+̩&;: zk\jr搩W:Pv)= umD?7{E'@ЃC|qAp tپޮN[G`AWۯ&p1&ta.B+WL]DžA ZW>NA77N[G~KX=h =+stmSE}V>zp{tmSE}V>zp{tmSE}V>I/@8 zg wkB-곺@Ѓ3#wkB-곺@Ѓ3#wkB-곺@Ѓ3#wkB-곺@Ѓ3#wkB-곺@U=Y:=(Xv$nk~{[mulMn.O.wTIL γN-裯Wpj^gh?~.蹼1zA[][yқGд;)Wpzfo)⩸tz1ta0&ZwkwMrW UГ]ڥն=Bmhj?7}p@q9ߢ8L[y #iꙮǵ1z|wɉm_X\eN'}%*jVcB*}($U]\!#Kmqci?t)M7}nt]=4_TyxoV:~N[_.:$6km4BH-R3K)?}yJͷ<3=Ac%RY3-9;l=2J`"@f*^5 AO^ 75Ux,/{u1m-ƺ-KG%L:,j\]C'תF"I^T_Y@U5ҋGE{Zizjŧ;IOqVc1/qS3ŃA V 2kΪOEAWRy2Se~炫.[M94hvL.> R:,tWv;yhN-ndI7URuX.=?Y… D b&eUY4A͐s$$KᐵeJtӵL#y{np@@N3azQ׈nKU{Fa zvPirG߰<ڂ>z{zםpcFӊSg8:JADLڪ 0;"4*|"{]Mq+S{>cQs6J5詸G#Bл&*gTV%,Wpz ^=٥]Q}}\m#̭C_XߺЗMgj[ --s$v4%)TPR]|?m+)܋3w쐟C2i E]P2)n_viA/TA=7b2'IUVʼLmw&ʒ[p$j[Ro\C{m$R HToooYS79AJA^:֢8"Iz>39zz└z4 B wuL> zp{@{ppF JmAݞO7=dz}жX/C$h t/}UZ4Zk0= A^(:Kk_AL4tbw *;R[TfD&UypfSsl{:|s>D]3WvhHM[w_;˛k, m!=DK!kHndKl}yGk&F#Ar͟&R 冀+ev $3J>j[)%Lx*2SgLun1SGّ._ɣOq<(T`sdK-kQE%_K!MM*)Uj)\*2SpUa @4G Ɋ'EZJctk"Ъ,/D8#+IiAj yGɯ'Vls-/iF΂8]i4]LJzzWHE.*-va}!· }^5ёucGEF莗:'FwƷlUh}&$_Tղ;tJ .Wu]((X=qC7E5]jdtL)H}u|E%(Ͽs*w;h[X5߮fdx[W&ʝL*j0Lū=->]1LhB+1 zUQf^Էl ;rN!k˽^.vG.&Yeg[y Ct S&XI zp t/?ӑ}5-k^t% kD٤*}<@{p9fvAkֵ%]I:-/()}@{2"TAzzh@0@g a4 ` :;тzg>PFлppF  =8S= =D8)"܇р`Azzh@0@}z =u0L0PA7]R+ICѭBA!} mڇ!PS!=D8 =xC{ppF fN=4¿rqf'a[^ʌȤC̒v9\qo]Q"CpVX]ǀ;G'cյn8h3=ֺ*RYjtI ;\=^3)04 zޡtܧo6}bFBmĒ?˞W>KMWgs *L.8UbtZ NsEAVʃrc xj5D@Cv]nv"C|ZIăRݦx9RX}K:^2̈́!"35%ewlokֲǹjZoKYp,SW 2-*RY5DTک=-/7tN vГ֪ YE*e$/iWңrW)8ox \\"W5IЭ |#ԨE*~2hս6L$t'PTQ"͒CYBR92m8Bӯtiɧ Mw!Ʈϡ9 hEc{HrAh]}3.RghUj?zޡk*_羪٠] .8ηZ75Kb{C4I*V4].()04ڭrsqRF5))UdRTa*^u5UtpyMg5$y^K- Uti4"*dY MR~;!k˽^.vGKmAf_Oo,c,^0^Q@`xpˤā9 o,#VЅ7N/()m(ZDd!]GxGE#t&鴼@ 3zp{@{ppF  =8S= =D8]ٙЃ?S2bu0L0P BA!} &(L> zp{@{ppF  =8S= =D8WJwMG#N=H}uUppFC`jPQ76޶/em Z0A9x =D8BEL`)54PtW<8C{pʙ Rj:hJ3A'v[_XO߰t'a[^ʌȤj%%sz3CgCrqc! Y"ыzqqnM"[cQ+LF1Wb+3-:d0 5C*쾗k{q0r>a&Yؼ@(\ E Jz)tU~:`CZq.gs4#VU {-Y%ڄō\ylY#R+Y^BHs-#Pxz"C|1RT&Mn)%fBWJַ`cFe1m#H=^kg19|kuoDbEtA;ނIn2> K׫..7tN vГFUĞS6RJ̴1*L - \\au^ `j'=^kg}Aoֈ֥Qgn6h0MƇ]ߡ}*I7bBЛ:!<;t0]6FCkQ:,Hx]UB~LvnzrFInpR22,C*r_N&L5&$UW;[5ϡH+W uxZDz6jn܈po%gƓޏ$VCu{5+K*R[{Ťb =1"Ao@g-1>-@#ta9ڵpb6Fk0[ƧeX-UÁ ] &V!a^~bW*zlcP .HlձAV `P =8S= =D8)"܇р`.LD`0 Eot F`t F`t F`t F`t F`t F`t F`e!0  `0 `0 `0 `0 `0Rq 5X:lcͫrFY:(+_<.K@!p:gz :ހA_<AACc!t1' V tzb 83~J7 r?2| `V):0 #:0 #:0 #:0 #:02V{O6ssۗ7̱|Nǥ҃=i-Ǘ87}ݓKWAoc/]8STC<^ <w'c˫?'H#}x>B,3MZ(Ҕ]Q>ra:JƒPsw%$8 KXO~@MS";72/糁pŸ5ₖK*z֕ѷbv|mqamu!+Tt8\.RBddJJ uX]Z;R~e竅YB#zUʓOyFHJwq(׺MГy5dIĥ’PYZRDHw#tI%]fsj A_e/^Mz?57~C= 1 k4': HfGv%+t"5\#tgti\ƥ\t-/׌ ;bI0՜vgC`Yڔ{?b)w!0徑F/gMU|]&bXRKA'_[ t\YbSŕ WKJ̏Eq[R ]˗W hR䵸BC`2ElA9))L+0 #:0 #Dos7_!0^̉ ;I4@(NLŀX9tss= I6ALE[>: & n:Lm([̕;.,Kfms|#i.n&lEjڜܐizusW:gy^ib. \pHGowb$666rˤ7z-t挚3eq ")ՅlRd0PEɴ܏5Ϻ\UMܝQ0^Xm-(Zlj,>KiQ5g2葩Ij!uV00m+:` Ѝ8(I#n}7RmߍZ% [@LTŇv}V&輣.VAA|,3ViwqbUPK6A/J YQ0]AϏ$wu#}?MS, qNs컊y<:AŢ8S 8952N<;Pn˝ÊڢߴB/g&*c+]ɲX7ܷu:a5].=-Ң|B^ڈ jz/V;Ey|D'קA\D^6@#z>[(:0 #:0 :?~ LWJ {5Pe4m&О-]I.YXvd눁j@An,՝[c-L%GmvK+RXZ==QIot"qA#nx;ta31|OnĻk3sa'ڽqEw8?!A#LvMgo=}]st#v>u1h#/sSz 0q x͙}i s){tk݇Dٰs-A>6qΞÛL&;j@}L k[6 m!#_]DתA`"xtA߹hK!@Lq5%'jgK^O_,`"-7:4/WnUKfN != mWY4n>u?9q;j: .G_}wru d ]NOq½%?}O|L9d>YᚎEq󝒲?~ucgA/ ZhZ!芦C1,|`y^Pg'0̍y7ʹ@|P&t/~XfJM6G-@ @:Zp6M"l`ښz.kj?yC[@G*'S~A#j3qלNߓrυ~s0tK-&cU>*O'WqW>nGП齵ݷ9Ϲg35w=CGzN."\ kjaiqAٵſBAP xA'¼6C.%U2* qڔRW:^`J_#t?tp@:0 #:0 @߂ïÁ@ abG3 W5 ,ЄEp΂AChb&.+G]K,'CՅb_b9jNZ9T`؜Eυ3)M7gB6)A4A,r Ta3ru;E1`=Oi}~x!>5 G :?9}1 }e'*JЕPM`J@M u8ݢt(b\xD Pȷ/#7=QI ߪ[&YQy:پM i/!`LJg0ؐm^Ng ZK3!ܞSˮ5*0.irgZ?}aiq!A/g'>6AgNmm]r?7O"kkkJ3rH-+r_C̲k-Ccr$:W G  0X…s8{o믟|W^yq_~n},;ԩg h!`t.?;9w͔7~z-3O88@a :lojI9W3gN~ـ: ֿqASu OxAX` oja:/rA߿ A7.课z8B9L9\П|`o\ЙX+c3gNΆ|QP ߸3~ Ͽv8 Y"I텠,@a-cLs5=g:^u__8!nÿ5t~gΜ:=L_}]޶[:@)rg\V2JA$ ~ة .`[!L߀-W^xfAݥgJ;Hc~Z~om<A7.'O>˄Cű99^:: (Nْ̲aNI9N+=˖[Onh^-VKwR+d]XU(iHP(cR !nkf\āChe Ռ ( 7Щ~4?B %X,o\y >},xg05?w vNK^].\< ^=,ljѓ˸)^"8ntυ.-wkM$@)K.JDԽ͎-W9#%(> QCJ'PC| ]ʱ,boLlۧ]:J{Z.QP/Pf:lD)m7etqw.OGRqSb;#:5mn%eʚ#·%WA7&g}vϓO>ww?]?xguH]Eќ5d")v>RAtN>tqFEe_5vP*5ȥ,o{s~[…m\xas͋˗/&Oчtu kYSaby=]#ɨYЩ|/N*%)w2ZY|șK Eű*-Kٓ >0,vd1Րʚ#FlE@am.MJz!M>ה8m \]yO*n笌Oe t)_\Hꂮ\%,V:cNP^7s(l~;%y?RQs/?N6"b 0XG>ܥZλ|yj@ v: ֿAЛý$SqoǸ`: ֿA /}M@a.bW:,Q]X^ti:lzAxǣ/_D_LҩMS:,QН~P%b~mG !=}7*~PX9;tX<AW -gj0|r7 x/^ BaP}QW^dۖkbEqL~O>57bⱡzxu%oʔ61 ]m͸;@>Ula`=|jZM OЉE8ZޜEYԚm[,p%Z]|/v\XPViӪVR 2}Actu( U|ڂblܤ\7+u\ AA :9ch+GSm`327jN񳘍Gt%t[~"X2Ta8)赤Ru?tg`mj[G_z eu?RtWM8Hȟm` nzwYJCwk@am(:L} A7z3ptd 0Xzko ATA7>paܹ7Ξ}o'_}W^`>}嗟[_?s̎3;;gt: ֿ1AgsǓ>P ߘ}=O>޽wcwiWyf J 0P 0)A`oGh#:0 #:0 #:0 #:0`k endstream endobj 313 0 obj 24591 endobj 315 0 obj <> stream xXMoFϯ] B;؂'ߋ`lO>lS 7#~^g̍R֩ˌ(J %>i}Ld$7ؗD(S}l +yפSq&_@$NT gz RƖLX|H)Fz,{L% E_x*$7!P z\=q(/뀲ND z_K.H&ZzV>:q ;(4(`P ~W 6Pu{ι֛.~j\IJ)]OdwGųmrUH[-ayZ< endstream endobj 316 0 obj 1400 endobj 318 0 obj <> stream xM7 s>g4a f!==M`Es/ER"ekAM{řW#J5G;};;C~?~60__? wpQV~q/_o5 ?~OzaZw'd ?2<,1Ͽ;]dV|vȯO2gw4"^g(ʽoO1iK(׺ vm:Bc_rc/pţ *3]83Ѭt=%q^;",~K6 4 `G0br`zl<+0;%GATCoW MyGD&[U_4PTYdW5eTduKcv+I!rJ1Di2_wJE_ֻ﫱0Jl*(M%LPݺ)!W1 ^i~Kd(e Qnf*:hFI QA5JU,S!1b).5*de;=m+dXJ]W?rP x ])E|MFq!R/K8"6-;Zip: }BOzժ'r6)~Б+ˬ\TΦDuqvɔiJR2Ss"T@|GЖ:A=O\lb"k0F irwiOE[UT$u2!ojOp.p9$ޭƼʫʼs2mfxu @bxK,ӔMV=շXY-a)h^&īywnw }v;;n7.$NAы&&xMC6]"PYK(w.7TD'kh#Xh`oV $UvtWtwsO.0@0| /QN䨸)A#tg2dw[ EU/^Blz4Aƶ"k[7&Sj򛤍j -g3|wI*ٌ _?rt^LXx2zz;31cfx =pX =צTfl9OhmqLa5v(YhtߠM:$> stream xXKFW`oWWK-ث1$CKNI&!$d/W?$Khڥz|UU4i\w=moOv;ɽxF?$Fܷ'R*ğ_wxwJ_g.Yl6/xsrݽ)!C==}=:?⸇dqy$ϗ1@7#D;d Q2۷E./jnb.tc ־!i/ϴβǟ?pmIp:yZ l+cr,-_}ǸT%yO"mـS%]mQCV6C֩jNG_W,}B'l(vC M}kp: xJz+@ _9^%*xNRׂܬ'8t%2"!7SNTsQ ׉/,%]X*"qH&OD`[(zj| d֦<+V)"C ى2$pi 1oIEQ}@\kn,zC ݌rAm~x6|)ɽO|p **DKkTŌ&ulod$]6B|mx}J*fJr|!/ PkЅVN#Y R;Fu122I ֨2"nd!wa)X? KXt2!xquDއkGS 0y<SX2vrVyt`nƏe> Qݙf>IAyb3rvӊP:翌0chQ\}>f#J=#0V+$C8SYRz#=W2K6#"ތs~Jjy/`ݒ?>a+q -N2<"C@12qnu_!r@K4"4 b35 6Fd+_]D1%4i&JkTh˔5L5 {f!]28Snօ ~1R_.ҥ7պuY&lIɝ.Ͻ?ELhӚ6ji-FvJ*㖘8$w߉lc(TSwX]]<oʅ{yhFQn%*N+l. endstream endobj 322 0 obj 1244 endobj 324 0 obj <> stream xXM6 WdEJl 00I@{ @EONK~ER_-;8X&)JͿ<)wk?_>5Ϗ?Snݟ+}˸'gZ~A~ӻi7q4s xMs{;)o/+O>i؇~=) '5'~FvRQqsz.!kpgJSgDWe]Nc0颻0MniG#wxRrJA9*к$,r!P' SnxN2О8RB0J\3K(^&z(CZ%Β:φ] > stream xVMk0WXGI!^' =ڦ$-ͥ![co&,h͛3?ƚez@ϗoӕU9Co,=W|//Q+'zBײ-F\]xfm~8W uP{sjp?n=O1)dz|,s?6=wd:'?F dit"*vv$/oeH0Ej}.9L&rE0Flyn ;M4+:" 8BHȴEtW-NDsB[Dҫ$<,$ |XLLZP"kh\BF 1a}hʆŽ 6O/)dڗJ3aE<VGۅ^Æfuhi]`2n\,z* ~ ƀD4nݔ(g9gy,D4yq.gCa+K -T4C܋F,B+`Gr$AU0׊vq5+ p 6M BS{PUe`- D9.÷VׂssK!ғnɦ(7ۃTzx5N5ϑupnGJKG@һvFu!3%<%7AvI&ạ F2 QR'kR>SYVtC":յ|s/GCdWZ jGߟ9TJ鴞^4=/i+$:]*_~Kuܛh endstream endobj 328 0 obj 815 endobj 330 0 obj <> stream xVMo0 W\ DI[;;m놡ݰ^GRGR;]QTe{iUS8@4|k?ݴt T3vO]hD_϶:Nǰ=}mo8(=~6wbnp0(͠Ӄ }\dxM^o=0虩Nj0`hmQNxˎw8|tm^8  x1NyC ҽ#a "*w)!_u%VͤLƌhݜ‘Jt\ǃ0&- Qqʭ.Pc=\R !LF/:F endstream endobj 331 0 obj 910 endobj 333 0 obj <> stream xXKo6W輀>D q zX6],6-Γdˉ D83|`7t:͞)/6Ϗ?7w(wE14wWw_7pkY!m؝^uxdT ~3::.6ϗ J?U<ۛǻ/S!O[W><A$Ҵ x6U9RFw"^=d]]cg>[0ŀ8!'\*?~ ,g:\}";N 'F%*O*򤟜ګP@W }EH'°0qÁhryt baB( Ew0QcNY Vg7BDJq ڛ^95X,_aZLHE***F6t C{>`G'f{4wQlQwX{Sܫۑ/U4ΥF]En,>WA%^ 5 [>do{QW-5$EkeV`)[I Eˎ$S)CWư3hAY %e$uYѯy %Jߏ샘BҵH.ΧM h΅)j#Q`MI)jM[JҒ0V,ҼXzM>U`AQܼK%͎(~ g L~Zʺ 7yE~Ӗ6y7[tXku2557P]dpjb-c G֞l+C_U2m{Mu{$SրLb L,O*HL;.Pve{nMPk1pj/ Deʆ| |ၙek{ oC}6!<6z H0vR`dV эVt#&X3Bu*;͙훒J> %rwД_ʚwhn6W7v7SaVև+j+`1qb+n-Xk#If.> stream xVKo0 W< exi Nۺah7!Y42EɏLt oiCw|Wީ (hlQ視OR)zgMX:l~:7݂i:SwG;u~5ܜ(} QhGqx3$yYhF wv,,,`#K= /zٗGʏ@:K[V!e`vV;<&ttqR<پ+y5.Pbb MXNosf4u1aI,1L%> FerH~~Kա$2-XE_C+䐢L'>l:Rur/ tjkYfutFJW%ӆuɕ9Ec)Vq:Xv1㭼0]s|>` V|yf8I?ǂ9؆M2!˦󸮂`q65Ic0&eݕ5M{\ZIa,T ]cގ}%G}[O)T*mE[-bDR9z4J`!a֍bm{\!&!{RDk;WUTLDXz mSg#zܠءuCaKQT񙿐8T4%b:C |0O]x;ztuEyAqW7\^2 &I c!` hWQRIW]S:ʝg17bFkzԳraY!d{83IȋOIYJ endstream endobj 337 0 obj 811 endobj 338 0 obj <> stream x xUpU>cABmH)R*PJ tmŻy} ʂݫ`kmKB6iwKLf4MBj2t+gr~=df̍,9/my*s!dA̻H_b*L62))@&V,3!2sPvl xS45FNh eSbjLYIkdf.JwV vƁ;o1uNwa$D!#t |~sB^{&40V@~9]7`V@g8A BR iHD,UO e ̌BA^&{&Inu5pVSv0ynNëH'hM]P}5%$+ȡ' BdKo뿾%$YU<ž.Y.%̱BJkxC (sy tr eB\ޒ@A OWVBV eZBĤ$TT@Hl3A CR ayÿ!K߄"9~[oEH\WC@V`UUj.zMb&<8MD~OƜ{WY+Ё{U$hjRq 8ڝ2[OmJfj*իP?^8PbPQBDU9 --\z9vIf:W_Y:%\=_pB V^h CMZr>m-׳7l_kx!MUߥ$6/fi?NJ /;DDso}Zd6|9Cūi#?^+ys+,k؞^>ˑߨ޹fk ׿ _n>'YX@tTE?yؖ%]cqbRhv fmf} B},o*&sީٳ& Ëk{6YD1^>F~>iQΪZ1]LF/Ygr?/J0+:#g_ @F"olWzw?GR6'6&hǪUZ>*y*7ga ^gG'rBkbB2 7 ұ/)3U*O\~y"oN>ҒԻ/ir.DsI7!yW#^!JfĚ^2 ԼbԫfK+?Tc/ )ezoC`P;kߏv|iIZbeO&ka=[[Q+?"Ql" I ]l~)]\zuzeDղVyW7Aϱ>6I+L }~xLjBם0PI6b+ܪCwFs)G`+Amkr]AXZ卽2رtIV:t`A^eЋ-t[NN'uə}lkYjk*ʿ03BActDҕ39dyJj4vKCzјbcMVNA䩥J%RXܢYy'fhK#E,5q(A|ԖojdQV_!E]]%g߸)_&}5@%MRHuLMߜ6Y)Ic1aN]A~{ǻ_%9y4G%R'+{Sx*51=l%كdJ! T;0(( A(RD1cR"4̅ڍqVy?KO?/7t֯gfTZ˶YyIUetp}@f"u^ڪ4¬kG4H=.ouw^ =oN.%%:o1cw=+D'6Pr猬\6Yfݓst"ukf&S*<[./Jo4Yynf^_P}M.֜$CWu0P);jkkBD Y#[}sdt̟L<.t<;8Dz`R;*rDVf)fjtP/QH]T}jacrAyfM'+>w^-wk?Wc-3SiWACМKACu3a" k&4j`NpPvt?qD@:vhBW, Z>M^NII][>ia(h4_~KƬ2;v:W8yA{55~ߝ=:y[0oOsGY<'\qkɴ'OCM`>9oe U𵑭ś'y}~Opؐ^\Re_v<#? |4Wyo7(4o€r^QƢ,U 9)h]C3@2ōb)7[fh;Z_c+b@O|!kJnP{&aI6r=a}xHFiy\_?{PzQ4 pסW 4k $z{%q}=F+OsOEܚl-ݜM$ILvô ttMCp)t/'-zSh !S{?dAoχ7 މ16 %UI&Țvp_Vl(kTdӰ)T*_ Ù1#䯳#GnC~V0IzvҚulg 7ᚽ+@;_qHjtu_.x[q pҪփи]O!agZY&q`Ii;~e ?s;0 ߫Hok(cWfpo<~8+2#,E/ڋᧁ<\+b:\@} ``xx 5"H"|ADX GDf"K_//*Gɂnsq}__ō;p7/ ~ E"|/r@*/ȗ`_# ₿;~!@} ``x误? 'y00<ןqKA 7[Ja7Pa_ kzæ__ѣ}OZKk}"03s wA#:4<ؗ}\M-zd~pbp@DFN$̢[MS{? >x,ptn$XciD7V=N1;+Ao>%/,%G!%nVl(kTdӰ)T*_ Oϴƴu;Z#)jTL ͬdץvG7aHu5f+nFI=벿]b+rINo+_a}/mD[F miξ T|?f;c_B5)KjN+{Ooh~fG"E]Qخ~sNǯ8!Gؾ> gXPy+ /9p4:;;6ׯ77CjkʃY,^Nl(^{Z<=!6< %{e1D)EѹEhw$#rX,5=ͯ]hDi6;IR~ -,/R+-f3Q ,EQ\b(6ūꪫMm3=/y=yܚ#>ˢ>$YDž!7j~Yq9`3ܻl"WP T|TmRkʜy~ř&PeW_ ,cW6< %!5U+N  GZْ` jzB]y-A_r _7 ڤ54@5A+_ R/z\Ekľt,/Q]+V yYᕋN> jhi==n뻋 Vד?G^!Y7w/ endstream endobj 339 0 obj 6178 endobj 341 0 obj <> stream xVMk194ZchoCi)IKr|HvhG3o޼ӽ(6hoӍE ;Z4;'{Ar,F~xvj[|"5[unw8j3v@S]PwɎ&N3ī6@ǴwS11aш6v|;Y2jWb=BP~;YT5. `phe O@<#FspŅIiK~4p DGAa1|jf9g{{_O[]8"BӊH~:qjoZ`1gq-w)*O%W;S%}vI|eC *h$dyMsanLÐ5"JNku] r+^ZB`ߥN3aR '$pA ݿ!*,WE#{>2 u fP^K!29J֥8S > stream x |h RA`QAE@0NP$@ZVK9<E El(k[#Lȹ}ro^ݙ~f|1< 7v_q C1EKR .0Ktr3Li5z`gBQNX0&Cdl97B&C'-U _[ je^<˲ ݞߔ^oX=?`?x %n=e'^NH`pΐ7_#O6;/:O Z#X֎Uv\%"SvlQfo^,K@P>ddJ=R|(ÄIyMk˂F|%q)G;̭!pD2Nt3@t"E]䲘%83!Z|MV*l`e*>TUQºda/?W]ϖּ˪ҜK'W'9%V̾ᄊY3ʦNI$‘Op>q,+쵟RiøGjKD*kvv0U XO@26 @+oƷտBǪ_̨~nAճ~3Y_\62#ٱ%uα9ϊ=,LPv_SNl t"ޙ퐈,ʁ`v-K[w_mFծye/,zn뙹ıUOv=+kzeDGKߕ?n~`@K;<_,c`ѷt{'*&S6l^YٚVHzׯR̜TxcXǂ1t mx%SoWPޙOaG̜X׵kCzjZlsqcAR#*f(1|ݤMPr0`iO 34ӭJv3ʎMye?E2˩,?ޡ;#k8),UKkҜ~LV`+ӓj^̨yi :bֽĮeS&R<ˆ`IɽG& Z} o\r #yacd #x;fM#Uz̗tm=?W^Jl? 1wTs 3s]O._P\;vCYr O=WS},XG [~ k|akcgNlj ; }5vbY*fq1SUK貖?cElX a)`BRc݂u=o g$٨3t}k˒$t`Ms(A\FQYU%]]ʑ*X#* Lv*D+!ULY&IY'zN qf7r?viZ?\623űp-X։ ,1-)U!t_+HY~Ľ /v3`1ZڃMi.g/߉00[->6}*vdb)YӮ!AZױ=Vt}yd E/U`E&ԨqPN˹xkT/;N̘Hn0lCkIIה}u+;e`vlb kWcgƼpX7x/6) V'IT^VIcj8W}>5`)w'Jߘ"vq=G# cbG7brɱG:Lr.Z2ٙ9rQ9w+.wQWteTCʸ!%T=X"ku`'KE+sL N vN?Crv \udy'w]Z씓*ߏqRccfПR'F,Z:īE<P1%Xeݚmy抇*'jufTfLp{unx5+*gc8t_wo)u쭅TBKRV3R>r{<lב.`uSΐOe*ƤE J˳N,ZC'3 *;(V@{h',>qW.Nvu}ιC]sܟ"J5{nx-%~,Xҕ#]+tTM:/:OYtAIdș Jf{D!X)x{FH{gA&'ʷO L{˿R΍;8眻]if~=)?ksUН1Q,juqqZ=pDŽ]{_u1v١XEyoξ-LoI1"M|XL=UK Rt~H67-{~#h^?ٺ3I i>ϸ"5bV\EG=Ի*5Oդk$WWB׊wַK;k*؟ɂL3ϒ.k❶}dX9n"~:O<5K$yh܍'x%S(]#bc^?Qp_n|K\{e[v``xm~|%;nޯ;Çs[^S} o&ȂevJkЮl-&[F8j<Ь6Iptok1ҵ D]rKa}yM?-~FkIn) J_6!3@eʃ4-7됰H|wZvZzaWj=@/@0$Dݍ5Xm|!+Bİ{%X w݇ş `?Bt+<*Xfua3P fة  |MlpUY)+q{z}ڪ 9~{B &I@`, &IhCBl\!s ٍ@`5 AtBEĤ@, &`JqvbbvydFh0]Hp$x}~Ĉ"P ˅f5(s"+w5XBAd'91v6G";SfvVYQlZ 6l6UTAu] WuQb`ui)s;[|*^ڞ= 0=pMZ>9ýUvuU/mżd.MSWڙ3w ST܌ʫ@P|Z. y#QHlY(TGRr9ޤ$}ۙ Mwr?l%vݸ17r^=r.\оAKj*Bi}C'v%}WbMy4WGr!>Ͻ[Z~EVF]7`i`xp+VW܋rOrcě`XunC}?/w(.-#ZP? 4yFvvNQ̀%hincǼ$熾A=uuutr]J(.!X0y {4=j f <5=7=jl  orep{4=jl ,_ۣ@ٕ5.G]2usw}Nh[8Nhs\*M4 AB (>ܽ|gFCתQtD'zAT>z~ w'־^キӶv`ÂNukʡio[bod󻤒S 47"Py3S s$dVFN݊ivt]⒯G{&A+7*F5򏮓'Z$hpJo<.s+TI]#DYsik$A:]s=-^{!_U]qːKmn9haEMqcs @È`7IKU:(Rcrwtb=TFFiI pñHf׽dTW! huy\>cE'O8T=FQ|>G E׈"5GF/oNHu n@~-X jgQyw۲8\n(,ۥA"Q"QQ"QQ"QQ&|^e嚳n@2!kv33:C٥,0;5,'W2 a, XRfK.Y]"9IYbZ69*k H\5؀[QuS†!XĬXDuGSv9Iy휊i) 9 *4lH,H 6XiX\ E,j畴c)_qE쪶զn{r)yNŃa(X^aX~0V:r׬RA}f7_(ݦZc "ƪU]"t{e"` 2:jvؼV2W15VfTOx Vz `+ud!XXU7sVՙaA.V~28Rf| {"fE{4w?C`e,%`e,%`e,%`e,%`e,%1Uj @H=XD{4{o$ ;'!XKۣ ",ۥQ `eb@2hv{A,!Xg\+|`$ X0 L`$420 ! 6PM.B &I v;/"X>"`$4 TH7 @`,YPQҢoJ  1y+:eǿ%"k` 䪬,wL] ͲݓM|B;/ @!=bOo">>/(v=]]{/ @!!}^U.W]v^_` `Eߐט.'9gΝ;{ԫW=BfCztX_MX_ ApN>uI{pԉJ/m?` L8'O ؀'kj\e^u=.!aa A$ᰫ9ސIIp&fؕAʗ FOhjjqzl+춘% n+%` puJ/rhCu Um+nir> stream xVMo0 W\ DI[; ;m놡ݐ^ɖ&i1U"Y֨IiѸVh}>ݨߍQyNSC#~jGb~67Zň>_ON>܏ǦǰZNmWsl >6{AC :jV>%Xΐv%# #/!0̮qQ . ^?Fȓ 1.}@=a 5[t . Fcz5 9c3r!z5c@*_ׇ$I gEօ֯bBʜTE]J'o]Šv#W.yL"xE!g۲n-fmCXs-\lr8&\Ϥbi;4 [@T& n'ScsR3R ZTʠɅ}8-XoeD`ID.()Pi[RAvX4I;R09L#n8r I a/DxWYLԸ.szrU~be)KyMr`b7fL5Mi7OMq1wrfa%+Y+Yt'v5[-v,*}kZUũ4hnfm`A 3ceCܬ(sת\gM40<ׁzSs_ֆR/? endstream endobj 347 0 obj 747 endobj 348 0 obj <> stream x |սT>RWQAE⃗bD   ШVZ ǍVh""QJm`$<6n$c̙g?g̜sddQ~ۍ'q@pF7{v3kA7lL=.g/򲎡ב>~o[>ed%76[IVS4oyMs[;-9O/]Ϛ@Uăi8Inw붍&- 4R:.8Xq}zc?Tj ;^VK dݴ2h@ZF;Іo)M]2$R$SFr΃ǸEI-|eTp]6P_w9q??aILUJ4 ќh׹݂ ql mR:~Z;nn787{oՓWHP+ !"I݌FϬk7i`|`r5`z\9qF]z 7o@'iOSD>zn$L]SULIPO} ~3.-]3Wǽ`3*WΔԽfOJIy_éU+ WLxܭe7 zϸۛV(54AU3EHdͬ &f*;S:ǼGdhW!TAGz/+?VBvj~=We)%3qOل{]u3B?Z(QIeP}r6 on8X@"iIy'$)M2^Ȯ{qPR^5^bRz؛=co.]): ^9x1?aT^e;9a鍌u~w{;iO|YKmcx>'!FGfc "S§jfJC*'j.w_A!=~Jbj jT=$esJIn]Ui[L<J4BC1U>mYr3~/SfG@mY S'g5Ne S*F^Sޣ,ƽng F0!#P!!anߔm8<q!DhjEyh?w yC0?:T՘rO+ӯ)Gq)U0pA*81i=qnkzչ+Z?Kќya7/&tlqWo=ѤfGH#72%8я(yA 6;itЇv'4-bEuz[4޷x_~7olWT_Q9}îKS*ek~ LMNYTrü3N6'ē:0Dڶ _#?(Ե}:gDe]s>9"z=yټJǦ$͓‡9NoE #2_i_5;zGfѷfZ)AmkҾ{HS``Z_aWAVHG|M9U)Bɲ^Oy[P|#loJʺ>7n;i䤻eٲ{Gy8#}'wl<>:bs'%Ц.JTN*sPAUw{3~ojo5㯆tRU~SvQDŽ a'SR'Es:U&izp5c6h#k.)W؟y&V6 }&)xKń^UzTe\coZoU;۟q] LQ):S2E"L;3&& JÔ9Vq옷 M6} k兩 (޳pu{_EC*zy}]ۥx~vx5ajL./ə ЮVq%BeTk 6v8%ox?|%ѻ^ov6zǷ\ͽ:nÖ}xqյ{ n6`LbvLL:VA:FZ2>.ڎ+c̓s )o9*|JT:KO/Tn66L,v̟_EXziPrJx>7$1lLh%=}F5W4RY>]CLdu2.ߢGGĘRBF$z!i ?H|k~;@.S))+,] R~َmZKqv(n}N՘<\Z37])4ھ)4)4)4)4)4)4UL}B05-d fDco|F42b*oPr!S)d V2b+d*䥥yd@YP2!C+55g [LG(0eRKX++Xy0+yB+\NY)MSSpU"B W܍6 ruliqTS`ZcQbJW1s% ijțSRoy^M[li4Y !h v)BMq,=zeq)9UZcAmĔl؍ YHx7p.!,wS'D W ;Κ?fNAsO!!)!lBe-|Gma#OO٩i-?2]/Ճ hQJ)Rtzcj+$d o|)Ă))q,N,dmbo Ss Ln]YS4d5mDʃX) BN^&g4:N6M:{;q 렡YcATm[>剺\Tq kc46݅;X$T0zg5a#p2 0(cԅԃJ =S9C2%h-Ȕ|% 7t|ʓ'?ʃڀ \6 7jJщ&O)lK'@=sF #cA1cJ/``YgJL!+3`542+a(x"~PH&*."eP-zM)e=PM,2h8ӯ%y9ٕ4cQafrgΔxS֬֘2zLN?FYQLus aG@-d*:U eI2b+d B2L 2F42F)4)4)4)4)4)4#cj;@%G;FńX); (*Lh##Sh4[JFh{&L .\LLLlLlLlLlLlLlb F47R*d fcd fkd fkd fkd fkd fkd fkd F[n+W\|/pDnnŋ}UL(Ю0 ǎ 44jk6{XhQ"Shxڵq`r)f MM:8D Z#Sh7Aг?97O_>|3?//?;;;Bр й пד @ii $S52v_~e\( ~l~H55 hA?;:8ڍ^jL|aF n5ǭ,X 6lَ{mۛԑ#ÇCDkd FS5L`4VpNfr࣒ٳgU] 7/}|G› z `&@A'u}"Sh{ʕ6S C>=q/qˏ=-g9i8!=\yk.`)k?ʦYB+V5}g9=*Oő/B0ud 0_A:t(p@`@VVVXeCn40UQn@=O'{EfL^]s{r2U\xG*2v{<꼼Rz{4[}]&ɿg`Iキ__ni뎆2! LFz-,,+))y7M)~tK替|ӧ__ΆԼy*2F52F52F$Eh[S1ta*S_([ h)4)4)4)4#cjq#htzQ8,,72TP.CaS"J"`<L@֤uH19 daM:!^#@֤uH19 daM:!^#@֤:m9nw)ַq1ʼnꟻ=b/0z7c*} 6Úe_X1ŗdKq(ޘCWTӍ[hٙ6`jsK0EncȔ ʢRT d~M24i/%hiB˶eǤܶ)59I O)'/KcK>TŻ~Ka z}e% dʦ3\SեWڡff@x VR4*yK;biT~mT Jx 2=8o^&QX0*bg^Hټ% dʦC6fг"i(BSzX/a?Ş)P:5z6tѺlŷt|QO5 NIeSg!H)٭U,O6܏Mp#}G_Cy dhS2J!l[q1\"WGLRf { [$WGLCCaSb%4æ\2Ji)M:2Gc*vh3n)M: d R ru+986()VrH3pH1lQ Sfbؔ@X!!Ű`_++91;6dJQp$ b%4fær/BXI k:jSR4l[v0~),~#o$3 bӬAް^z)RM4?C5ZLIg5%X[X)`Je_z)R6xQ>~h]„){`MjQSuu{Ix ۲!}6'=~hmܔ)/l-"Sc . : ] zvKSi"lp)<#ukѣM52S"eon n۲T-EbŔtu JYOԗIOرFMSTb["[|ksO P/ ¿SabH­$=ZS\J466^ S L2l]eٸb 5bTҩ.6(bTرFf.^X iVH,ԟ2sKKCcC{Ĕ JLW˳mՎD|DZ!"SbJ:9f,eԕ{kK5CL(*5a*x5AѸDe)R F"Sb ޻zrZ#zOޕ)B)| ӓVW1q$(n[!RxI[ڐmh4^d*vL w<[-|xh Z!ۓ=ZW_WU]YbTʃRSR 򪐽T0SՉ75Vz+08"Sb:F <^d*VLUy5PCءҽ?jHxw]]ӟ)}eG) )):>5W'xT[^8煷F,^wx¿mdkZʬ6oKxkӯg3,ݟZ[kOhLxwCϱf߉ 'O4:q(̙ѳD-O:p$EhFhFhFhFh2uX/ŪZh4͟˙x\tr@knp v> stream xWn0+t.`EA@'@{ `iQ$-Kp%KNaD!Hۼ)zMOg[]>7Sh bD<íeZyŶ?nAM{ھDZmO;7 >z?D{A  ';M47< t@,ܸ3 'xeK!ru"^FCL݆ }ƝH??.d 2d.3gꋌ*^Y.xv0=GБD,qSLbm¾ČB޻}_XB}8V;h!ي^^E\எ)qsי՘\UL#nM 8B|Fz &Ra O) w!% G#Bg)BU\pr129n@qWk墠1wc> stream x `xiymŶUw[KRP#WA@D#aA0Hhѷ1xUn &MB }g9vg|~\fyn@-0|ga$F c U˴jaGJ d@K* m1QA_W YS w(dV; k<̖Ϝ'\>Y2p%W,aPqN$5W MZguAN>!Nuvc$wB,*|"\*,6b@US ̼=!6 !]]&=ez AyA[fkGt%e$}Y20d9HgP`sf%.]umzc”&>&*LTK_Ijiƕ CŪ )W2JH0#ǠgJBRÃi5]Uw}C[I_!A\1et)baX1}Dy8 Kgt+1$8S,O&%qqwX4xe:L3k#V( !AxGoJ )f38B22's13 |!貤Kg,= P3T_>_Qwzp:jv?ٹLN18#TilNi0p`::ctk?V\£M72}dŌT״_2P>?)c+ye@!;t.vQ;cX޴j5qvii0x b :KY&.1#1Z_+^f?eVaߧ~|{ĪTfukmqUTK#k6O㇒{HC£U 3L]:>+)ZAL!O0 oҸ]D 󫟛,SӉy~7ͽwʹwWp=8ě ]?"R#תPr)f|+d2 9/LGw sTCמ8K*[L`1YNΝu/5|yՋ=O>G'VW9gLŬщͩOWz #^wn*0|*)GE>*%c+u{.47|Jz 铜dD9B|޴naS\jӫ嬝$ˉ,[;1fb1l35ʬy2SJfbv{/RHE[=zef$f"UM cv<6oͮb?̢OMw/kIuQWt̵E#~ rZUbvce /#Yo6fgO 3Ngp<ّդ_-I.FmXM1f"&1;$ WTkUw+Ou?/~iޥ3T22:4ͮlp!}~jw{B1C;TVUG`[>ۺQVU ٦FjC;[}^\W|T[gVf.0qXb* *fyΚH|쁪+玭5 o.+MzgcM;\Ⰾ~&gv9vwrzrN`tVsjZbvɣV |[IcۆyzV=#LejDO5 ?6zQ$g_%bGn}zw1eA/MS lY ȸmX#{9srN㌩B'\5g{M̼~|杊TLb/yQȋF]Ko٥Ǩݏ^fGVUө)tGW|u\>1;g%g\~r&fGMgE{58%Mm=ekLndL7bɵGZV :c]3/y1]60a|8] tǤy|N'DC|Y?.iL=$uGMl%iS\|;)D=՘>>ݑʗYؘ_OGMR9=UiLziy'{*-4f0%ͮnS=&t}fuk(3+?\IY4-lL/uuzaʗɽ43{w|z^'O!5W$liU_'oj~̞*g kwx)fR|EW1(8>wdK>6O&tMܿbo|o׺'3dX50i]/BnD4#f+jv?W̎8]i'No6[s{=}YBgzda{%2U֐݊fwiG ;<##?x߾^s~u|nErs..pq-̮T1;mj#Z$c`t8mF(8#hVϨ$M>9fo N&=;ٍDXqra*}dF j| L#RIs{k?)Ggv߁AP]zf/N"lu-=i{+ïO5{[KqefיqZW\\BDMnٍ7. ug1S5…oƦZO5_w%qcgUsHǮg<ӄm:>/tWG4:>N+Khݺ\qO|<ΝSN%%Kȱ/^+|AA"ijכXHb7;ғI@,CR]Itw>zxotl۱B?pfשqZ/_N/ҫnṋ5kr|37rWQa! rnnJV͛裏4h uV#Bxb̎we}Ytv zibp:@u.|]s@/Wn8ڻa7w$˽#G;[owY~ի_uqw;.G<Ρ jk`k?v{IMm]#lmkSy|!H`]ݎgSRoi-3AqZ_z%ҥ.='x{̙3f G!չfMo%[w86u,%}1 I1!-+sD|JJXE"9g޷6?.-KS,~{A[IԱrۼ''9 \D~dWpޤ;"ޤwZ;;<0Aр;})C7 (;ZI1 5ԣ1>n͚55|>״Qޯl]){wodsaٳeРAdd~[]wcQSC^PKweˎ2\_[ a ,HH֮][YNOs [VTxW*VUלҤm(fG ]nՑ=%ClPO!6G #,ad/T\\죐:Dw^5ۯi$o!biJ_6?_2 eF7G&C{A\)&jFvġzҎw.w|Buԑ]_YPaW)7L.H^tSN:bGj]~du.~BR7ina<6 '~di{r8$vi3uo72?8esvfn`vlǿͭV[<ҟI|7O?Us3>{>?ZU7A{?p$SVeqj'Ax OAxė\HSȽ1:{i:H.Y){'ytν&!>I],[v..Dgf;K#> n'a2;@# _PnK-E}?TnY}iw~c ]Y4=fg|Wx<f彽sÏ^I?+߼}W_ePT {KJUrO<ݢ=),<2T/H>죐+.U[n"Vu~uL#Y>hݡ<ҞI= t:חv<"_۹g'*P1%[Tw@#c>/̏t|Z!ܯ[CƔz{ۍ4iUNd4|caz,ejO\.*ݳ4&s&U07;cËjHJOk/o333322f`l@'x !?yf~k>o֭ :HN>,? RȄ ~mmwI,줎em*f'3z} ~18 |W.P9A>.fVgqݘ э>IB)-Em}Aibv}Ӗ.s,1nv=^jU1w?kmGN/(>~Hη}mM0NNĸAP|pM_5noj׭n!c:tOxav VgAupZ%fNG:Kl N5+&$8 @: X=x :Kfg4 Df! Ⱦev@̮G0; dv$,0; Of7oC _ C.O7҇.`^0;@Fh;oX1@!`x F`v4xc0C; p㳛C;6g ϼM& "ZɵpF0;@a{~B %!ievqlv?}F_֧fH0"kvGmav}Fup(fpI DEӭosTJS&9`,*Y!NM5jT2 DhתqSj~Q7e'eR.E-`b0"MZƜUF S2 D

    -*=-9LWD,GvaW&,i9ឝfY¯i> ۂ~_ z9Y޳ F\_F"cv3yӞw>סC,5gls/o2p.iw0۷.`]a5|www<#hgwww<#Oc&#x F`v4xc0C;6  4dfGGH8~e@ev 4;21|fD r޸R+ 2*\f9c7C^D0+ 2 f!]:x `vR+ 2*f%gK]U"dU!ͦf%++/,-fiYiFl\a?UA0K>PKuvdfv|j1%_h7+ a?ut wvQ@Ov@bt0pK\^L&{I0In@Dj/1 :J\Ȫ2\E! tQ-V렌=X$1I*v{m˟iuȋRF죶W\El1̹OxGeyXWo~(WRn{ sx[uʫ{B酺 ~'Sy6;LuU4@MfyEʋ r<'jsx}8js ^t]:GYr)~w_(YB':'`̳̬Q *jXC1 AY_UD鷹X0̆)Ii:.$:gԐ zT=Kf0~9S)ۅeC]evNOxL^[&J"[`%C &e ]ۻNo6.S[)M}MdUJZ'1'I!+ =[%c+u{.M]fM]'ҿg2_hefdKmhv lj7\6e/-ٻtU{F\֟0;Gwcv˨O"%tIdczt NzBydmg*1yg#u*QUk*MyV9UDDb~8@tQwë#&G.{jʹc+2F:"ט+\|G^z7}M5;=DȟL?AuM[KαDg$=Noɖ-e~|Hj jWO8y^ԳO1M7YzI,#]Գ뫏ɻkd6jddGvLM{-ZË +wbaL:Уf79c'X5oBe3Tz Vb#/yq٨KuIAipGFv9;ҒBH ޏN'L_Ӛ4mJÍrloT,5xxx#~d|ܻ+guDU/QT|@;.GGv01]\( ,f7^6;M;6o.(2L6K?!.qE1/O>vPQe15_8C(U3fP[mos'=w^aO^FuXWVWtWiB<'ȦVBjn:+![$!1enc%WQGT޻|GU:ݬ_WMNS{y;=ps~]Ae0;GB .'8ΜswjqZXKrv6j~%yZG_ΖzΒ ]W=eK,IDL9d[%'d#{Qd[DVw#?Ep8@ġX{orb]JS9)UwX= ʡ3"]󻾟bv~낷4UtS(U]0gz>x&Z%qyͶ*Z0yb7%DPVy5W.eK,}m^ݲٱr^Q"[ ,>aj+:47pI<:cc~Y>>N7}HʇV3?''7~bwߔ]iug=5[G6b77;eRk]RS-w/VaS%ܦVQc.h"iK{%-߇i2ax ,4{9ʞ^ONGnޤ䫤w|܋B[vM?5J-iS{[Დrf+c73 R((Zd a)V䁮)]WLb͕Zޞq{F C{&k]$#;bv}-BEi*ʂW8ZKʻ4;R/Mlf Ɩ-v>5 MT]oIbvlX̮[s{=}Ys:mW"S }L-t2n!qѻU2 7SzOclծ]/s+ԣ%s.aD3;bvLcav=v!PmΙh^>moQ}v1;3Fw 8މ`U?+wrA?zI<y;.)t7ܽW Xov pg(ta={ٙ|4mG@gdF'mI:o,Յ:6p2cmz˛/L3g\áWs]?}u?Xs;_~w/sse WtYsa݀Xm;ۅDrܳә۫ԙ=5QYv*5X^S*To?рIKI?$tsl^̮T1;mj#Z$c`t8m]lTˆwaa1OxVEmnjIiRE;htУ)G,Lq^{Vh٩ cҵ\*ߏٍR VTMoƧ%]G@xqYsXLjHxJ½')da|0Eze cm%86ݑ2J1'KY/Fv!Y¶ٙH SN>`ԎgSR͏!;؝F(oȉw@3q;ҒBH xJX'(fgrƟ5F,oQ[mpPŇB3bAGGKu/ AHY.QeXZ<ȖFgKZZM30_2@J ׬*#;u/L(JfM6ܗdC5ѪLI/ xfW <7^*a0;;WmЖ)FI)ɏ9n%V;MIg(RY e3;83){[Gf%`v[@b xDh񝚇)MQ#ԭ*)A1#]*?{ɾohvv&iv4&9n.x|CgGGpܘ,,/fߩLGkGkA޳$[PX]Tٍ/,TS\oIG,] ;%*h"S-7ƛ)cyNmvlfRZazS4%`.&BӘF1 "5c2*FS iL|Jtŗ-]e]+lq/MlfrQcުxMdksHf8 g^:n03F&QӮ|@%%:0)̎e7K#^oO@nUiDmGOƅf `uŏّe!نÌ욝:畆0dkYV:*F%/oˏqƐ'(# bzЀM!znh|M (#0; ~!LRo*ovFYODb5TexDR d:|TMWb|]ARߠުޛӌ3R(fggSsirPmhzώs:ԥjav0;rJqav 0ӛJ2;͸O1; UeRFL-vpyDle%f=u0;9x0;:D$N?rcv&;e7;Cc:]Mb:[!@[8͎+\_kK?q<^>D T1:/bP$Cx@jt!|>Rn*R7j/ǘAuhR-f "dv ?^"~]+"tfq`vvf"+0;0!oT:Әf#]avXf#]avX)##H$`vX)3^v i>PTmfvmESq0@n;~: EEHcLE_q0@ͮVR(, )* .yavd& l59 YjvyYU%ڃJPZ jh9Jq]+8;V˂b׵ʽ(W5f$vH͍OnXmjmvwM<;˂b N+wvΑ!N]ס`vxZV^1%.`DvcZ6מbh2+2;nJN]}Sv4ڮDNbdV5l憳3xU0;@4&;Vl˗ٙm4txkQ=9;pRN:eN(qp8{N#dv>v(hAQG}Œ wpm{vDQ3NP#ut6Gv(\ff6&is шcƧ-0ޟf|ݳsT0mZ51$6 fq9>C~t# _b?Q+ͼ$M}fgv0@ׅ:Nݷo]0|4 *av!('~$? Aq0@? 2V]ynvS L]wb~.0]`v)##H$`vX#Q fq`v1 WšݎgSR͏ň.`^a5tU_?͜0;f#y2)0df#yEf rU&Jþ%[h&"͓!&edK9u/ }IfRxcG] :8ov~8_P_(B?٪J\ `?=_ymZ̎ytiL Y"_eAJrk TnV =!]Pj3LmQʌaavG cv_tc@ZKM}Z ٯ)szL2=ܢW}/+#;nhvpI4l7z[@|dOijҚ]*~bBV+i~No->BOcs'K#vǟY@>mfC8=u`FUgvy6KlNœj`NDsq#3{'¶q7,FvaqӃ<Žg3lhzѧ[hH7ƴE bdk/z{x64?٭{M_HsO4HjK{'Bzl>jާ1@bt'~f>)ΐ@>]ⴌTJzFv8 Ә{s;Eag' S.\3l-|~/dI^4f˽4 .>b{3xNr@ f'vg|.ϫe4SZE4 :j'¶1fg2v)rꞝv2w(Ϫ߉v55Ә^yu>P1yt1Χϣs6y'8Obg0G MNsɧi:%򲹗1-j" vp|3Boߊy1.Fwb](mut*vń.`^[ ?wtnǘ. <"\&.yjvBaᗎ OQїVN`vW+'3df̎t Y`v\ZQHCtuq5`v c%x 9J0;@s/!avf_8C(qf7۲PY}E>`Ce\.6YeMWGےjJ*]Tʱ $mE~Aʖ|A W N4>~ fGjm~JVwStyvTd^FsȺ5`vx$fG:Ҳv g!p0;; %v0;1D[RrrLc0;bN#~.lR/ MKj֧= yGT+xb[',d%|jt h TfchHhv-ܳqcGv8Q)n2*շhwTzUD7o_P̎H\587V/ۄ#UM$H:e` #e՜a8ٙLΘxGlnS eIRhz'`_q7Uߴy&:LuP'Ƨ{N$2c/H ?hivԥ4D6. zrda0cG Μ :>~ԫxIxqQE'5>.鄗3#DEY鲐dl(##KM~9ovDkd?lv/[hjKN45Uz5ԕv Z6nq:U|2uc(Ncu=<>nHk &Mo?Q46jOjGijv~~SN$'O67%RCo ;?x]:2ycjvQsq D/asFG6#h1`O44,?3*jL:t;qE9X1ta/'M 552;\*DM96"O[TVgGST/*0HzGx4;Nis^.l/>XЗo (kZ[krj 6T}}?Wk,WO*! 6gu#tc}.rGpyз%| vsyyeP﩮**ʫ 0Pk=ֆ|f !]EmIuA^!yu!W!g웝6dKɽ9^1=sgۜ<|!L1J٨ $:d^ij;^(˙T<5%{W tUYjVxf.8R:-GMڊl̔ 5O-o [M -iyɉV'2XkSe)0T jΗZAX1;w]C6zBss%{ l1OJ1$sQL{ݖXtx⨽^PpTqU6nUqhu3[49hn&nƪOWZ㷅@*,XM3n!A*UyiVgPw,P*n0;GB >DS&Y:t=>*Ŭ=+R2W|8[4,hl=^[Q:b3xkjb^Cgؔ6Be99 0xus=~[$mVfT5:A^7e W5 `v{DfDu-ٳtȐ{)|LД=S~/M!]/dn4:Bښr[ݻI_SL ̜=dyRNzYvi,X>DnZc\BHxV*Fnit Vnp  . 7XA2B3#D%Wo,+e|@(Z"s )|!CݞKWVi&Kez13#fT~cYq0Ny$vzDxbv+9\'Y].g٠ԢN.\ڠ.SINJU$e㬊PJM,͎+[si\xˆhSN\*maeNNݸ`Z~k>PV1b/ݸW' 9,7+-F w Gjjj)KRRbvĝ$eed|"ݽZ٥F?=Fοˤt:;=#l%{׌Nb쌌tS5˰K-VbQj!ţĶբZC@\WڄdgjgjTf#VsGTewr[k4G<>KWjn]*])Ϧ[*Ztd5Tnj)/wd%Z(kjmdF֖f+"^-WS[I0Z-d G]j R`Vh8ۣڍ6a-Lc-&D>[i l|m,W"nbȅ-fǓ csKE%);xP]fx%>$5@|ha-j7^'{u$iJ oer(/e޾R&RBA-Jp4m0wd~Uehdl5c!Rt̮*wS~6u6n;t[lf^,ym,1'ɚ>x8z(V,;\N6|l%Evuޙ)(G)UWc;.riYWmL&*5v}t[Xi$\K9zylgAJN @jRԑ/Z/rWܜRt-,NIZF9j..ʓvg[eaHytDrr(.NDfS5A+-F }p fwDرce(X&K/eJ.jPf\VLSw0~2m652Z0Lڵ[f8TIW3o+Emm+ږI-LI)Xha0ZX[f|pt̮DQQtj_~Q5aLv=zTI YƦ t{2To_yР?iKSS*Zr_mTfUB tGTha tGTha[;R| tD\)%gLR~DCuubnA H()I4"P|DNS"<OII%$95b%b beeZ-F Z8:fwÇ%qELW(Xf/5a帇Ղ;KY6)J9죆r`m85p{Zɇ*8ha0Z-6k݁0yA~ACA.Ev(\5Yk6U;Xl M@ ha !cvt_^6ߧOl.rb^~Cּ|CCGui<0ZXs0ZP!rppt U `vf k{zG:!AP'Sfw   Jx,U*5uU { "kv1w3AP(.ERlVw"/[q,*1]脺]lyF bZbv9yGv"͹6CHhG6NHRr<|-MfpGg71 A0iS̋:h^jdiLtDŽ J$Ų/Tx+Y%{FvA X6)Gɔx~˦iLU< JPŲil׳|@OmvAP+ *tK}fA1ovم  fA%`vAP«NH2;0; @$R\al5T7bXAEŴٙNcZw`4~*2zSDC (Šm3@:7#=; (C* 0;N(AAA ?AŸB0;Afҩ@$<0; @$<0; @£3}av jv $*0; @k[eυ Fڛ9( Ce R](([v^LѲؕ5C'ݺ.I,mMӤ'I9ٓs|'ys'{>ON4*?]ŋt6lذamL̃<(;̃<(;̃e{+}[[vH/PW/b_G_9ggn1Cp|K#[vڑ繣gs_Krc_GBp94^-RlĈxi2I/Ύh}7?|L|Qvt!YJB bD4_5a?羇O Q(;:_V渣g? nٳJ@|EQa_fK^P- Lx2ku/ʎ. C2IUj vw|O%LeG íw C2IU*%"˅|.NM¿|ef|;eG:aKfO&?ziTfl~%}6厗´$)eS60(ǠÔ|r>K1Wδk&l4t:EeשP $|W}pl㖩*aH2D,]vq%w@Ґ[$g8%(Q*r֚i+Hq)P|_2F@C_],,;t~Z>:TЋn]Sg ׷IǚTv3#?O#?Pzvs4#Knz)=l6NFuq)GzOEǑyh঺ aW <ՋuuSn:Xbm٩jGF|e5C#ݷYTxZ( F}㳅jP#(]f;5)H W-B&o%7&ߦ/[*a%j/5$'8 ~NSj |O$7WMÿ-:R~_ jw뮨_eiwA,} vuujv&>)>_]Pvjlp[6(';}&F(Ja=&<\p@3ti q (;[+&߮AJRk돨э􄯁"tj-(;Phߧ15 mFMk.мiiX6('1]-oRvIL>S$0ǹEukh!tɃ C.qrfb,~r)ʚWxVCskKzt/6lW.(;:P?ЗH6@Q;xvmޱd/>CPQ_3EyxA9ӽ\.HGLÿ}_98%#^\%gKc5Yn_G;ȝvEQt _f0);5F N7OL£0/3#)6fdl#X |W.0/3N:Nov(l I^[ G48|勲 ? 12 ڝF?盙GCkj/dⓥ;wW1|Qvt .c򛬉|/|3t7 . 9gʥ4|勲rpmR%?|٠v"@N^ȉ3l@^kڭd(_.|*VVJk!{{QiPgU:eyPveyPveyegR߽iyztMko|}ǯ-7wlȝ8ZვVnڭL%y,v-=1l,jmiDpYnVB{{Pv _l'0Vf-úinrk-`Su :MegU? e`~; endstream endobj 354 0 obj 27855 endobj 356 0 obj <> stream xWM0 W4%qҤJ-+m8 N g?fg$4L7u=#:m~= ^ϗg#[QFsfW~ߚW蚷>=7>v>~>7Щ}׺=?BN͛sHO6vCz0 (tp~_k]?LD FtR6mNzSYCGXMK (Z,bOpcNzL>!>⤜La`srla!%?O)O`pM39do ncƖ%ɷݔLw\0R l.RG.e >>c u3 iQ$$%;ׅ*P0]BIS2b6m6.qqJ_D[;dEȕR,;D&]+QN :AT$BU[y`QAH|:8 ~e)ƺji'7ߵkwzQT:*GZ6+o+/qu~wo%ؗs0m:Hx.7h;J9U)Av+JV.- $e8S]_LAA1Y&*I> stream xnF9}Kɤ@EOmݢ[4~籏!dq0Bmy쪃]j` >kOV? >>??_"Fpw5f qGW UsByXV_`~ſ ?ǣ2=jQuk;|/}Mo!~o^ B23\\ˌ@.UՀ0S\VHbps1&U^$$=ts>ϰ<X3ßi} 7!gF ׷$@Vs4w4ϰ|}(Ul׸Pд I5fN5ͦpG)83kDM E%>i` 3}&%#DSՉglӮ,<_H{G#t< )#$*X3g B5ٺD[i֣0z4>vONj2vF(ܺ%M<̯-afXhen)նݡ~R8ؗKثH=p(bb Vtdnf7 ] J0d@Y"5$"÷ma0"Ǭ}aQ#B Se DL T k f9LdC!AJ21|7! ٰZ:˹}4F:'ЩQdcBՂ2l暃zM}5@25}M KEXHņڦӬ>P(RvK?`lX Y +kgdV%-CXX=y6IU!TPmf0ea0фw LSBBc+WԜd vː C@hԦMfSַ䵾z^ƠuP Fh3'W]NZ%DfrĚ ˶k\e^J8pHT"(tD~\UVY1tPb(79氊9i&ݸhja׆,oRS7TX'yV"AWX<_Q!_$a3zBlLp&Ƙ],.E?FTs;$[c2LF$(}ЦWh d[9@K66ЋPrt-[yd\b8Uq' CX2wE`R.ŕt"Q5Sf1B֋*sjEsyuM6X+]gi⿛&b'd#)6)3X!Kjw`f^}FC曐X攪YCe`^>=pa2V'1eqƓ =-,wKRw'ŖujMƠ%rԐ#.3dL[W#]ZJ-p8Iܞ`@&䬶Ȱ}=ANnlK+W +t))J^P,Aw\RkirSb"f9yu8mbsV q!)hr_16{-M\ި6K ?h-vB&|'("EH.'wSsſώq| E7 <ɶ[ntaaZ8_b HQ!C*z?5T^ c#ؘW`:mQܴHP  endstream endobj 360 0 obj 1902 endobj 362 0 obj <> stream xRMk0 W\H*#NVv v;mh7$9mR $= cMcNP! /x~|9wdc9eɿa.ty9z &r[{= cBç Wrfn/zf(v++^i 5&*+PSBHdUu^vUHm-UKEqMNM~Hoĵ 7&R衖˄jiK^BYi0tԍK-> stream x xExYo_]XuZ4 b8!D@뵺~ %x"A.r" sr'3 [TLz&ө=T;3KUwfDQaNò)CF ʄIc)¤* ab]2a|=k&TpǵCwdqhSdh0B Z>Zx GY^]6/^o/s{bK="/ W,T:zM]g =pWX':ht캿S~HM-d5dا, R>![my0I Q%Ýj´:b.j&^=eHɣV(/ȅ]g_ C9yM@i/Y#d:7w;e.q bN ǤS$^ab-}$%cHRBS* 8-6tXIBll42j4П&i5:L4UzgrXѓb"BzvQؽ+? ) 4)CmlJp~_@b{ :t°DZ(F :nʉ/fso$Vuz_V9ɕ/N|nBŜGG:.yhlA7|9Gu2mܣ^Ȼ/#?yHG.~.#x8œ^"> {Q`/vs CŪw⣥ kׯ{킗jޚS̪N|5)?Q4|#aeO(poΐ?2z/X;#^{ GK-$d Y.sr"flaf&}R90ߑwc.+: /HLOu|ysvW|aRų*f)91}c:@Eޕ35\I-vOE؍k -`sΡ͹7C<9efC2?)w~aNX +-V1/.3Qؙ=hɜ 3G;/{jP{N7}i؞qۧ6/>9F2ni6nŞo,dn))LL h䵩 D/bkHy2 ӺRIaM~(ѻGn/|wÍ,&(["IhK+9/JqiGb>\xX/rn;hswYNIkaym9; ccc-Tt"ո'i*2~q*lM%#o-u[[?*jnҍ4Ukc+tҿ"S-U&Q]1kΒEXE{ٹbkiy:&`1XK1IW$ѴU:SaS2=F޲-kb-6&Tk6O=Z~KӏzT}Q0M6?e4Sc8ȵv{OVHڂ ZRjUDki{ꫫwjbӥt[z=iv~gsü{Zls (h#HTDʤ F?=Q1gBю>en* ~]:?cݽ5ñ[7RAe@~ܢ6%ђ?y]F!sEڑ.ӸzPW!Rֿ~zѕs _1GZF쾊ٟF3gE_A>A⽃Zj#,kW)չaWkUvskqƩ zi15{]1N:`&|?k<7Cף㫈q~1;=tt½3GUW섊l+K#GjPSbVݯXJW7bI&bfgeyZ [i'v~֒{e"zݿ>7-7|o[X'HT2όh3c+f=R>cXb\W>W>j>%B"jбص9Tm{0kaKt˔9ELז6ynOԭm)˯VȥN+wLEV`7'{S덌fڰ˨ Fq괝~<וol{2kmE?ޘD7,(um6̭=k7> d|N.;A?Ɂ #*f.OP N5Tr*_Y6ʃZ,RxwbZ<MZ]Lb1ךiQOzN }oR=| KYZA'ӯڼyoǾ,w{_<>sN!0B!㹌kɈ r@5jԗE޼-bn+(yݯXTsCæ&Ƥ\yFYtsU VqNކtޤJ1iODQ[G]Q2 z~ Ō˨0 6\R6}tBiaV&=xeߕNMDv/E?կ"ʘ^UojMx'ΊbU}VfK5Jd1]b*#3&]5y*xҼ~?=pO;:mUbN,v[ń<"esљ'vt }jqSxxIK>dMK?uڞ?[ş Glk^[?s+,&?viAIe23Ze$#Yǁ0yx@G@w#bҙKDm% cņKЪ|e3g!%AMY/4X= b+s ݗf?0 ,=IGU򣼠108}]sbTdEB=€N:?Dߛ)ix M";[ܿ~@2;)C=Џ'SXy\B{ܗ||iYI-&Ls! m}fC[:`kL*_dvcV!AsX#b/~ ,_`1X bb?lYYl0Xw[!'gn'2r)4c99lo?0'7wQ[bbdg{Z: Y`*>.Jp,_`1be( XkX @w7|.$o`1]H_xXdCbY0.$׺dɒ ̟?7$չ4{l.v©D bC,>4IC֩Sח帧OĞݻO}\Lt/'۞8A@k,"UU̙3ߐ9IyHPL`AA;1l%mYg1u%%oʺc*ү3ÔO tedŽJhs}yoŢ-}SҌzț] =Z,-Akl|Zj68߿?}?QJ21^yO+ř/e Չ2￟hHX( a@Jf̘e'iiil{9λo^_/:NPǎGO-wBFd5|(bNSgŨR_αXݍU;$+ś3YG}} +ab[!0y 6|X(ȋ@J6J"#c1Bz_*6ᆱu -Ύ°a!G2qo^"6l{w\q.1ɩ^% y=* / ‚3 G^vřg[یnmjIre:Q:Զ[wUdhS@Z%>^Pm(2MncQ 5e'+LNNYù{ '<9aJJJZZ̪UJy&%ozL+WƛW8U[_In?LbE˖vzBBO-ٵ+&i9 1rw&gM:3bb򒦯11%/͢Qm^䢪OwL"8 XlJ[G!Ž4L[&: [OYv{1ô=ZKioLJk7ҏ F"0չ+_1cdCyzQQrq ^hb6}qĩ|ծ^ ;'Ńx_[c»׎[3c~ݟش6Ē%KLŮ Ŕ3R^ilӗ"=u,W;72ob΁:d#hXlSڵ0V^lݎbE|A/If#n1D 3XC`vvHD!C'jQxC^C00%AxNfsRqm=/_X\L'(LVX^OԒ:19y-ӯqg'+-&i$ϯg: ['$9̍q];\v6t|uIMYL7sB lEeƥ^.ϵ.b? EG}^?:P#Gnܶ˶}8 qeﻇ8!exaK,_^4) ͝Xj1iȯD\%g^Br-396!>yiu1ygFQssMv,?8<:3[4nNy]3J7v#5vSXLPfQtLbf,FbbV`<}nff<f +W<4`/| ?Y~~obbbBBwoGɸq>#;abWS.U씾Ŕ#Vl.bx}otPm̥g۲nw;sw<,Ҍþݜ7*XQ } H$8 ,_`1t` ,ֿ@z=)9}'HzºbN =LY1Waimo,Q66bUaimo,Q66bUaimo=۔WZ_2neM1+ 6YY K\#-&ݵm[=3NI 7z'}cy ?,zzkw;cvYL7bsc , VqLS#Te+S'HUpmZRC0M{;:9=౑b$Y0:vҟvŊ&ey"Npƃb[)SʉTWm(vrNBs魑bpL;Ba bCA]+FMWUnG;9Ή X )v[LZ&p)qvn3\f'!]$C;yHYL?Ux/OG&΃'`1o1i.5vܡ]1~ŸD9i,f Oj1c1σR?x\q^jb ݲbW`L*Fv]\b|<8CXLvLPK6{fqM1zxmܣh l1(z<8??p b0kd83D$>Ut(`1g1|-UXx~ ߁lX*,mm?8XtcK 8BѾڷoŌȆT7.35vbC *h;J*LMN&, 0s5.]DE贛-v Q^QZ={{TB붉5a1AcW;UT[;(3< u1`-I ;Wtl7|Uv˽ fA1+b׷ V\ S~C͎䪝qETzSlU/lM:cMX AtL \rWW7]Lٱ{֦+_φU/&N/kb,֭_D@fm{ "#X(,]˨=% Ҏb2jOm{ "#XE`x^ H0-fc`1X A ,bXtc+AğX,.\7Ap,Qօ#΁8ºpxA9GUX H8?Ėł_us|XA{-V-$e蚐 Vo0:0U8g|z\~֮sg`1A8M-'KYi1jetQڝRO:|)anq1쮼7AbIlgJT7gYg1*Mz]u5.zs] a1A8M-QjLTO$2ZgtO|Kk>?%VQaRmn?`1A8 c;ayf̋i4V0cKTAyYeҒNwgа>l<.er`1A8sjLb.243^ZKtvT`/VKw]!xAbT #tm1i./9'M hcWe iS]bYL:<:.X AMSUL[|s>-(B6p#F!i@Ŏ4^-[{ێKJG*<5|!<./3 Qj1O H8 u bUa]n< X* ׍G$qTus`1.\7ApNp,F:I O0 u bUa]n< X* ׍G$Ey׍G$lºpxA9X̷ @ts> U|\nmrVf5)ǰ &,~ۗH]~ ,f ]+2Cz Ob迤>X,p_is/U!i췘{۾\bKX{n< X* ׍G$qTus`1.\7Ap,Qօ#΁8ºpxA9$AW" ?  A~! CA , X A7 o`1Ab A~! CA , X A7 oc1 b/~K`-f2 EDAB3L`1X b/~ ,_`1X b/~bYY[9fgd -FnpDnvD> ŲllD"fִbdThy)&n'K;,vT:-t4`1AX C7, o`1X Ab XLR?A-=ebѩRaj4D b_XTlBTߔ=6YLD&=&G{-#I^vA3[l^X!>Xfr_U(h9}nK]S)QXL3[>A=b TKVrɂDj tʹ!v}*/y[- ƔSg5\RC HBbt&RRN+SWFAX-ԏ d^,&m\ 03}&mnbd> #!d1jL&zU= A»ł , b A ,!X C7V[[hY @Gzb/~ ,p3o11AA ,!X C7Xp; bu`1,}CtRDy !!m-)Q5/3HR]UZH~ P؞yQQ Q}Sbi}ɏl 2F%oY/G״@y,QeGKŧL  ]mIGabIŴAHXUlyQ%; Af%*JuѨF=!1j侬褢sPX̗{?4&r 1A%T-NVi꠬QdV挢0A`&T-d":xw[b bgBbm@tV HGU#Zl}9`1A.Vk' HG ,!X C7Oр~ ,_`1l;y ., o`1X Ab `1A~"3OV[,#ѩ&Kܓ05xm3 i8XS]` ݉4Sb$FIdC: ^-9k]@9 fA po2, I?"n5M٣,2g-.r)4 HYe&UbRB׉O5^G\3'ibZg}XI+o%jr.ьźo0Xsa1X b/~ ,_`11:.b1Ohj1oX`7lb_vb-t4`1X xؚ(,&" Hf ,_\,֭,Wp,_`1@hSUWV订@m֡Bnr\xa1@hC⬗1n7)4|NeY!̏6oxҥ}%mkf'l^a%9>6 ɨ$c_}GqUM]Bߤ[ RZB'q+ ޯ\pNbFϞ=s̙SM u^,>b1| Đ{ӧOJ4N56,bw\osګ]b/(d?-T:miMMԩ5^-֎/lxa1@h3a9d0pAYN\8P.$ €%Yɓ'N(j1?I}is]h'$ BW@C5`姁ʪroxs4hԱSRfmNSBu/,m^]Lt/iEyxcc}}]EЋ<^lx/+|9SHLVTKY4P-N{ NT`6j~T`  OWH:_rE3ןƺJ1x G-w^[Ǯ&/lȮO#OܫkaY(D-ϔO80eXQ>64:*ʎzv8i3. ]vRܫ76.._% Hٯ<%,j؟2@)Z8@* \'N8KY㥇#ؠ>ݐ8cXԃeJ#A=Ӻv/,m^] _IPde'jjkK Ze $I )Y`OTp$ BWRG/ ܫKauhpԫbFkkkjZJ9C]ᢣ阫$̏Wհ 4)=fgWIၢc~!/,9rp[jj(8s ݵdy߯etbJ[iNքbЦ|?y|e=&dT2zvzCc{|zZwhǗͽYm׼K-vZUkp5XΘEVU/Θ5Xu,"t72,y[w¯Z#! ' endstream endobj 365 0 obj 14180 endobj 367 0 obj <> stream xVn0 +|.W$+ qSۭ@unX/Q"eN,02)O$MOmꝡ׀q.O7 ~lkH3HIE{TO7t4oP|T^\}]?T2 էpYݟh| gy`{zӥny;tR_9O.ǕY3|>}|+g) PBW> stream xWK6W O0X50CSmd[4̃/)r曏j^;à,=>_Wh GfDK{}K˴緷Oo?տ|n z0cc۟_ ܽp6aGJOfa^E~´4Mc3i~䝛vfhE9P(ReҺ\2 b4kI.)9&@a9k7a!}Y&+h_fa&0\?<(5KH4uBжdSRzI% ̀! g%!i2_s!kԲC,ɶ'UgAb*Cvc [d%ᇰ֣$Dr`7O5b>!!G+0Jpy]Q?0>H"BkjiN2Ь.#Pu\:Yyx(5aG=WΈq $J'~-3,UЌGl##3KNU<)gXv\y_YÒgUK_IRH'J@yQfc+`O[`̹2ȓ R:XYQZ_$S Hi9P7x'SIOlJ !km@UDCAm8;,'%J&vL=ܜZX,oX*}\:v+켱d̚T'Ǽ9][y|ػ,r47b\Z_Q @R&qMd$Lt6&nl9 cїw5;\V`&S̩-kڔФT.}lŵz JgX@ߥ-5,[O↼-lbja c"},"7N^TPW\ akߦ3SMj RMfτ>lKm^oW endstream endobj 371 0 obj 1184 endobj 373 0 obj <> stream xSMk0 W DQBeٍ$6xgw b\c7bw0߼̓wl8u3InVs,R`xن}ö7Lʚ>z~{Rr-Takj1U$.X-6Ẕ*F&n/ x$lznc8Vǡ\N>rC\''AmP6ұDmTjN`KMaJd%{KɯQEms-hZZ%I} (,TvBzq( zo:eC=7ʃoGu5 X7jES"ŐoJ_D endstream endobj 374 0 obj 395 endobj 375 0 obj <> stream x `ս7GiU[[>,Z& (CR|\|EHH"@ $dcn&&r[#[|&;iu;-m?a_J7KֱW׼k o qX K=c:Q2gqY.)^*oU$Ys!:kf9i#(H\翁%#"`0 coMBM$D(H4J7 )&|SȖ{{,W<#p%rݿž⺩Gi f-[?Š/Y޼zJ@EJGڤ!85(`08 n2˲+?Ig:{KWi[6LoP[ͳ9g5uw]z v|mnmG9 733z_|%'̫Ηs|.b{ ˻|O:=--|MK>x{ףSsnm=(hD="2 I}Fd؂U:p/`0 6ʷˍ5Y>{Osl.ܯ8%~wtj pP'[Qs7YjG(xp/U`08,A樂_לz+h}DY]EVF]w:?[~ww\1n%Z&cM ƭ_q mbj7*}ϭ;r֝et[6qt≗p}Z lg-ZY6 YIVA HFeʲ`0 #(uW/u}?9QD׷<蕭/k{qo}ĕl[>Ɋץn܂$>ԍl5߹rwXhwֽRFR- #J+D4 {bNp#^<0AȆJ|0>˟DٲڜAd*?NxSp)9n8ȆŲOQ$lw'"v"H h>08M' NM^mi| D\]Gj~y×]S9'~?~q mei1zc-ފ|h;v'g?ٌsf&AFE{O]ܴOe'wd Ϻ7!y;"wdNCQ-Nd"Ɂ,):Ԭ{_O"eÍ=R|;i~lOuR±/}jz `G4(㸓_?UM]|_3ם?rMknbU~{VIn\.)Ƹe"n!HY 18.uyjgFyv$}ܳ,ْ~0SN1Y$E`0 cjB\S{o]]}Iݿi뢦;~4G[ro5]}Ngeq!"7E ֌gna?;-7yZx1pDQw/`0 6 rvϵ^eם_矕²~zpV^ns+ת?~S~qҁ,_Lƭzeu ,w.:;e@ ].=֊z7HCh 8zUw]M|Kgn܌KuvٿuY󤌟ZNQeե[u"n帇q.>qCjs&108g `0le?6H9;|[6Zl&bZϏ{7F/у׈-N08i8_408~`wu׈[ ۏVq*$+oXn9d Ugj,g]mN42SٴwK`0 uPǹܬկL|૫ɂI Z^OHFp[זaK.M b~ &_08'%"_&~U7=ᮓ.; `0xL\Ym9s˹on`0 n-0 p `08+nY$'/) ǹf0 :PBc5=XHYt|/]*[=I:y>!`0 Gu"c-?e{<f-)T?`08' krߗ@J2+XTL9eLʦХ `6f"L\u<33G0,s:MS!sL'V9+f `0XD0Tׯ9EܒaKq9(JQH`06 B>w3k`0< zv cP<&Ϻ˞ lHn 5T}?`08!G~z\E*uY)?*MBzL'_Gn&w>`0 ӉVyx p `08N,`0 `0 j-0 Z[`0 6G bA @FH΁`0 a-0 p `08`0 qޮi 8  b-pFLpȆ 18 #&8dCp `C,nY@XiFh#ȤB7@3Ny@ P2F$ +UܩҰƚW7kXgFgQW:!UO,4',7 -L >b򁠩G9;>:3t<ha[ü|>AK?>' ads|6]0(C2>?$mR.a)|)OR'~tOVG!#g-r >bBSCgV0txZx- M Yq$( Jk`@jR}) H-j >bBSCgV0tQ^C)˫wbu׭әU)EPgkNj5Wt?x^y)uMUպuT >b*MXI ::e-8nM1*nu7N\*RRO_./v i@ q)G^)C*uϫ*#|z7} )bzEjD[XQnGLYkT}? :$4ut;WA\ Mv}jO8:x#B:[zB S q Wвu^h<|b7.m z֑zR o]B.Wm5uuّu!'%BE§NK!UMe?!V%2vu$S0uL-,-)o0DMh9΃{t\o&ǠF:$hf[ip!:|=iid?n鱭ڵ6h+ fqIvV}Oҹ]=\=OW<e[g%A<]8?_!ms I%zI!'UG&:-G<=F |ZYR*T-뢳v骸+xzU# V=_Ohae ӓӏs3-3>~bjK`|Ru9nד$tPȝGX5k]^_̤kPV}IkW\F\YY~nWZh4[MMMX_#+fwM1^&,OlilP'"B"R(f綸sυğ)zܩ7 RGklR%#4'YH>aHcp4ZI$%INIb!yphtI벓[-Ԩ;BRت. KDlcJ Š6NhA n1dm85׼qH_ AV u0dª ґ3sf.|C+tzB GŭZI))_ RׯԾSR.1èuJ8"d=oӪ_57G:HSVZXw >b*냦*P9$.㯮y~zʪ*T ['kNԜ<;ɭ6j8 .ȥJpI_S -VOR; 5*# Nds>)gx>XH:'OI8j3@$QXw@ 13+Z:thah[XܪFb_6t1,#)\TXʊbqqH3ta>!b _ #NG<&#X~:Ptr5CN?UdƁ13+Z:thah[Xܲ>pr(C"'/B+r9dYv*T|iʒl;MyXZ8S&E~ vtf~W >b:T;P[:[҃r8ɎB든xRuxIn`*ʲGVh> 6 cuIrf4\ ֲ7O *UU`ܷ`wna'M Sl%hK*XB[:][R R7 PWai ኊǏN\٥6J̏,(մ:\ғO^/[c 1c_1Ƈ@ H/KVցJvlyK'mZdkm{+Wlj˫ڽJdm< F Ƭpf;y˒EY'd)]`y]Qq] 1Y,a Y˖2mmCL]w/SU3ѨEpk3IbG";=6>kvlxe˾x+V䓯[ow>Org,T%[cPPuV[&P<R?>H!0 6Gh,n|CüѺ7D!ܲ[%% ­VN(nM>5)JNOR3Xj,Jdkh8zίd +[J1c|h 1b=q!4Rǂ[V\zڵ7o>VRoްn/nQ|Wmwn[M-4U|CDә,4ni+˗$n^`ۂ+~3yDVx$ŕ ΣO4{zwRTQĵ.Ecí+w]gҌ}32Vkˑ# V'(鍤zvӖǨ88U*FeIHXP84V!8¸T僧+JNW۬eG[S[V+s0ڷe|v c~Kn,)EPJTғNl"u@P&.,FoG&.::5vVʕ۶?JZII&%}sQ= iS({׎n UyT @[`08Glr>+ٌ\gSQ?KǵZ[S[l~>p99eVܒ2dS5DV#k {U e"oq ZȅCTv2K2:bLtkժo}`ŊO?=~ZkBZǝ oꆤ:n MqUfbT4X+eRs##-0#[!w]\Z b-Vv6c~t+4祦j;$nm=;_gZh_CW1XkwЎLжC֚5t^{ٲ[KG%%-A-ZI/&%=nb^[`08G_9ð-ZVѓnŔnm)st tδtҁ2xcCۏ 8ҿP7kģ9Qo$nld].mme^NwP{v !8ZE~{_0E5hTb))-!F;xw*~؇rfTa, j%NBSTDZ`p6st+4EItt[)np3gt< @ -02 (.𩳫gKA,?x飯_ж dNӪuOvtO&`p]HP, `PYnƠ-`Q6n5P](zޫA$OnZWJ^yŲΉ"o"^_Y'nG[ HO&ĭy?/bΠikïce4o&DL$T³iT>e>L Y[;tߎ=3u si|dK&~߽,!y9Egn_[ HO&ĭ[|ah[nlxŒ~ERz͛Ұ#Ndl;.N9n9Wb}e>b*F..B;s̗{l(h/֤?᷋+c!N_t{6w<ŹW|>],)I6Iz >,A*A*);O/yM;@D q+(!rE;bI|SI¤Pp+n~dC+*I7ٴ:/Rg]&Dk 2n2Fy@ dB 6vYelHUn9rj (%p!Zd"c7R%@pKIS-GvٳF]>'VԾ(4!E7QI@ ɄVuw=Ζ6Wcc( k1{(܌'^G2jw~h} Oѭ閔4AaÙ7ZgB)[ PeB {JJ8UX "Omeg3;vG@#3Vo?|__ 5M\?g_&nI+F)~,:7AHɄV!B|tˢ"kDZ ⧶kY0O< 5-Xi{uo]koF[txJqKMh[ PdB 뜉0Eu 59A1h▰:Tl7-Z7A˄"3(Qܢo Y)Ĕ|t( G-(2!n5elAe܂P2kN 2dL[܅9/Z_45fn@ =)25Z!Kz+ؽ{*mA`J Bˤ'XWay睷~ǺuX(Kb@7L[cV\ 6f-FN 3bo?^/-Y|m8b IgOa:TîWYulpWI4[yhX7leEz뭷HŠʒ\: _jzRn[oBQ&j}PCv-0Ct|{!-j/41zv:Cl;Fp+BˤN1kyq8Kyi2 )tXCpE/CnI*uqʘ &Hf@֛;y&?4$ܚ1دY&==}+WD/٣]dh)fE?)HQ)ʸ߂T![GАvt)6/O8DN\2Hf@<-Ih ֐NZVBoʹWw*K#M( ^ J[`08'Zt˿Gl 2ݺr>&7|vK~kFT7;6|Y:?V`2nҵ}^ Ĥ9zٞYL*f[}L}S[T![G2^ѣLk+Mb}=8lNS^ ÖQy*<;n+W#U V !9=6w^tkɧ'XIٓ)+W\bI~,'& *n+p+f-FJJ bByj+;ٱC;e` ^f@֢q nz7t";OlV)QN~YTߵXa\b-5ln/3V Z~wi{Q9x`QGI[ HO&-sF`ꘓp+>d]%/=}-w΢]-zmO|s֊ n@ =@ Cd%@ L[nbNf-Z %-'97cN2g"tp˺$9yIYn@& q˜-4޽kWo ۣ-w-Z %pKH!d2)2&&-m5~ѭ7Q ѭ0v-Pdd n-aJJJ[Q[T{g(]3A]ȇ~MVOB;)ʧIBf]4nI銲ӳ\:6:ieN) Yu90ֆUWTUnHъn! *8K|!іaeKʜnIH,lLK-a.""i[ \{Úvp:;JJ w[d)d*x)R&1 I1gFt+9ev,=ĥύH-("2!n-AnmdO}%[ovśenɟnVD'k,hԸuʇ];9|ѭzG^Qrvf-(;e8E-ҭCj7Mw?. n@FɄeNxV_Et'J))s8؜\'#HLKStn8S&AXe8Yaf=)ji`!0Dhza>0MQ1''-0!E [ZGQy)q+|}p+|![ЖݟnG1[(> >n -Zh"Q!ꝓa|$ Uí^BY//.-0!ELQVng^6&:v^JWxs:-b^;u!I\\TB\ ][Q%O6 &{t6AC[I :b,)&4!Imآ̳a0?*`&Q*MEkĐ}Y^@q۴LNG]p c)K"u83FDcƭ}d,nScn $J䎟Z-"#( Z+[RzeZ[^ν}}]vg}-͗nDDMuphl;x*@Z2!nE+)Ml'!('%|}@Ys˦Vԟ(Ez,r26[}2NeHxVɁJ°-ٴe[[ H q˜2hb;.5nS.1&(^p+pttvt7LOtng{Sl^sj| I[ HO&->nn!oأ_H nQ)<[) Jo7b52{E bȗ~pfj}\&;[-(.7v껓[[ H q˜BcVi)=ʴ⧶|`srrgԷn,_hZ2K%=*_&bnU6k~9lF.س(o OB@Qy*cE( .d (PL*)aD$2h\#Odg3;vh21%$[1[!w+>i{4܊8n)K^/E?z'9,49k 'dиf:VsB듀[fr;=WE#[%Kʌ,u?OSQ>UJ݂)cNq[0Ed SL"ܒOR[cUwP˄e{Tk7SV/Sg֛4*ӨV %9EF+di3^/~w[~Q]w/SU9Bя)A=R2#:k>ά5hn @z2!n6PB#ƠʻnKuZ0q.ˠx H%L4?n|CبCuo?nԙ^NQՄғ q˜K@&zj?a;#_a~rEotKwEW ғ q+Z-K0­vyˁ&g1[nMTYDvfhH{(܌'^5˧0$~aD{ռOtL/iKp4b~CH)pK [ umD,+}Ȋĸn6np$-"W-c# ^;hLa5V07QV4Pڷ}vU-?/YɊG ֶ`p8lVwlA6Wcc(CCx90l=47Nbq~pK_Ry"-[Kޟ9Yz_ Mjw%h*/Y ʎ|gAE/->QodgnR#],x5aF*pK[GnA߂4"`$~en%Ϩ* EV`p8s.Ntf/ޟq œ{6m3 Bˣۍomϫ׳ RзKtbYb׍*p+B>%{$MQ`1ӛH[`08pn0_ e*;-%n[@~2 n}\esU HQGH%`pnUhA#/(0ln.~^2V+L_J VPBLD}ʫ,=0f(E4[ў Np5O[yG[zoAdJܒ"W~jeYK9Rn:)c,Jn"pf;yAO=D/qC8bt 8 J­u/J6BVOaiL$$F`y<-XnmV8HukwuzssyF[Nɱdc劵_F qK+:/S'gQ/Qy{ MQ'bt ԻQ|6xT>|fVSZNX2 rhVXEp+ii?7 }v";2\2-c7-lU;[ɞt//WN.+_8FI0n!JW5Rc $n/Z"ֲX4чp륷⯓ OD[`08^-fy6~/vnk ce*OoNѽn@[k.<\8Ua[{1b C_\}_-~:bJ` 1BX c[, -Ql6qz6hOy7LT(/.=-=D1kz__z*e/fPc -0c%܋}}]vg}ux[dݴ|qi1EG9[O"+)O᫚:?-=&nU]hXǵ<,OUTG_GQJ]sCpD.\^-S^XFj(q~͛2HRDxE:(dn%E|snNٍ!j>4ge_Q8Қ>Z!8V[n]|\u~[v;34x<ѣLs39)6/K#fPpkL2\3ђzdi=Ne/:R1Xn5;je&U6kAّ/B,rԖ>̇crsl-U u/ޥk]+?u3τS1%z" M[A)ݲkв# m4U'-Rꚣ&-0c%e8Yaf=-X^8ڊڪgA7NzRD2j a!0V2\K>= ~jK?HUvrG-Rꚣ$-0c"{JJ8UX "Omeg3;vhE@&nч6-?-sn,nMoG|tˢ"kDZ ⧶kY0O<ppy=ipp󍌌(<̼J|bp pp 뜉0Eup+({gkK=ªy=Znڢ]Ͼ f?gn- (!8.[VPCp\Ffbp+tk}޵:Wvù<-'_Xr/}QU(`{^z%ZG)QbИИu\FJkWoGA[A)gVoeλMV ĭ{竏/䋼CknEsnc}gHLK[A)ݺ^D9[bG6­*"-*Gwf==]^MŒz_XFHc箃?pŖZU&b~1#F{nqUcv;7̷7qձ{2UUzo^Z7t17 ]hypPރ'OD3_2O<88Tx\;A]`?ؾejh=yͦ7}dN߆&OJa 5ԣ}]٫ҍjZҵ15emM}8Dt a74<|}=qK- ϜXROH-7OpOm ,=}`-IǺx#3pmT:—PM|Bm+W0qޥu%(bsU|+k"ߝ iTVwZ<(֤ZQuK~wĵkUy۵E ߳Xk`L^I#Mt a:·,!==} l$8 5=zx3H%ݘDSmŷ,ŷn(,lc (u!&6NE;b'܋ZOtfa=+b%dHMdg%T+viϧ䧩O.eVv%bnk̜8222wY(W ODbTBy#HQ䉜­ ^T[_K!NͿOE\{ k xP1?βR(pmL 7<n+1[jj=<@3+ŸVMxXMЛ6f;мU,0{GJtUn%r8Y1htV7I[ky. LK|*|.4M4n%E|snNٍ!j>4gsOh} ne?Bl\;GF =PF\ =KB b,Bzx044]qs#՘Jcu0͎JRd_sˎVwlA7EYDvfh/XxأGf<Sl^9nISsiK{dѬ6ܢ^ze5>w"BZQ$3 HWv*F-uV`_Cg\ gtO)y=;1L[pSzR1Qc[l5Ԍ76Oј S;|W\D52{E ≪bȗ~p !qy9~jjeC[1Lvv W] Nr ۋtinhԟDZy Z{d-~1CN|'ԷyIyh-EepC3BP2Qfb E[|DHc(<IFT媾x+~lcJͨZWw0uGS[7*o8FqXn٬3|V`Ϧ-~p !ǃn7k⧶|`srniÌ;&jܒTĥJDqcpp-+-Q\#Lt͎Qy!ECA"#p{n}ȦfnRHFDSXZʏz3r ![nƼՏw<ucK7'X. #ۘ.eI]:^h7ѭ޻URˆ..qByj+;ٱC+_Z?I.e עm,[~B[H3gOE}te n-۷5,5ꭹG*{{m̸N4&X1 V_9ð-ZVkГ ׻'J}>Ȉ"T$*e>2af:bcnؘ`Dt+XՉ#p蝭//Y -kiv=r/l3gX2`p"8X:R[(!8Z(qdn鍘[ `p6ytk_/XwvWz^ݮ7w8gԿkK6V_Ŝ@ fn(lyǢj7W" p anl|g{9Ν;o޼ 8 ,\_\{8(!8%a^Z//p巊%JkX(!8xвt\zϜ9388`eIgf7P p ana⦨X,híN3gk ,@+iѢE>%5 J{b)U%M!ߔgB[ p Vs/b.OZVvܹsEZpӧ{zzȼeyʒYnuo&JyvzRj~_vEX[`08G.\"|s͛Gz_yŋ/Ydҥ˖-C_zpK2`p0nuw=.m:SeՋn-ϨGˎvwuuV#^ݩ,"2@ ƭzG^Qf-(;n--Ihk…a-Zڲex+V ,P$> x|ҺHX ֛H[ p ͚_?@g9 l*ۢ[K>====^̙32<5seIAHKE=z Iy3 p a[Uw/{Zu!F 6ޭER|jkѢEK,~WXXk(ì*EXV[ˉϿǗ}EޡڌG\t7D YlG_x/g lK.vp|###<3l0ꈠ(2ܳ`ENg}KKc[[sG鎝Eep`],CRFu mڕ_W44r:Z[=wՏ#ݘl9^䥵^\U8Y빅YϼzZ .-PenU9οU5kuu}Ȇ7¨qy_zthwq(pL塟4H{:x\1ci?ec-hTn",p{_ aSlGZ^oOm(_B0S,}cMB^n̠qk,s6yt /-Penһ_"q-ZwUvm5 8WRVOJ^gNW`|#1nNOAӳpߗ2]7 IZTctG yOk=RI76nIPޞ|UI2GOmքK쑌ntwVLϜkŔn9n",p낻ג{SoS5^v_Z=>G*9ݒdq7ĻQ]T}i/mRs,kX gwnL  Y" b{*بE<:Lm>6nmo>?yg'}ot+V|붣ONys|Ū@ѭG|d~?>w96b-ohQ QH+pK=5hfsb={>JteܫM)'m­@T1~Sgzy8s/YD9,zvskƛ@n=b3aVw{w~D5<ٸ|Ŋ~w7]N[T3] ո:枀[7g1l0̲ۯEstcCMp8Y EDIbz l?ًYZꋩťZ#*vu)N~rawm$n=^/ҺMK"Y,Wɻ}=+ȭ/^?^n= n-YdEZEzUdV#SS%)Hgts \];1\ZTy9;5̐EX`vs3L ڲeΝ;s#SSNXR+B"'qYG$=^=0!p^xX#- 勷ʿy4:l=S\Ob"t,^1 Flgkq1cqn1cdttdp܊d1~솿:}+7>!!aڵٴfIPI .],Vr$=\2X-`aĹl\Lx`ܲ_m~WQw+ޥCCC|ɯ/_RĬFMNpKIKXY,[:n0 6z:z{ڻZZ.[z[eWaǫ>tYLXXm/|wy oc=ݪNqKb]p 2X-=Twƒoȳ3 Nf흧kGK;qy/q<*JwƩx8 'Db0y˟nA ð6,cY3PHڟrܭX[:{גfkw'oaG[f^ GMPȒİ%3뷇"d[0 {-ASSS!믧|O7.o?qkwO#4܂ p a<*/UmyW'bK.^R@@R-`[~0<\Q1?pґ?w/?;>*nA-ܪȰX~aؿ̥܂ [r z%w{W5^A$p 2\V/3HlaJg887quMNNq_vw7N><c4knA܂as \2W$Z>|m+l>62L-``nRFl"6M||y2C1vRӹ-d[0 *ܪ3<{aXA%#>*c_|(ލ5quX-``nv)ԝ#^Kux(~rЍgK- , þ-crj3v8&Nֶ-*_a,b"x{ݷBӈ}V&.#,`dQTh+d[0 svʣ#=mMgpב8.xį3.YCܺ'?Iӭ+j{/s˾UVqjn=jZbP\՚_šZK ܂a#e j~WQϾGn.!W}h+]w%[go5IE'uLЛ+܂ qlմuݔkRk4pyP@o__GoO{wWK˅zYw? cgS@~|}_O^|:b!ģ?[]ܚ[>p 2X-Dv sB\,jm;W[V[YXcɷVYepwZ_,&kw"~rxsUVDđBq0Q>t9HyU-`y Y#-mR+,:TDHn1k<72BKuT9[sz^ڱ䃙(g$N9[?xxxߟ&x49Ċ[6ȟޘ*/JSՓ9̒ά.df갪,(RR &]a"SE԰йXlcvGp%~_/3޻a/?zXH>ks-ﲉ?*ĽJ5(?  ]qBki/Q[F%Mb"G2"`=]z{VE|m>Ϣ[rY_}Z?55~謚[nA-ܪȰX4oN[B .++s4XMNN ̐?lv=߆Ap 2XnVy V{RȠDnYaȥraqHq^nAMrvy%΁JGJ ^$9B|b'6N0bݩ9ĒL4/֨@\lJwah] ܂an7>M VvO<_JfߤSEO2|vTSsł{łhm ܂an2w+.%C%^|`k"zb_Eu(ISWyIq<ô-w܂ p;|;S3\Q'Tu{ng+|z 3/O\hT[{:#=H zEJ3F,|My B^ĭsjX?_wB}sζޮ{/s:--mmM-Sunfփ)_S!U򸮭Y 1/T葀[:n=f~W?)dv C:G z/.G';Oo(M´-܂ wqCfQ>?>50pK<}-v?pk2=a{"ͮ>Ƴ.T's5k޻>%OQY ,/+>g=[zA:1^֜>e)4x6WAF'JOYȋ!埃B2lG:` 1")Ntk a*wYb i(2uF]:A{Lʳpre3uk<kK 孏UU5O°X~*gYF~p[мOFGQxŞQnO-.%& m#ǩM$p [RT<: e(È"t=Ӎ [&}Ѕp:f!Ҋ$G0E,3`;yXP1iP0Uw+:S|e3\:e(k[]Uј$\-T'VP53{좃\ᨩo8צ|wyɿfuNVZuR,nQ=}}QqaQZ?UT7UP;kudU:ΔN*R4-h"n9HMM93J\@gT K:2cRTN쀚 𘚚2 (:C4].@k.t43>ƚWՕϕN9n{ꢃ\Z~ӎ[vo5/n&64/W_,514rE,nՎSU8?łVa#ڑ[IVZLDyJZL33p X^-it1/ړe;7PYcW@o@COCtfs5[sDd6}OrEi1|%qC䕻Hbamy%ʜxiVN*wPEzӥSϔN1ӽ[Y$p [RT]TtDI\WN)[,T6ERd(J5( GǢA ^uPȯ"o7bg})OKE)3>ƺu?Z]Iv[n}㣶g2ȍ4tII!q'{zx="n)^#BXJ+D$kRJJ&-e"[,Er"UϩHqC>K뒱!sxHFR.L!Bgs=}xwx~9w^3\陊*ۗk|l?N>?#X[NJ,dt n"*&;J$"\5mě%ZMb*s$RK%!ݢX-T `q+:nAqCT=9w-WzkUyG>G~zxx^HE B)(s-PY0Sqq(YF]y/G)ĢȊuf$哥B ULڕ܂f%-S3\#NƈMKȿ%eeğ|%?v+srRKYڽ[r"SQ! Yx(l0]'K&Oӽ[-hn0Tb{oQ";qdžN?ϡת~&x˫+8B#q˥ -X:Q0J@Y"kN&L$2/ؙh![,܂an7>M VvO<_JfߤSEO2|vT Х[Y\+g&YO/nAp a<ܭ\zVDX{]ğD~B,N$~@<P2$#HIXk0Q[1yK[GGWleWNeU;>*GRx#tXD|z /ðrQD$RAI1ħ h_UѕZJT{Mq Cv4K[̐"ua8(10"p T n0 hp 羥Z\0 ewq 睁[n0 7p r]-}anA ð/ ܂-u`]­==lJ=={:ja+(X2Qllnmy~˸vn` t<n|٥4?ZO:˄>D1ywNy|W-c*V5VzjTZf*r[@\+p{v+0(b,˘@Y7.]-u,֐210 g[] ;Yw41]nǹs].t<Io;p}'w w1x.m,m>]n&['qmҀ7khv0j&\-S厶*Ivaf[VJSNjl0o cirma-|LKm[@9c! uc!Ky+vKxvUn6vn{qSp r]­E& Ůօ //gv˵97F.4re auL$QRUd .@m͌@c6A]X8q|$pNNF'(.3n~#o&G<|>O_lvC]&p r]^-R [0vJN5p r]ǭ0lU0(:IWd9lL-uy[E|HhRPQ`4a+s}eBc } ; .n,Qs%rJJpGKT3p r]nVEEŒӘ%C%nI`̥߮7p r]nVy w~xnn_s3)[&~h[rtoj纇Db!a0Saq<fp X-Mw3`8 ܚ5:yP)W6shJݖI-㢘f8s|Sڻ\a n }e.Fa57jKE; B !Cؗ1UW!:T)1|+Eqp q8$OBQ2\a0p X`Sn9&q?oRz!\425JvX#$WCZ yQB>Q|Dk-m$xB{5WxWy, 511Ǜ !& 9ȧiD!~9*v"4YhX$xŽPpCl+,L+s[n0}[.R/Eˆ`avj P?>/z:T)Й$ 2++: l`Fc%D_lL6 ^\¶M>\+5 Wm@hހ _PEi.x<|$M.d\a䱀[0 {`_VT3~*2$$\?/t>q__s}l"f. .$*կ>/WFW넥~fRگS4_>Yk%Wy, ԟ޼^}[===ݴzJև/ewґ%T$uTE' CbnX,TpUl{pb2FrBgJ&Y5>*4[5_ZHz"\n4')¥up@-c`/7dqV'Ng id.Bi6PW'ç<]ǘ]n,%CLjM±.NIOV]?G[ _P$^+S?.NH$!P&KɺI9Jp|+IO? WM_r%+ ܂ l0n55571#*s&񰐊&U'h77 4 T&,O&6mXps3YfIfUUql{P5Jv\(*T6nA ~![γ|PDHST^^=/Is{tۦh殓ViyE1e ur[n Cuh֎[axyll6!du=o\tZ25;w6 50; L".os0sܾ$ 9 4pċo4K!T -l'dĝP$-b -9'^s ҄|X8+<+ ܂+Ia5U {z[nq33n ]yd'[m1Fo2jkkj5]'=VWԩRuT:EOEZ NN_vPQ$UH!(sKR2_'ٕG  }h▿/%3 ܒ)q˪PG '9XcUF k$)AE%%S V|U*%* Ѿ-c k1U4kR3nA]A-cvN!s1VȜjΈ!A܊9g ڦ&JOY3˅̩[ SkLIMd@OFGQxŞQnO-.%& m#ǩM$p [8\Ȝjqk^Xw+Ch_ ^EVS&GŅGiTQTAdՑU8S:qpJYV@Ys`w+/ҔΔyp'.nnUY;\s捻^[Ekն8*OUXȭvVҬV8S2bR%[,܂a[ [qYoITw~+h*w{eOKV^,w8:;sbvwˏk+Ug픾fB,XʩZ% (TORut҉3fw+>nAp al$nQdV<MS@:fMr'GN$'u׽A:Ǽ`bpV0n uAQVJT$U$p [0 {`qᘜm21av[ku5uT $y$I2>BNFw׼DNl;&n g^QIBK. lQ"a@*ĥ ۩,ȋuN A [B^,nK%g-XSeT䱀[0 {`qn1#=mMg֙7O@U>I$Ir7JNl ?j)}[w \[*$Uz8Y 1#pH&X\p\*g1y ͣI8vJ۠2K[&qJW [ţeNQXRR[[Ь&ne&\pEe j~WQ򾩽Sk('6SkH rsLcE3\$_ڒG'q1b-A#ۄJ4'Sv9m猣Y[,sf5ًŭ"0:rRJ\'K&Oӽ[-hr **2,,a++s4ŭ޾ZZ.[Nz#L-yO%6SHۛk+0OdgO[=/[RarTu1pA 0]-v<)KREp։jq gU;R%ĕX2ȼbgnA[ˌ X,9~0/WV2TwkEŜQVp n\e'Vȑ#~Kv>5\h޶&9qӮL$~C|4PG2'.a=:]5(*IK5)C5mxbsiV`[Y\+M\6z­*GBM\6xxnA )R7[3#,cY3PHڟr n%g:z} KA;K'eo&Tc0N.ט*O&pa6[$$'tY KG$0nz R-X:=VNb+-ʙՓn%U:W8bK'Mw <-nה1m '[sғpgqלKp69oX܊ɲЯ3ʹLU8(VNRub2l2yA-}a/gX蛦ɲ.旓#J jU{3Y={/ ,oVnn|vj4=L]߻Ūhdq?m.Y5zh'AIr8m7{ fM-;g/}& (r+= ܂f!oVR"7/v"#ΥEjػU tsTC}q&bw kd &lX"^yX)SlQw*V) viZ٘֘ߓ$i1o;8xxܚ%owڶ;E9{F9RܑsTʎB_ć Y΢IF98J2P!i0ѕ$i & D5#F,|!!iEt33}z](^m/Rgcrj3v8&zM֐r5ʁ\nw$N'9}y;9I3cIhD$4AD/Q BB%zD\_b[8Jn߈bqDhn&.dAYrJx#d"yAnVy VkFdr8I{/I1TyEisuis%$eҫHQ8XwNL`x{DVkSݹڲK"b(+8d0i;ybǑxl}l y'd󢁲w`"cmGu_k|NR]##ʪUtg^LG1P\3nAFˋ "`[sz^ڱ䃙(g$N9kλV\M?d?j䚯~IkdN=U |omp}0Τ(H9.&te.#w*_r^B-/zQ>U?GsnA 4p ]{}3y1p,_KL_ P,_e0U2X-=>&{㖽_= 10" aUK:!Zh%nA ðEi׋WLڈR-`` HO-`)></6u`-\ , xIלB ðwn$6r_̶)w֟NOOynA ðwۚ~P}>[Cɂg#9bW_['7=rzc >[n0n®콏v?,q(mqmw#Dk:l5E[]%r h)pdZa]\7u`8qu-R/pKrYA{[nAZՖVXysFYi=*ў`})v&w{c]W|BkurqUDZκ3ei &JguqilquP݂ p+6pu?yuH2o%nA,cY3PHڟrXr\?x0mQOm w6uQQuf-qj Z+kȬ5Q8ćũʣ1}zZť/|32X^ĭ'tOS"nAQ{S-)q][;N~ *|A»D{DJ"zŵyH27@x)d[Pㄸ裡cp |-4<4txT.yc$bZ¾cccms 5+aj`à#GڒJä\&S0+b).52$4ޕbu-AM1;W]=K{zțnAWEc?VEҀ+,6A)u.DҨl=aB4{\,V# p D9nA,d|[.)Z qK: S,:e4/c-+lgW,"WrA& rՎ,f"]v0Qa\-E.\Dk2=Z0b,5b|$nA7%I]-\2),䞐аeʯ=[L ^--kUIly;n9徘mKS?kQ τo&B7/z̸UWȲPU7c)X3 ܂ n3Tϖi~~GHX`?M'D( ʻnA-w_ؕѮ'/-Nr(qMgm7h낣˿4C-܂ p Az Z{^|́ –\Ϋ6\ZWZL]ԝtOcmQWd$uq-?r,p ̸pLNM6LTᘰu gF̎$[̧Si՞onx 8&n. Nv~_\Bb,@3 ,p ̸eP3::28tV4/[scEԂĻcVﹼ3¼vFb4zI3J֣-ܣXZ5䂼D'0CsD-)qf4Xoaqt[GdKc|jٺ,kQЕI#-NVgo&nA np9hqkh`b uV^VSE'RIiqӱ{Qf DGDġ-(!5kU27\8tpX0Kx->o8.geJy2nA RJki2#^G.QnAܒ`Ojd=Z p 撂ɩ)& ;a=ܲhّ֓y 1t?͗o!7G-an%y$+0(( OᏘ,㪀[2h2@-K fܲmG(ik:[~H-i"jAg]1 \^aJ;o#[1[%^(LEPǤiUdsA-`[e YJcCBT<lB acH $jӑ!L|2.OX,ؤ,\+ A`-m$Wc-mվe/f$9foEAWv$8 KTKhK@N܂ sbCMPe dQuhUV!*}زPqEE5@4-̸54?0A1NwWK˅zYw|©P[֓$Mֽ(LV"#"}%nZ-`2UI%*byLE8Zc6넭(Bi`S0VkSݹڲBfaȳ3 NVQԍKy3cV"_e0- mw[nA˘o&DPlxY׊ezX XNX-R)qbNK;|03匤)p+wً$ۖpgӱ_WuEYgЬ8^̒Bv|/Lbѻ- eЋ bCe c'tI(az0Q줢ˮ6UT7=l}hزP٤ZB4q +hqn&l[Rcv^UwDk3N2, 'nA˨n'_ZLyatOTypSQJRp u-4<4txT.yc$bZ¾cccn$p 2Xs5s M-5)575\wD.EY ,p ܂U-`['Q4܂ p AznA*d[-ptwZUrގ[Nm/fҔ;Z}<3 r `8 rQmgb?>r-!dܑ`+DƯN^fB[r܂aX-w߻Ѯ'/-Nr(qMgm7h낣˿dx xW*p 2X-=p`k|o(v^ҲϿw`{n"s%눣on o ðxr8&hL&*pLGp˺{3YOfG-`{NjϷ 7_RDd|L}[Uz5}i qx>f0DF"0܂ p aeP1::28tV4/[scEԂĻcVﹼ3¼vFb4zKT3ru#|]9Q!.f^p6MX[[-R~x;{z{vUypa8He j~WQ#쥱ߌd>w5lM(ʎ$RPlOZP22DZiԭ D r~ ŭ޾ JZZ.[z[NڲH}'95MnFfr7)^(p 2Dp)nA*q\mYme![֊<9nEhyj0;n1fa+r>X:8G38PW.!eQ(d[-S0Ŝv,+`fISVG-I-Φc75"2ά%NY+q%q`ͽ%|:SupK:&,JW]ȧ6I]\-`[-w߻UmI뚏q Go?xU %#V+8uțM > ,p 噆Jyeu4or̛D;_Kطvll˕f'd[-ptDJM1;W]=K{z}*hnA˟e^y+f A-nw.p H - H3p 潀[G[p 2X^-As[-(P܂ pe\oWX,YY&4,DÔCeb$K%4L jX4ڽs M--kUIly;n9徘mKS?kQ ܂ O)aPƨe{`CN'' JS%- e nXF pu5}HϞ?rGrĂNnz8!z qnA˧[ePr$1q]RedxuɌtIRUdq{@ Zr[{J" YP$GIt&sk.8K'd-i[o_+bc>.S@ Z{{^|́ –\Ϋ6\ZWZL]ԝtOcmQWd$uq-">܂ ȇKJ2tș; 'd}*s44lYlXֈ`" fr8&hL&*pLGp˺{3YOfG-`{NjϷ 7_RDd|L}[s-=\+.㣳  AjL ȉ[n[0lNLCCgG%n|мW~9M"杯%[;66A2 `v[H1f窽+~'riOO/ZR-``[P@ , 8xp˃-h , 8xp H ܂a[ wwrwZUrގ[Nm/fҔ;Z}<3yts QnVo0 WT n3Tϖi~~GHX`?M'DtVK2y,p"b}a28O0JVGR_B86;Dj|5w\䚢 .R[ ,pAXr~a_qe^A+9_+yuֆK>Jki2#^G"nA]e- A \ݲhّ֓y 1t?͗o!7G-X:8`|P:,JO,m?$[3 , þp+rhE=%t즆UD]FQ֙ĩ54k%$W#3WpIZs81_ʻ"d[0 [n&l[Rcv^UwDk3N2$s!= e(nY!Kek"V"j|_; XM7'r]CCgG%n|мW~9M"杯%[;66%[܂ pKz81f0hHݮNe^c-+H솩/N5d &#MTF'ϒ(⚏[H1f窽+~'riOO/ZR-`%r3YjŒnÖ$K1[P@ ,▅~ EF٭ i!4D^!*R ]1Rltp NiME&q1Uq5MǭxF#jYvTB1 _`_ ;w[p 2X_ć s1OgW\V)g+т.ixu(CFazP,vT PWǢ[4qթ SRZ ջŝuc#/w-[1Jf#} P£/kFܒts)J(,JQJM;=QΓ]=(rڻUNbI-R"*yx`[-kUIly;n9徘mKS?kQ ܂ [UQadi*g@xpK ܒIJ`@K㖋}P3Ns)GJ޷y\n<u▋jok>Al' ={_! 6~=opBJT nA-*/׽jdpJ/}k~MWbYHja/[ڸ%$ "G qZIδswqI#%KLB9aEm1w f="[W횏UDx{J" YP$GIt&sk.8KipknAMҽ4U^2\%DS1Rl(IfO/A01NTAx0Et;S%ŒST1C:W]ҿ…8IuA7a3'kܢʭJ-ﹲWgm1;Ƹ*\I:[E|<pknA[ {v)C\w195Ed2Qac>:[}7sz2;0o!3O]sU{]-D&"cZ%Neo,,# DQ]#d<{r|Xu[av \FGGzښցyKcnZЙxWc=~FHVFd^$N˒RnJL ܂ax;qf4Xoaqt[GdKc|jٺ,kQЕI#-lo4LJsK3bO ܂a[Cɂg#9bW_['7=r^p 2X-  g6H1P`/㞁 kJh!}VGR_B86;Dj|5w\䚢 .l[[nAP0}XP@EZh.Vmm!U_s{C鿰=W }ָ;Su'w[e/I]G}KnyI-` (>,z{~-X3ƻ<2=n{ty[mD nY`yf4H¼|?uqVvKokᖸR PmW@\GrK-` (>, XVYYܸeP@3::28tV4/[scEԂĻcVﹼ3¼vFb4z^:XxZ5D5䦀[nAP0H[=RbMQVOO eq ܸe j~WQ#쥱ߌd>oc㨲~]I|,^ <`@IX%)$DA0D"F3 7,BH `0d!$qҶ;݋n^wn-cs{禎ӭrݭuUBUpDnVxJE[ (baŠZHhabV-!s@f5wi5`[MgWLվ),xݞɔ>y&_iUq* x VXr f|@R*`]0f3GAn]=5Hni+[ōyVm]o8r7[2_2֩VYZ3ֵ=T'7jI*{7 a-@  $nܰ{C?oaV[OV04RIv"bqŲ+Vű'G˶ س'콲9~ RY}M%[/91xE'xT~>r fNn }Z][Heae^[uU'v4ZnH~~ד^zdl7TTnNjs.,-@r PŢ_p·ֲXt} [ð۝ydĒߥR}uoccc -@r PxX3 g"ASޓsv 0G %_, $;M4;T3@nJXݎ~ñ/#;"Z.yAn1-@r P`蘡swwEr 3@nJ}qVskjUTHZY~=-niS?<\α ;s3Nk57o\-@r PL5C )?_)~կ~k&|LUꗇݚ~~w3@nJȭ{^no]#{都S,kVi.=t@3@nJȭOTx4۔UŖ.%(8@%}! %VH@盜>߄wt8\x[e(1U򗡂m?CͯwR?QI_-a;fŊY-ءG-bQ*s[Ү1d/!H:Rr f˭Xݵa8tiw[wWЩndөVߔ8#Rɬn1 bkpInf[071s3Tny<1t,*Ƕ ?H[Cy[ )4 aDW!u3"WjV-T'؍ 5n*;@n [/^egXt}&Sǯlv9%6xKQ[j:b=OvgM+5 JkTяTOVܢKHjK܋]"!"8&XE (bx<.n5tnܰ22̄DZʖ[&}WOgcgk 2uqcu^0UmW͖̗ugLkaumDbV\ G"s %` [0THk89 -YYWjQU&f_*ND,κX{%ܪ8h6W{䕽W7/A*+?Z}e:O{Pp x( u`yT^˃ %_,u-Zha2*i`y,B}V]UA }m8 -:a> g~[f o bb˭B0vgg٬>w>T_ݛ~aXDB"@l0/r+3 3 %[vĚ,hܪb꞉NuzO®gi"*r f|XtHb!ep-Rs [0RxQT\ֲ Qy[Tܚ-@n [/n_k6pȎeG--%~e-orjfLL *|`rKs)o_GK(W_ v5Qw:JD%})g"oqMEar+Dxy,[(qltL (ba0tй~pP(z i2::rAV;tc-t7>N-TVDH&ߎ 6լ6ɍT % utTչ55**S$L@? JB:m [ocۅgUm䭡uUBUptrK!5"% ؏&&A3@n`Gu.2v9%6xKQ[j:b=OvgM+5 JkTяTOC[OQb##%,Y- a<- }E*L$4͕-`r6ioۮ7-/SWT+Z,-^Z*-E=Ǝp%- a ,T^n* K/d'"g],˽LnU{rlp={}Z}+˛ GkT2~b1DzDK'ʍL @,r+nUpj!W_OzJ{цPR黩/ιqoR-@r ΂-fa;?#>f%]PK9  -@r ΂ʑ[`T$zܡvm! a- 8 *Gn aFr8@fȭYnn!ɭ▖҈ekkmpk[-@d G=[[g\AȭPW4m)Uz.Չݚ7o.Px Un 2/[ HO{1 a7~uUw1U}_vtk<+lr fBn@\r+n%f8Qp[GRYQMY2^]V{<6;gP0YrkXhJ9<@  `'Eoz*mFJ2T͞scTQ'* {&ݬT3x7Zn[ e@k1w Z .^.vz 2::rAV;tc-t7>N-T2[ĶR`6VěR3Ҋ;cÎAr Yu}j]Ou".<W:m [ocۅgUm䭡uUBUpDnwq9-nP e}mψ/rAcihޥըn5]1Utu{&Sڋ䕚kVaG*{%Tzr™ɮe7Ji4 204 4 eh片<"IgΑ]Dk y;]d"r6#Y>$Ua6} M&^Ur/IAFq+_e <FEDZlghi7άۺiZŔ5ʳ#Y h N Q 9MNs:vH_58Dv1CDm4-|7Ej+Qe C*-4y#[lf(6YYDMI·c>yZŔmFPm$iiC&ewt6v ilQ7V[O{vl|ɘZZzfiZPL PGAn&JJDLXH-WJKhz ]|zhZ";C@ gއHWh7Y%-|3ÀA4& oy=-kɐ/̜ e ~F g0k-4B;*3Ubn[iҭ49O%HUܥ Q҄,4VljUŭ́V T-j?MVi4_l! -b{063l02d D+4d}$$&1M4ۥilS6֭b Mfh5F3G 6In* K/d'"g],˽LnU{rlp={}Z}+˛ GkT2'߃=*/xĽB{pBOqq .6IJNh h퓡#[Չ&Ysԉy]^Q$aC. rzh 3Z<{Ջbcħ6ʐk7}Z 4iT+Ru un3!_6nXhj5v Bn$B}V]UA }m8 -: O.Gq@ \8ʭ=1Yrkvv33lVXuTSMll,X/bq V@ 0 5r+= z]Ϝ;n-DT9Q#Q [@ Fܚ- FFn *bWD uuKVQrmPؙqZۭyZnE=Pܚ!گnW?YN5{c>_׎nM?{'W -n 46J0%SfM42E2o8ȏ519s~SU0dX2 ^V{^no]#{都S,kVi.=+ȭYa >Hf_ W!ة}|7$_)U|` 5D||A|>"$ Ða0dX VOTx4۔UŖ.%(8@%}!g5+ THPo}$ >F F^fƒG@N!'jr.b }1NW!Ð rȹ@_XnsI_: p0Qc/Cyn;_;FU[Ħ<1ܦ>zJ42n#9 `ΕP1q6ζNlvqv`dD+w~,\Dic )ͧN!a0d25bբ.,L.;TXu,J0UqѲm-k+{,o_TV~*g2wSt. zPh<rkVr[wۋWBB Yp˭;@f.n87n 272>w\q2tl9w Putexwv:t_z \blN')|;/u<{ v?>M%7?97Ϛ) ' ~*SGҕ 2  C#h[w ĎS zSK6MJMxqif Xne׍"fI$ⵆIBqn Mn9'p !@CRӡ͛59vdBeq8y agv\7 R I[@d!m(H]ڍ?aqQIF (J=/7CM`|"wȰ2  ;; Gܚ#'t]|@}.{/ ֋Xܚ[@nʪHw]̩WB[vFӆ?0l)+ppӦ ا&dg-4p+sx<,]?R\7W U2-; 6p 6֗7Dҭ|6l/aщmiÒxprJT BhDg c B3שNI̹C;Q"*գ!2U&3'2Al"4,V dKI7Jߓ_y堚q-KX鞨-̐r`xtBLON0M+cnf0JJtp#X7<?5>`r Yz+5?d2  ^n= *VZhiBÒZ鍓iurLWʯTkV=&ې.|~ 3Q%ȭYnn`T6ZDbuWʬqZ};ډ٬nFh20{#oW &ƝoD^NDdHf:zfZ;9.qDŽ?HWw2U7 #p&~vb|I΍$093F.L.|'2  C#a%-@T-U'~iIdauikVz2f~2nijoj:}w.5= d[%F7x^[8>&.hlVo)dƁ   ^Vܚ!گnW?YN5{c>_׎nM?;Lq8Uʮq crF1z$r8eE(r&eJL@70Nr=wl`GaBK4;AhHv&\؅'l|||'!&zXzHzp\o C!Ðad8ZV*Kx͚qjwd沈N-dO[xlw! U60C~,f.Zm7ɖ c Z|0VJ| kάQ0q7?Eъ>x@,Is7˶ P`@!ÐaȰ2r+;p|ci:ء 4H|L"?rG~>\iǗ (Rnk4#M)2,2 /2|gx~xsr y|- pnl=6K`@ @F=-Zc:`lx0@ T AnF]ZSݧx0@ T Any<# H[@  J[@  J[@  J[@  Jܺ~|6k@ hg InZ9klQTsczna%cXÎd[y?sHe[a/Dq깅bV<@˭gBxv\؏F {NRg#92vv"ĹTe2r l0b?ɊOt]'i8}@ . ?G endstream endobj 376 0 obj 58624 endobj 378 0 obj <> stream xWMo0 W\ DI[; ;m놡ݰ^}:"#EH)jV;Ct/O7FyјNsC'bDbloеL}>7m{>~4հ7[{{Ʊm/Wsi8Pdsσ ڏ;=?4?u7 wfPYky[',?O3#\fq)k0!ӛJhU/( ԃ$- qiz% zIb=M.zwǛMH ĭmfZE;ei lP(d'& Z~^!E1d old#~D@ʣ]RG|{"JSlN$q Ş]VP' "R'#]8R,cj6)*k<7>gLEJw_2+srWȉΩ+lAQDeՊh% ݙkr2RBdUfAVXV1JLf ȥdk g.T5J }nK̔<@,6'L+hk] Pc<l!G, +FE%ES=Q%B%Prwi4غ⎈9!#Zߏ ѵڏU!x3Bd)z $c$ikqC-0\ q{ ;P5l >\DK7]ז{Pd+V ܥ ! ~,rVxc:΋AY)@LrB>FQψkֶBiEIkBR5QV2B~\E5B604%PFi]q6o[`ۺ f:Kخ,8MU(f1]:U}{+9fy# on7d3noL$̶mIl Q@ endstream endobj 379 0 obj 997 endobj 381 0 obj <> stream xXKo6W@|"`=5âipZt/;/Zv/f373&=~` ^ǟ? z?;+{zoPFr,_߆߿y6ϿaNt^Qq´$y;evAT?cϷi~vf־Hrn8VBf^ݴ/M_ PSOFAVn_4&IA NY"F<ʪ˞ ԴUy`\Β\ma.J57 AzpBңr!ABmY AF/T$LnF𺼻Y\o!Ưzx@X՞v,Ngn8Xgf0C8xs\ma+g˕j V2t\et9zgu'A$VpRI9 - sBX^*߭ܚbWM68'biD`S^P59ۙ6Rz @aHos݁85 t=Ob)2E**1L#o,l:h;iOP8?~vd7/cY80hpo?So) L-*Sgew*{e#i{0tr:c{\ܫ(D޽*Nպ4[~ ILL_祯n~qՏ_7׬+/b1} endstream endobj 382 0 obj 1385 endobj 384 0 obj <> stream xWɊIW 9#Z@tiAC3'{zqی/K.QԺ SYDe6ck ՟??+5ǽU?8E=ѷQ^?-ǛOg|Uۂݻxg___|9Pm]o`;8[v [h{y;FC(y{3wxnOA8͙맵|Ä\oMNOv2`{DبVϳy$193b}Z㐼"4#  %6i#W3GFe<\{ )E&@"$՛v72Wr}K yG~`r @=4ݞ&i'q!4N8Ȓ8t%8KgX)ʦ[&GMM=b( 0\ @b< ^ u2P/3e.BF85Il3 U`Ѧ7/2X~;3Tz]}[M$x (an%ULTMfc̘^O%cGd ֈQ˱b٩{Rc&8)G[Yȗ0ǛUp}1vk$r_YTxOCiyb,I kC pf,Ti1rR1zK|[A-\n^ y,f-Ǖm@IĪ.%F! PdCcp3}8KȰ OFiqlK%fϚ@2!\Ѿ[UcY2^U"YZmOӐ,@[Z`/3UR,Ya$P̩z迋wzの};ek}[wzu*&y\8Wr endstream endobj 385 0 obj 1126 endobj 387 0 obj <> stream xM6 :XGL6h"m\CMje;XG|i֣Q߆/J Mci0*};aː;4%(}㼻ox~4NJ^?xu6LpYcGnpr4 O4}~So;iy0g=,6NnYOŞ w16ag>j,sz`Cn0 iPڍOx|q|),!Mwi.\ݔ,.0{b:q[@Ϯq7%e&QNms]G1(W *o  ;K9g}Yٰ!rzڐv:0vA‰zw@vTIN)Rtͬǘz8DfZ"+FP㮂u-)4IƊ! PoX*,Ң@n[8 +!"H Iʷ !;D &{ܒ$ؑKrʗ_UgAY:Kf /=Of5hՋzZ5gl܉/)HحPT^Z{A[\4-$͈LjVabKOՀ8ƻ+Eq&).-)tnvs%Ί}_[+{݂ u +JB*'zUY)$ EʣO[j8x$"k2HPF*U/ cWMuV8 x!側^ʊotɀ7CA AA /h!{xjY707YIь<E3^^̍kmX@U+\V^z귨j@ryORq ܂؞ӿ?`zW + m o"enF8h"I) ˂D!-FX'fcԸ@Y2tv6h6ܼÎօI}#R#<_N2 ߲y֡-MbDZK=XsҾ..όb˱+.T39akyƖZ^^J9s': endstream endobj 388 0 obj 1120 endobj 390 0 obj <> stream xXMo6 ϯẙ,ۀa 3[zz6--JDk&]qvv{09}z~Cu]ǽK8E_{!.MiP˛Ntϱ?\vCu?u6\>.g#|'ζ{<]#Zl@SiV6aeр>7˲m_ gళ@)G8z*&CY73iꡳ<-;/~r6X PTCZ,H.~fK{+kڲCr15Cz.G=6vly̔X4Иqc;NtA HĿK&IĿKRt 3bCQϛl vj@ F!؆my qiYxei( Lq!0mc^6f?nڙ| ]t|K]JGvSP5d+ʰΌԦt7H5 quL8 'zʍr"Pr nshWyK2mC꼾^m[֙ʪ.|n`ts'a\/RalVU+_E$Vgauh=~R~P>[5]ka/ :;4XVlZ[}Ӥt}gjV L ꄶ b֗Ao[ߐBԹTкYY]LL_["XmT9q* ~6ƕTYmهXǫ-8G{tۑQ $͏K K?+Jq_G='ius? endstream endobj 391 0 obj 1568 endobj 393 0 obj <> stream xWKk0W\et_ =ڦ$-ͥdIGbhYh^YO&uCV1XkM5|U#VY1^Iv߫7V;vBPݼ{W}kf)ky}R\^׻PsQ-: (.j @UѸR08=713l;i>x};481KnZ5D0 A4l0p6@h_bgxQCǹ@4j`s~$gik5<`Cˆ̓§ks.nD8`.D#eӘЮKF% ^)aja"ADAh eiJP72]RiwqLl:8k^(rcVWhLf㡲U{Sh!s$#ڽ~Q2_eE{9?ҷC 0bo*Y$W]IqcU8wۏ'8't19U Q!n*urgR,u@X l0 8&Y'# obDC Vyiɲ<30N̰ L$n>}bS009C Ynkʽ*穦営q|~źG-m5 u1g$dG!*r'Uc%#4Tthrs*4sM tډ9Edi/j/`mR55\ҵg}lH-բKVnX9+rx=/$-|>i%]/gp/Um-{g2hYC6$K mfFh%U,_KNҖ]HIW=B3%Zl`n~܉C endstream endobj 394 0 obj 940 endobj 396 0 obj <> stream xZMo8W\DI CiQ4]l.~I4l+jaD&$||3y8C3?]M59]#|^$ȰKb7̷=<ám|>$z#>?)}ĶHOU-y8%4݅2gz~2yRʔ1s۴o+Uzǫ0!ozcN'|gzq%E.)3APCTpZGK9,x<̾(C,pžtwb.(Me' ҄].aّEQ1KKQ d(7݂ -7`F`0'eV&Zfukɮch+@ᠧ9-Yd}ܬKC{` 9.1T.mlj&;yH){d/9H 6 Ȣ/7y(CzbO/8ӽMrs:A&! }k^}.7cvdGce|:N(u[>,Ѥ)gM<46S4 5C0'n\pt\FC*6ݒư!}SHяXߵňrPjbF,,uwCJa p$UHe܎$ v'I:|}M> stream xWK@ Wy!ޑc6@S۴MKҿ_IWɃҥǒFrt WSi4 ȣ<|V_/_ 5 GftW3'g?$NF|}<oV?ԖԓfWZ4jI=4j4ԻoE+܆PG{}6z2BBԓXF5Vt^J{7[a'+c{dD]ؽڐz& adM2p5l*z>ʠhIeOm  q9])0hbтhkDٿLw>%2D`M#F2o&UCB#AcD2bBA94X@#>0r^ Yh-.jpܲڔ&&%D>9D)9F 2ET1EA`a{pI" *GKѺ'\迶8cz: )nЦK yi(jT{[~*uXܒTӢKLz4*-fV)ۡ> ]œ.|` H&%dufY5E긱4nٲE|b:Y!  HuW\ pJxzEvrXOTG)2Ywn%m ʧƖM Vb(J>A2P+п VFp: endstream endobj 400 0 obj 720 endobj 402 0 obj <> stream xRj0+]/: JOmRdǥPVhf5%ӗRa6ZGzЇau}5]36h8!ygz3 Fg8t=_iIowi,Kh|mx nQ]+7M.|Awz V ĂRXڻxS:J|W[+!>/dƧQ-Ov1D¾bqN\[ַO4)*^ld?@ߵ endstream endobj 403 0 obj 309 endobj 404 0 obj <> stream x |h4-~Uk_VD F9 *( 7"7bES@D4JH rg$Mޯ}>sɾev;<n>#R9'1g 7&>y_=\A'y Z`j*Fnr)mD0A #Ëa%2AJ,KD-_dӅs:.s߾U~k[^ zrZ33.'Mi7gb37TX+p5}$#c+#dp17$7c?]q*DWKPW{d;DUSheG*(cK%xE+. io>]HXZ .'k&gA"x>5IJX].m޾-O,Ϗ(y@5o~Gz~.dm7lnfVy`N.`N kt֪WX06{lY'bJ{cCK&F(~x )]_0*띿:~Mu粈E?f5qnO{K?Z^{eFȵ(&D9H%\6hM^}rgT,yby/!ۜf.rw p|o~}iCA{ϖX?yy,p',ߛL7ssq lti8]r߄\>7pé+L߲־}]{/W>9/LxvJD -HyCe3-Qؐ‡nκ窭7~HL ~.?cߞ%]$H~7ᦞf禟7'+j6>MϤ33X[f{yl"1nrYL\ 1sWk\Rbv؊E?3CMS:ex{?|K7ef_.~KE|랬='sdGJ6!OV?+~C7-)g7XGDEMxKErF83W="ԯ?(iΈrwX@C{c0j?w|cܿl3W\-.9]`էF\~!F%~V@Tco;Σߙ}ɲ{ޯ_) 8X0j[t{- ޥOf{oΨ`ӣq =cἊ4F6.)j\M1z/ܷvip-MXJVrIvg<*V(a7lw_)iy[V~6-/6 0zmǔWCfKRy.EΥTzKGt#U43w_S?rdK%4/zB%<}Gom=XT6z[qaz{`7ISVQ% M#@zЧ[ʅyT7zkZqɸjo߮\B|h;G?T .n\Ĩڔ}phEGs;qAd/k,;JzX Y Zt numf[6m~+Fl/G̰_'Ͽ=Cg_eQi?U]8܅gucm})N1 2s8"YhB E4f Y(?]LWiEbm21_tH@cRWVEf(ؼ%ۢ{cR8DRĨOfv[91l]d5Fr_kSv+}`#\䱡eSG3fW6cK˓( KK/lswRE_g~)s%=G1AXAr&8Zu3E'I5fߩHNۣTB\ͮYeӻK88/9Kޢ8.ÂzԐMH[x6Vy]jřMڭȯ2 ӀzҴ~eAOƔMU6}KSn|k$7*F|%w]t{ VL ig\ʄbB!-OF8'f7.d/S۸N{ۉPOJ֯暞t 竞dg2;t,n#d7}8=#NM7 kFM(A^9舸񻇫_A6o˪"n}t:U(Dެw^^_J&ɻWM`'r.E?eCpv`]:bQ7wyܘ@_|?'yYE7?}bnrX:f{J=.zTv2;'bOv2SCgP髖Өw,(G :3=}Uz_o2V:|Jd7Z1bV.-v?XNjĪăR۲z[qn ң=7 ̍(ji[Ar e=wJomr>70bEӂW?_+?d Kte`ן]Yq*FC :scCpn&7?_ϜpY b۴#UlNp%YD4מ9Ы>_?d ?rOp'7\]kw]s%ϧSO{sgD;ME9EMmDgf&` GQ[xfJDQhp;H mP*f\7VpP _>}&'߄76$|gCrݸV D+aQPSύO4~.wgwRw ]@5tϋ 0SCl9?+m7G$s[q<ޒM9XC2E+E̯Z>/x}g^xSűcs+!\]3 ~s?9`N% ,hll۫J몬!?$h݀ۉeV$}i;asD~L@<]A!~^rW/D'fs?wvvvtv:mE͆):?>&&>@,9z@v~t#yL>`I:`IL|.Hٔi;ߋ5߯K3ٛ|S\>s}>u+^~,t?P???cAn%uqq|} Y9y3s/0RȄn n g.@HJ~bݒlݔdݘd-;{;/^ķQ!&~8+Vg,[Q.yL97L&pER s/('bl'ҏ*"[QbwԵԜrڠgK~p~X9qn]ݭin- ?3`yw/~oxEœABuS t9)u?#9_}㈧&TTkA_g1[jz½ZOD𳰈t"Z$*?.qoBW`!yz"HM?+ghF$_ |}"ys la,&>A»~NysԈӻH?#fN+U?UFg$ψ|?L?_xB}ܱMNزNgy<|㎅~v > ug 5$Ub֯mejj~dK'bmg/hψ/p'~v:;:$ȴhmi=ǹ[5̯+~|#?Ɩ5i+lϼXrk%2[@te'iYU_ݤĄ~@M7|1~nmmh"4J s9>_?++,y& 3;[Tv[=][0~.)̶ך="kinQ 79/ bt܇p7bXg Az#3bQlȂ9Y?q4"~F̜Ȭ8Ӌ~om dտϼḹi3G#gM.Wz q)(iYLϦnwGxG [Exi)2eS]̩V5.!=N!k ,M[% ֭{qX V|]60לoj;n?{F-Iϡi0}ugKC9a*7i<~޿[eOK.o#nolJ«~^hB˯cu]ųx}q{TY.ͣW~5@CMDS4 sZyĨl蠨麥Jо -IxϡhQx-u_ϟ:DS$H?E7uǂ]pO*/ҙ㼜v|.jɈN«~Ah#t0ֱ9:cAt~asŹ]T`znj!09:Ds(Gk?{>ulF⾠)DvtϷY |G#H3^ ^lg 981sGgِ̉̀C?2cB?g^z;luaʝ/m'znEpYwy]?13`ΎN9YWs8~ iO;$?+hQxEyG\#ɜ?/<~ݘ!0!i#SHGGg-6g}9mỚE7T' =I2}H04e^׃,1C &Jh#ɒiZ[R-;Y&Y$V7OϮX,JvӸnˁ3n濼<ʒ%4-{4*W:.[s?#fNd][# ރ-Z>k8)gs}z,*P F%g_ ;?1U^g$$AYK7tɍM9Xu-S*_?+>Y]:!|~ZgAK6/sRX$[7%Y7&Y),_z;s7$c?kD>1;ioǦFnBnK?hr7:lGQPזSsyk5~Vw[}?`Y{V:7qu$[n} }#! gL]M_/(~ڢx2H]nʂw&g;&qݿ~vE2=T+\s٨L=iURI-ݒuWW}~VƔbE,jS}j»IUL{%g3$0?3ngEbEM-yb7T#Bu{48^ Ӯ+ tg/[AltVP޿; 3"U5#r6x /EЫڱ:xDVP<$i?#oWswZ8ʧ8NVOE}*|>豕.ֆ7u@ABYyV \_Оm9r"߯܊0SnLF}?u3?>}թnF"7u@gj8i3nL#8U0=U?%ψY7 ,|afS#9Y?FguT734 ?#fgF)"٣~NUg&99;Lg?@gOzp}6HDŽ~@M7|~6mL㟟yB)ҡ%?~3DZ@g$?9H8~ i3!DZDHgG~9n.Ի,3`W8GK8k10S?gVT F>%~ޙ~򙷿^jئ'wStlYKqO+fouJg9 ~Ϊٺֲ{$_ĸ_Ԇº쐿 55ꪲʊl˙ܑ|9ޙ7X1aΒjr07T7CQƼy~πLR?f[e;٬Μ:u<ׯ˄g9u'_=8˗ 䋆gt?a*tOAogu~ Yg&f|̈́Hω/Fg?%oؘ////~_?ó~ˬ|PQiםuEC0ҝ8n_p=_tu˲>>+#=3`3ρ%>ϵfgmۊ0t܇eD0߿π3`H<6ȱyiyI}-%9}abmҔG+i #ɒiZ[R-;Y&Y$V7O햟=-Dq:DZ"~ iԅN_-'؅,xGH~ i3!DZDHgV?s~ i3?GHgX?+pg2=^&5;P?F>BoA4/B! l'Seu[@ljնhwO̮wC~Q uuڪп{Yh4bgQU47?%π{ɭy;Vǩ  Vzyk ?#3`.cDgՈg hO?k|?%3`Hgs3~π"~F  gπ"~F ό@"$3`^ig$B?#$3`H9B?YFg?G9 π"~AguP?'5O=/o\Z/D\ܣJT3wV$yij_4:B0cso>Fqo1ɸπ"~ig_4l\g~ƈ|t ̄Ngi~qDZxgs\}W{gղDԾE~ i3?GHgV?s~ i3?GHgV?#0@H~ `ܞs_ך="kin 7g3  ~&`:lY賁0 ~ `6?q4bHgfyD² E+w澴0͡5~DκϋW2t l~3j?wvvvtv:mEP4?0ݭ~J!YAg1 [U:?0UnMmڦYKYLvf63`yk;o8t0/a')yRj[,\E~*犹Up%w~ `6?ϝB:::۝xnqt49[5-i YL{9^{A# l~lH}+YSYI$ZvlMlIέnn-?{ArZ[auX~ `6?/o#eI9$9y ^k%:to⚁L 5m0 l~3˷G"-[>K|qRdkySzѶw#X&FL0gf-HXX-'7s6%lc-ktgNs"FiL%w_M0g>NUE~fv& l~3=,4Ui c*꟒QZ/3`98ņHn4폼i:N}23`қ[ h9?0Y5 l~3g h9t~ ?23`C?0 ?#?01$3`AA|~ `6?3bHgfAgwgf3?#~ `6?^o230z%!a0gz3Pgfsh?kg*wx~ `6??k3 b'hH~ sh?sj's6)0g,?*3jp l~egUuT(43`Y:BMz?01$3`Ϡ3;3`C?0ĐπgF l~3s*Thψ!~W?# ~ 99P#?0L?=C~ `6?sFH|NSުJ\πg?ӳJT3KkY+6bhEP~ `6?~1['y.b0gzY4?S9ob?.3`9ΪSwud~~C5EP~ `6??szͽueZZ"H?01$3`Ϡ3;3`ϗ0 ~ `6?3bHgfAgwgf3?#~ `6?F|~ `6?ng:\Btgf \zgfsV"YY=[h>a0gij~vqV8Km6O9L?0{GlžGr]^h#1,3`۬ }R8K?- ?mga?+OMqs 9?S?YնY&>W?83`03?#?S?3;3`03?#?S?#_Ԛs!3dg3dg3dgsKh ?#L~ gπgπgπgπgπgπgπgπgπ4~p9a 3`AVU a!3`a23`a23`a23`a23`a2ZY~,+o4~F E-YJNڊ  &C~Q2[γ  '+@t]d? @p`Ng0'3̉7?oyo~ s7` w[`*g0'3v$oLzlNQr\"xg.+<>͏5 .ɗ>(/"D/"hCZ&;,/'G-d/ @B|E*oL#[ 9ʜ?^00rG -M j#xgRO775V㪯-ㅟ_D_?z| 67kk*|9rWg }$ "~6[3tsp@"J|7˹rruJ"fHAg%fЧ{pnK1~Y =^Eyw}k7tYiLAgW7䭳FnQV/=(nF4qkG(/ ?RA<33o QShl-(@Cuv̛CzZpoΔfV^}ㅟ_D_)t8Msm/"5ۖ; 5|~xΓC1×ӹ q3G됵f<J2xgWuZ8Сv$R%'r^30jjkK|99(yui͂i%/wq ^sJ5rjСN 5 f2tv{uMu$ׇ=^Kt?FeP͈A ?"G&5rj`nȪSSb6nSHWF (ؗ>^zPܴiŒi #Y5"/= z諡zZcW/b/JXI J"giF뫪Jʊ>$_2cݏL_ SN ?R PWWQUY\Zd9^ENd’lW~/?D_UWUU)e 9 *SN-ㅟ_^{fi™> stream xVQk0 ~ϯs!%q!pV8CS?[c%$K>V5?*+hM_o_{^Fy"Oϋ_"fƛe sqٔOֺ<}-o~nӹW0~N=9,n$~v~u;`PAP^.^:u+tCMXK+zÚ6hNiYbGSZ&)&9 oq gC!qQ `s<9L#t R+|1`;_j?û/O[tP).KޞVaZ+?lVo)^ nX0 xoqY{Z<4vxEH蕖AK-#b: a|8UfXF#Fv}cF\.D#bc~`=>q-dh==VE@8$1א*1nHJ{ 6qbsz `ƫ%O^)SŻN6i 58 Z }롸&!p &vǀS4n!:J(oV#|㧑rhқx+'=eϥ_g)Cp2'D=ooK_%TD3HpaMƈȞb/{z&HLF)X]С*r.95~r3|4y"3 1CϚUŔ1KJzׄuKR}8 y¸fb.'4IYN^"9Mj; MmCcL8j$uђZ 7zZ f{ y̚S1}^-i'-1V 2$r)\c{=72XO1FfpX0.5-e6qB\'2EpK9$tc%W7!]-k+#"a8)itaM3>Up,x J8Yv<):мCQ)1lz"8M:%f-qv=j-ULfatYM;e.$`pIc΀ -+b5륾#t-2QݗiwlsoyX|$}i^}04dۜ -eJe]0F.fAr=ȄN] R xJT|:}Kc%-ǡD4YEvepErܩFņq,>7 endstream endobj 411 0 obj 1106 endobj 413 0 obj <> stream xWK#7{V74 mÒ&vC.ѣTg3訅@_>v:?\Qp~գoY{eX[П_p?^Z7K__cڽCÔ;~Zń`k #7Sy>:f q=`a *! p\M䲰f%,^hzf*&e7u}=fmr.S>=o) aϤ ]XӊK1m02̬on=fǍA qa{+o%'?p}ldܻfjvoM; nqX<rG'FN&$ ?O6YM٧9HyⷚwS3D灀uZc|| ڈ-Fg'!)+$) * XԩJxIg&`Ttxvc81 >VG1͹j[K7 'UWJʛ19գ~ (T.mo(c<ɖq1RgaS/RW]8A%E=o7"nZ6-z(q W/i@FfD.b 4bs yI GawDzw;[Ƽw;GxW6ʦ ?B̄i=\h4Kl^2`Ү'.$˓!bV4e WZ!P%֭t-v4讳E'eiCw8R^&o#JK/̐K? endstream endobj 414 0 obj 1025 endobj 416 0 obj <> stream x}{`T׾f% ټH.@+%ِ<7 !j ŴW+"VYŀhK-U|~EZ*m[wfM}_>;gf̜99gn;BqHmh vu^ !t!lXۭ!IJNA?{P2Kd>%#{w$ Kۆ[bY)ZFb?v8z gkы%D9IG ܨmG/` աhZc}t 砥-A?A p|!&c0TKX+Cȍ|d#E/kO^A%НM ui/VDѯUrP)v?P"0JcuGv(9hZZCQ$!(I(~;7W 0x4 VU ݊Dςyq K(<]#L :t3Vvx|&^h-t=-8nISb(4BQ ~t@O7Es\/??~9t DϣW@nNB2_8w#w?wV_`@eY 9oD[#hA@owR_gGƓD\:;縗y?sœRp?ĖǾAدc/ ^wº'C :^Goлu[p2.bނo?wqxT&rʸK!>/+5|7P­6apZ\t p\W bH@@zAxrЎ_}h?X??uoBowϱ '`7|q|^ R߃ǻ~?k8ogW|pC$JL&r;M^=9LWIr\>W tn{;|5p!~+$B.U->[Mtbxx8$RT,]',#LeH3l5<4~9 ፸[f\\$~wy6Mb90ab'0F4ԋ~wv堻0,p): pk2gy {I:_))/1L&{NhaG^yt)U!gGCbos /"Ot X4-"{?`O0}/FOpm4WO9 =Vx7N+cv5M#Aʫȋcc{q2=`&x,wA[gt`A<6اw'-t]MQx/P~)6ݨ| ҉Y%fHq4&WΨU˧]:)e%E'N, dOgf)q)IwbB+6l2$Q982mVͬisrZ*c* Tͺ'34BL0j(&hjnRD_ -{3)g0 V(|Ct7T^Zۼ~&lHrsN@3@Ĵ8qfI &ͬzfR\Fe1Zhyd.7'+VEQڌ=PP&*VD%6A(;smuHFƴˣ\3Wp/ΊǶ&s+a7oިD-Z>Guu0%7ςo\t!|mQJZS5Hk|U=$is7$U*kiu);]hsMߠGU<7w:`Bm be'5* P< RJRCh#!5Voz?*di=_. 5b1 UQ8D^H Hq+"K:d2`^}>*[T keJ@j~.Ji˾%eHh4PY|5d儸)Q5!jqZբ˗+uV^PKGtk (WsrZBƬpa@c4b9L4$sl(P+FG:!2or+rYgϐdi(vbnS/|ug7o6]6 lͳҔY7bV)r VlPl-Y"lfLÛTŗ/ G4eS6+gLTVKFkiI%TaW kJޭ"򬂕0bu:V':EPMx/S'IQ"n$Or$Ob1“g@>3u`sxL,9| x`ģn窀>C "?ŗ#^>n7DI2yAT ䷤d$:i̽ H8~Slk}274ۺđD(jn٬X.nA.-$Dydse(OM]oYbX[ݒo)peXHjq,`ϖ$K'q9V:38ʔkʧQ |[޿1Aβ7dl+8 `72NekX N Ü:L}RqBpߞ6^D(@x'4\u}>SQ5|ܼkK= I%W-w2a(~eA~1Ǥ>-G׌{Fr P'Qiq:HQ%uƫ-Z6$ ƢYXg ,b\Oe{^cq8NMsmp ǹ 2J87Eu.☈E?< IX9de$Cd{\D'^:$!@ƫr~%Oy 3Od^?9&En&U3's'๢3 30hGd*SBNEs+: ˪Bu QAc) $V20Qс$8wlMLzJWݲC3_\K7U/y]K`ù=tcIݬpƭ#FM;G Apnax? siBX, ;;ԀCF.J>;Bp8Ds$!"``>L-\E9 &z&sC\jK2!ICb LKjyQ[ W/8wB;|䳁Α-E^F{I:W=}Oož?{ګjϮQ㐠Vp rRTխK+eapQ$3~*=YD1X9 a-=)`GXƽ/N ?4s77n.)w{;Yz8rH@$(H,'8N$'"~_~O:ͼ;!p H2f$ KL6 97YI\/ga{3;E=ZChOLQP(Hj4CAI!(ś 8 '(IPrb:uL|j 2w3'PtOh @xȝ*^>𳑚j/4v98A8$b+aRa$,\wwέix9쒸r-ssF 2\eH{'ďnwMD ~M&f/Ib-Ml|A6&Ckv;<(?]UO SU蕪BTRQdG`bDbg&N꾑?LeF:̠edJFdc2~tǮ ̴G|ƈ8WW= y~l+Lkt=dGGM7-5n%ђ2k̼.uAtz~i=ҏm bXjllvdC10 E.-,B,nM"ziD-;a^aޓ ؾESt|┼ &0k!!#!2Н\",Bҽ"[w6͟3ﮥٳh@: Sko|`Sv#T3J-䀚+S0+kv.pn3w#3Yb:gY ,z^҅2Q\TZ܈pzStxNsa>o:h>bMF8Bw<~uk$LhLԭB(lXDd"T^sy12f̙)㪭+g%5^#8zsX/vH`iƇӁvO4b [P|~ESiO8mS}4IH,..>T ذ8nGH WԽ6p`\&A$C<1Nddw2eKptUJ]\/~$ +Dw"H>ďG" Gȿc;)>`#)R1 1Iҏ ;ERQ 6;6hL '!' <0.fjJ,3iPdGf|>BIqO~z썱y x.V3ϕ4=5b_n$Ů=f媖OT'MP2QeZCxwOhg}B=A0sޑ``2qAGfJG[m 'W:Nc=}gf`D<'}a&)y͆/W`׀_r2ڥ&'lK֐55j#uS02yM Ja9`9ǫf7{x/XPZ.wJ;b8 m>>dblI KtZwSF\x?E}^$z+"p0`AYPL#il.scxX9cLusϿrQ>N{[Pn6:݉dӢTӱv]/}:>RAb^~БX N5L#pCR<=(sނiq WCәq1v-)y3R/lZ^37;%g_}g$/*, ]R֥H$/aCh{>:iɖmʊuv9em$3Had+6Mq~lBF5x(&Nr'kAi8''S2CةÙq4y~Ș*5!$|i?|ڽ+|+^]Ӆt.ظEyWoIgg#ּ2|z"Ze$*5 lK4edQ4؉yӧȈ!Pe<{7I  4 )gN$@DB]Noj^qo=ܔ;h/x!|+^96v;OP-vtZ*r"od]` (\_Mk 7 ~Ϳ̻I!NQtzWO9 q%>B.,jvb?9\ËƏjn%)DA'6:«T ݈:K,}۲r~!O$MvΣSRui<\7)"ӊ΢o'KzM9Ы d_AL^p w™ x3ȒQ3Q؈B`(‹Tل皶)vcY]n=rv퉩2-Io,p,J%$ &<џ2ga 8n/̅DR,i3 2(3$fLULcGey~%}r {3#9#5sBfIbgIrJll㖚ٗ%o$7oV6>Y?|8/;r0Zww%=.}`>7⏦;}/~ʇi~>Ks1&dgc]:.)'p 6rAMrJ:Ε:gg+ pfL&SZ6;aRQ@USM# ,1DQ)5Tr8>EAps)Cup}/ H`K#151.^͉s'XDS@ I2 k^(Mad̥a7c'2ˬZ&C\1w~\~lKcs}M7y^ )0*ْDOC߽qyu˦zW9:~xݗ]\j~a7hux f~[}<0pX.5;+?1wwsoţ^%G~KOǹyv'&aK܍ۉzD3T[*d\RCq p3E/7n9r<6vxb^ˇJ/.IfPA Qmrv$U vѴXu 7HX! i r5G5i! \k8:悃R\}P]{_Q<9Q G΍o'ИwNj= C#:0[@h̳H2=~G!A.geWǞdkjqz-7'+]5 u,Zqߊx&Oa  |g(A] W[b1|RZ5~A6U0M¼ǞɧۖWfu0nc0%ovqsr +4Sr&l`Yܖ\71'%'+f *lI ;^ෙd B4.-\`g/}vsQ,'=EC@K$OG|sAzqTO%\іt㴃w[dN4n-Т9=ń~ 7W~.E#illD2rBBgJ(9Q(q6-1*|dB1{n:,lʝV}C%5U߫zwҜ|_z4׾ǧp֎ӟʮ݃qݷ>ҪW_LuzdAI1u\ϑ[$ݔ@ G8lvLe9'ce,tbr ]w6C@VhՆzϊTAkb #`d,'{CKp32zL^i魷 Eࠜeݎ;^|k8~f "k63[L{~޼=y"$H7>xyf9j}S~|BlfjUl888@L\ W$YI,[kmX}d|[-f۷m4-ɶD^%0Msd=39/glfסN D 'ao[p[wHn3X 9wSo:w;[ZΨ/Ogj뺬K1esI9+if\Oz3MLsOz;ؤ\`HLq9f5ɤ7+W='0˶܃'pl#_,5) EM連!gܸ\r:$WY>2#EZ >j|4~pbNiwu=M8&!@ }v(삝I (lJ3򢕉 QMgws@e+OuYPGO_F:1USU#F-C ]@D__?RWLLuB).,/wLvX|/NjysaxmFKw%l}g/xʴYUnsW=5=oZӒT~iaeyCgQs3Qy'8ŕ8ݹۆNbe"۸ DblQdH)ac|# ! 5oIӆѯZIZJ6Rj U|7߅zT4. m!FC}\LR\B ZOPwHYLy'x7r 9ʝ XZ!pq>5{LXg؊m䉎E߱"S@6m)ڕAO0gP?>;Ky<${0)QQV!Sz0p38@:o_a)c: t>ep*ՁEAr4Bp9:̣S:su%u:̏Qc0[Wrk)l0L.'u֕GP-C(P5@!բfχh RUnG3a@M h&_?JCK 邺kMDe)@:TjCkj EZx6Vڃ9Ff5aTOC>SgdE"J`D.HMo¿1ү|ў_;1&Fc:J @_733n}% EUo|nb >QzYO:ZEhҴ4unWbVR^Fyú2hGtf P3J{~/gZ FI7"@XA]5= 372 XAFFt7lD :kХPty~}{C`驶 u{l a,U#^6vml,mz:GtM^7b\ Cݠ0NS: VQJ٪_WT:y.4&M=װv}%aJŴQwq]kmlcPKF6JEߥ#*6BtBP?Y +lb0Xx{ԞhRk[nҵZ[Dj_Zk6{#V%}Lds=qxdCnЖq < /Zf2V_ 5Iu|%|Zd3ML.khO4vGcf9Qmu٥lШMN-]5ꍴ93#w:~nbمc1_QTW1˨QJL>$gSEV|yFXEAEvnCjn%Ps}I!=si;(` ο#sEŶ1md^jIcHdL3}sRѫ e_ä961WP{ͣݭE]?[ uVt^?沵Yr#9!=BV{ Lm_A >?rV{a-zx= 'Eq_ƭkxDb/\  ) Ql7d:NYOF%p2SI\8kMTTcd"L4 U,@{Ƒ/pou !a9ook*= v۔]|O[H w7367`jH]wo;z"}y t;H2 [vhu袓Q"0}k;LnkfKk U.:K(nc50lo聉46i{o3\itGڕ!vDPiv(!][Ѓ!`c[C&RB`1>j)N 5ۭ.}*tJ1n:{(= JS;,FEuwS=GB nP S'[W`PwC4h )hPoWGHF ;Ev6Z^swwǔ޼V]a[[[[?ڵ2HG+ . Ν5bz܅ VT.X\L]SY9rAd56[GFYLe G/b"5S{hmg4`: ՑPjbRݚ6CSAMtQ1&~ U=04;ĵ]#D"b36em' 4,2wl*`M*]0/\.1m}afshu/n $ =KSR jϪpW3 :Myu]8ܦ֫'Ŧ+t3pW3W_Z>I47qkam>/cNuŇe$v>B,N trdbinqITL8y2KkQ xbpg^xD {%7Ҙ_ͻoލ|nw#߼7Fy7ͻoލ|nw#߼7F{72zF#8ek0ΌcGwg3ˣGΰ;WcB@i : }[jpUX##vh;Bj쥺}?9ǎqq9u-'ë֣vլ>gǎՈvuMkJ&|1_ʫ|_> jT~:o⎣jY/^EDjcpWT57 m_1Fv`U8)҇=G $?:.VO*IX9W+VZ6&'AKBxn>Z#H*BHAA]o'ex UO𹹃rs}ށıF"-ϟ~π-^i=zwu7Oqis?M'2Xep 0XqDZ"5c1D{%C!$P\(hWp3A3A3`3(ggv@)IDD^HBHA^H{ H&EP*bcN08M0k-q3AJS "R\>4 ޶&MeIEkZqz=ɓX6I lhYek-2%jYkK̩eV-hf:1~F_#Ư׈k5b1~F_#Ư׈k5b1~F_#ƯsGsBzwdy-;!oMT/BZ RlH~H>ÕlٴA%ͻrCZ6HE_ȑq0YaqcŃx%ˣ(Gg@| >>~Yh +Ɓ,ȂY)?N7eo.Enȗ d ͵Zx 26¸۽8#,lȀSGvy?^s~}%k`cދޗ|/zu0Uw_Eﳀ3 pw6p.~?! ]f?퀡`v/n ỡ7]oʻ+pƀˠt &O<;; WP:ӳ؈*d量KEٗx'eWzLJa'KFRI?YϗRԟ!S%i 6`2 \CcjK(LgL_l hrF*RxF4P5$j%[wbF5UJ!lZtyTH*TU;%0]ZN;ܘLzn^U,6::](5"z8vzlCiѝjԺh!buUћ+W,M$rnHA⮬̺*1D@]Ԕ6#jN_Sq 0u B%*p=<Ms&ydQ%=x$C]c+. wex RwW7骜 ݨ**ZJI3.oXN̺.'`:QAAxA`AHA0AVuUp*xM,|IXBB7W!LP;_U0Ttac~PVL!Ӛzkz[# endstream endobj 417 0 obj 15823 endobj 418 0 obj <> endobj 419 0 obj <> stream x]n0 նW? L0wA\H*a:=-+zqQj/8A_v(~ {g: Q ꣼`'DE! S㞛bZ&lwӼ% h-YEFhA'I!*"ߞsɵ՟2&Iz.+y|@2;lr|q\!wȜ!?o}6'Ρgӷ*b,쯰dr?!/S-,?w?H,=ލ }>.'YcnpXE7 endstream endobj 420 0 obj <> endobj 421 0 obj <> stream xy|Uչ0><$!;9O&B Zi p$s=^9XCȇ }0F؉2-Cs0eF|g|}Ct _oBϡ3P~Pm$Ȅ&؋k p ?~zuJ4M??Ѝ t3zx+veZSG( Eס8=mg(ͤ.<=AQ;ڀ/Nƿ?DB9S+y^ ]x(1O8V; ǰO %$K,4(2YAOOf4-S⯑\ɽ aumڃ#GI͟1v$<7O4;CܟxLQ/= "b_;.|7>Fs^⇅رWϐхrhStB^E؎'<ᏉBIv{/|?_K" 5H?(/X,T  ^zZFڟWK ߊ_(dANW[yMN>.uq?A%}gx~gJY>AX)6ҵ W Zb 2H@{@~O:\4 xWj\%8[-x7߃ #1 pd i Qr-J~@yF C qan<7[]̵z+k7sp/rp'!C…B| / g"bX$^&'M BzO?Nsm q7!HH<%@U\ bx)ŏ2Y$Xb:B&Wq=vw$ =hy !W@kѝ iVaeGw"#ܓh:Nӌ@+W}~t$؉KЯ`*(s5 4Cq[D NZGqW>؅x995AB8(:wi8 ՃZQ 'VIc␾f$t,l0a PYl1 BԥzՔ *'OX^)-_\TXiRqj1TEDF3C@V=C 0&~@ hv~IJ6(vUk3CfAr 0#T 1xw0pZTf[fh^9Pe~:=4= @@P~웂@|3''HRЌ 9i`3g$鍡(4mfEt̀8}@bht4m7)pɊC3|B+Mj4}Vmcs軶ڀ$~{5t}#fjW K*1hh&MLPBB-/ś1m_"6Pmߍ/t0ks  l DGĊSf(e1(4b@k!DND'B1b5iPoOii?C Oi0RLgTNFE Gpx /4x 8NadBӮAC ii7 h5DH5:ҋµ,9#9C ɇB3 gٽ-_dG5KB5Vfn7h[X"h $P^2ZFVL'2n@(Y֪Z5-1'i-f`90)|~|y3o_>,]}z^^5۫CZ !~#wάa` I7 Z$Vmxے+amjg@ފ,ҘFc 2J:#ry⍃4y$ AH4B/f} M;DpLIB*1(B 8~OWWη7\4G#^w.+RI>DJd[:fg !SW!fݢb7ϊTޜWp+c6P-(9jy<*(h%̖(F~Q٨n0oE6e&zUxUyS}?.W>R@_3i @+I"|[,Ҙy$јh Lp>I~L_␌|I1>cQUapVT$z `|AQU P/YZț9A5I,ʒ$kx6Woۮ)3 9oy[:_NZY ~1G,GٸIjK$ϕvΈg$%ϒ?IWKZoS7+[U/Y񒤨^^RJP'յ>14H0ڃNq1cvD0ZFx4 0u7#eM"&}҄) ۔7h(eE1!aKt]`c9f,M&&KfOM5Y%򡄮MgɹJ6ռLR8nfꍘ "8Ra1Ƹ47m ||>(mnP:*BD8P@[  gN(ׁU;F0$Df4epmYA@pe Φz=KPzVYd„ <Ģ(&h<2c7gu?{r…5K>(_1™v[^Xl.L.AMrh%K3@+ Ґ'F:Z%#z."G 2S2k\Q>?wO}͏r_=kEE !wr\=x?4^ x]TUKv#;)99+[Hٳ}eYw8cT`RVJ2u$d i21(ؔ*l(OH>HQdslekl>;n덉Pah3nPuVKÔ8oa /ԑY#h{.''%v"%{؉qUNY7߿tٲ.{qavse~5  #}n$ے=:HG:"6S=t\ >t\hĐh )KI",LMDOfnޛZt&?$4\I[``ѸU:Ǐɺ)f 1f!et_qWq6x9S W%LKX1g؍;LQ~5-Кbs;yyF?*:ĐsBݻoS$w8>^tkYfZn3rK?lYkқ:_gMs- liҥrsYZYzY,CU-77ym\w綼CB~|Fy 䋾4xHR9maM$SD2t}@߅8qivl/iȰ,"t(Xot< fguOh l%dB/1gOHN[k}MwG`Z:qY$'|uia]RpSוt0'܏Dq4~`jF"Z ^rkJq<RyWP )0S"\uİC %1!OCRthԧG|陹vmTeA==#b x. 詰1R[GaK|꘹̈+&g-^@a9iv+(HG# HX֢:W94e01fЁCJ!a=n*Ag{c[y3'W[ʉ}XXKO׮8ɛø(xYNrq;j,}?ai8Orܚ-qEK` Ew龋k;Nb%tԐ "|M^znU],QWյ^)@~?'_5e)2^&jL3oΌ3qUB.9Ye`l@An'[>p!.ݝ{do,:yAq|س0[P2΀gYIĹ\\..&.eddWYLR㚙ttAA e2ِK8{.l"f܉@Jԑp]QM}*pt\7}njfo5YK.N=.`>7nŁ< xTw͵k[#'o};{ڻH޽ :T^,rY(cf6bcB8A Ц$tlKmme,YeoT68 --׻y͒SvKA3=AU`Q~:]TN$7ZqRҙҟ7ERN{6tE\ CWXǶ Q:c"tYQJv;Gvz/\Ů=;w~cOvwO7/bx왯(o@sY"v:UUUQYYQAD$%EEUU8NT9MPz I@+t/_L7dvV[N}{;r8 KF Z6K:MU`e3U/*^y0y-aB(B(B؏#{Tb^oU`/ ÿ9{,68})Htߢ\޻Wd*9K;')[YrI>%y\  ߘ*fvz$ n ^ #gZʆذM#0}b]>A`1={%lRb']dTǬBStx]be2gxN-,_Sq/mrJb޻O~\:P}G/c}2Y_E+lZo¿)2?g5=gDDD\\oj&9˽~nUb>psQ/;K9OXZرŸ mN PPX$LS.PXV'Ii@pEbʢTD  S2'!%bA }PN锢c6.hbڅÇc3K,'ﺸW`X a gc6.Gm'JHvUfɳ"e}}cN>c=ElƈH.l,/0z¤$3?hII{&IhH 5}ݧ~ &w;c٭z^\7} )_+)‘?9qeۚgc3omsٕdvZv E?L"IH`.7<3#pan5IVXWkd1fC&RVTrtJ*FgWqc=S Gݍ1jž=sjv͸a۵kuq-2~ c?] tݥ?w}' /w-wnyyPyYT}{B|x9ؾGI%wOL"I4t&\Ġ{VZ0V?a2tR//+#+sx]#>%vlo$F,n=~}mw޻ O`594QOA!.Z࿓;a g44X¥k_>M̊H39LPY,*k&vᶺmn,[uմQXMؒ"*^bYXZo*X5 .׻ۍ4zbZ=H =Y0 )){8 _yqkgk ycgg ʭ:+;}S&tnQz}4BS(c(tgⲃֽ?zYNG{_OpՃiwq3VL{Y~Jv{`QD/dlF Nc3ɲj6y8TQy涓7EH0QL4ɴ)Ƒ-f֖IEx,Jqv;MHMSa jurNdI7H/hWE,M<0#_ְ8wV@ƙ,4gR>\Gw%AOu}>[;'Zi1-( fn?`xqH͵Mεڤ9.799ER%n]ؐooCp1&!<@I)R*«'z9y{zw{%Iv.v0m;_3Pf`|G'VΣw!@L@mݏǁR|茀=Ģ'S#TVZ 5e'gWA>Xl䤷J~+?]Aop<z-mzI7td^[ED^{C_ yEy|'r|DfE^~折 @nxIITFeeULQS"j&WPk(1 X )K >$CWR\+D9B2hMB4fw0zIֈ2-wj%{eg CJnmphyH<:_'O-؆ㄧb~tS92W9F%[/mw!g]tooEdK/ i)4bv\""@ n,&;$+Jfcgp(vm^h~`ZK`ӳp R,OLT(j&|(!.ʼn$&$ &(a)YZ-\Bp(uQ+ҍ.tŏHGYČ0 8'0O_V7Øn*0&/:m8WRRj9 I d!`L\nf{),UG"dRdm(8`m w3T&;fydɑ\9сd] Rb'ET`~om7 L[Y6-àa}^LW= ^8=I O4j7Β208>eFv!bȑ[>wx7[Zm5"e0G2XG*xɛT9%gy{yr׮XSҔo}ԯᶖ5=ҼC#7M8zeh%O~|޻Xquy/hK²J>gTRn2+H+n%;KOcf^-"=Nz SR]QYE0uH^*)jf,PϤ'K6Mtfh m>|I\;e6hC2h `OΧplc]~ (rr(MO3?;!KUG LyJ\IøY6j0XJ-*-EI(K`iBi'pue7%/tq||,Ns`3/[)|P"X YbxjA=pҫ<,IYIwycC7 &qUʺ؞Gޏ=?#v[?O=>$}>VyPIJ"z]!\n )(GʗwC٣>N_STOTez FQA(_J43""e*"kL#d*q̋zH)qڜ fI*nv eKD_lV%"숉 .Naă?-jz1pѐOC4!i0>Y/^4^VwsO`-C᰽}k2跃 ]4cw-%ӫu'q]tqZbq3~XOĆboލ8~/> Ssf ;Sy.\y7Zzs42תˬkC-f皴֜5RL3;C@?5BC=F/ =tJ ]~U a5ϒDB5*8CYMӯlOr_KQ.jMCǾ~=E:ÿOGH%/`pRCIx/G׃vyt/⫑{vb8UE%+#~ ی:x"lrIz$L D=?^8ऱ5Pci0CBU53IdwLj9ա6lHl/9jlZp֛nߺ+jNQDKz#d-J#ߏ)0?q؝"6&λ'Do ynv? |d8P/axw.w&.f; |zEz]s~AAN!Յf«Lq1QKÖnڡ]zc]tUJ^ƏsEU[7+Wޣ^a|ąpWbwl8 ugiRQb+R&%gwU޷'k ؉[]bQg=ܡZxp+/P,GE:^[裔faEƉrɼ| 䈞%5#y`=IvKЁS6]xj]yj]EM7M\DHfG%伵:f-\κ0ĘW6Qb>ݚf YKGGS Ŷf|R~Sˆ^J8㫹^|^ߒ9+#d[=^ay{J6%uD/e[^tKQIh% eFRx4K&'O'dR*'t Y.)n$#3;ߓ71eiQ&=DDuZ!42Z:tFV`W0p|Y=qv"cGպ5ǶoH#$NG h!_ +A޵XuCç`uƑe2kBy)!%ѧo۸ڣׯ,[t!x˱glLLtݟMZ"}VI9'p:$CLq^6b34||d\S8` Wuzf.1)vVPlс_yظ3/;c7vs-o~n&0}v"R 2L8azIJe*򸽒 YptE,_:lZ %8{G9 d4^cA׷N2Z/^3Eg"J6iB$pdZn,mtMĢ8W9B, ,xY8zRy8B3gk*JZ^h(.lɤqŰ(!$~|/;G=^7~*K=#U`Z=r܃zc"`dVx :" >E#,==`([ X*Q^eNr;&ЎPJ I(mKsu/GB7[m  I[nvTC3f [.? kii$gONV9e\PBh*' 5/(ow s~ULyD8L>rƚTeVf x@LՊ(ېxSS;B68'/42cɟ0oԄBr6gl]|wͿ셧yxKgx~x`3:Lpԅ-h43ż(DvII*SXD`땟5#@倊TAJ2YO=~+d=P~<) nj8I*F5|ްo6Wh.q=!Lrr6!xz ?Vne ̂>Whn%KIy+' n1(>&JrP35r-bײַkkkl?<x.$5iם7TKQʟ}ܑqR/Iݑ+SP).3uZ8i~9m1"X=(Le 0 Gnb,gC,,i Nv?ilB53 "0`+v騌m1`{ۧ0 G݀do4`k XB; XF.Uk&4_7,uŀ-J̀ `Re< e)EH}0,Q>7`/`~OeB/7`ò@  1`o7`o]07&]d_-`_{ jRZec4A3'`<f%g9l5`%1ڹـi;?eiaTllGqf9LRaHB&,Mg2*ЭpѠT! jeobFe5F[ 7ZHnX k _DźGcަQip0hä1154XF8OiCX-c`m%IOPנH!=( mFUZ!Lh1JS:'LsEױS6HzVc }-B3%Rѵՠn1VVqI:ݷĈm kckڋ  -Y{ KMԧj]!#ޠvs־*!a1VƵuL'ӽ4QɢLÆzCvg(m,vNz{6#|m|FY }MfuAel7ɶd`#mQ{:=fHhS!eg"q]'6s轉QiɦQl&o`6:b/?HLژ}7 "h~ YY6(ti@m3EYb2xhw{$&Q6:`¼_ t< /T:TB>R, fwK],R&M="khzBO4h~NFYgF,WMPoQۖsXkhB[ cJt&Rm5zڽްGgD2#sèunf?z }n65b1od̀TW3˘zvoP6JXoJ7{mԊ50_z]gPǰ!oJern/1JXQ'l;< YlcFQu,=W-=FnR6\ucxdMx}$+mEM?U|п9M΍^tΉZb4 qk<ϵü>'7ڀzW{mƚۼo1Ask#kz<±ѺsTfc5^{FZ듩(>a{< `}a,; %!wmA[RM,muoz@f)Ӻ=_KJ5Bf[GwTkkkhƖFDZ{` mowўklZڣچF&Z€v/ DImmBF7j hCod }cܷn W辭:imoeCݴ.:TZ{h/vVc-47AG 66ZZKt]'PC[Ӻ> 0o9(Ю7tvFQ$AVJ,-]I쬣mc5jj}= RѮ>l_#CaPTN`Q{/Hm k.om A֞u hv{tCOgC'E0-Z+lTTaÆ6C` ;ڊZz gUx!M7+l(29sO]:g|mAv3/Mxy3/ui ujĔ'(Q[T 2Mڦ>ZJЙQB,A8AڡxÚhJbV Z@ :VS5!Cs(0.J)m>7EYر&ʊ0ր녦Ш1A yi5 k [P[dv(`Lnz:`t9r Τmhjj2Rͬr>Mfe5ֵA'܆= !e;6A[m% :7i 5(t~Gs Zh^cA7+ѷ th}ktC\}cp2 霉# kc9Ӂ5X7{  A? heK$31RXP).Ve5X<~|$r|BYEYE'Z/Ɗ r5j8Ir~N/p ><̹ft6fTcs4n$,?/c ;6c ;6c ;6c ;6A+g; !LHkK;7sg1s^j!עPCH;:#UǷx.w9ƖIflso[u0[RҰO~"5|ߚ[wtΥVc<ؼs5okI7.R2&4ߕ6v{J(^GZ݁lvw>~*ѧڹBx档݌6Cx́%)pPء H7fqZ./m6őp/Y8mDr(R+!a#)RP<6{I?Wū8Tn*E%(;`Mw 'dM=JdN:P=QTLm잒'8 T?ڞTT҃vmwG#;#;qITŊW hRʪVcHM˔t"T@`q+V¬f²֏-;DW(]Ƙ;ӋRcgod{}wySR&q_|BCP}O"}.^_Uޗn? IJwOnt(ySYĈ/hŊh^ u9SY@nӴY, ĎrR-!oC,`MfהF¹(S=sY;V8nW◇t5(хݚ bn+{}r${JzN(-kad+]E[:kTE?m{_d 9V:.5UE/ؗF .}zWYA?u+0pO;{k)ً& <z_7lMi k&gGtT!+]iK51N#˻*wQsx>iO8ȆP~fED#EkM5VdE=zP_VBP0h-EepE ,{) ÊeƿqLGZ,ҜG_\]&06fasyEbCzm;$+fpȁȁȁI""""'^ " " " "+,,,$D HHHHI""""%$t:. BKB%DDDDH!!!Ih 4M BBI ) '''$r~ 0A4A4A4A4%єDDD͔D@@@iii=/a`0%[˫ a0%a0A LI L$J J J J((((I$n&o(԰4ŕӃR}dC;,m,-rI:CRў<jH1S8;% L6٘>bU%uEn[Q*뵏ۗ+;m+i QZ{2CҨE=~#zW?wtOS=GmLǍ i{o"^Io-ﳼJZrP@ʰe%Xae~vk0ld`9˕Ϻ^jB|bq$>g]=TԒ_Z|rG ZC3 nt t8n-^A.6'y<=HӦ"-~2bcA|b⩝e*tAmTοR w=Uׂ?-SPn)_\-`Ձ◴*<{|?U- _$fo6c~L[Kڍp+_**jQ=[QCNGqt9:as0q;;b#b&NFsISFE>쎗zb2]^קap}6DOuQ-;!KXQcjCTGE,C2DouJ$&vZa;Ù؀3wR,a-@rn ACTs&zPۮrE(s}G9N⛑iTLs6-^EoyiyғLoo* ")p4IYË"T6A١e"ftE8 P/މ.%[|ePm\`c3֨_f3WFZS֞;"Tz_,FJR-ږQȗť]VH>0p gHk@;$D&Nti|ᄴʧI˹U(< mDV$"yTR endstream endobj 422 0 obj 21108 endobj 423 0 obj <> endobj 424 0 obj <> stream x]ˎ@E|E/'tu3cɋ<O>CAa߇[HY:4Uէʮ>C=Ŝmm0pĊvO^)I㶄a8M~_ݖax ܅.G}\iaXLTy󹙾4אj[_yM}Ti.ܦ s3\Bɲl* C߻"f^CeeY,SwW8g ‚KBʹny ~ccy>6#`= L2seGCQ/ыK9Xc6GB_nqߣk<=/ѯп:qQ?f+]ed;l]?/twi =:zWsX2}e֝6C8!K?qdl endstream endobj 425 0 obj <> endobj 426 0 obj <> stream x|y|[ŵ+]dK]YX;v VcgvIJ,Jl˖$BPR $la-$؁BB.kK-um X̽Bh}?C̙33g6gڎEȀv!}nqBupJ`[LzwT]}Ǟ@H(ݽ]:kFMꞠ kQ(~7 N(r;>wJʡ,<)(p4v'v%ڜI"j(W#pcPM˄UjA FYXmiv3=#3kKr?ɮC(CރM%SI)yD(:$buat|_@G{у6|EN0o ,ɎwQ)BO+Q zFmSb+#'E4νqGe:~yrʡN!ҢbۂRQ%ZeӣK8_U;6r#Z#[CV$CaՆ{`IP UmG<>:l/pğzf>e l^Dߠ xznWSiSG,]&Ab/b`|J du[x^C \C&T\>|+c/?+jTTTԎS'~ 2u|t1yaV5:u/|C#8Cz"|]Oc&!i#~ 9yM0<|a%$%FoLL_ZݣC= k.*jZi< =~G‡8y&;s7TFRM⸉q6=Ϣ8ODρ'#[ތ/'q!ϑ3#GmѶAxԍĆ^#wj-zh1^IuC>@wXp ~2Rx'[b@$y.{ {*܁&ѻA.ـu![cKͪ?Ŀí予<{N :'FsO/ZI>w( ;_x r+x=ZrG1'؋;p?}~ }>?͍*̩'?ߚ:A*mHt{y'W{# !=z  x k*6-xyD1ׁ*p>j&h+Y&Hjz-[﫹V-\\^haiIqQ`AO[rHw:i6kE4N*"Fv)<+VѲ,D{\T\Ȥ> OMSbQFERGHcxӚoJ 71c#nh!;z8n zַA#z]6+*D#:=zv_@KGx>Q\n3zMK}]ZTǵOGy^Fj0qum\`H!:t4Rxj1u{ Ne-qJǰxaܺ}L:Om=6[Iwn)~pMZ7BЖ6mQ):J>zK{׷x O.sĆu$ܚ"KsdVq6c#Piqbʑg%A\ HI&ނK O+VNPC(m+.x>=ޏ3Q! R60Oq7^P@BEmc3 J-Ьui Zi̇:ߵE.K#x[㤝֜J֤n55=`GYJM4k}8NAqqͦ~o"sJr:[k[ @$c`MB!Yr瘠Sd,5UvFcSV1La3;|ޜ {9`#7ݫSqg԰}ljWG={#䑽IM)#ް&у|ă=6Yr`R۾u$Z% K$j`GUejy`F I0 '2|Mկ/Nhgq1d!@c95j'õKwxŏ'ųMը`S-,u[ܖ\aģO%ԧ>I)KV|sMil$Ȱf Iͳ5ZL\jyO7 h(Z]j 7؍FH41CƈE*fc%WB>N#h)wIpKRRUg;s䄜P=}w:(-HG\ P HSWu|FzeK.`w15_My$.#h0m䁘ŏۼM 3ff"Z$H (RUz0" /yOv^Y,nu-lQv+V|{K`tmG9d=޳5vRC[?/<כ׺wܷ4 Xۃ`mðӡ|)9РVnhwt`ZҥuKJՖiT6F"* )hQNۂ4hp*ZK!UVL;uGm`#Jj0 F1 j 6fG5{92ka58pr 7LFp -wvmZ^mL3Ҽ#\AVF,̄=ZBڜth3H6ED*DD!} } 6Aq5Q;?Ar6 Ԩ]ƦN&{ XiΞGxZ@sw)o|M0bN|ZM`҅3pEk[[ꢒ%_mqb"F sYP·]WvRqRNT8E< b~M vG2<rɔY %[>R:׶^Ouֿab|;|_&c[s۝,iMĴG5c(\d2o36mQmiQ>^rlxeK7" oo=M]+fjR(+}7XpO+?PdW=7E9t<~Smjn8Vz;rrί{+?G]Cͻ򭊍w]s ުooh_VRPpsAxUG2l\(/bSKztnAn_vk#ySVjibW=d^JڬǦ>AgR:vaǍ.73,+pPkL˲E2)KP]&%R:JߜNLjۗCsqf&EjkQv>MQ5z$VC"ۻOILt=!RU2+wL +jab vIG]mo<1bqF=uM{DHơ3y[xjݷt5ݾuRZg֩1Mkh2 "+pfQ,L6A0M:Aɤi'YфǤkk(♒ ؠB9{AATM>Èj& K%p%;b Bdqevaґ#oO^qw&t_/|OŗA,};KpKO *G^jV5AptCizX=F6?RZ;P{;{1XQ~fo&4MBN>öjg "V{'Q|ϤqQ *z(Ea2\g{>}[tl Mģ%&ȡiy0s_< .#\Jܠۭy"t ;5;a7Y&bL;q8GOrVKFX `CQ{+)Q[b1^m|ȕtDGKH3Yٲ3ZٝfKO՞hNJNɒh Ѭ}ܤngO_կI۝H`3lbOwl)ɛurʗwXrVb >ӷLDQ]o'gϲscb)O Tъ/k7~'ۢ5o3~=?24q/è`uD ߐSޡ?.׽h_5CC$Z3_W&l Cu!.,+-|a{Ҝ4Xu5,iNgƦ)"Riƙf;:Uz~S-ihqbѹʹvNhEC3 R zG+QըiWU%/(A=O B$t ħ{k~qɒU]ڷK[===Ҫ1Έ0OcwUj!GkE(ipOx\i d)nb@5Qʹ&Úkˇ[G*%ӮRsB>sZMd/ YwG_?q'V>T ?ydkF.8ʂLwfS,'24-kItImnuTK"]uj#^(U0abPK+M:uSuѼ641s-J<)o"'XF~V^S*arjmt =af) '~^=wMhpEWte[C+9JZ0d_f|Z3X3},[lx]q㶄cǤ>XI`+t7!vL4< `CF޶AF94:T\|)t '_hȢ3&\>O,I%<. ɉG>+wRÊ[`H!|5S7`^]uĠ<Ƣ||R3U4jc6,:ިcTG_b,Caէ7R>`ǞgzpLHŇj&(Ob+hv'%ǕUJ]Z(s YYŎS w-VLWk@^I\B<,ʥӾ o%z`˜3DP[TzjA!N ҃M PV3Wmu%*ۨY!IuVѹIz3v6#db1} UegN Qr29`1lQCGGIQti}.iB{,MO ڡk+ $ RR|l.<}ZO#ڂHm:GL.?O^I/ eƋSYv(sݡh_44j|U;r2(gFUUb?J`f9*YK~lHt%gŶ4t2If"Yt4udάZR>Үsisv3a3!&q|df[wQe^5LkCjF3\%s/ MV?g=se4#T֡m,7ڎfgWE/>/;Wf2\?NjYw#]rT=dw×J؇Ip_"cUԨPBB)WJTmU^^Z?_u%z~x ǥ=A)J G,zR?/JhgҺpDnaUUiKz{XTZ#ۂ"!ʘ7Hဢ{ʥ(fQqU DpWlL,ͦa"> #[p׿ v`$)nX'Ǥ0TT50,ƫHh@L+f&GP0ʆFDq'< >-.sO@A3!nz ، ]-cyJG0?lX % ʅKJKK ,]eReUF?錴T6Cq1݀>v[vsl\*OhfṃܳS(7΍̦ė |+/_A| W_ė |+/_A| W§OLCDa~f)[b:J94I\s5_TdfyTr ǯϙt >~_4j̭inM3E>ŗ=fͭepGwzB: p |Б[|ckϋov,-tG- rNaa`z7ýM͒imC'C@{O)ԫJ>6v7{ Y=Oav/av_avgx=/bb!]W}.k`7_]Ϻ>r]zI8Ps5`ygvZ ̝qp%V놇O @M\-Yb\nꡲ` .FWYk6=Z芸]lBy2oq5fԻ6Fm?&?$JؿLBؿX_*/{,IшƠi4 _uz_"}yz,z'!"rqr?@Ru1[),FԸ~#8&LWzK[F0qg -cIQg<Zu^s}N]sk+JVIRP9v>asM`qr˨:_:(Ȋٸ%DVk|Z㷯.kO裵e+OׯxT쟦tOi~j(X0:0;.MBFIߢttw> endobj 429 0 obj <> stream x]Mn0Fta !$Qi@`H YpzfV9fxUQa _ְ~0y .ccX~J |{V9uusf`!,ScBVuKiX:mӂkTLe`{Q%l*2>g59"NbFs&GrLs|d.Og|@9S Tg_KΠ{?w)O$k\5e_Byx^1dϢ?I 2;kfLu6q9? 4|4x*zC endstream endobj 430 0 obj <> endobj 431 0 obj <> stream xԽy|U?|ﭽz߲tӝ,`$"5Ⱦ DPTPeW qaGaF\g< =Vw}S{|Ϲ+]=ih-9s>-Bv\"r_/8 qs]]jBW]zΕ_:c-BK͞1k:Bv=΃ҿ`GX\=-Z2sFͮu)o_xAdEivn8]nCH(VO'+z]PٻOUuMmߺ~/lh@y% 2tKG\6r1cǍ0q)MS?(KHx /6=?%=Nk8= =g|ډ6'GЯ+h*܊O_` UAFtp ½ W݂]Ơ%6|Yj4oBu2tZfdnܕy B6B3w(A毨\q7w){ OY g-Cp)gf~7kx4$ wwy4Ӛ9g@p-J!gޏv}kG/XNf˜DATC}[KwK7RFP=Y 1;DЄ*ͼ<o\9W!Kr'6J<O"ed y[dxbB?Ih0(4FO8EA;lFr  $W߹_Of@/Gmi=v~x,5xߏ#Kr1@oy\  fg2Xuwfa!c۰~u߆; rgH$J#5W09?W%Zk[mo/7>3*aCxZxE8)j/d$yѮO(1}Ozw-76  Q -$n'zk.e+܂W'o߲w\z l'y/ 2~٤l%w68s^ʥ n5wʽ};͝_WBOI~(50]xCLTz]o4@#R>h/zgǹu`n/TAy 4I@R\HJ\G|x*FN x>DlߣNE[pUo ߊڍg'7QG<)x LAQ9_[@G@/LU.82 ݄P'^ɠBmҎ  Z!8458?3] }!}@;-RT=|0dzMC2s~8s3@xmGQcfK]Rа+ѥx0UG]!R146Dh^f^D4CJ'NlpQÅTW]yAdyYiI"^+F ¡`z.;MUdIx`T1869Қhnaz (ѣ5EC?5N gٙu}&6" WEdp,zhP,ҎmbMNFdVFہFAV:dMvԁ^hjT?t w$ZCA[A ZZnj2xP8mUъΌ]يbIv *lc"imȮM[ tesR5cVnF}3 D.5pʆGܦiӆHSzuS%!͛G-MSZ- UٱyAU]iA34MhS+:;2gȦ SbpiƠ]i=A3y[rxu|؈SDojvĄeV)\d)Q'ӝ)Z+"Y RJpdHK.S'n˺K3_yRTGz])Cez{_o]=U>&|{Kl6qb m >U/Bҿx?.pVkAqs" dEyM=__1V1InJΑ'Wj״?&u55'pEْ2RWht8moCh|XR.;4UHpqvԾݞ<5@~pZf3Ȥ.-n݌vm)8Ÿ_Tv2t(a$"މ d E=>Fe Vӻl~n;ぢ")E":hME#jeZ(:huE>\ӯ[R-::O夫+gDHUeءR毧2Fq lPK\cEښ}د ]R]z|X%5ڿ`C]xt.ܺ1/z1%ӫϟH"CeԺQ=TWuQSKesƥ:y斋KґÚй@ Q}uȼ\K93Z٪lWZrRR,U*۲EǕ*oD8EnHD^mvb'G`sL?mIҧ%gM?J: ^ӥOoZ֒tV{9gsc[[ÇxCřHp?#5ӱ'Q@] KC>CI9׍"T3*b.krQ7ٻם,-xx1`#d,-J߶#+BG/]zs~:S_TT=ZXRGʊ9CV#b98Gg>1]S咸H.n3T +;, .  ;$7/1 lbb# l`A~x|58 /'y^sM]`+ PqtjTpkME&+zU髠?*sT\ͫ?RSTmA}{T4V"UƸg"׈e2(aKDuJgGi:LA3kC\s}jQ?ZFfj',lʪd%9ʅ# mla}6ͪ܁MWALT$pXdR* V؍:baTkrƥ%*&0*4$V>_e4/[lbxu.-Lnn`qu|Z\}SM~Ӈ3_E=CSMS)k2ms{kj !JqK]qDœ Zӆ;Z6$h#bp7G}K}k}ϞXwWj:=nz K}`{&~*x*5彰A7[;GT kL1]R!|Ԃ>gzo~eV;oZgop쮏gۿF+_Fj+]Ex/Dy^2K )em6PX̶^Q90Q*?K\ ?yN>>yF.7õ84#o{ȇu?GvS%tNm!囝@_mc{x, q(BQ-qRvM)m )9`A3f 9(%< ]`NN4vBK5t403bFܲ ##EY hA*-]gTw2sKQ2V75OIGp!氆Kӟ4";w8qA1^P2h]Tö5ֶWok[Zfmcqk_`m!5FMD*8..h;jE|%2t D+[NgΉ_<8m.">"SM$>pp!P 0~כndn|}>ɝv< 6{jg d|D8<>WϮ8`7 my(Q@lcVΠF桲?Rncn-c6*@[8 KH\mN'cO9. n{v|: rXTK(p^0~eTTYTN4NƺT|:jAؙGΘ \qc |O{w^:dU/ͮ.vY+nx+fpiA'r^jo v _i&_sb/Iz<.6d&#wa3ӯ1%WXЁiL0&2,blȊwF,џ1g\4|@Qt(LMitv(n7vW81"2xZ #1|:lIeԝ^Hwoݴ~U>=ea͐ɮߨCrvt N!ڡw^f8Kas¼fwA 1㱐&ۃ2[ \-?U{5ͧ>% }~սi j8h {w4n};7Nc7/03px߿+``{g[RTe Zݜ= <־k~Wwsb3;)8OXk~y;cd]P!'K뙉UZoawƅ xH藢D*'"2Y@̜nQf~2 餸t@j0vqWWYnsQ~m\g܉W\qկO/|'Ϸg~gxo~#o|!&AnUu+ΌW]?ˈZ}me̸_ 6I+ kU g蝘B܆p(p?--"gUH.䂍Y/^OZ: tQxS3!$L 7B

    pU<@ ԀG1 qW^HFMBFgH8g;}(|r,*dy<w'Y4|M}a~qb!0 a.p Y(]XeԾK*#QM{YcpK\|2ʈJ;HZT _4V>RTN.-BPC+UGC8)*O\^qC8"OPəLGCԬ\c10Sɑw dw:D&Q"Q9Au@pg: t@]Bt3!c@0BqguߘNLWR- ) L@wGWܧ cPU& o0o|СнZߡXI&PS "/D) QNH%7 =B dcvq3P: cr&RBm|LݰRxS!-Gf0hI޲bh:c-;Q\u||Mђ&h*DWƠ *Qp|= ?wSq>|^j-i$vt T<>gC*NYm-1@ .Sd|KyjI; yIgI^bI".ם⤣s: ́wND4: ⚽wND4: ⚽wND4: ⓽AJDФό: ⓯AJDФό: ⓯AJDФόznJ:v( :wS^bݼ$k@;8Ω&a)}I}h}HE Nuon%8뾮2tPxP׻Rox\"3h*LIɬppg4$ Fu_-V@حV9qlcq+%6sBJM$uՉ߀a4&8Y8Ru6oY^"v\ʱh 9kֈ0jpg{wqܖ_"h5*)n6W8xqx藡 x 0 C4AvάK/ h ,CH lŻ\>e7D d/ UMT߀A_5gekjߨauy z!TJ-]O XSCh u!5%3GnтW=?}s ]UU1Wk|zbk 9 RTZ%uq K&%/BAQ!yekϑbo~Zj7fz摿Α@ƒU\6,i<+==^6Cw3$H'44Ҩ($SY`ݜէ<@!w)qew~3рm0muݣqΜx}4z{ b}ެk69M4ׯyO<|;cBH@Fh7"DKunrQq/~~rC&u Vm:s\3xnS`oްx^kOY)]FgLnC &KE5 'ñ")hJƒkx Kx|k1`9ڬuKFfQe_.JS,#:6 hED (;3Gʟ{^'|5}68 @8̮@ XIuzu@PÒLIf9S5 ?NhQ5@$ymJ^}2V B@PʎV FZ؎KO6b{p( !ٚYϷ]'jjk ,iw::czXȭmyX5ϟ}^%ξú 3"Ϙ[1$"N~wv9 IlB&.>1{i'7vX"2S SG "II_I0erhgSol>NbV™89|6͡qӼw-_Z3_3 ϻ J>|R+.Ƨ;u$3+_wOU4G8yߙH0_"]Soɳ&<8MW&,exytŝ\","e69M)ݟ8ރsWL1)+{^+<+~{iIm]_uhi,ݬƖraC ,Nx]v{mNt0/;6@@L&a፱o[;N~Xo+Jq,RJT`ՓęCHw_5wܺXzLw=6N?nJ,^Uf&f^Sښ]{qܲJc݃3_1ZPAȭ?ޛ97k-S7I}6yt1T=,n{,aW1&M)h XuW#s-ݹ#^/ڐaRPKAb:&U2#Dtt`n܁-|2~[d28F6;j$!_u['OuQ#o^9? J"7Cmg .oٓ)sTEɆ#m\;k{a۷6ŘhCmon)t HxPe v}eV/>t ot p8Ӯ$<0FbWvrZ6|: =_'3xfnLR+< #Y#Կ%%NW%-XiĂT^ eԁb*T#TkM: g0Mc qoОːo?n @k&zFE{$lMZZIqL҃7R%iV@»7A@|@¹ ykyv yZ(!cc38*,1kJ8uϮ̿{ 3HkBUTM'z!Һނ ] ;Me<%oe05{zgK\jI#ןVU%Ct=wYR6^-lQ$,o\xTqɘT-c -k̫ GVS' $ao0 gr%wIqYlw DwNvm~1a:cG_5s\: QȈ~_"Iѓxl >BN7sI`0(AlW؟oٗPVk  `1Ж\Pl=PJRiJO\{4.yTTtAV8Y?k}u ざNQ-|awx3/Y8 I?ۏƃ^|Y*Ht~c1a?M !Pg =0l 9sͨ,W 3YZM&lnh47`ǻd-f{a:M-&tQ\#t'Qυ<:y{nY>ԑosQP$x7v #E @?~¹8#h0ծ^4%*=F]-$`z&쇌gCЇ*}/S8{HJe\ԙvQn%3li >6 QD;7GNzq˟ a}xP^g>lNySvRH33p%]G`}T B·l<ճ- @~t pWAw_;gd~o2>s?Bu "dddTWR xef"ۂG,;k?|Lë&GE.0n¬ 4<@Mi<שKO jC}hX1'MNb8B74]A7"@!v?H̵]oaD Hx4B CEE 1>* @b"*39UT8!qʉz Dcs:c^ jE{OD#. }xxB "%:ćvLwPDbL:>r[kXX DDdލIEœ+=` ~ 9`R[2ޒ $OOABd ) !@' 'n+Zʕ"3k4Dro#ғ1h[m[4ޥp?oѢi߭_@ێ3XEefd:;K$B@ O d־S6x-Uԥx߹- ?T\X(-j.X{t峿Zo'upuO']|9xnLJ20D L[ZJ͔߷1jmAuyń?@KoJ|~_9=7xd3\? JAZk u¿5h р@ O+RF6k{nޭN09J6s ?eyyʽ.mxq8H]EeRMi3.LZ`xݣ>LGD>pD ^[a7>,[.WvQʃ\Stπ#j)!@&k .'҉F&#̓^^N9-ɡT0r^.Ɓ&}ڭA}x#hDkkݙXϺ'X[v%շM{#(]̺^7աOӍzRZ{E[6{5+&ʈB}֋ɓEz2w|e^i&VBX*z-7ڨ.~ =RS- QKX<,#"]|!|G#=""k { zL=6hz0ED 숫 1@X!@dG>3$|pB VՁAG Q\\G ՌC"/!v[^㞟?T{ҽ^)>&tbHo g땮 ?`P֎𽘓B^Ae!|E"Ix8 "D;0D#0," (}4"$@7D @GC-b@zC<#jˀpad}Xx>PjTO0'@ ũU{œ m vܾVV_}wˎo[f7OjxaG"j~IBFWv@1-5Ɓ>)qjL06gH$ `N!,:EEis-P0:D PVQpəF[%~K*aT .STFYì BI@o1.K2WʌDob;7m8 }fCeG$a[J `l:s"<6_}f<pU w)(͂Wcr0b ㌒(uV˫b"Pʌeǀ}.5۹_}SsHEQejPP)G~zZ4)_{豥YT^+&sאSV_rRu2LA.Qԓ 95˂ s"Dy2%gfC gJESs| !!GDYS˴,,yriQy>S5sQ@x =H霧˒2ۋTS*hG@a@MvSTw,N)0+_aƞ]G0S{a&Ǟ8.:HxpƯ!A+"c'0'xyA "@@Ȕ9P?SL٬}zg3즺uKD&cʰ1Hx ǜ­&Akp`N/ } }!!Ga 0v˰zj@ϗ2ܝ|>Ճ "E,qdGhլlWh7vzǤ돧4|:azx[c@'W§@ Cig`gE_"(A/$"cA"$|DTf H @$Wb&^A?TǤAH0h|"@T>R@|"N˅[`~P v@@$|TfHPi a`6D X-thD f@LUcA 1@$-8z 0v腻ϴRX [ NHxÇZ0D <G3(PGTuaf!~(TmQ?1`DWxMg{CxC%x{ u9>&!%8ln }JY\nܕvn Zza)VW}YRē1r{wSe "[D A0r$eGGN,_/߉)+Tf^pIjg+e+ko@fac8!o|pYuZ3͙幩=1bC;w@󕆳M:RrWgў۷J嚐Xgxv &d+d|@ZsH:UJ*v+ϝ+} b "tMu _O/ϝla[ s[`a'%LoYtt:՘V"@ׄ/-A{]B׺U{Ve^7܃'W0hD t=hBŎ7V\M,"ŃH|ѣPC ܓLa@wϴbxp!eWV0GN >H"F@;IJk%d ٻ=we_zWv]Yc /POr{\ .x{T{+ab*@S"SA"tCcE @>6Qب+eG#.&?g-?90"vt=JvY ! E!>+ ?y(gk.x-bP ݄gG|pU7Nʕ5pfmRNrn@^C@Tv)Y}m9sꪎe΀ j0z

    0& pd-{OS9U wblJv5nzE@d}Փ?c,,߶xgfĭ~hptArr5)2?uq#"<;~Zr=3+ AgT ^;h %|LT3 K@b$| U6'O:|:98J_H"нQz$Uk} }_k á0@3<>@c@! F ZM UiLO~# >wm~7UeI']LJK !G\վܬPoOD9zڒZ{ft"Z^6BhCjeMEwzdEu=ڻŏAo@Jx咉 |.%_U&=+ j=33r_B)LY^5.mxqߪo.4ޏ&tq/~|9E"Zo30$5I3I1@˺qU^;HAyn=rvs/.m3@ O;lMa/nC hD/nq^NM;nťw8 r?5##c}NJnn^Cϻ匤z7E ޘ"H.$"cA"$|DTf 8h Ln^COg7=0hU`:@!UޫLuA‡rL u^D t C5:H^":SBz$|Wf:vDvha,"T@b$| U6&;uJÖ{v""}[O3EX"D\|,u g9DJ z/\>|T/  D @PecQ$<~@ !G\] շ谵. N{kR1]:AoL)ZyA"IRj+1IN<8[S^ժ}r]'O3ܠIgxz`sO%"i9j@Zrr Pmm]tbZZITy?;u}o.JVd71$|Zۍ>>JZyA?2o-?>:գ>2oNƎUktGlתJ䭇S&ˏ2d F+Ctk>n>6&J`p a, QG6GځkE‡MVHu V6bѦ^K> ^yU <- 4gΦ*S]^WCc((X[0 x[y^RR s7W$jޚ;֮g]OW-K'U݃DY̮Ƴڃ\Ѱ МQ'~굷so؟|'؃?<_yބ򿷘,~2칛kV[sO)~& J#eJLe]~>KbÃL;HY5!e!KZ9m`**à.kt돐kѵ䣯9ʿyG?\d]u[ޚ>"j*7?G7ߝݛP6?]RAaf3~܃h@tڇ!CL NUsz|~(u*2\nd %GԤUbo¥fBV>2+?ǝwrw) &ۻ~|Ή%MM ~:q)yw>~6jf]sOKSʛw?3<ȑD<^{0U.L&ͅ%eښaއ?z۬),z?wd2Ky{{%8IZwO{q$N(K=5fT ׼=/ ;^!GOrof̢#Յ>J^Ν'Bg ߃~g}xSZ^=SGz&Z, _ T=owU֛ʗ \rd˕_+_cާ:Xt7 v%{O]G I|jğL%?dneQGy{ WȣOFy%2//r$[NUN _yYabg{b:L? ^kKw*9-#˛//ys(ݸjzV ]B(vCa tZqvm7xdV2o5.xi?uq$uPw JG>Q:WYVOWIyUq >4;u@*䓺PF,tc }`ڎEJO ʑ9J!?o'-|ę4y~/á_o5?*zX Q2Nrܩ5\;T f1:kdb{l䂿? 803 l p:`em}o4n{kl5kg\X`]Z8젇&<ӢH2g7x^^k Bއ{C1t8#B1VPFwτv[;n!/2I'ONy[,?~b_3zHI!wEȤ|>y_Ԗ[mH7ʫ_T7EixULֲ?pO逷,bkJj[, Zy!<;g#v+Nh:g{uKewZy)[Q`g ±0C(qWWosd`"UcD/@oփJ o cC8JC>xbl@X#!E X<16D Ѓ C2$4v[נ}]a]"tDr4PkȠH_DϹ .o`v?h{Q:Q*M#^xϮAnNY`%L''v;_dW׻Qu ݮtN`.ҔVLI{~j!AmL\x%TIENDB`n@|&y#zsPNG  IHDRsRGB pHYs+IDATx^ |Tye~lLt󂄅:y#*R!5fKT[dWYJnl0P).q㗊 3DPEijiR#A4NR7plsιs}3sgw?3\s眹l||rjjJ * RL* I𰇥30qa iQx³-vj#i8:d^Q%Fw C9   y$G   G % <(:zPXGK,z+^ mGxpXG5+#=Lz{Y;NgТߙas'O=:m:c`['== B`ڴ2=F|0Gst|?M-0t፮ɣ _YF&g]X%1BòϣȣSNLxco=֯h|"rR1-vA;G'hJm2ڠF9SY,$'P:#(.Qy-٫ ǞGO $<ѽ3<{ǟ,ܮ~|۲ RIV=?&o£4Q#7&^Mٻ`#bS_5}gpwqY?} R{ǔ̡w!Zq5wyP?ORe=WibBO"g_o*ȣ5U4I}Eϝq0ddQ'@|Υes.Ns=O̽+.Af_2Q7elL!]@CBUN5$dpIW1NqAkABf+4'(Ss~llbjl|jb@!ei2䊀 ,GY(jlL{tOwq׿zw;gVXHn[ۗx_2M ?RD8yqaԻco.9IuEpN 穧&}~p=L>} ɭїnԭ޺.3g^y'N3gy?~,Ld)Nc$E<9kժ]'͍| Snu*J9iit+%y"@+C񳛮M{M򦏾ԡ~ڛU{7&/W^~_?~ѿկ~}[:|0MiY+o؇t5馛.]Y GǴqc7?v1B]S,+3Ṣ̣0n85h7YfjF ׄz7r?zK_4\;u {i+cc/<~څg/3/ ʬY,~%+*=9gق6G߷[droֺu,~0?ʪ5}WrQ|MI KO|.m0W<(\O)V,gn/gʺKs[,v{]PF+IN`=4=o+cA0}'?=XMwy=T9|xeD8؝O;1AǓPAme)!_~]1g2C_ڹ_}9uMգٶ?~G?/7__޿L̚3fҏG\w>}:m>N lްS¥|Y z~y}1 -m\ۼi],f;8{{o~{}gGOzV|.yz߾S|O+_^NKFS~tW~'ߘi~iy~W).5ũ'|>y}{$?MϺ/+W>Vn~ۗiЫÏ=ԁɗ*<][kc7?mv?ޡ\6"^]ǃ)ŚE%6uMF'?6}EXm;s;,;|` ٺ۩jp:Dì9\>h?>̊]_pr|+r3|5_a14ɦ|)dI#tWqM//QO{>)W:1>W7-x^zQ㹗yTA `#cɥ.&Eʊ^ eΌYkxWniy]O/ɣmq}};t&24#_Wyovm{챿si(Uml}d;RY$j@%.Okc꼅SK)Y9R57"ƦtM/ݐV,`YkdyxSLankۑ7|..bźذ mZ$I|l.ԉVnX̦"B%mEnd?ݰq>eCsimwgTȟ&1 gӔvMOyK'hbZz.ө],aݐEa3z3YulNJ>܇yv9{cMf> ΧV_ WξR7{̼]xt e>q}]D`)JbgGblĦJ9ySekנ-oyjs_'7'l[$;dU0rRX)ŚEKن;-:7OAlS=|>}Z}h;|r.l*u7kM θʧ>o:a zzo kH'~Y5hJ]_1Ƿ 5Uy]SS˿7_#%Ҵ5HL]'oOO}#yfOn^˿+Ͷ;-i[E"xbM̙?d;Gh<:W{ѣDoc_ڊȈZ|@B(}.亙ޝ..Z_8q~'fZVXOqRKNuʏϾO\*>vSӧg/%`0l7 h4Dhg\A>vt`g\kgjh/(ѳ >j)Er-4MtRaTkQVkFe2JGFDí  !   Mn{p&* qE>9Z KEoNKAe2"$=x4msE&@0ylӠC*,`rY I(CNva]xSgTxBT* j~vм#؅35ɜ?ڛ* m87±aC*)c.°3.N@@@ _ErA@@ LaDY   /"   &q'a DY   mӦw_ @wlЋTy1 d:l4 Y!{PQ ]|hX2sԮ޺Kܳ /|m#+,cOު|yVS|r %7/?H0s-NG?q-JIS"Op 3b6jr5'u$W)'wyo'uU( bm?:1(dTQ^9g1 >W@)'U*GZ:a]o{Pzw_)h1 rI QȤCdgrnjUp{菿 /|U̼'_CYu/җ`lx֏]\5oYȬ$w]L|l˶E輅6'FA@I%r 蓓.O>-'~;m&U$ư, mPjyi`zq fjR Ϫp4i׿j/ͷ PRy9/acQW~>k@0]+J g=:/W@@HDsd]5($, nt(^@P*}tE"]_u´ Y &ǞϯyW UUf|%m 5eo/[p2D(|x4]`6dH@XG*Gz E@>ɛr99/m׿T|¤GȜCiogT МIagDgg@]9O[=3鋶=GI^`;s7?o^uR/zvY~3.mW%`7!<(ɛ@$یyOny."0DoU\So0QfطvES>Ms3OztB$` n\|zS&>ʵ2;W&|PDMWMߵ,7sQjCWca[=6."!Q( .] M7K[mjXP2Ž"YFՖ~E9d[]h ^j ѱmYD|t|/{/Tf\#qMbƲQl a-U#frHN"ʋ5ԇZlU-sF6}W&T2F*xSCV$p-&m S3 )'l-@A\T!_j5É^b1&:O[<?Aco??eљU|k_ҿ߮Uo9/ O,빲f*P 蜮"bLKn) *=Pj}1🫢Q{ ]D=uhlxkX<]9=6j$.dk]Psu2RYL,,ygL}J Ug UZ jf{n{ThiS\WYn=څJc4$9\l<^[A韯~{,GWR/`6ЬtV5 4k^?mRgYR4͊4=5t鷞o3Wbm54vJ1}7}ZwU^|LjIS f~ߦX}-\zX`E[\m䷇5]þNUL]GR(Y|&N%%?x?fh\KT/6W?-xxL Qa\%o ]U8Bh3ckqc `Ny@u|!W\[]ԑkUu'љRl^W岩1Yz>vi]\9GǼ9Oے?y_*a.MVu[}\,ɥ7 25+MR+l) =o?Ja/{$[c ֬%l`lOX "$.ǁ/ٞ3#j2<=vDUg+җ_Sbd0 )(7Cd#NI7ɾ_xـ飯К];y6t=7oRI؃:=niRWJV9]4ս Ah W0|>-.oYS2߳Os#zkU0ՒyW_ Ll*P`Rғk.ܾs f?Ⰹ5-nl&CIŴFJ=˷ rU݇V?^lQ\u`nYmkn<a6ʹRι3۠\SRdۮ@!f&^*r]9_I[kf*l\9ٚoǒպ`yswEڐ͞Zx^1_^A.__[2T6:u&Uɕ{%)+ M\K5Mg^EV:aJ3WmY+mK|v!/= /)<Οm{tFAנǷT,uo}9lO8ۈ=Ll=b-ѥ73(dErw|j )9{=JK6=}LLn 17歯4/ msUGMFMG^Ee^zC77 l>aXݶKyKs֛RBNdI{|iZF|" o&uUmC ;;SJk޺I"ڥT~24}ƌp^cqyyrOJ_鵮t`'3W Q%HU8'kCViEݍtKbŸ(jimYh=^дuq“ #' jXx34dm1.8;P 0&9D(` Y!@=D( @@O=j_uNj2æOz@ 6@sKڐ"}џ=! FQ   X*ۣ?t8\(/~#\qs {O/nȥЊrx3g!(\tG^pmBi   PKa:@G/ʄ)  %L+xt2GwZ5GV>6 , e])u *ۣ{WFP:lsI@# +ʉs?EF<2)1 0@@ 9@{U;o7+ZKG`|`.Jް cVH)MP@\қnue j>hпY>EktwB+yzXZ-6]m*}[pɚ(njzW9PD:.9ib!MHvnGNi dA,1!%z\Oc0SZ}ta̹g_\],:{fK~n}n@ f Z[,KTH(e nmY| WPfʆEɖGR;UʎCa&5 ^AsPhؽ~ޠt&E1Y4M> 2*$MŹZ{bJg]uUJKW*d6ug8UG`ixM `IyZ6dqg{ Ӈ)ħGZl"vEKwBʊZ^ cVt5-c_oh=ӧz%)W,Iq/.MueEg:qlMaҔykW$zY۫Q&[OQJu=TWUy68wUu@֗KbMG[`#JK1 * ) [Lꎟu]޾y_FlϹEڨ"_kVgtwqp2w)Eݮu5=Uj[ HoKRۍ@jӷ 7kbGۣGz*=+RI=gZT|uUXx1:2_>u<[(f]ks֗b2n)Uav2%3޶饩|jt=z,qTķGz3f*@Ҧ7pNaM\_84G.KS]0/]4ȑOҦ"{b> ʗqNj:i%eݓZvBC]^|V@ȣޕ> xlQWehZEN5%E ?IofRWRX$stnqs}B>';:-eOcݑ2ME\]Eج!#jb(^AB.6dݕNvBsWvno^shU]@fs'oi6=z9m:\%}>=Z/Z=v]'S(N:MDBuكl-lJ|jEsq͐+94#LȜkҦUm+Zc[yVq}m);٪E{.9VfFe=08fE]>/oq_XV=3!ngg`2E:>qŖ R>[ GR G74ltZQi4{ [Ee= 4!f)hCjQ8M5T( @ _WcQwc?pf'$[ ZlAJِnzzZJh'OÕ@@@^Bo{\g/,Cр|aݷN%0xiA=5V ( 3g!(\{Ԕ'\( @@@ uφA(@@JOb ?[d`4eo!E=ۅaPiY vN*g㢡E~䣟+VrlW)t#rR@@@ G#  Y%U(@@rD=G!@@J]ëҖz\[Vgrת2~sHjwJj,QdtpzPJ44}S ZtJL+{xl23-}t?G|6E[! fd^RYI9J{}iTmRzXF]n3zf[ݣ=K#'NuGy$46~S_Ok͝wڵͼժ '3t\J\ᛯ5nzЭyMlBnG.ɃRdJ;m6H2٘syugywx q|@a7D}r-!neʄu=H0e 2f"-&Ё-)j-#Y|*H bw"@ovEe}JrrIm#Go$߷6l%L k+KTH(e nD܃):~(R;UʎCaVTC]xBg.˜KL00:I)5I٦ɏ>ߜ[zU|1h–C'v3͋&T6{8euNd2wgi!vK;W AWyYdM,eMc!l)_ 8qK1bBuyF{oxڽWR/`6ЬtV5 4k߱ZnNmE>l&bkjk3uO+j籛 c{v>(_`O=:]Ҕ+U gd_^qLW2n)Sֻc(,\=!*蛎 ŜFuE,yJ&i5{%i :vFjIƳ; @mbc FG:cpІ#[nԈ^ZOз\DK:rsm 5 =ԓp)6/|,MUvtHg"\MˣS 5|]1%\\)BĻ[ל [C|V:aJ۲C=˄ټg_hHKϫbYqlNߣ*5~]ҵ!}mqR@CZ+Ko1LQ.E|tf6Z5Tv#2{Ff+!:EkmSŠEsG؟YئNQ}U~3I5^q,%cܩh6c_;Tu} &3́%J%{dENS%_ ,q|O@|zX 4U~T=N?,rk_ui޲w(r{RL.Aicpjմ$BƞJE&?N߶iXKM/˚B({Gq[վV9}YJ@ahzZ4m]j?Op2VwU /׫pF)1q};_#Y|t/DN{GQ}?-OÆkEьaD0/2#gLXuK-dVw#;F݋$|Q]T?=O!@@@߽= hulsXGp)tq:zt@D  y'*   x ;xt C{RO{@ X3R,NI)hy& \r*'Q!eClN>vv{+}9=zHx]q>0 SN"gGI}:1%`Wv?q^3N[[b>;rIPVVH`~]}Ξ៟u]So0QGl!&t,qRiDPiQj@]MK5&ϲs~UB'c2޿ofvcGMߵ,7sQj,+@4BqIoqu5evn5B K2vnSʴ 5y(_`O=:]Ҕ+U gd_^qLW2n)--^~ZIa-^RDs.o Mu U2R +t'iтSs!M~cMF2s9/ƳW"(kVVl ȠRg pdEe5*갍5b']ԑk7(iН衞Kg_ dlӘ|Yzv9.-l}Jrȫ"_k6f+gMvU RCj\zӵuY(SCjZYm̧۫,22T `s~h扯=,^4ݶ&랼J쑁Bs螝.+ Âhն=ȧ'c L\g. \C:P-td(kp{^^FC~e:>~9sN!mͭhFgVQ=S|jR{TJ M }Koz.^_gt {T8|$=W:Ǽv]f$WUn򛹂sz8ʩƲk omq46I׸]guP3r7g[(䮨^VlT,6Uu l]_zOnu`nYm@]f'k-_þ}`t;=U-SY~J1n3A~,Ti:N o6D;qj6(T%G= $hd5Ͱ &7!Fm[+ {]u eٲ~zocM['O.8hU#Kwj 'd!(HUm˨e34l_VYE0^ [_p}Pݧƅ̈ԷdC 9C  "ר{8@(lQ6ڃ@QXybʤ뵢qhu4F,XG=q)tqWaگ( M@@@`m@@\O;;=ؕh=$yKjv8)@]g%֔wWÎ<6O?yw#K/R=4Rdbi^L0oyɾsgϺNǩAطGC@`tdP;s=@&=̶GkHG=sȦ*K!94&A3P>j_J?1x<˧Gh':8kO}7>je$p4?R7lng͌]I KzӍ5a@,s!JfVؽjSd' ܑ^;y∲t|.`ʑ'SQu+D\t;Vu3~v'=]Z޵ݻ6LPu9IiSX܌ԑh S+l@gǺVs=TUm.*^(vy)nfWt*\SZ}NaؿXvu(͖DVfwzy}h R&;6J!q[` _r3(`Xly)}3_xH}1vwgrK>PR]yN:jT#"mj:~soWqOmNymFJh05GaPn?E3ܻs۳{U+-C/ Cl ,LWi 5$,kv\x'n)6[Ln2hO9]*_Uڪy=;VMѩɧGf6[S\TU]yf˜b<&oh=GN4E<C#١>%s0["zY3B^ʸQ4`o3k s傼O2a'cxeb}1\ûN|wY_Z\@[ pN) (pہkDۉsQjg$&oleR3f'Ux[C.\~IZԑkM4NdPOR U@˦G :|]s" iyt*!_>kN%.n]7ݮ׮RCj\z38 SCjZYmzZax2PқkrJH0:W/umKi~Glb;q/*/8m6!R}T 2}ƗA2R啋ŭ8JF!wE e^|ۀ/Wսjl]_zTXԁM̲.V<XOS,;8<}`t;h*ӋCFۚ϶h[CGsCNje.jZ>rO)S|!9\-Ko1LQ.E撒>z9c5|gD%sVCtpnا-C^leDcB=:EUe+ut&uݓjؽVRYJ%SYQ5ɤ]}e=[īKUUwF1VbTw/0%hJ+*1T=H}G>S.cTu} &3́%J%{dEK{6NSuJ491?r8 ~^?e8委ݘ?*M" xG|*   -CJkg~?KzB+F!0s%upy43>5>@@@ igOA@@t`{5,(f=z66( " /%#^POoE -hSɐX~5#IGԞJk=43KP!wP yzFA l(   EF GYOI7lno;n-qp]E%\q:"rJ̎iO*t4/<:Yd^[bfΝ>`vTzuP8qF^-NJج7Q[cxnI[[}VnBgB"hiLG8({w>vIK0k@|?= hf(;2=ͫ]"}Jli22[[c1Sti%+E~SoZcNlSVR>+,0uDldzjWN9+L JZH6Fgcx­e=e44) Wt5[}GWW+U9hV,??ƒ]PT~C>E4:2ԉstWƕuZj(Tc.MP}'[egtfZD׮ev5Q+^*9v\rvjkc35`ScNI[VdgRmk?z'ČUVlH4gm mB6ec?n1y`F.g\rEE@ 4BEԄn&KuIp-dlQ(vpXe oRɮ*5=Uj XJ]9nV>їWV%9MFux rji^%42+(VdL#>D.JCx"(`?JcV*_df7bQEVEjN φX⨈Z:cJMB~cDnLprj#չ m+@m^8s}xjZQᆾt?h]Yk8Hەkc Ov.J ܊Q8{F2)&y+iBNcM HS ZA 9:+D9ؼ/~p ԫ=j1 )[._Bm4Wx=lfZ36G]] _8X-;qirml>k0 jE7wzImw) _c"J6 KVytz4(ml5紿FZVlFKE1Al=%۪3XM칼EUھqU Y;:VUUP]p@H|pѾ.cqA+bTiJL)*mW-<.)VG+[7DKm}>B($i-߶ '(6ݪѣnfWG UM8vsrjr<6h A_V^*niR&>7iav!ą4o0'mcF@@c{r2nbQtGV8Qh<(T(  K E3lVG}Zը8p"fB,*PvuOÈ̒xinYE([s&Z`(D 6 /w_88   2eo=z-V@W ( 3g!(\XG'J<:z+A@@ `D!   gܣOM.%` nROvY ]z P2Ck4 /fDT 9@  B <^ CM(Jw̹-zX@%٩9oQɖGh0H)*-R4Azgx~{Q\BբΜLĔgh,7!5K"SQLVl94 Y&jM4})^W[!S8!m؁Z{q= F!}S{(C]| 0O f#&o @}EW?BXg++U%hV,??Ӓ]&|փ=}-FGjQʸ24Ƕ\B:k8Ug{ <*pj-㜹څUY'kG޲g:q{];Nk%$ݲFJ*d* 1ٔLO3}Ȏtr{^n:#I0`j#u dخ=l?̣OM}(@O$+%H&@j <:xbE  h   P ыaa pJ᪔+$4B+H 8.b߇b^QJ պPxBB.4L!GH)$uD1a403ZgA@@ ѣQ@@2#?hGF=@ Ȍθ<:yM93g]u- @@@ 3=@@@  ʐ  &m(@@rA=!@@M=ۄQ>3Ȓz}?ѓTbk3sA5l9=j5%u1.CB&,<IA@dO ( fʄIhpR cyzO_Vx]%YwpD)Elyf\q)9tDMz%ÎjyZ7~2޼S]OUXVqu2vm<}?L8fvC#U]wS3kRh GXt: %U RęOTX 2+zU^f3~r=LHʒ̡AJt,?&$(Bzt]1%]ݡ&6sbRޗB4~ye^lF `'%|#ͳwuKJ#;eQwiW&|(X{t돺%+/o\kw+)o#,#S'P6>>oπ   $=FA%(9%W0@@( e(#^rUA@`Z,+=5\|b7wv QHrL*H  0=D,8zptJae9G`}N|IƪSh]:4姆oh[<8:u\Y[Cj~hkDOVO ᒌVfKw}v@@ Jd|O$N-Jhwꥑy 1?qRy%WߠNęnmY|9nXΞ1R1IoZȥx/hЪvnsuV,RzȋQVTs8vVU2ۿy'n64@C9bhH EB yXI+rO(5"]2 tzȠҹJLinJ><=;=ԣh ҭcTFR4+kv<˦v(rpFYr)ã S\)_G-u>Tɼv 46'7S,[^ @^ dͣg*e"Φ4m]pk^js=:^Uka w^aP>[3  $lL5`"ݔA,i>-_YWlhDiP \ }$,$%[WwYYFKnZ7•W*=":4p=PnTlosgt4 *$G_യk|+hy8/V'7pegqCt0{7‘lROF%EG5|YZyvғPPILT咗u| {LX.dw~3jD6XDM^:f!JB 셎   Pr5G/Nz @@BsLgByA@@ *ѣR@@2! =GJM@Ȅr2>*al(Ȑ@xt-u~s7_77SOOw_R&~: 2/y~~&WRqqܵv@Mn5 Ao5H'WuŴk~ZZs~gnt|bJtHqMY7RaU4J%:n @xt75^vbrhQےoSė)t^c[K'I[nTF!;ut: !tpMO.25H. IԸ:iu_SkÁ%Г\\ioNM1k\FI˱;Sou~rj'RŊ=yƱlʌnSE$c ?@xt{xM w*GGsW,_uS2!{;u|Uȝ}Bc&# ;+Qɳ|Џf!K P Vحuj. XZ;vvMwFZS3:Zl1ήLye,TG2J( YV?л}n4$,JOɘFZDe"S\@J!Pgm}@&rGsOӐ 7hv QJNPZ-^ $rLʞ5=r3z@ 3WGQz OɘZr Ruf+&yB{ڔ5#&l;t`'`n@{-ސ+J,gcѣӧ\7E:wUZka^\)$k鸞O]=ڢ]>PRNO" t:ٞCku";)o)i,O*"`J4E}[/.L6`57O7&^Mٻ(#SSLMM^0959>9᫦/x yy)l4e5-XG/*|5ɝϹle3w]te3C/uKf8}ͅC"ԟP J(QeF;М|blbL񲱉1S61O0.d3x\EK_"Q^ld~<_v{mP8x(Cv;Q6N^51۱2KN}   @>]NׁgSJvÍ+Z(emq$j@J@ghbPmoaXWw&>kժ{Y%Bq|g½T.(w)e:T }  :=zZx긲Frʂnm# M/X{LѷI?d||;u"  @rqr{;*ٻ$u vʂ?;k!ߙG'xRխ[1B_Bl(iv+/]w!I@1  Pt4鑣-u]C>eAvđk9\JcT>ɮmN]wSeS5\ P,oڱc__tYʲ֡C=KV2萀%ܸq3C?ḍe_mܡ{oƟQ!@;&ϴ ʾqm^4]OGCH ׳JϋF2<2Udã+uUuT}{9󿈳t`24_^5[N~K֤VkUtKsjmk{7nָB2T=wasռ+@dţc{ KKcxb$D:-sHd_A]^{߬+?ہ)wu! r/1IW ?٦{L}2wr=]JvʈMvudPZ^+WU,lr~b{;NqlmicQmTJ_^-Pdǣ}CEu~=#jQw̩4}e5^yX@- @@Su5i2:>oIlS.x~vV0!Z^Gͼ%REڴPIU5 $ dɣg/Ӈb&cяiJp~tQ5=qIMbmB]3kَQ⺦X i.2:t9֓Z:K#@=P*w:\87BSX@q>9xh)V4ޚb2|jŠ򚆣:v̛ G)JH4e읩'?SgL-.HDSY0߯Ҳ65ًѫz{ELH7 'љ?b 9C}겕}gMT|VbOOCc 0ѕ|mϬƲlmiOݵJRi/ªTGVK7Nɻ\"Z+ EϘ|7%>m[![49 gk^Oh:A\מ!DZyUJ/SqtXaǹęUmW"1VM ;I'($p&K4{B#ƕqeh-nJ 'qN/0'qldPag}M]"Rq_` Es|ܒ&@x睷Ο{bb|rrrj>Są''/YxW>5Gw@T+ƃ@. `Kڐg̸.K^rK.E/yŗҿgϾAy(%؁;xtmvNqvr6_gs1S׻G/_G7 %H+&G)NUN==)ZVVF@T GfW 2cb}T %&dD=#| v`'wN8q7ljg,9x"`e<|9օ;׉#Sw(&eC@GC'ǎ W_}22pq% f#R@-& ,0;uΜ{H"^T c 9rRBSW]5п%lWXpaXDUVT Px,F L@… ֗Յ;c}zTr!#ϵ3љo~ʖVs#%sZT?C/'sAJGB iA lּe\j&l';Fꯠ4Rk H=C=R zDW5`^+ x {Sumg{L^/:sL(ݣ~ߘџaww;M7lOo֦<&"/?~A=ESDAκ&),}" Vn)X˱QXB&Cq&!AF9vtbs 0Uz?(ҋqt-X0Dx7\G%m 9sG/gl<}?O;{zye̘qQ釧Ѡ;Liy_a]N:19vv.Xsv̹-O:l5$zygw7VPC\([One65vYdcB$.^)pNkZa97PSȤ4`h3mtwk%O1=1W =!gE-tTAgeVG)8I14ݲ:~,^B6 6{\:Q_}*t>5]BsMu/iWODgv:r *|;eM9Wg_T3^ǧ\5SOHL zɼêκf;S ;kb\˔S)+s6ڏ2J=ԣ*HZm.Lߪ%sj!fҹ?=˚%^%݋!ps?w``Og>s+;°yEƩ\9YWo@:'[=YSǓeJvY^eRFᪿS ITGYr("l&G&] .&'}kҪOǏ,Gcs__O'OuK/2:3d^9@Zڌo1V2S2Eu_^;HuejM,l_&+X&ɽ}~BC n rg]ŰQ 5 נFա.[C:ӣ/z0Vky$`^Ggh-{Y|WA|TV=G/G)¡Ë8ciPhu%Q- ~jJwY/CZҦW„.K[p INZzL+TZ:e%EqU{?t)zfR[9Bju%<6M;o[zC~dC*X q.b .ı Rv!ݠ|߮-=w-ח4ͳ/<*iWvA|s뢨Ƃ#0G/ZM P؞6 ~6 ΍߶9ΰpN:b5 `!@d@@@cٛq*H  E@ L`/S-|*CL%6qxUaXӣW/C'*j$G @d kn/zSP`*[VoJ,5azNYlR-b4xhZ$sYj!guu'P$#DW+B1)0=:-]W@g$+kk%9 ޿EZs0 rJOLsZNw(tv @fXu5~I^NXocĝ˥^Pzsw?.fkJQ:?巳mXwm 5,c7jorGokH@V? ūC9R>['fBiK,%M#cWRbO:ѳC֟hI6a'aV5跲OrcTd1oqﶜK/bJ@sCA$ MXrS|5Xkӛy;a=Y;Y:; nK [ִcvM2f?{ځ %YbAڦNXeY]kgo@:laYEiY.@Vg+ R! lk|tϝb;Hu&jw˚`;v[W2)R= LE*x(Dv9z6`A&5v +F?xhc~ZDg^LT F%-YR= Bl&9*3.*5=J@쌋ZH1PZ@|=5  =qm!!xҨgX=̼le9Kgι/x֌fΘqiM6>\0lLNEπ|hT>'.䘏*(Gr@b&pyx㗿k/_/~1;Qx3  x0( HoӤ.K^rK.E/yŗҿg2N)ӒL %D*Fv) }WWwѣV{"G=rUJޓ[u_2wlKA#7pwnS|jT)!C EM漏qw81ywvAJ=! x_~)Nw;b փxGf %b5\+WߑW++{$łx"PSH]]cvk^H5 ]A /BA@`RtN߯jlGSK/) n[zm…$bJ5{6DCǎAX k® m,X`vU3a 7x|0& 3zo{:9Nq xt49sG/gl<}?O;{zye1㢼i B@* jӧ͞=_}*t>5]Bߋ @;or,n/lHJg^> MUq .Kg-\{o}=ǞK G'G@%@.ѭh`R@)(!^ A@JvƕLUP&^ @@J3+!rG R.ۢ<^@0)Ԇ V-m5"-bVA-"(RTGLlR*`!7@69gfvv7&c=sw|&46|Cݓ"{ X⎥?%1q>B`(B<2E""~ .֝\16|iFHbԏxfԳ)XY`+q+l_r8G4+~qbl # HgeԀ3 |̀ @&G%43:HCol?R \nMH$[\R~X&Ww;|C?@I厳858"k@-V÷hT`^d`!2[z8,NՋLL  _l:%xZòr ;!;%G\_+7\w-ar&h8K?i[)ʞXuuyNN*1;* ܔF W2C#C7!̀@j?߬t4Z,ؘYpUms5*khkETee6Q F (c-[\?e@cՈWǦ\ J!jxtW8_m_"ժL>Oxߢ\%gMxQ8Xbs$U lIһL%QvQrqsX-tH`PYQ׽śfa[Eq+x\.A_Nd1DSo|R&J,0trN-bN{X!e4 4:}cS8t rqsj &?WA/ǾI{"fKEKcA/̝˟yfs^BBao`%A~2 D%Wqfr9g/RGuaD8 " )㛖8 0F9Ī^^f zH'ҏ*2螇37͌I#e&?i/3#3}˨(}IXJ`Х/v'o_-ѱ"O=<Uh|03 LtWc,)f5WݘnjX%ä g<:7s3qkJRD~ 4'bꞣ][҂ig* SNI/\ 3zR([Q??V(̍} 7v 3C|ȀTY7A`'79ܴf R Lz`,0i0fD dgdexd!`} D1%e|9w5{& q+;tA&eܙp!no]急L>;C4ʀLWT~˧ŜԂqvo,xd G]Sp BvYD˘ۚ'z +d~ [csrK!l=k`S,(`r ЙB iq7IGyGe!>F`$>qOI N`!.įBw?`]$B؍.` < c)l:D|4+/Y^l_G$b#`^#ڜÌ x.],m$ T[C?qBҎ;žߒ6O^@~R8{$y|aa+ "L`4$0,zٔ %ˆqKu.y*}\uЇt塍AS Btt-(v"]M'䎺N@˅^a'X+~^t,)S<|wӻWk@.K}`mZ NucA/@jIWmTfpߡdX;fn$]{Um֬@܊H?ya]:sQZ]p;a ڇlLmii:|=bؒa _tcPAے&B^2́>4q58+t$! @>2B/2%ت%K9(TD) 1kXa@c=n +C89.L,)5;/Q?G ~- Lm_n&у-94x4BN9|N8ŔcG`|tdÿXBD@c[@"$p<,:"`l =82` ! wBW!n7 quoWb _́}Zqt! {n1v }`3k!}{pfB6%pؼ,"y c a@W \S⚰Fl ~2, ŋ'a{'>)\ (ʖe;,V*6zв@&?=W~AOK{㵼^)\2bOy}TYi=ޒ=D_Qx<.uf^֡L&C@엸=mJ}al5q kr*O|'8JjkB^Dn[r%Ix"-tMb}&֧bDR{[͂Jv+ҹ"+,*Og=ތ" s/P NŮzwՅ ˅N$AMϡ9/>r'j厏C nkS_۵,tAYRTTI{ 7{lTw/A6\/BFr`@!{s`=^l+@"j$8·ܧT+JN!  #W4"2BФ" =b-L@ocҷՎRzOhyXD#08F /lI:D,Tޢ׆E|@c@"Q`9!@D!Ɓ~DTQcQ#/lza 㱜U&Y9]¡ *Oڴ8|LNô`_*9 r5\4?MK3?mC*.B:@lTrjsWufM\띚neΟ|j9\OYiNb" DA/: LfbJTߟk2t eIQQ 'e/ \³ PɯgܽF.B 2TH~3,'  bg1W` MQ'V#=*Qa1yD'c١fH@Dz $p/ =lD "@  pF /&0mE8D 'ItKc¿XBDZ!n@"y6.  3Q JHX~S#6G:^+4"]/ɒ" q\.֘X8W,Xh1s}/0&);DQ\v?]Hȝ6fWCV[1   ,lr4<_rYnn<;d~6[}uc8Xڢ} wy| <{ÎǬ[ V&/ "q$$phY.UAsTE$qà^bV_!År-{ A lY?eo8tܚ-_4(zHHOXTiSbuMFL@E%p8*7ϙQ 1"'_[r5wK͢zܹ[y^G>_.mߍLY!/wH!cWJzsՖo|sIRͦ:uM}<6abP,RVTywSҍ!Żl0Nx U7o?@6<ǎ Vxͣٹ0{U#HWGk}d |e'ݎ_Y@x֕ \rnҀ$~9I5_Lg},"yYCeҒ{U?z;%u]v'uWuȬ+4떌5QV=ڢoײ Sr]]Xi~%|%>k~ hDO~+jL_NM)L)?9[kB"mkeJ/9/ =V ~VwUaZG7%#GYZ7a[^_FF֩#:p¤,|мɃC޾QZԨoU:4 d`BBJ;p3x au _0ʒF&u{09jMTlg%Ut=Mg]B$a7K'Ӫ k՚.N;z|DpZ0N`՗B{ #Grhv4^[?2g~"C\{vNLJgj'7jHn7LټjO}i׌eDAWQ<۰ؘEf7;.㛭^M>ڟ *Jb>;M{bvӸ"Z __ \RaFضjXcFA]J= hb.4jȒKa/M%ɌZ&/8m SCz0Rf!@`Ip)Tpb:@ 1KD T C$Ӹ ia0Iq%Z|>(#f FIm5.d$Oj+;TԝL. NN´fEh`ʅΝ\q:NBH:;[tn25g@@N'D /en 7IENDB`nW5ViӤkO}PNG  IHDR+sRGB pHYs+4IDATx^ gbS](}IGPdWЬ 1 My1Uw @@D| l匑 *.@`fW1==;ǯlٞ:UJe4_dKE}ٙC.{d2jH1>h4iq{_m_ThsYP7s|<9dvd?RU.J:t,DHQX1,bD"7pKH%a@ZBU qs}_qkq~$n8?5}1OaI^n}KN +"[(lYn2^@*@2]+A5Owv(PlnD"FMKx ̶g +]uY蔬i-?O1)?/?M27\l2/frR9CIͽ  `ϙ| y$u\dw1ʓI\v!/ܧ\4|y6&Vա'\-)SY|&@MHmIg\mHrK xſW2YrsAz'?I7@߈M=J4_bgZYC$ w?&5Nj|F,O/tV&>RR!$W&W:~SM< vJr" ( ኤIKnǑj' KK@.,V'BUE^I&(N(V@ғH[ηy2u{vK \uE:t1ZNo6{56 GRU: R3-JQpQ#_e_LiQQ˔`]u ;{O6;V]N>}MTY@eEZgL=hN//'=l'ןK[oOVRb+vmX|+Q] ٭JguUq0,2Hu niPfxjg_ɞ=9}Jv1SC.z#v>x8ӷa?J6ƚxmbZwV iU^i"(JDDŠRL y B9EP?U^Eŭ%OIP*(ɱR^G3UId7:%h83G!nSWo⃠<yϫU; D֦8Z6~-z mw)+&0OG=#;N{4y>ZVEnigDA)OtTihwZwW^" W *7T ]i,z@TT÷di+DȀuծȁ@Vq'sVLW~g/ #V'ȯa7kh[y7% ^BT2줺};v q"z$",r=>y"0*eױ ~ۯaW}Z\~ '@+djOp./=MA>V}FU'|.^~Vh$x[$1[IٖARнrms/'I&T@uڬͩV HCY?Ӓ+l YR.8Ny7\_D!@0QOY~ǝtȆ%?]<EmLVyk6,sJnMa9a%P"TV(rW%;yy.m&1V^=Y!9ms4KU&VQFiQEt9L*c;M|buJ0 "Jğ@{pD T& XYzd>ϬPup?ν'1ZuIWa}af %-VU٧Ԗ?+fg:vNjH}dޣ²(XS'~QtT%.|ɭ%'ֽhO}xi g+اEc'j}{^9 㻧e|@ /m`#Ip}C{ػt:t`i-n.$-n#_̐Tt9=N7J?8\54/ؗg+ ++u H]i,5UPS^ZÖX @ҙp huU{ζ [t*O̲$Ba'v[ΰ[R mt1>%wݴUR Yd+}}}IGD>yB٢Yd\,Y^ivyѳ^`Ժ6|觰||%3ۭd.|UD} R@$|pS=>t�CtOS^m9EYFXO"ucy׾Μځ/Tnk Ò`7מg-$CY%hxe)@ <),Ee>'rDOr4c\m;|\+h.K^͆ kk ԧXp@SeY5Em7˟"@TN>lˡ]5S̮?iimyEH4CǢ 9'@h\#c4(M?Oa㮌5'Oy\] s#L]]s-nWZ̶Q@h3[bPhš^>CaxfOA$t Ͷ@jK(=)'Kh>'obA8 `*z-3ӦM.&V/Jk7v}>*WMN~W<@@@'>Qv#t0ș N  &šـ@(,XE kY  PX*@  `PY"_$@O|[h5@g:+t=!E8Q @(t;lt9ͬx(܉7@ >X,(lv= `9(Q@l3V֛ dVu3j̺x0VݺA̤bʴB[o_~0907͢/Eve̊ rUylݜVȱʯ$EJ5s3NxrmӢY edq(,ѝcǽ.Wk-3}2NPE ZaS$ M<@X@ F =e(Tu@ Yz\7HLu (5T2kRHI`FGy&1Z*"dx6q~FgΩ^n}vY_'d?EwƏl|cf& |v%¡7""3"UP3yHQ"dL~!1hP1)oxL-ft_׫ժTsq)_BrK'_PYɯZ Q 6*NC7AP}*cL=_K~˫h FG .>H(PM ZΪy}C\obݙK[;gtfFJɝWN|Y Ty}F01? QD,+W UtS[OU^*"o$_* d -gZJL*.X:(*=ׁk0|>dBPdZ}r:qk_,+:P^bs&\g X0dx6K|Vr2l& J?BPL,b\Q9<Aã*GۂC- b馪YGkT"$GxVF*+RFab9xQ,mA `Z!5T WhbE禘dz[IJvbẼ,Uf"'fX3sk";6xhQk[|FzQ SB3 `eEP^LDt\ AbE 0>8*b?9 _5dn8d ȓ|}evi;=Qcq&=G3|1?6L%fn\7<:ʒ= w>@hq+tLy9Hb*\5ϢIf,)"th7UoṢ3_w.{6;mUO'dOU_Ы8A*^пJ%/26 q|+ɕ D<ѽ}둍oEP> Q@kkaL[1w-#qiA ֕_63X[+FM%T (lB?  ݎ4B}ۿrq)^\#ZL/Kojq @aF @@ (,XE kY  r =  fiܙK`V Q ;! *.D @ad  6*"D @ad  6*"D @ad  @aj7D."2~ʉwk)5Oz@d 8[+lQcXe ͠g ar@„Pcl|,eh;H۰#4D @aF  #(l @&@1B46ndH 1 +@@b! KL`B q@@ PD! B  %D@a4   (l,@!MҀ@,PBHWX1m @@,2a|@@ c@"="|A#Cxn>C? W S2 \ݧ~3k>n g8N6M}ŊU70aQSjpgypίFP3X5/udq)`J&M@őV9Cd 5%ȍH߷o)eh+9{On<|oL$/f&H j{U}o݌5v€ CBv#@6,{U[xbBv3'9_`xNb] :yٲϽj{￿zU֭[G`v @Gkuԋ[N;PЏg(u?/8r)\v7g:l?(@} ^.S'{W㱗j>kTdž:[˯?¶CR6lv5JH-\EaIDYO&{^_m|nf[F\þ<^ZR\Aa.Wh:v磙  `%U]|9+Ʒsþx74rH2yߑgydy֮=q}+aޣcX8kDPع!&D'`TX% 1@@ 1Pĸ!D'1@@ 1qaj7$VR@+%I rHN=/JAP9_P6ی@:KA0*eQd   `(Ud/ıc/eS&ߣWĝca.AQK2~1~J.wL=;gG+ePs PVaw~RX_^'R؄'V(RehFc&)2-  `6ذfE~  b,UrOaҊ{Vg^*UV|S9>dusL=O}PއO8Aws=p7]cjS [Xv~a+~`_#_>\*-Ƴ7,f^KҴьMޱZGM5+}rK 2(yZB&"6~ŖLc#Š+nq9â@:3*l,I?2c^;S+f)競C.T]ge,ʡذ @nWUVofKRў 9f 8( ll&1\EpkQ//_4_Ypet1WDW/ߢ ͅTjݳu)D'Xqդ輡l5엢M_x0Æʚ 1ԣ_k|Ω7fIg::e3kf\/-}3f sځC_r+*R~D %exN X/ NwP1cYUb̼ݺ*\6s{z[mr%2z+,] v#5jhny_ƣyj>8zGTR1*'LgxvHgY9: 8d>~fK2u yc\آPZ=B>gkڶWT,n 4 -EƏ^Wp(..91ve4ӶC%]U8ڷ5CLWc@;EcQ֍CfC-Y{|!Kw}v_1T/rcc=:-2]5Qpx+ ~ػXFXдk$o ;e~}tOFnʩ) ȟuj7ڵ_N 6ve6zŬ_˴$(v= H$Y1fҴcl6 q jwiӴZI(,xq}Ҿy5i~k+L9w6E8>=yaXM2ISfJ]Z1aknKWT!/9|!dŘI.5c7o7 6ʐ쎹W[lvӴiZ8Va^~ еKǍ_T'݊vaBs@6c[hdl &@I DRC6,pS @aMʼn@@@  VZE2[Qw~ L ֽfZq(,͇M ˮv[ɑ01ف}k>RN<9wš> 3U5/Wam.C L ͽ/(lG L ͽ/QYPd(lfS;2NZ#W>4n~2jSVUFnu5SZb`R¸X tz}4ITh 9Y ,ss2~CtPkXu9Lgn ӿ&Wc6~#1n\jRbr6_P;f BMfVTϨ$~B^_L~ORi7J0DJ)/Q2AUT25J#t^zP/N[uO4 Z$K!. [9n8A5+57^c+~U[phlɅZp_h~]w1R9ɱap9,=NZ-5H,`զ$-҃yEa|1C<@,Xp5;凋B(;K4}ZW\CvOb!ɲDzk†Wz b 'Rx3;GBT(On#՚5↳`$h M$[E Mvgf7ql G7_̳b@ET%XqnǓFE1]|x;++F,5@>c<Ĉ H^ qĠ;0gU $VP[^ +Ɋ  [{d :t|pQ⧣b2~H+X0dZSs ~3&CEvKkknVˍ ~OրH֦ }f  8(l@"bUVE  \@ t;J &\8{fܘ˚ZGV֑ە q3mӇby3 H9(lʑ@!͙FCARNV݂$U}Jzh܏&h/U 9`0ңSWX>JXx<c M3{_x $)WXھy˃Ddf8Te*"6ʐjVarʮH`٠:a H}ͭ5 BqՑo.eV52UX_k)-X@_&x-_/0v; W߮ᄇ#L 7TWlrl&r2@jHB#k[DXmn3`PF[I3qL=x};g:"?ŠUk$e$i[VafثBj钨 m_h;+Fz}Ui?MlP=P:i nr{Yf |1mzEK@b2|;*l[MU^M9{m{ }eFL&Gl UQmh) lYgN\6;fm :P[Fުaqq㾹q$CTH@EC~vJHۉ4iF YaMe}!3@+0`rY>u2uba8  @+,wQ0LWL] |M҃UVE K@[\5-vFߧq5lacq(l2{͢w@@ kĮdM! iG v] d (lt% vi%@ +B0lX"; @a1@@*PX"_b UVE  @a"|A@ 1 ݼPX"CP @a1@@*PX"_b UVE  @a"|A@ 1 yCa- ,A@@b UVE  @a"|A@ 1 VZEc@& a)@a&@@@#X@a"|A@ 1 VZEc@",(,NV BaM' A@@%P@a"|A@ 1 VZEc@",b[o|XذEN  O@b}>*]ypc'|>  ~W|Da!  @",(,XE kY  \ae@@,4VfD>    `(Ud/g {w2'=-kA@@ a"XzSؖe A@@Xź  $.f$L$aB,KÚ?x 0"@@*X*x=6-FnguE*K"${~Qf7ktmfPXrZm6vqϞCفg1W|Ps ʵBacHJq5{q7ae$]ޅ [`Z{ ?l~KQ&@c\(Ȏz;f𲍻]k 1Y+| I%*e,8<_؋e R\kpK 6Ӿo;B\^ xmNgr+rCa3d&,[& vG\k N: hk6x[djHTM'HQ'좉^(lGт&@a?,S\I9nZ8䦛P0FK(TT[=~$nJUU o(j̟Dаx̠?w4:{nZ|@< jXrS;,U\jF5ۘ`NT,IuAa"BO'g_={c=VoPao3泷'hV/Hm+ k-)"ԺKZ9Ӆt6Z#Pc'q6:#+$aߧ#F_͟.R^ذ vڋ*w}O9g~j|`ͣ俊3Oλfӯ/ %ɧWO u` SltԚ $=$kgzcu>F(? Wt։?>5♟;\?}ƞ׮`0a kj7]$g6Q|J3sp_J}p΄g~(ggTG8[ - [K֚:wq/iJ3hmwK3?>\k/ֲz!N@%ْIfq&MʌC!RR^eK `K rgAp:蠆} ^eK`wy@$-3}/K=$)x= "(W çOmkm2?ڋ=2hYH7ק8twvői78NkU~3k>]>Q $g]ٴOm.|| v[nɵBa3K*gڒ6+Yú.i/9jx=N&AK [?)|9^(c Qa1#@",(,XE kY  :t/x >d-1v?=%{|na'?RE"RN e7DP4W//(e#&"- Dtމ)+(#<YWqTb=W"7jjNJȦz*'u L@A Dm(M٠Ig ';8ni$-C3[%%&nʠ`^ 5;KIENDB`n3er.`JPNG  IHDR&?w|sRGB pHYs+3XIDATx^} |TŽ(o$h%V IA*XkB`*b/޿U j %U0Y+W^@!!Ǿ73={v>~!=;}g͜YDnu'A0ўALza&3q8`6N8\d"&B\|H@I ؒS/8wz(? AL$Bi"!B"i;7NjQB[BAiȤѲD$d,V3<\ ~Z݁Nm_5b\mt>?D?۟GHd8Ҝi;SFr^e0tP"oU~ݘM9DjLMNdf|39u=%R<+$VjD+6Yi4K(Ej,&3:?IcS :C%8(t-"4b9P6kzxb"4J# [[+ˬj($7YLj`~r!szzZKW#b^KtQptG x/7t(G6;ij%uya@CQJFohzF-+^ KrTN]FV(ĠbV 2Hmڭ0g.K#ooO`%䤋އTD7X.Ax91 q2,ri&OGf<㮽ieNZJ.7 5SRќl$%^29+L*%0~$jjR9a8^ta2וKf*:Fl8#l֖N=rƎ>R]i%K/]һ;1eZ\KEIEDQ̌uRL:)A,NTԥ23|,6+>Td{+.xљ 5V| _Ή]+˱06{A(uEX>.:-]\[\}ER$TY%:$`h!%(yQ+REhi23(B;<0z"]D*Ͱs/) iVԯz#B~uW|$5 7f6"4TGv:R9}OEsgHVBlh_kX`f:C;%|MQXkM#{f~@mxmtR{zʈyt:,p4:|K7ӝ6Ͱ &d'G.500Df9t6 KQ_}aBGV..XacuM!,]uoJYT4}}stУœWrgV^+. sa鳯-}2KUoQdZ%dفQd߳z.]jnLo>̺ӼH1*7F*;/x5,;x ggg$bq3`t8x`ql-f`EEZ'O>,epa6yL?^yd%:OkpqWOXμDHQ4>1M׳8%GMU5^%2-a{G~l=֧Cf߹#-w-##uCW"@2  ^캜px0˫ޣ;ӽW.: _vV҉m 6q@̦T64IaYy{:CZ;ZHoot' SΑD]* <%b% ;MU_q-2K^#)Ib'}af]R#&$= )`.^ba[PX0=HQ_р~R%8 $$ w^9zz8%.7h돀W%^ 1j(Bv KvJ-cƄ Ϩ7>J 3Ёǭ fH ±2ElnJCB?\کO s9yƯ~;KZEB.\x%"EXAMۆfY*{7fM'鼹x[ςg_:t))>GL0h10Q򷮎%#`]3r㢭ֻdLۯJgmܼ7--a6lNzJ8"-kgLۗIJ}|t\H^:oaKj 61Zui=dA{8_֚s)sr mOu~S.Ŷam}OK?.G#2ݩ૴uӶ@Ȯ̖ގf-ߢb "AJ?>9< UaB&8ߣ;Ax6<|U%a4/{OITBf)n2[P-T@F w/ҩT'l=;D 8?5wd@ת"th`EgMtxHE]Dfohqn"})RRA^5؉ r_ޤoWtFT0{Y ̫8DӨ"aa%NjWg~'{pxщux[ J%WN-aw6Nh)ăTtHS ,[JTԢ˸=B_Km o.NΤ{Lp0e8X` UX g;?5IՅtΡc*XA3=䥑 p+)x:RBD|J$ySބ*&fhJ;`!fvIm+c*pdKHej YΊ-0[1z8Pݠ!/"{uK*pR͒Z[iӃe]`$# ^zKD !%+1TugB/Y3,#W[N@)20h ͔xm*IRA&WMKG:珕/Mx.XO(al pfk2nJnA|&aIVUoOS(\krA,g_O3޵K}aONlQ+D`>ԋ\=O~JO !)*6Hh#S$UU9*mTFHrT8 0O9(X)Wp4?ӂ(3+*tLK6קz=#p@WTX/ݤbjԻ#F. V~T8J݆G $UE*u5H(+ucT-hX4uTwSXaiSd(Oa Nd>k( d1DJ*}=tu_/SJ .,l!հc‰UցbI5)lj ?mi!xPBl&z℘X⅟(]sț;t/43#7n_zPiPTQQA*>'EU H#-i%RA^x̙#wJ_rn7gVW9! }fRnOĉF T^{3oϙ_]=[=ܷ鯗Zo? =Cj?GN)gμ-0^YHOX*tgBsSP&pR yQ^*edۑoUޝC-"ׁc( BRUV[ʋ]FUTL\Z`7y8pPYqc_Ze+JJVEI {2QB~'Pm_O&P@/C!U9yba13e>pێ%Www#=qꫯhy,gƭ> a3ИhdZrݱ%+cm\ ,.#iCxF7I4 [&4YUm)]2^HF)$}ֽDnR`yzGM*YE@SƯ4[2__H@vۡ _?iY`gRO=oPHy!rm` ˆ$P/_*gJI⒑bBF+ 菎ġdC:k=|'^֡,o`u$Rq鲷tP 6 ٫o]靀B-,p"LO0H 祓~^QU'7q %4,^z[J'oScs ƟzXnTusi-=94[*oIh!bKhft8="*HTA_B CPvs'F?F)[`c7G`vUUHrAT Xf*`pI#~p`=;,5Otdn)&XbɶQ!,O!}sr[VD gޭ#Qj8ќ=Hq^9lCAVd7j.%ϩ E\5,N(ը7.]P3nAɆ}Ј+//{@_/Uwxr.P?$DN%_w W"oYixJ=Zh$^/5!r>Ԉ3+wh;Eu(Jˎj?[vEDREB~7^4>Q j EHqN~T? *LiT)]|4Hh`2S ]DEJ*m_p]LS%}FIk1GIU $U$UW1*kBR߽҅_:i<,u1Q,mT^C յoEËT Tr#GQAQC"IMjD%:Q!k\@"!D)p/j ˚ *j ˚ *j ˚ *j ˚}Kb!8G^Rwh⼢x* K ⼂x* K ⼂x* K ⼂x@O9,qr!\_>Q?!B| =yҬNIKմRW̙36lN'WUQ/_@ȅ!R4/)n M@#/!BTWJj>!F/F ?w|^u<Gegt"M/8_}o]w FSP>-.!Bd_ܔ n.Mw@ooPB4Hչ3IK̝RoHi2X`(\R.Hwݦ]%CΝm{?U< 蔟NotOzRrg2VW} eHNpO&={vnC4?Z/Z\_kc&jبpKi &`}]||*str8F/nX}C2U5sz/``Ӟ-_u]|f mo\] aI1vs2h0/h0-ѱcj==ɟEA2j7u~:":GWb9ʈFB@qO{;Ff^\cZ{e@s设5KûmgAc*7,KUK|A@=I-Oů%|>E<}?uu-/&@>EU7n.^pFE"C`[`:o[kE>'r֗;wt>عO󹹥>lv~n)%*aᳳGߐTØ&T0("QE&0M|MZD$WvWӁ@QH?w T_uXC@ǯvI~`Έ@#T8Q﵅K8T WeXxGI5K8T WeXxG ٿgqkCi?z {J]a)5ُ7PAbVh ^7.j{*&B|%RqRk-‡J*SE`09" "`0H*Eq "`0H*݀ȭŏl8N@,DC#~Vqk匡5T(ϼɋ81-^pT1Rؽ`c;HU چ _׶w-wgTaqdǞ8c:bPBcoR]:1p7Jg:#﷋ɂw >ӵge 2ݱO뾏W#ec\PCKbyU򁖱ڷ\rm˟W#gT*{qs;$gYw#{c>B}2Ĝ-nYEdC`j`2{f!'֠,|k$S ϻs[0 +JLHYŴS?V {̐UWi J> ?$Y"_YU~d窟% w|?hNUp2yFISuݚ! ԎUK~85$>ԱOXxD bМՒ?F]%M6zST 97Y9W3v)Qz>𾪏hp>3G7jzd`՚o 5 jB?p@ $U7##xbyn^}/ػxJ?x%9g]~"AF$&^;.|2(YJ,fG")C%&pFfUl]0MCϐa7VƐ1 C/I&x_~d YB?yQw Kw9Wv,f>7}hտ$ko>92,hF~}nT茜JU"ԪxT;A M ޥ SlIi) ,&FVH 🖾5zL^`6H毡Q2eY~ڦ/@'0_X՗W<^Oz Üo)  K&EO[!V߯8٭r1wtؽU!!kKj"N*DC/B 19"*DL%ti2K0T@R (CB8M 撚=MCB UJgǺ;FP#BZ JG&wpb#npL0$8DIm0$ 0N[W9?T=K\$T[w Xr O'D P%jĤҳTN)rI=SRt?\ci ˢrrcH<4ڼŋA3I6߲{^T!.#3i\-%`P(!?SY67`{*-.4,B褂 Ey4I閄k/.K9ʍW[&$1'y6ƵMn\Kb]qt}!YiN:זڂriiz,R؊IwKJ %|S&(*exSUXq3<MaIV\4UPψr;u?{L;Z9THNqAYUDyO cº15Vܗ*%b$6tRIrK)- +Nl8[%w%fTUj˜_@('V Q'tRD+IEZ0VLGWLJI%U3VQWP~m rFTGpcUjYUyiQU/ɢO*J8yT1<%l a$|޳pTv(; f*jIU`җXv`ZIJSϵ|yB:=w\}?cuj?i)NQ{i yCݿZ&*KU LG ¬ լ[i#–`@Q"~4[˧ Rſ/D G?%RiJoO }WBkiJo-#"*ik/T<更 jQBI^ȧdiҶ=b!P!Rq|RlTLIՐk(^I.Tz,s*}{=b3&86vr>n)qX9 yA&`lH*=`.^.U#$wLX.xQvdݨ>R^V_-lȊNJ"PO=IH|:hRt#7ꘪ{%=a_HUSpF`Ϋ$">bIS+U-%G yUSPO=IX *,㖒S&p t5NqW U>}TpuRpAQ=n)xq1~ -*-,+.8 "jjG,㖂'1c3tN"A4`8[yd#(-k>3~ IalWQ c rN*~t ڸ~vuNN8vNo)=nLaYc*X? ux1NRoE S,ywO*g§U~Q-PWHZc[3 Tki7 x%{'pdBy;ˢTw)/e~Uzd ) T QkR"_RRS**ƖPI.Oh Yu.y:QMߘOQrT'> Jؽ=* Yq"dlB'UT[J8F:-T! }rT҇wSͬ1V<:چƔ,,)*l>I'Bqɜ6|DU4 OƩ@4|8 ?G쿅q6M A1-!O*C{!+,k(Ʉq*JsRR0qTef #ǚWaf &3MD#n߽:0gd3_Icxd{LD}wZHb@-U")Hc`D VH2T*4OTPKRF~a :Lh#@g2zfx8iJ؈RPgB UJC`2=P"@0QT# mI7$GI 7$GI 7$GI 7$GI 70O5 ( H>R%_F+O>TWQ;#j $U)j ڹ0CI|ut,-*M^T[Y;!j'1EIuHvM^T[Y;!j'1EIuME7T!b < QX#5_#J*Fc*ֈc~I*5HX#%=HbT0PR1 @/)F ! @4@"`0H*Eq "`0ifNC5^|z`(H >ԋ4_$'v_TQe @Rl*5? "!JM-v`@Q"6`@Q"6]Q3+whwXQ @Ӆ1z˔ZOPEDxdR&֋x|Qb "@QKEIclrt@RE_ RQ".(=U崷9]వE/ Kz.`ifYc髞@REyHnmn6LK7׾3 15t=>mǒ-EREio^]s&1rP4<jʺ@2LY멝ƋAt=*2~گ~Մ}amkG YubfyկhxnYs 3SP*TIJ5T$d,H bTA!22GPIw-Oß; Q='Uq7?{S -(>{ C.29z_jbNN.& AqW=ş)faSR⨓(}M@oGbn&xQR!FU/e9Wp˶uN7=~˦GQA,UWovKOG7eի[[dㇿǟ߽Y/\5~Ww=u_$m|"0/෡p%T1r޼azSYE:uTo[oNإ#\_Bz~g#X0$'!<Ƿm;Ro A *J˶RBCo?(|:(@ /[_@N?K~-Cd@|z|Ȉ UpIcRA{ |['%my?yiqV2:_ILg`’{g(|E\i جSF>Q 4g#DՈSduWh-G[O-,["iX SkCaiI՟|`͘k֖~j~jJPXUkH7Bt =qx Τ @"wz1"IENDB`n7虲NÛ,]b"YPNG  IHDROsRGB pHYs+IDATx^ `TLV a ?"$6M0m*V@*-b"TA, JbQ,UX7vlY% $$̼mf̼Y3y>̝}ss#Du$O1 @0(al<}EH@-h$FB,R.$&@(> 4®3uZQMX؆bb".^ӆ~G鳃RaO^xJPsjLx2U?jƷ)Yk]{ַλ|?2L:9|Eri)Ըsg=] qKiB~2S3zҋ1RprUϛ=q_&63._4@K|mQ?ɯ"#7XڈEö fb+rJuC:4~Z:{ׇvn]ٖ|_r$ >pv&`Y drǔH`1jN>9;<ǀ*1z$b~h}̃Ř-,SPJL/N__E5ҁכOmbBAp^j!:-A뻳8+i̩/ԕVCn,ʄyi W|Acۧkk"B߶'vawɑkN}lgCj7HzH:Q TwOg1ݛ&U2M s"!j V# zk>;؟.fc|5C["ERr;L0ǞD(ُ?:> > 72$*җ]!GH& .Kkd'nsuwnb&bݤQd`s{4PNqۘ#ttQ:x RFB~I5AJ:Z Iv":7 tORRHe8qJZ_gLc1ig!}I 6CFb2IW`;vm0"f-w>S~;CӦb:ocsXS#)mU ٘*VGIDH h'*'D(VpoCn]O{ 6x` aȥd:XKZL@"`Af8pТږ5Vx; KCMgE7I|f:W΃pX~j#^_9"b6dW|FWIrvttnEZ5#-H\4\5-9(c=x>OE0W?cR7P>!7=pm 9z9 7g%^/|# C-g7&9@jՐ՟3%E HYQ]:‘3i<_w4\"OC"t'QusPP6@K@k,{rPۨֆf͍q$-V-]=}PCBi>zY0 1JN-c?S 7$ W;C|$< K;iM#Y^r CVt7[/[GH w Xb'uoRTfŁ -sllhl0U]BQj^4&.U/:1nb UypD{Ziw',$, [/{P"&!u4FX?)-5tzrUuueuKU˕WkV]i1U6V]5W mA ᭥ʷ9p`?}QƤhֱQtDԃI@H@?mhbڃU?UH#l3D< fQb6bM|(:tv[=(v0oGG2[VtFa ]TtT `/]+-pxb;` ݇E٧Jf zZ 3v|]c<ҷysφ`$Ju>͕l//V6e38D&޵npz9 څ}eԣ#+ A3ٲ\P ZM]P# p9vq+B/#gna萦X@?pe=;ټ A@=1! ZW5`CXB(2a h{Ԯ6G2_K/±9&ooc0#ƭxr4?vuF]k2 7q)I}_:L @H '<#|TsGH $A $@@.[@ ڹf1@H څz b@H5T;׌0@H :TPoA?@H &j@ PTMPHج,Ti @H bH $<P킧-&H $/At6J 'F+G/;d5xEI`Yutd_җCWp'5 L\j7o=?G!O`-v!ߊ pv'O|ᦱ٣.!#73Y9|L_iR{ĢM:k<8R;:^# 0?]2_jц=ꊾs7u]?_m5'~j@fH}7~zq<6u}L|x] Uo^ϓſH _ՆV V-c༦=$$'5e\떱pBxRbOڹm|1 l珗xLh.J^p¿_{닧Rsz D:ogOX E'1 P}Fx^<(g$K\r[RRR0FYXpl NQ_?H*tz8ŗ9Et\M|Rz`|Gv͚DV,yt<3fpM7tQќ?1oTv nMv?.m|vcٷ%REbmjC²gh&v~!Gu 5y?~Y2ѿpL~[<nO=c#nIw-bЗ~sw|LFJpUp JMmnKtvPw=}8Y|/^]Q]ߺf+xϵdMI 9#N|#7dዳ>8 )e1-Z^ݔ7Ϗ~ỉ_,}]6'G;<_{z57(PtώDGY2jGgN}h(><ydy!z4v;x[{Ų=`P.tl5=xvߤs% aSXwlC`f*RHڷO.uA}{.]LJno=;sR,ҕyB1U%D?965SqQ #_.H#|u_A.s]8+!ځОyD8{Aɬ#?O=2׽me@c|)_c0hʀ 2xvd=fc%]trNƁAdC0GR`o:隷 99HU[֮捷|GƩ"žڷ3âm`JN:I4xzvM#?ˣe&8^ިcu+ϟ/0_ET$TldsǻR/?q<=5oxZ=5c_pS;։شy6}>Hzw\?17dSYl΁?lnZ Zon{GkyXar@g{_R@LXe;K=//t:ºl&XM^o əoGO1 8n^ T>}u(ET ۀ:;к(s;ܻ /7׸I*|w׭Kuؗm&MNHw{yyOa}~!ڂ^OQ'e/t7.%< BJj'J`ЪǐkRhmM mѴ U ->2WvЏL:MY) hXu,v~U;l&j״w T4mcbMD*pK#ڗ&؄fs~w@SRH Ⱦ]Κ 1(cjƄ9~z5Z`Uh6 }]Ӕ]pJ ̦#w xzC,V6_gT]ҳKtP%Q횶}$i`H]v}Zӧ|w$V::w3H @pd$ ?'Ft$:jh>L#>B!GŐk2=fCqp$l1g$FK%:!$pL${ѠV§Y}ӫtRg H $C~R\h@HwYiޤcwE82gاhwRgF?^ kGut<%[im2pj;Ȃo z`N.(w/YZϷwdë?Id3vѤ&=@ּ#MW@恫'e͓_Æn[^mT|vޛTg깸hb4E3sBH O_*]/Nܻ07σ3r"V,ُqcǾy~^BJ۞KIHTSs7U˧)O2q͓岶ޛZ2t^o Ocb`ufcu'1Ou^SLU]B.*vOz׷ :ypBe-RE ԯݪ/[c;΢~gT4U*vYhEv'Ekܢ@E#cS ((F5M3%N05H\No*;밻'`*(=~:$} Eݾw)jsZ|y6҂C:СNy8%,=6ox?eo4Kw7&)_c8C,諦#0@H k& t l4t ]9 g .`=ozx ϛ@; g+ >Dݪ,9+@M{ ylcE=mv"o@!M@X9$]j+NϏ@ $@DpC"@L.[@vE`VH%ftXrVR1<)pu(M[- 1KBH #]k2g@݅a9ś'E EՁ< }o4L.zO\i,jY#V/5y1¡ViǴ*CsM3.zEGGI+rc(E%h!F#NF7HB "xa^f+$0% $u FMH#=MfI gvQUƍ6tG|@W04%N LΪכCfR-Ȟ9,&cpvkM/k ͚i@I:yR;V(Z'wYNVЩ/ݗ[I#kR;* ?PnF_r"1U8zNO$IHT ҏ4cLM 11%P.(86y@ (F:^xU3Tjf5R!vf2cj6CS)ĘafLh!dih#Im8͆7뮒KR;^%=L;W̝;jnqMŎ(2KE + &jVMK޶?NK"I(qa2h2p|hhT~fQ{߷@pJ`!-|??C n07ҙ< ԛȕ:RZrxKr`N=H$@H!GcÉ%N-GSU[gTj͇]0f7Sef $RķL4O>aX |O~.,, k:qsY2XT.@78¹ 6RXSɉw4,tqvSt\ gB&h[>aqT/㘾/mf+*yu ԶL5u*t!FCYg5HC={рO H 5Щ98MzuȀe.Ǿ9yjOSGðC*r`8O=<ng-z'_,U/!WՒ+=_ l\'2+Zv3=F¢YYgfkMJHRJCș{fb9|fAR1_&/M&]֬ddPm15 Vpe#F(Pk0n Tz1<}HL&:`i}K KcZRn=13b{Ħ-&N1c:vDݦ}t6/?wR'3K?㴊 sǷ\Tw !wn: ttˮ*X,e3ɜ-~00/W5P8" "YT*Һ\ULʞ /?mS+LeQfk~$\l> m9l{0- 4=@E e.1W_2bcaG!: +c``v (bqQ4_sLEԮ.܋,V(Svor{.!yS;HI(B'b:bX<ssl,&h&u\?{kDLd~XwCoSy9`H؞YT[jzA0I?^lM憆c~﫟 }3+ Nslޮ)Mj=Ƿ@0 % ,e f$G -<^<#6YdPOxr1˕J@5喚Rs\Sm\d9%N FSKɱ>ÝLOt!@ؚưh*xЧkbvmٙ Njx^׬p}'f.sNus# <"A:g/'WW Xlo=awCқq~Fy;OT;OɅ_:@RuiI$maAw?m WQ%T ~tegRgjyDt;8}GWfC0 8S.g-V|LbgP>:B tOawu o+#KL!{{nu Aa9u3 朹q@𜲘S_{bֹ͝v- 3.zۭP_g99ʙ)JQ=<# `A.=OlSq>\B=؆=ࠛy4ϮNNn6'~-?Tv;wuc3L9lEs4BV4p+*9Nhɝ>QVtTwȚfe3EH 7n8q 얃tMY;Qӏ}Tc3``#Bn$oWoa$ftk,5Gq0 WR̐ЊlNAb颍~LQ(Kb0q 4 =vtwd$ cy9 ,~ftEb mI.X^Myү\2Ĝ|{ܱg~O’QUDK~Xr:ZE?lɟ͎W.d~e_\viA*ahLX;MNX)L7Xin!ލ6{WL腚{5 8Fw3H. ȆYKy9ͫ ' Ui!WaPyj˥n O6|{|u4gf[=i5kHkee̝e0IŸz~Dw˂Ťh<ߞЮgvgIS~ycGf&nseK:'j+hkb.^4#o]h! 's>&:m:G646?4rJHttpɤ]2'EBRq&(TF6}=`309a]xI,]r'KݙGkK7`&aØ FXGC NiIS*:Zû}_ma+&O< -a~ ~iH[0Mj7JgO0gݢ{BaM@TA30q~mI,N <O'iPFXYO ,K>Có׆? tAd0;=jmz0!N=b:p`+ݶF]R]m(l(%m&>2쏦'?w;r $kg.nս\YEIv"Xjm?_L>ʵ&4|J9+6CFb2IW~/N< ^gFuK:y*1v t\|c@'m8m\,임1F ZĒx''hG0 ̄ 1LfHoyELhaaճMx"󮫫!w׮n: 7ՂvH+ 'i]gSf̐o/ [RϊQLriOq^lCkb̲ $O [2̄ V9~P^P{t(,HW;Ys}}Ocjg`}s15tzL*%E)rK߮q1j[= 59bnˆV?oDǎ%#ױϿOݮVTu.YIg$d+%:*U*i?έHf$ᏱEyTЂ=Fr _|i)|WHﱺk`}TqWo1?,8;Xnz6_ yڹ5o8lͧuݙ'u;HekFέp)>YM;mh fRy;UxY X0暅zf.2_dul66Q}TwR0x֔ Oʇϖk:U\T}Re˕UՕ++TUVU_PYcmj@ Ճ},_cYN;\^#Ϊ*+(>'ڊG_UlSbj U@_l/Om|()^͚k/H!};CM0'=`N8};p-O 6m*?B5=Ck~XwRCq5]wԮgLraZb+'L~6=LDh8Yӭ:Oַ*[Ҳ{Iqi% Qjˆ>_D3n䮿sM>Ӗizf\ITBD H8Bݲ_PWonh4$fI?}}aҨoG~W3֏:8eqG'lV;Q;()drܚΝgB`#뭵ǻi.N"tZġդ.4ݸ % St)wU@#7mH*T7Y.z`XM UQ|\`g* u櫰TGO|uqNlOh %] >! r׌/!px ToC#k WA9ue00/sladOG^gveo/l^d|Y;T@Kdřl\([tYU*`']Cu5#[(W>[z,.iFք[sDu;W"MA\%N /lec5f<&P/{&"@;("MX}D~d ݐo !n&"@49R) 7B[|{ϝTX|꒴I_0 ̭w >4B_!4.Ǔ$Wtj.a$oHupiz۹7olsلٺ#ގ}FD17:2kUMgS[- 4_ mOW)sh0EJ|B v~2)rV7v~1[$J _-̑@H {#~f:h& $l1%$bB$nL7}p7 $|A1$n|MfB~m:rk$H= HΉOs{]nR#>΅ڵiw_mڳc}<*Wn=09@HK^dz#$@@ F*"$tH <#$+BJx9j~jѤ~T:OFcLɞ4H ~:wl6u!xTzV9Y4= aJ_jaVn#Ll5?I}LEMYTjZH1q*Μ1P<ćɐp@vQQHW\w֬y-A(읛ֶYJtif!+A>e6i@ ƣH\͓D(f,UrE ™̜-KhTNy &GH $б]̛vTr/6< ՚̜4W@Hun^o>MT^~^{²ک6;z؞E>MHqj6{j~0u2Yy6Oر =0pD$`G;&%I.ёL?%mq;asͿ>ܞs͇/OsוtC[ƢTR&bR)rX.nbz?b5p@?߂.'_t67+}$2iPyg3E{) G^Ἕ1Dp-pq3u Fc-:r &.ĩp!dO΀ܟqV~yySOB67#%yv: ED/8據 xj^T;36oXWT鹉ۂVgqE2d3mVpOm5&ߺ HH  xQyvD) %Ei'üL}W!1h~uQ;y 5z-X}"em>y>P;R?X;}sǐg\>{~׭pNLGy\:"լc{ UwNY9>qtLsvo񹉓ft`?Qz%'Ջ%OG:E%P0ayCxn""'j7eZ+-MyT^r\%yMGĞ1]wo ÙY[?P6?q, '?Yߪd.z+o^1PwurwbiqM~jzjwAJ\^hn=qI#5YybLB4 .rz_/`V.$, j$qҨi%#1=vmw~TK;-umym+6LM7<+ [''R*BG%n+4 #@H $ vSֶ%y* 啢K~BNl;X)B=*6}Pd|7sd"yal*d@:Y>0+ aRGWQjVʼf>BH 2zWZkW}ҩev~' pWycVD[RIn.m'Aϔx.U0PV'5QŷM q6wykg'S,@5/%Չwnyێ%my +p ;'Fk[$ӻB"5'<jLY6Fp5`|_lN9",uv +L$S2Raɀ,4SYiL`hfr-KtWh0@H@'juKM>9yBGxfOHZ>b{&H66FI,ϋk&*}_Ώx;V\V^)U̵R1vLӟ2©Y|@!N@B?>j-|⏏@b6H  Am[kKm]bH $O>g<[ܵ?mb $@ߵzh(S0xm3(lJ $S&GH $"j@H ?]k2.ID17bwGRH dcM.kzBڳc}<*Wn=~:~:ӹc/ar$~g~J&~Ѥdo H֯>{.kuFH  t;дBbhS:tX̧^hX@Isv|n=dz4F29 $DAH %`01LˑLT;jwe?g x $|MKss$h(/;*6d0ì"_|U+|hUSIJNZǯ0s$@jgPAߚu XGat+m+Z[%G f2(yR/CNEs \Gr'|kĊ)@H D&m3Ɂ{W4+@vv}8;C89{jV0Q8@ff\Pqm;i?XY"$B;jd9C$GfBR"_k A<cf G )@5Smuӑ1[N@q`aH $1#n AUsf>:כ*ç`L_,IdV#Dqq8{o"ybRp)s , , $W;:bf%k7Xh}AB*8/J\Tw d2;O,.rܶu\?GH DՎs&Vn2--:7 7]Lo12JeTc+'M*ᒥ\ Yfn3ꧦl@CS-',f nBu8Qlqq(erUM%!cXYeuabϧCV $6wԎn璴L\H\zOgsQQmuMHh?qR (z@w LXlA9T6IYsI[:)sB= !$J|f͕ޗ4nfk#=;$eg-feWJN*~o$T4+?кJ:~z15sH<ŽTa~$V{?9=S[܍B@YSFcL~0[$' mq?wΝLl$PqRF#@.9**js!WSvfڃ@خ?j Dw 0V &nj.@!I?4H $•_IGG]1٭w LQFH 4/dR;y !WauùO=f#P;-\`~y>fPѭ>#):K @'ݰ{opY8zx:ٱJyݜ԰7 DH tڅN[aM?3?V鲾SźYs >w*`.E祹Rpފu W;h=2inG#\AiYNjEy dUBH#n@6Փ}@E fe z{S4o(c.JIWY`%SBUtg&Jyhтߜ=o*~r\؟q`+f./旗?d,ƞ'TfO#C>j8^AV|N/_DH ċ{]vEs{C}\nlg'gOOB^Qbx}ґ4M-HU}Yi6<(= hKLf>л [3Q^v}; eew0[S1_CȀ* ۇ,}PiD.; rXbH ;jGU'oj&pmQ$6xd^srչ@3srҟ)x?PI~Yi6}sۇ~1>L}HI>8A} T.Qz b9 $CLjJOc Qڐm۞wCgN|!R&Z|Nt*='>HpJV-HjeݦMw^}[^xƁgV8'o$mjֱbYAm‰ J7V4yVh` wNe뎹~DqB6ٴ0C~تWփrĎF&ϡcy 6Sϟl3٦?.stDr$A3+%1;0WߏӬSȌ{^RsfL2Cc N6ƥv!Oay8jmxڇӉ:蹠jgܨy;?_A=p+ڋ\zr/lg0^u6(wƝjd?.,ӺBEClEqx[WbeY%:pK3+)psJhRqռ9@ML@^*9Ѥ>\M.;Y Ose=,y٬Ѽ9g-(;P 7]\֘Zzΐ G݁ʰyN3+fmC@4m̪v $:ɔ e_u] J3 7Oʜ4z!x7HO-ߴEnVT!2 @QU^όRC"3x7YX*-0?r_&/(_*톀bCg;m bKF $P;څePZ 6igoF86]K<j2C0 ;Na?PMIw* 2>kB7E 3@H 3OVܞ{NUXdXR/Zfi_|/x b 6@H #Hfن/v @E^..!Os4H  t"Fw|EMa)R:tX̧^0\$O. l\ ҈Z a`4H DX.tivrN )Ej/xv/]jww<0xNd7  P!KWW6_m!WaPyT;^@ @ծtзy@MLծGH @ d, $]7@ mȵ{m4v,:,)⹱smTZρ-ն՝<@uAJ*V,y1V%:fϷYݔiD渒KZmxdJ=6em#inxk[Q)L3n™;y$~U\jHrRbܵ$oWИE혾4BH .]v [ڰmND*Ղ~@Mh%PSܫS֦M.rTX`OBڒ%#1Qa4)@0[̦z@1aѱ&!*&>. WrALïp=׿n|4)w[}4YK)fC%?&cwΗ68r/ k^$JrZJtW>uۑmΛ-IaRbT\7jWW[k4m:+@DI۵N3n:Ej,, ״4biN T']NIE_4c7kS'f0%MN$/Nߩ63V5 ͧ@j1+4p34L;`| 2;Trv-=:MۑokOヂ^\5 ɾ6.=-؞d|?9 |9̭yY5S*]y`jj8iw~@E\B>}]G^8!mwleF,ce7>m?Ъа8: [CjFLO׭,'orMK8zvm;eL;EG@3\Xp: t0c1 sQ>7R0%n.A8̑G/EOTSkw4Y#gF^GqNc3roWs/B] fk+ש7%dƩF°4\~[V̇Dz~2~ Ls]zZ( 1%H3Z&x"BWuR_-[O.u {܋:з#d2O>j#cIqY>'yk>psAu0.:j! X/uSJ{k6N6/.]eE1l;ݝZ V4,Gl1O]+-ǭ.LN*FscRac#Cܢa6 p0.%.Z\b5~s`ź#ގ?|1+_iizfɳ6IE\Yor5nU'~_ h?ЪbOWSM7|AoJᛜ]uz .荾sdj|/zt }pMUxuP7>*]:i7|8}Md܊{F>TU@G,vK\^rq36?fl{_!n8ZFQoUwsy5cI)>I֛ XavVnx麏n=,kG^[y.)1W~׎fo{>Fȵxה7vSw bi,8[(PH6&ӷ,`UL)!ץkrG|tg. eUAskTc)lk[lb=ldz8av`]Bj"r_/BNռUsN֍oiGyKĒU uiB.j%,Gt?iA\J)ރS;_tХ/_0(zje;K$ye(39᧦ϖLgGyp١au[Ӧ^ǵ]*}4L0Eo!1^$?[Qw˗ +hstdzfpVY`Xm/{JVG8|6\NZةK1J/AT%Ēwv(-;yHq00K8kjѺ7LۺX)Вe~⦏}y N=\r[Q7<Lh<(]a45jv٣ދ|4UtM-b 5M5vydFJoY~؄~Dö֨6lJޞC M{9}YұPBz~Luu]2WbZ2s>JM+tkBJM}clԇ=+[ML؍d `RvL/.hqMCm-CLL01p~uiKĕQ%vi~Th77mKuGzy'ExS=!Wa/9˒uVãJ*)jaSIyƭhu*9ԇg[^ROɦ[\ #LX"E=_vM}k\W%[mS3G\9xJ0E8%"޲fuV}{'O*FNtOwd6({:rZf%f 7\:ѥd?+Wז>ګ{Mߚ4.0x_kgz\Ci_ο."uӖm dȴC4!ԥ^ۻMaȫ>L_4l ՟ӡI}i# y9':B g*{'8tIBH ؠ& Ag'uoI[1E-'o/Qi.uvTUD%͓bI" 4mc)Wu{Sxш^ERmQdiws4#*n7X~m_:ٽQ]ƿW?hե?h?pM3ݢOE0.g$S 0";鿿QJΉ&?키Clf8_Bo ps o S7f"2pCҪ+]`Կ$'P'´E76k64@TqPsȹ m&k|Z$dz3bG2\m=7{{B6iZ3tOW'=V_WY030{4ݣm@5+#22tSJV K-`՚Y(,d4uT]"*U͓qN]m2d-V]EVj>JT'4:cI}]]w]ۺ?i@3 g.|[5&ZsQ03\[ܤcoEvѿܷwŐ;S#2|4)Cj=|v[jGcE$y&dyS3 Eh= {*3]OV 9녫J|Qa?6OYyY ^g'\)OA<1-ϵ}@H v %~ 5EyXt r3?U L;N=hK? mEa-UtRZ<0( #$ xέr7 [Λg |@;& OĽxf +d9o&9@H %j BH LO`HӷқGwhtZ8R_ 5L@yRYFOOG2QCl@H @b c7 W}hGa*+6o` pX3u>,5;Pxpgm$^3 Nɩ"a$ѭ0GP;̿]Cʹ>^ @?WT,  3V渺4usAY%t*K_SYeEYVdQ,TeKLL(j2f5C ެHa%a/k4x%I0a>"ç[հ% @|r|*0qe*N࣪\:L[Q_2Tz!ÕJH K_^㪱^">>>jW[[+C5;hY%`uUF>Sa:Ja>+lͨkO؏ժ(*Z bT)hc|T\@5{$l(~S?vW\QKw=WKDX7_Y0Ho&ZQ\4.BJ;ݰ#~?*㤊$:elT3&1V3ҏ*[;fKekF~4O/KRHqS|@y᎘L\qc}٩RQTRJ5a-FU#-00.$,^eu5vN/Ѣy@]Uu_g߾6UNW/w/i7&M);a|*d@y>~>&>~Ʉ8[&vD LAHEwT%Q\B; oLe:K$N@Zci+1ewhN!'#<7 UAG5& F,G/He$wΓ;Y,li)ݾAXby_2d1kirRflK[RˤkJh5c c l)Y3ݲ%01kJS@ f4d6g,s7D.%kǎ]˳4g'ᚱգY ܵC]`TeDtc8ʜVf9]kƌY[J"*qkK*jAٚc@v@UsZj) bl@0* ZU)F0Nx ǮYKGh&Cy'wcɄi  Gh1d-򁗼8#E,-FCfh: 164X5t% F+rkӲV} 娬53 #aP%ݯ+ ;ti?LI1y" R*0IQDdJDXe˩(ϒq$Zf.1[ ۉ}Y=zc,5,+2?d`L~pNKɃKG_Et?e'!DhyyvsT2Z!׾@ g|ig:aX:wς#}yY,ԋCQ:ι@;X? M9ӾsJʀ^ dEҕ['.>_YEU$IZ4N9=B%!"VܰF^ZiT9#Jj4J-(œ0+o $l~ъQ.WWب1 ., KW&^%vhz2 7{)2&d3~ugϜ={f+lɞE,џӽ\?C^C/sJV8VCצ uhCAx~F Jv}~E8eOɱCQ&4ct ՈZDe+-eզufӗ وiun ))֣'k`)zɾR.8(5b˔]>#&)9ZwoY9b`)Ȓ} K5tǜy,E )q!4[*p- ޺ϣC"xaxi|Ch=h쵘h\vPBI6+*K\0rY.IlIB.I(^װ\x j- oN{EYbu=e 5p-A25 [w Nה;=Er:GcggxNUiܔ賎e k: l_y{_MaTH>#P7=I;ZhS-,XWΪׯT}_}~7P\Le>G?gy ҫ E'ro*2Pu)@2^=to32=ޅ_R%t4\dZF%ӲgT2+QYixǭ(!I%[r-Uy$门y?DJ$\qkXX9!n|H%"TV E(ݳ@}JK'!aؑp_xAOSZZ&/e绲^]+ DWm.~b<-{K{%.%7 H%J%/~'OR0;4JhBU:Π¤;^~*ӏFp݇#SdR"~o~#QbbeHت9{V/efW V^n0K aO]ށp"@Κ z&z$l})މ2b/ OfY;vIxHXr|BNxv2$MNX\D=,t^;5Mkqy&}Dcr~Ҳ/*\toX[*N.ݤe5w!]2C8 f"af8Hx /+K{kvǎP#IYͻy5x:77PTBIix|Y-w,5G_;{DUof./˜羹c8K(h"&l?w\d.k19pĦ-2AQb EH /N0q!^!{lcVe4<+{p*!ݲX^v},Ԝ=]T 3yy ܡعd@Fj򨂼]HsmAsnY =0y ā4H3CJhe95@VցXH $|vQBΆ;p | Mf]zS bg9=[1) &z禳Gzkv07$'[h@ $tgԜ=':éog,ɺw/KRa3_r"E6CZrEs逃Q@H LD3`[$%><)q@.n+@HG|>za6H $|Gw,1'$Vv2X/$\;1'$OV]'t$*S;LH $j#{H "jA"$"]6= vh*@H b *6FlkH H&Yk2AM'mGH D Of6:@y;xal$)B$v!jXY$G0@H pP;xFaتʝYE!XY$#]ź3/o lyѧP`Gqށ\@H $+b#8ܕ0x !3I&/9Rл{/@H JjW==woU!"/Ͽ}F2?ϧHCZ n2YyA0e~:\ $"ծbdwO, &d>׆#Arr!gܖ_PNgs+q.mf4M@H߾JH̩l0Pւ*BVs O9{:>tyV^^GJ@H P`p-T/'l0d=pߎ iJV͒V}8;fl1@H :ݎwO僖pn`'KҫpN^k:ѧu'|h`"v3zVX$n#Q Z:g3n-i߿u+nSu\2IF- $?{_J<>n1g ##$ƒ@@JvԷ gƍ!ݔVBH `G259 )ah@H @],b@H HPZ@H '@WwHhٯmKbX"$ <1[y&OHj/]7-S12@H D,Hf^h8@H EPcH %jM#$"]56XJdFŊ#$"kM&'3/w4 $}2ɌFH DTjo $ H $<@]-Z@|v?_8E 1lU 'DUU xrYE<qg3@Jo/=K{<(If <)g',Y59?.;]ڤb~6dgUò/d1M#k0 $Ԏd-,{42:^aeddYj♳'#3g2,8jbT;_75NM̩'Eo^7Els8H(M%vf,6(DҘzBx>ҧ笐CY\75Zy8'gpqYg2Î@$q"́@⣔yˋӖ8'+!=w4):v>13$_ xvsna~-gnN*4kAnVnY:(;"!Gs9GLylC4G=@ymm p Š, UP9vi: Y#AH #v\<>|͒VIn^9eD>v`IK.":v:!$wj҆. ]S25LGOϼ]Z>kۻpQ&$yR8@j3v,fuvq\rH $Фv aO8J:mj+W*!(9hƕUvq p$pI>'C~_:2AGg 4y`@'3jΓ=漿}@H @k $ŸU;@H $@]x-Z@jtJ|چ*lB$@O:R\=sT@K@v8 vh*@H b ElӣH "jA"$"]6= vh*@H b ElӣH "jA"$"]6= T)t8$ pLзVG[@J.R[FH DTHjm $P"n$@$@F[@J>.cBR_4umTh7@H x0Ԟ'{௕]]-lEc@H 8TSLMGH "@].v8oVM $&T;0@H څH $j@H ?5J%-DN -fS](BP568FCTL|\1J]"?sz U -vv7 ._X,l '&oVhoqԾuFq٦#<~l3~ ctЭPXu%l2j}՜'IT;jGiAuΞ!99}u h"}kk.3 S|sl=Trv-=:MƷC{#U '"qq`إIEӤY8o_ꦌ`fx=2ǢbWnqT;:06^,r40i,/t|0y 308f=ڃ]F;C{û}3Tu|$L`5T 7*uap.n@{C/]0.X$|lms f7t i__OF}eC=ft%yu0ImjLö%GX]0r9.9ծ͒mς#a)lYfLBB ~ZSJ([;j2^!/WWދBY>ƫEhZثlZӪ>1% ]:vAyU~y߃9pӥ|ai{ezkd|8pMU =705el;+t샯za9:=+J&QUg;=.ŋa}ulޛ㒄%&~'@NÖݿ")IƬ"9|arUm8(W|Z}﫪w??R T!}ޘB/}8U?CKɇKڕ1>/}7W79tdu#CZC_J@_αkBn5$p^ٱ91 8$G]{ثAG[4͡<7چ{v=@sͨcT}_ݙ9@Y}[O]H(!}!#.+KJj)RKv #{آW SvImjÁJBZfqS`|}R)=ypLzz\x|J C{K 7lnЩ/_D.\[%yb*;B |i]:Orpi9(Y֫y5m+#s HW~0/KDM!馞XspJUSHT^2rǼ:uw(C{ඐ/x xUUաn IܵmSU{hplݿ9#[ɽz>>-q*'s{8I6ڮ.{kL-kIj%*ڡt~#"з'~œ0mc{+6t?_%: Յqt4H >*O1!~贱 gJEEu*TIͦRNi~TzQzkO#3?pG7<n:FAKsGX]}3C/a8kΙCʚ#ā9pKaޫ.{ T;\ ii劲I߳:Th|:RG^w#_*- as-S:WU+ܙ6=&UDuCgs࣯ǧ Yλ!&oԇ_y1k}]bS^fTﹰW{眹tQj-+ܸU68Œ;B頮ͻVv[M΁9;?_*QU;V@u?y~)}DqAgltE/7U}AC>;O; DN,Ef݄b3)c*'y8{6?zT izNRǿލ$s4t%7<Í7<~ɫGpmk_(oƾ].FrQEoC6LaӇOϰ;H墯g 3?q7 vžRho5l_x&@U},t{Xv ?Mp㰺Mb)7/+>d7/c^H < YO&ʍb`E>.KGQ£wB+/ 4^4C3Ci&{>ѧ A#{Ȁg yG#ho4qԾWk6ѽCs`ynE6E2 bvt^qbcuVn_H&g^ g[ڷOi,o}|w_JƓ뛴nN7 g.|[5&ZsQ 6`J}Q|\.\'z;z4[5|ۏO[@ޮu¸=^|(ctsb@5qҾv~Y#&`00\DTo4F&#\,)qQͫaB E sFH `!;%H $!0$hJvMIFH @ g, $.!ytf/ wT;@H 󤲌DigjPNuX9Fsn܋ S 螁ڵ_p[uП-V~\VƣL#S -n5[-_[(܃,+Ԝ5vx~+0ƝܽR}_+ on|ApVnX?w t'[U[?VC&f?Ew*٭mf E˺*IGGH $ ?WUaG#4IENDB`nFRŷ\XH({;c_PNG  IHDRBdCsRGB pHYs+QIDATx^ `f7p-!$@ "`j &hBjErW_쫆+xTE4 p" rH @ !fwϙlvgtgyϙo9#40[A0єÄ$:⌬L FhY ZK*D6ہiuX$!Ǐ&$' 1N?V%2f{^eBjr$Cb/LR$,`j#jiza.Cw :eW~07qQmK&Oj$;W.Ԙwa5oȅ# gƥ6śZJ(+Y@RnVHDJɛۦz$G041UYP)'^Ré:VqD2.c_X/=j qLkEC8HsA?M<Ɉ @ v XF+bD {nH2L[NdL`41bI6LFo$/ iq!FH4ng`bWLc%vkL7X 8e @Fb&&Z&MfρpGuEZD &l ʹ7PB:.Hh\&j4zV^&V욍, γɉd|I̔ G&$m"'6p$|D VP)*bC%VYS(7G$m &dLѦgtI [rRKt@6ZVWl  1K@@H֭&1`Oܡ Sfy5gL$f&&X}keg/ 첥Mf2GјC$]tĪ^e"aW3@pf;Z13 kYK^;c&hj3x%JRb4/]lӱ3l=Y%?N2vΰ{uNg8K52 b%(ɩTQ_tTTF/,Xvq30#%[g^jL,,ϛ/Xc(Ǘ4H6 >j/;D|_ Fј2fRh1H3SuU׋I:մ\Ӧ&v:'oB˲,,嬓;Hx 1NK$1I89暳BB@7 qBOj"x$@\J_!.;J3-meR4مiR-AN'mդ Q4quHd^-7^W7feM,Tl? 1N4615OMmB߫I,k,5bCHјvè i=k6QXSWwOp.ε]$:N~Dƾ-jdNH$IKQ0fXgLu"k2+G-ɉw"-RmG'];ScF )YS3t5ЄKóg\45>֣dzՖ%),º8qYg%s-T,Z~Nƺ:llekNx'H.Y>Ws](KX25- Sp0WH K*'nƎhNIaLY-*.,4ֱ11K;$|y"'J!R&(xV_[&H I:M6ftqr`lO ?pE~!8`,b"\b3kӰQ}g ѭffiDQf[*5[+kf4蜼M]}tݐ0<0_Ph t}e7B'˨@ 2 *4kc<{4՞ԟ|nTEi%b46wLJedM[4i$Q,,d&M ðKg#:Sƒ#cSx|瑐RX=تLk#}.5pi6?&ݮ9drՆd%T"Ƴ|ט݊0IVf!8uTh x  !;KC4󐤅\I|BM\'%Mw/ه. E!b@Kjim`4']Z(cqOq4V<rti` :JG<ˌ;l [erV;=}u4&g i)nܳ sQ^5[5/<]|ۆgNJj92bU?z&޸t"akve-ِͯyUƿ%9sēvTݑwU)=b=ZQc+4.q}wٳiC06V񖽓mwX@ F P$9)|:"-Y'"6I S' 4K4 X њo'2Z#}R~Ńm =Œo$H̪kۼ[SY_~_{K)cCo1Ru//g$Ȇivzmn"S1۴K7=oucVO%l34tBmqo6N[Wׇ,#ЫoHtbj˪6]Lk-Xfy͵^;."N.y(Bߦ5f;C$} 'wuIW&=otwgxx~0 ϗJ2qҹ+MrY`MJHXI=6p!mؙ  EudСrE)h&s_??8-`~b<"8 /Mo %R6lRkw-k`h6SL cAEsz(QC#I+P.`4۾bMp {i]`i4fVxg1un< fF5rXXv]2kmdq$c$ҭ`Fe¡#J+snD4kψ\n,E{4 (  YL|˸ƶVm ɭ:= ayxf&%d'M/Y_dw$r켉5e;NG@KFω4ҰffFQ^6DG:;%e zʣLo 9-?|ٚ kjԜ=Ws<=Qܹ ]<_SwjM_2ILizmBk1XxqHvXԌ"fјPLK@iAD  "^6hxv/|xJBƇkr2jl14hi77Euj4V]]*%REhLPn#:"\ LF h-t$ŨVf-W"0s琱?~lf35Æ)o_~}ȅI%:e I]9F T5Pnz7оagoj?q:?O>V{1Fm0]G)"u>49dlkhc aN@URvmiY;wh6gm۷Im:9PdL/UL4ƻK?%k S.VHZ§ؘT$ :A1 XOq li0 ̡B&b·[MER1$]F]$ɱcF7s/<~xZ;a 3g>|e:wΦbGZg{MoapKO%Z ]E@4n;@ WiB{Yh2&iYl0:@;7@0v[8~YO?jʃ.XԩS[omܸ$[ii^w!R{'ͽnZ;kP'_yRSSwljGoя?ķ|s.B=Ș^Nt[!](Pvm؜7,;\weք%Q)(Vʘ%򹤋Lvy{wzEҶ:oK_bC, w45\39>s+&7+;BU9.ڃ@9m4ffs)z^0_7pbs7Xd읧UӾ#uχfИNP-L=K{D7ސ shlu>y#m5\~ QvO wƒYj4ѣ``'NtQUW]S #V=d]{m_i~Wv6+=~UƆd6d09 KwoFw^G\]mQc#JJ~;NڕuxZԖNL{o/\5O닾w1/*]ruew}u'3N^QA_G\a9d=Gc}7R6UGF?>Z~cN{`O*5QWH9>reiP^̐R1ktd Vh 8SeWtm+'}*VK}olԐ.n["כ@2ȱwŠ%./Wr3>N?0U?;m[Svzm6<=?6q; MhݺocVf[y}׿Z}'/$`_0\>m:ne/*IXQZ}g⌖K/;B'߁Fcl`JGMQXqt[4J:sHo{e}؞{mtߞga8R4Ʒk4]6<}ͯ];`#ópBdH kN H@)_҄IO*%+mHT 7땞;~ ȳf4g5LBWD#5eʼn TaJV<ܵȼZG1oIEk)V#{wza)Myg__]Z>Gν+T6/_7YqKć7%)qui;^v.?,c>mrU\ >]Vl|onYF-Zq߭I_׿/9IG9\SvD`:HM0gM7)4-mkH>{e?c]hDur956keƽ謺]"~]ʁtP \FcfL_rJwX)xvѧ61ڛhv-j"7BLxuX1c)xY5GOiዹq sWXuZ_|ߝ9v X̧];dǏGstbr͛7-w1!eI6񓦔k~8oo<6`Kw޵{iwjYMB~1[`"o 'fuc%<_fy{{򌁎Տ{F:u-u|ZGM<{g7%]n? DW5()Mv4>,Nb8vH:GJ˰48eFd]}מ&MjK{iM*0M?kSZnb yEONV:8P[_/Ӌ5}!s>pguNk׺ipWkJ\dސj}ݻanZkH\Ʌ4>2Ξ5kgSTC{eְ_DgŨ3HȋQ2?~`U1+'K}R qFzFqXSfD!ܫ 9_| G4ezN2QG*hvɻn&Kf˷Ec@dDcA? L@Vlmo0O$6I_WR& U̦Q[ci`~"lDc^h,dkq"O~h4Evw3Eb&Q3!1yzwMB(dk쑝Tm!!pYm~տm[;qCx(# h@XGc )l uFdRkoq"DEA'6wu"5:  "`}Xq  !% )~4-&[ѧLn LA  LdN yGt.6/ ɘFm   f* N @@ F@b&D'.cKGx  uHD._|}RFrO?Dhsq6@ )өNxU#[Y]72 ON /+&g? ^  8}Jۚ/?&ܺu225= B^x4 c  !$ !|4   +Șq>@ CNUy ~!q7^5Al[rn=M@ C$\ݲwꃅc}\C^~Z{<5M\D?~왇 PUQޡe ^U5˝mW=G3@@ T~Ʋ|*sgYsn/HAj)qk-SAWiՆ?HM9zՄ7nmh\LB9]Qbu}t&}/C%GJ0l?Y]:K zcgl5=D띍5C@#uyB  (c]?zUd9K/q 7vd f*|M΁oT@κq9KwwIIk@3㖙=~cxJJۉؽCmLW(G-@#  U( bH왥+ls" Mߦ->m-㙝Vy܄ 3xZO+ ̲\fρ_Vf%?ԃe@@ Wq)DWV ajz5ј;L'S9'I;O0&)n6dSX&|i{sm>Nuq`km<( uiRmHy@@ /c͜)Heqe8ۖ@s/'-Η7>>/l}quJSO:'kɆZ#BOc7PӓsOHVBhEU  @ycm=yl&=o,IqOQIΊ?ۍ]9o&ZxPKA-լ| @4|߶LIE ĩ  A dش =+@@| eLZ#O f @Db DcQup@@@%   cy0@@OOHnɄg9œ~<hN Ul Fz H9hӫEokdߍ B~Y4ՏA@ @Μc]33ՏȤ;d&B #BzzՂxGhV(*I_Β5le\`D45sABH HX=D   %MRA@@ L2:׶u(|pV|նv7nSBz\S#C%}w5@dhvZ2$*6+{B_Y o#0OdmHxY;q:84u۩7*stlv-!P;tF%GE JGz]{njhg 2s?uomd WP@vm|6}}mynv(+5HéjOifCԖGOZqh¹*{/' QB2cePh WS,05aثJOwOEkVћqZi&0j[:GԹ*-׭^P@"eL[ Ndtx<5iV;Q7ra9%"J&ɓvVAh=7l_$ Qt\\jAyͱ*~I1x?(0pe, !.F*6 xr\0A -evIåNbZ17G/:ښnaNwuIGUy(!࣌^ ؊/:Ul0+gD9)Ggrl1"/Aub*tV笆9ʩ_\szG0D_ekcIQP 5U&͊6oI Gf4\#j˚:0`V%A9ԷYl~Q>Ll6&s8 @"217*FX:Zx>~C$ |LQ,jIQ#+z8NBjX}HljƜVe=/Ɗ c)@Aq.˘cUlNs}J~N;-2mGj~iu:466UBylqJi}Ж7uh9J"@@ jAXv_R6N(T75G;._'G:MjTYXzySX!c"¼B~.eIJzuW8LvK!}|`iN/k$P{?˹_4R+,v=@b1Q|gȘ||I#WFf?4^dMMZ'>d{/Fo풍9If.؝'cTL>4L*.|0%8~ID_ 3}N'MH~8ANDSX .8mx8@9)Q v.Y> %g󘵨iz웪ڥZ6%6ys&X0S* 6:T=6פ6zkfS𠖠tA-޳Ù !%ZXVV[u4RG8H c@@"d,;@p D0XwLf⾽\40@s^TFB>}  1$JS  + c@d,*N@JOOJV8 B2+= ?A@ * @Ƣ[ X4$nS  + c@d,*N@JOOJV8 B2+= ?A@ * x󠖨@@–ʮyid*VV! ^a   @3B % ۮa   @3B %Ғa Pwb72!eA@™@d,6# ק@@\  L2A@ c@@"d,;@p D0XwL`<  5   cy0@@2k@@ @"`:d @yc=Vy111tA쒑M??6ӡU`)M5(  fSL]J?y`0BpExD 3=hL }EֹSFt$)_ew b2Lb!7eGp:xO2=;   :!> K@@<&N X  1Șp@ZnK8,'`ݝܽbuŊ[QOZ+Qڎ,؝'@ɂM@ CX~g, v9=SR1VP nWt,vBRl  aL (2z>{ZK :Bp$R49BKr X9=MU¸!d:(#c dTV+9py;o &xҏg\wx\rGɾ%$H+o}-wckw/fsAŒa[1˒uScыޣx^,Ʋz/xut[4JƮ^Rr(*X~jTXF'4NJyȂ| vSeǘ(OX3u|EʾXQԓ=`VGn  (cDArm.V8խ_l򈚋2>GFr(&dH٨lW1aA1Z9*wRɃ]Fcg혽g<OֹTQ(Q O>UmF:1pƝ@@ *d*VV9  aC26]C@@<'   9>#1#퀎5Ug55욙B)WU@@_iU:EġX4Cm2/@@ |1$Mh@@ P c"zA@@2h@@ P c"zA@@ ڦx`b.4 LEHfMoi<xh@@ 2 `l,2 VH c@@"D2=A@l8+,Xɥ=.H'r;>i;ҵD# v?lyʑw2 A@N 2V*6v+w-*ʕq+MN.>xd,Ul.f#[-6WXqw>i.Gi#KdG]1k>hWv|F߸eЭcKV))Mr_};f)GOH}JIk!)XC-Q㳠AFC  "RY ̝P"+ɛ]8P-aFuKJ Zp?keQ@tC!o1(LKԘyL+V.i+oN9A-lQvV/d c@5P[&CWJyE5,SeuW2}6{:Ʋ{B%H?G̷ﱢ@b"`g=:k ?k='}[$giS,Z@ChϒNQ3ַ/G¬A|gcc0@@C/JsjYk4[5>8@l;4c@@@C d    @BI# ̝)mt:{lI5XeeL,xuMB=  "N)"dլ|3m2/@@ |1$Mh@@ P c"zA@@2h@@ P c"zA@H@ʣmf*A  -Tbe[p"̱yENƐTF 5?ȘF 5? XŊ[QZtn/,bz4t|6me oV>S&x%;Y!:DOe9bU9ꁲ}9J%9eqS&4ޣU17{)+٨a~qGoX)7P=@ʘ %Jo7RBۤiT6)bKZ,SDNJ򳬯]<)I9)b+2:BgcFL?x mq~+/5k;7InGGrtDrX:NJ׭yJח22A@|%H+~i]:{YdjY=xPutH֐Jy@ּ [4Jخ^"GuYO-רg%[<3iy"995@O= 1ulL07MɓK+ͧ?r0=etb  RܵͲ+@$\\pҔէgl,nydGaN43C{$(,..!$\F3䦧[(  ?k=W[W?Q2P{ 4gJoYzx78 @@-(|P Vw( $T6 &F   cQةp @bd,v@Ea%|GRFJkkR=?VY53-)WU@@_iU:EġXLF8e I tXȢ^ 2XȢ^ ]S˰5W# N:8@@ T>#?ٗW뒑aO   k*OW͍$">:}cr*O2&h NFKE6*c"ωm{G  !#d*Vj Yaul/Fd;n8 @@ ,@¢`w cqY  aA2#@@#   2:W@@@ VfĚ@@@+E[ưo8tl'va>|M-ڍz4  Nhe 3qD0XwL`vccKZt p׽ 8qiY A@"@2vl)=  1@3c">Cꉱ@)^=} O@@  @b2D>>13kbGt,<&`M fK(E556DrZ^6`OJ4c_>ţJBwf3 s[Cf_No2zPY_C'h5!c~P@Ƨlp砡;bݙŚZX}`?P7c۽ã,t ߜP:@ŒoE(Zlw'Lb_ / A՘i5, 6scC}cc=%{b_Ș?%@ DAdnjrA=QhL|԰a @aѐQ侈[ j٢#yu/)^H*F\GyCG9rFǟ]tI+ӛM6n6Ș;B@ jb}>|-\pG[k{?3 /#wRYbM^xć^}1P@ R tŇQgn~a6?d) ~f+ 岌=G|0_w{tÇlޞoLMm+w.&ȯQo/~Z>ҖMiRF:Be=d=#Px>ժTV~ت͏+a,W)E./Y_f5fŅ gI ol-l#Gftك7?)?ZRmn=Ș[D( |:z}yea!2/n{sS3uִU0薗2D2e{x{)W>~rr|vVvPMnrGYѕ% >SSsfK$ZK9r-/>2>cwgD4 >W#{T"eo6U?vE Zw)c+3Uo>OU]GKVW҃;^F4+w8q&kp=-"RM&Z<&_Jb_}m+jE5 ;A<& MY^xu:w"2r65e45d/NM&eMɍIĜX+g7T#ڋ>Ghe-|Ux uQ)3J@4_c/vHk{@ AOşN^x=~V4KgĚ^h @ &1~xo~zd DSهn3j/6kBqN0" zDr\\1.^$I`LOEj LJ0^;cnRc_X7   pZLŀF  # [   p#F  # [   p}c)=Ze$T!Qazs|`lXKNjD9^A.Xn+/J6y@iQ`VSjO ,C$/jB=ϣV= Y~=VGxK\O.@] 'yPV)BnC OÒѳ^f^32Z%?/7xF<;RVq:rIENDB`n-xu\~*yE!:lPNG  IHDRDB,KsRGB pHYs+-IDATx^] |E֯#'!H8"\*'aA]E]Oœ[\EÍ +܄rstә$3I+BOuuիWU+a֬Y'9BH\єlQ1tmd&#s{W0%"31[?"*Ps"("Fe=%hs_ 89,JcE()7,1f3Kb-j̙:Jy)m: b 1X7šbXFˀ߲:2XV5B`y߲ds)gahV7<f ^6@6{1 hx%4bd5'P{9޹M_ޮG&"E,HD`%!0t KlɌvq`6 &!IFı :Z DBMjJ$^EH0D G~:`.I0#Ledfj,¨9Z&LjWe&YXnsL=s%6.  6 eIt n)9Ҡz(kϢ$2IpӸ#zDDHxM 9]pEl8\βN̚Osrkkن ,&Am I2[ ӑ,EsMK-o>*HCqY)Oq}REjd0#$ QRt]Ymx1e#]Z >!9Ny"#-rDEr%Kr9&[$_S(Cwv[Qf.*0V涰" 1k&f2x%0R⧏iЂU:aМd4zxU0{03k/yeykh=yNIwH¤ ۉ[1'\mnggvm[k1"Ysv2լA{[l Z'̋m$WJ17eI(/()i1>woE FA HV QBTY0aI ,h`02LFWc0Ξn, q !zЊfg@Z/\YlEVfZ ,f)YhzU[OM,lJYqFFTԊBЅ7m'KB@BJdKvdJ"KyK|䑬Sl=X+R;XUְbQ1PHKСҿ]R%1obeq)J#P])Ъd8Ey2eo3vԕl;Sw1St9%\W?Qae;sb܇.vR軇Y>GW5V(HI4lrBأÍأ=؁RGNMðSHּg4'Z;$_ZB57/?=֠"4ID'I2 gc ӗHr8d|cN@H= HFziͭx-Fн XaF3lV>QSDD3 Fϲ%Ʒcs:?م16mؼ d~Bzq4H,96H. T-~s-NlҋW E }U<B<C9PrG ]'0Lrv 3h]"fMϣM?uEd^~g!;^?a>4Êo(K+R(ŧ,ހ`ɟ Ñ j4ScX3*b!2۲7xAJ5ƾ7_Q[E4RNyx`>ޠijJPy 2Oo̟ɜ'9[u|\lie:6yd[*-ot &2$Үi.EؽF4Ȉ%bQ.V("g/EGW-"[^@uJbQ/u}5 E_8w~l|"vm['L(Kn xeI$gY<<,\9}X9ɒE>UUiMF kj9%l b6֛=bsTx?iɲ}FAgfQǦ^ JPY !er :{k4GfMG6o}lQfxK%߱w.f#cSXWn_4e^=2[ee:ۥ 슶$keRPgzk&˷b, #9hfRI]LEl!i>LX֩oGOd_ ™2"E钹p EX*pFk#}I5+Y30}AG^ }x2E%sj_e5BY3ޢx1 (CH,˒v8sxFZ|'}Wl 0&DyS.ZƱF jtt.n8lp^x7K"6NhC7|}qzQ'ݿ-Mk\E~yYR;F2SFn7߼kyM)Wv٥>ߚ덯3EysJ}|8~<+cXԞ;꥙tthۏ`5_@/w2"nmԟʘ@I喝Py%5Nm(na ^䶻 =B:8 s?I'D_]o,k,$m|NpK2}a%0>rth(4{B| 4e -ce DdcX R O̷;o$[m/49?t&,y3$o~LcT6г)qʠ({Z^2aҬ߆SwT"53&& N;zE˖H]r:gsPyP$0K.V4Gة]:5s:4`b1l4'#VE(ף|V%CEH +>AeVVWKc]r൉ x-HiU(,g0,Tqʷ#0,ŜXt0kn( t:}GwlXYLB",Y| ;W,iZ[kj^$Zηr r rrA^^a^^Q~5_̳|'.BvK:pKHf$l™` ጕ xUlղ *C(9ή"u ܬU=RB2zY8?Gw*93l^5s`^ wlyYj*Z&U}<IS̪pÈ 2xܾ}8kxIL$>g7Ҽ`F\(Pv,tD\7w4դG$4Ï'7\hTG)yd6_0OfΒ`ttJl~EI^V*&ܱ'B73֭tP5M .Zpv6$]4m`gvlSu2}lN΁jr@s5?s R8iF _t:B:jhJK)d_u:HG9`P|9s@@-.kyr@yaf5μKrȡ΁Itʬuf X{b5YoԠzߔ欭̢9|/.YWr\oY΃m{@~۟-w"~[s.\`SskkH7o r@}.F ͈Qlhn۸atR(D'6N:N0swcKvU)j6ēA-dUx~48YÆ}{֪KIa r`v!k4>^4dY ⊦ pc<eu\1>+/]pL#tL|. %'~A(*C#G{ﱍ_CcW_UZ8}:{pA˭dey\bcJM|MN?|Nx}]Sfiy^! "<8S.ںM6m"BvĠPjn~Mz[=vTCr2)𰜽2{Y`c /,*Yvz-s銁dxJ>g0ty$% h3cbH0ȫٳI팴HKܧO٢E,5aK'S?7mJ.]l3G=(窛jH"*\  S9J ]ܚc'[pDU9<*u{iWԵMC&IMɶl7LPUJf:(ǀqӤoOzjq/Ecܠ 4ϑ m]L?IH;tVV\ZjHx_),FhAGbW_]άdNʫ2/[yʘɏ,-2U @x>y*miU$ss%{ٿfi,0 ޫ~W+p,RA6&4Ef_ 4BkЮ,+߮='~a[pXN3(jhG)[n!˹ v%>a|5WxLdz8yLdkeqnS+ڒ|δg.2 d8G @^K69aZZC8wedn0D̨Cxrda99 ُ?Nsnfl6~cDF.֒%h W7@T>|8fv$s3U)ɏ̈xtaXC"M ϡ y2@pe'ÞO?;Pf 'O4l;6F  ?r)fQu3_799;aŦw:SwٵVkv:ѱmȏN,aiGX%Kjϗfϖ0T(g*`H2egK HO>IKK]DZ~8 ͚%9ʭ;^( hZRz 嗥l(_6T)ҪU5iDwNP7rv_5bHe|'䗭K[ɱjWxkf.K)jv[PQtLNknsx81O_ @rE B>_ŻQ*P{LVV=-memnv,Mvt0CNE`ְGt5[CfU' D5esov/.^΁r@sX٫s@;$A@s`R6NE8͚KfYWX)xTzfukoTW{%5[Kn׿hWy\$BK|yoYsÁH16#':/4<By;O\kABlfH1+lf|B1<{?tCnj`o6>ڼ̰p☴{vC qm }FϏsLZ괅c4 C'L _}G:nfฯA}Y?7W| e7Ưٕܕ_Ǟ~2Y 6Vg]Ʈtm<6:u (1nݛ{FHأu٨/iNjEMF+|b7D+li)m@R.pHf8+?Hu!:Qg@/҈ֶ=3׮wcdyakޯ ֻou'LjIL ^)tPsE6g4OXjQj96+}͔ :ݩ:OC2 M!3w Nm[Zu)wZu?)4 әql nvJ՞=wIPE?v 7\-ATQ`P[*3gܹwoڵp$00ە_GH*w\m}:}xdgϟPddSL9w̤A+z*;>a(2?w]̆/GtnqWӮ8#*̆z},$/ TξU~d!ixo8Rz#1 Vn.61jť7,Rx^Ler1 ^/C3KmLbZ,.-xPFBt½{`63wY7QߴvDeX9o\]3g"XL*]0V W4~7rOem)2X%U :&Ji G85`n<:O ~<`6T:J% F9 Xq #4a(@(B yؗ'a=yoY-\H^gE%?UVF5\*P5g( mnݣЦXFr mP颬SɾԄ6:We7ijҘB׿t..ԓ0+G(88Lq0Yc&o$-VFN@9#`ŋ @;ð f?0jaVF74.-V`U dhא{@uZJJ`m'C(m]$Ӧ;Ȧ&JPz1IJ-DCy0sڰ kXq-0'&+lB8\]Uo 5T̜Hi,U=D>> 9kr{@ ϙ~9PQH)89PK8tTm%Ss t0kfXA& m%!'z˛7\sYsf8Pidmj:ʁxHxe66%D<؏[-O)"z*t0kٳ`>Хez]MǘtɬYGsfXWs ^ұiD5[Y#F7t0z:4@ 9D|V*ӗF-HsYKF]2%BntuIyk\U[q nZkV ,sX))_'\ŒSR"e$F)X5^nyh)Jusg+`Ze_YǺ+٢[us:kD9^uKLJ$J"VY[" " &Sɼy=kDni!I qŤ57eN .8NUud@[sB)-9A%)$jM*IƉ4+nϬ]~%)T=?B&Mmlr/iiL.РQ i܉bbʀITݹF'3KLgO<LH "N*nz2W-n" w[ۨy8N;)MZGdHb S XeL $?o,.LH H@rvrxbI$~Q05 aNF1,hK&>z jtI3 ?õL! J%i@{j*5eְ$`- i{@H & x3^"D_39t. yܷ\ N\NmU 'ЉZ>5(Uy,>&}LM V %&-hҽ+nik~} v.']ܿ?w65׏ Mvbi 7_?KJ4cAS+ (jpc5{~D b'0h͈B0[o>Z&H& NV1ugG\Bv;#n;|,qp u e!\-$ [O>;c[SF6h?e賃G6mL$>4Y> IHZc+0Տ=Df&@Eά쮜($% II(ZHH`r"l&` R,%!$SG,Qc_1}~3ݜ(XdEu_b+d ԵW\+Me5v_if7$@oSWsOiIw?; tYjmZdC ΐ<~.pNgK{7”/iI+hrQgc%kԅ" AvkZIq(нk,@ZO̻- :;pvʥO'@Qvbݺ\ Zrs[H LT0G+z rxyj 4 K:N_aQef1/ 2Û>>V';86fp:]` o:FA$w$i ,yH Zn`k JYXe硫\*N35mj7l;Thyu VcVpdC4N>v78zFCWgeL]-IȂlםoAPvJoBpNgck X #_ڤy>VIl,;y1ksco4=dhj*L$pqN9I$"oX俎`O;uiꃯlj]p+$ߗ׋߸yɤNaW$ RB$m}[,. 8 (^2(EX9jdžv:\@Ǒ3-GQ2'4|yrK4JVy4 $Vj:XG3JUyw .?M; _wOۊC Ai @}D$'% @17=r4ܹs:p=Fؠ[vfd7 |pL.`gaQqrd(OmiXaETǂa˜Cym9]psOl ~ 9*0=_xdM_8t*ZZ}-֭~1{Be&{N8xm$g'7N;up^\Y/)9l{~yV׾(zs&?΋EN',_>䯧O+ VϴV*UQT)Yx{@ X[T[_.k\K8}t=cH SAj@x:HFc{}`PO Y` %2#$L_rNI_Hbb&R{EJ#Iӷʑ7-9v+9w*Rq)giu}i$gZI; ö8Ilϙ\sE)V2csς ^ fY*i[PE֡Μ7?Kud5yMkwVqm-kL{O(-1pkܶ 9}Cnt{ l$+ZU9hTsY>M+ovp vW) j5z  $!I9 g  C_q?-dxF%j$@CP#%H0N96N.C&!ID͒\qd Y`͑=4~dP9$fB'Ӏ/5JVoUI&*,Ki4`Z 1Mb$R;+I8W\EV>ʟ`ljj'c.5W+s}@ dr3ݳo nX\k3kk\ Am%{ =o-9^~_?*lL pso+?x2S t381d 9ZOKIH#~DS&nfp o T $K2] % w_E O|5X`, EwKU`08ڞH AtTՋ>@=+hڮg-P^󉓆(Zx\^+ ܲ$'?)~ o~RZb+Nl֣ۚΕhp0a02;|ofuYV5D9~%ܗղ 5m 0 i*hl![NvKCQ9' PyM8@9x%0?zԂ@meV8{Rǯ{{vv,^SH L{,$?̂_Ǩ"r|t!]K'}~r[a]I &d.}Vb3#r_rUiCzqL/UL֮}21Qf9DT f4?%l]G|CD}-<?'Lf4XHoCL;\nҧQn:|4(v@,qYk?\vAJ-$7TG0Eu N^]"7Ǽ!ƘKJjQT?oP13@Hװe?Y_1%?i@?pي:XFDh& t;]Vr2hH.wtx@gx=X(HtɞiHV"$" q# u+rLfP~1[2akPUo@'`׮'Hmnnhl9 [6567t4:\. X9mV;44 NhF4f0aa c.7YF|ZH@y%sMq%n2F,'%;ձd|hR" `bQUS h?4RJNpJw\Py߳=t݇\sQ4xLmM&2:IR0͒15SʊkIE&(v P>7, +sc ⢿i48: Nr0ۙ.EtIyS<`co"A=y(БgT^P"$ Dܝ+Z5.5쓸+9E4M4ȢQ_҂LMl0=ُK^LġaH F8P=t-#M8!iχ J[] g3-Upp/2@6xPL $vl/PpWtb,Df&D@3#Ư}09& Ga@F}<ߠˇ7Y)>hL!$H`ݣٓاp8@H @$N(9ok$ tL2 $FH @$N(9ok$ uf@aB'Pid%sCT`BQE@Z@?uQ5Fl<xjͻ(85f|P%G@t~}\W6?z;bЂ6`t[=${%Ň~m`E߬3 Fl7o Xnb;th`g_-hm9dUyafOse7x8 PM8'<3X}6d% jڍ-`JBNij[ ʐO[vV.$. oo[;H]+&7Ou3Ley92H ^] O>}Ƕ*w۶8w113vubR3cնzNQEExArSj+ٽ(֚1޹M+xMt>R%%@ZC٠Vq8vw]-2閺qh}]IbfeMΈrJ:/eOse3#%2[qu/ҚB`u\m $P6jZP*`ޚh,vQs g:+is*gX)݉K6%OoW*p@wY|on 3F3-hdvl _Cdb!$P@{mr =kSuN)[WZSo%9 o~^x$255MˊwYm%`qXh?[Y ߆+@Z>o]wJ=+g/$K pe5xΏ6ȹHAQHv@NiiN, ӂ}'@wPeّ1岌?Ș>%cƔ?Han$yWR  _ ,ݳx/\5ykׇܼ鄤yAC{ɚY܂lAee!8^ɲBfe(uH|M&G ztrl tb"yhϽʏgcݳݺ_`MCZ80ux6@z7W`u:_V1cn/şr N S{ת/Meb[]Blp͂`W$f 􊧋^ZtK 7S'XZ|/J8${ *ȸ ZB9p+i|#suIy)lU!xG[&zd}qH.տ?j3!S|[ЎIqȁ /_⽳ĬC,?[&޿>wYb ؉pFSF : Wƃ6W,Z 4;~ח.lGFFdl"dfg ~-?dX $#tq{CR841jRH #[ްW?|>Z! ,Ϧ=rl/rZBZSS@FE2*QU#BH $z8}ڝdOeYMG7ow?]cܾMB=ooR]T >{ST^6k)נ J~"s b*$AZAlyUMc{) Lhmn\^~ @W.\.ܲtе%}vѽWpf^VZwv+4X|dpɦiJFl< 1MAj*biVmZQk:iNϪ*)!.^!`6ȠX#l.`#I~HK?aN_)֦uH Dn pI pmĀ%؈L#[ǦMH ҫ8BCP~q7PMUDr!7PC(eB~c-0j>ٳ͗'ݷ='m/bH >#`bq|/›gаa$@$)-h\0 $@0R IPk$60!rAI|Q`u`B৉ׂ:nT(MCH 6ͅQYȺ}sRU*%ml0SϩëNX=;=cF tPIcd({]e?ou7>klYRL^U.t+YAsE#YJ1 3n{ȩ޲L]2 5#:(CI/&Z"qQ )YPYI}M>R mu'oz]YH/W"z oܬYVD+˘-qz"TTeHW_84o sIHւ\ i^Y;Ug'OAmiʺT?55O>:M_gz0ڂ0hOAw^~k9]QRkAF}\a"`@kAA iz];SPw=aOpL)=cb傲].=4m%b_SZ]#7*uU8F}{$f3#:X I,̿*Ӷ߉:#8>VPd[0E3yPzE/;[Y7TrϦ̝sj7f`6{y+m8!psVyso:mԳwZ}HZn Nl0KdN)S^ q)p%{i^O[Ho zQ3Iϯm4aSIpaΗF@e*4tԁX5tr6mc`Qc8b-!DzR>i7R3N1tzM tc"@3V0y,0߿3 b i S0:d!{s}RX" {V^bI,G.%$%wO(A6K_ ].tҟ'X' thoi`QJ`ݣ IhC+\ οgdmp@71Jg@0Rr%kF d%N}Z蘿qH J )0C3A=~X>jƖ~K+Yx%,̸(Jg@mڑ49p-:N Q/:ޙDw1vM^rHN0v #2#H:(Oj{Ǣp-|jK97S"N8DnkX۵/=]R!^t̞ToK>-=L.9uEK34vSc3]~{*h'eHwl]S{nYyGM;h012<Ȑ_^N8uf#qÑ!pgČِha,ȋw>+ P]dC/X Wz.ΠT1!$ $`@vv*9 !C:&n`]tz&=c4B@?۩]fn>!wXjF t/ 8lVq8 ~EwBqhm͡/zu3#۩p;Xy/>#?]UCAH x)Ц;eKDw,Iz  8 HWn^fzϓaoݬw[]AkS{?#:덭9ُP=73ƙU%<5Wwn9c:B'`@g;v4ztvdL,c2Oɘ1%cnprM:i,٧n[q'ŕ&Vl˩MDy_[V 2-lx6m2TUzS+m`W,("`@ւNL$-\Wr{ts[ Q4gPxv~̊EgsJ=l*`?APj []*9M5=i[tY|}Ն˄nC8d{E/-E)p|W-^/j>WU7޶H1tn 2O_㋕R_w7e|L{ 6cApxW+OU+H\瘢I8iΤ~P ӳ'b͝^ѓ?O O,erpmmmn>|hS}9W?}*?^KܷޯoCϜ|uzyӁܳ/S^'vՋ;j>8PVO;Adc.{ )&?5wnE݃+՞'yd$}-,.,h x pq..%b wtgҧ5}قJnwfP;_\Ϧxl}˝ZAYa,F i}AX<>h!'O=R~tzJmzq.QWjsdzWHۺiMU>FI2c6#ڴ>h-xAPfjS3&V.(c;** <3z|Qv%9k`15sJk ֳS[H=*>:*RVFuU}_K峺Quy`gKF t_.υ1a*KiT_0@0Rʂw<蜹XmWV ٍګ;@D iko<"M:½``_h= %ؖSKqO?fbS Ϭ"s@CfsS~֙M & wb@∼Zl,?I{@Ҍu:!$5#:>h3ulH .|b_EjT~l[B*X0⨩:.иa)Sк8hS ;Ppcoq烎)!$brggw^ӆcDH )}Ar5Z 9< `@G~ KKsrh$վ/gF1IHʂްW?|?Z! ,Ϧ=rl/rZBZ%/y 4T|gOfo BZ#&/@&@Z6mCwg$-'j:GvqB@qC!lQl=)E$M*|t (g4tOݒZ]֮EΕk_~#%7y?'5!g[\@i)Ue^ 2eyO@gf#V|gshfI V)`i*0!$B!`@eACg].'K~6OErS$8Qο#S-Dl"R }tYNW)QQ]Dyйh_=3p},EaO{ǎnnDV* eV @H)Am0SS#-s9v>+!%tN2 D<3 R#!Zmyk2)#::mcr"E@tG3-[ܑjA"`@kAtcN>lv9@CVptco8:4AmXr fr^Vf5P n)+ej @NHւ>SGkOFn&JNHg;I;f' 9tov"HŬ.h`9*tl+/RX'rWأygŵӹr_~ <*mQ;\QwČYӳQ'f="i^K,ƓGkokqϫ YcK另HvYnbgrg$,XiRCQ(?\xUj:쭢$&P`= .`}=3|~,y巿5Imɨ!`"H D* ]:~Iysh}RH pP-,h"9X7@H;|GԁS7Y wuOs}\fE\pNt;.A%LJL[apYp,6:DH .8BhBd..Qvid; E#$2#Z=rw} lo}:TޮZ_ %MN=փ薀=٢á6xO>r{gI Ot^v#$0Ruڳz3eS{l?rmˮсC0Z`)۳HJʓJh#lH #Z=k Z|ɸK'ri32S]?-㺩`J_FS۱V++it%cS+_iYq~o>T[~Ƅמ ] s5vT>ޮ[vlQSv:*AucB.#A|L6UCKfFH ?({a@C|"ád7 . ǂJA=;*[B-}.& CK2X o|Xcv+ Xhʐ9*6vwѽCR_Ea  iDg{:f@H + 鳳U7qV?!;#It>?,KKje,xseMi pZ~c$⛀mZ SdH  ~$PpxBRU{NʆL=wEZ#$$#ڴtX.Ύ)eLA)3dLA Nn #$B!g;Y2`e *RU17Z O% `>ME@,H6X thܰc4;SMv $@\XZϥyЂI!ģGH *`<註FH n iA9:&(y6ϋpH @>MŅ݋xK`tK<bxpU3!$<hZаR<~+VeppBB\k ڶzNQ{F|fI 5> GvXNc`BMḦj1x,*j>ͽFoHh8]Q/,\UǢٕR (re2"7ֆ@0Rʂ>*4YAhϹPv>&B .̬$wሐMHʞ2F&4D{#t% mx$Wtx>꠽!;m $F t_Y=?x"$7/ۥ0nc0@H+F i-A,S[N3(;."$mZ A0#@&"@%L8uxK}][vS\cuFgt#,/E,9dζĄ ^Olz.i@Gn@)iHi}88f$@\X:/T]#@ Z&dnhAch0NP S A _gЂ[9b0tPcC%QXxaU"$KD8>Y.Pk˕1!$◀K Ar5Z 9N  $ )!{a{`IznX&F(, `H  V7~w8}g?Z! ,Ϧ=rl/rZBZǬǞ8r@![`gI&d[ OttᏞ.vㄴ@byjtf0<'! å#izA VRQtKrkQt;Z½EΕk_~#%7y?'5!gX5REILRY1KќgiJzp~W3@gf{F,xy!$ '`@\Nhkm>S喧׻M%Hpڹ9#G$ZDFlA{#cU\Y,w/ >Cy$E U4C<.̐Ce<04R@ @H  hQN74?]Çm.'fIt}2!v*b#8I: b'1ig؂E}ft3=SJMM_UXf+EH@!`@4֟>qءu|[nO%Dljԙ dm;gAx=4ݳJ LC9Sȭ涵&RG-Ss=V{hc6hxۍ@Cď^J3i }3M'j>fW'ʾ'>#_f [z{䔲͹"㜠OēG]-ɜ@$\o 6wgwՑͥgOzEҼX'[o9Zr;ɏ)Xc /Ã_ bֈ .%?$ D?6ffW~q7PMUDrz6A 4|[ ('ݧN?>?{_|Қd:YX9 dTgs9|С;| 9N`)$ @k2 bא@M[W6C! ?t8]/XѸO}뷠wÂóX268/l˩A#$L!4<'ɲKnXPM,5:SKh4g3#xgYvcKkO`;..@0@봠%ć.h?ȭI$%H/}O0 $!jt\O$L!:-h"So'>cQlm[vm~Q0D4$֞0К\1s?pHO BuZK]:iܔK3]yq?:iMSZֳ ~D8VԙP҄VcdžӹƑ3hg`^ zmkv|o-;k6)Vygڠ&c.!Р,$H 0@?+ CuY`=4 ۟ j AC9Dx>} džn,O-(ԕ!IsgUlFv**LcC+E hU#A9@&` 郶U7qV?!!Ew,4xse+4^FӐjh56tycH L!:-h.N-"$kL,bנh+KKhfMl;m`"@]0@봠;eّ1岌?Ș>%cƔ?HmB.@f&``I`A(X7LYвUx̸oa%Š+ Q%2V txL7|ࠐ@ šsn0NPq -踝Xx[:.D @Uڑ`̎f҄Q .$0@봠yCbosk!tEѾ|p_ޙX4YJS!]LBH ):"i\O(;Z E!tifVpN0V@L0@G&4D{# :'@t0@A6O:!;O @HOBuCm!y.pp>l 8'` iAgl.sHht<0Z).  D)Z#rI`#H )%a*40rjC'#Ȓ+=*˪s={X]TT@H/Bu$3'dWX}1&@H3SN;).?sufi-ΰ&/ @}Gӂ684_f]lG?ޭd{LH !` iAc<边FU$ <2ma-GVvcuOs}z6j`Iq5ݱ:Xx}.б a(ͅ@G  $`NpqDulԂ}J! q؂x{aϑ@4ЎͰxH L6@ :@#` ֹ)A]3X 0@봠{Z O F/]m%8Fπ.fyh4A{'C"hEѾ|Ʈx8`%'k}vJEb"$9ă4ln˖?m[ /1s`C":,H L!G׽yY:h:__cEזQDŽ'SNtoASUQ|Nut\q5sl輂kwY$Su#$oL!:}СǃM[}KjV԰sewak2MB[|H]?8^$Hzf7?Qxn2q-jƔ.YVmn{{4 ɂxк3!$؆dA?DQ]eo/%Y OB#thܰ(tM!Ц^(;ws@šsN!@H D ahA @[l 0C:h-kkFH$L!:}|OAă ,&$@T0@봠Ca$H L!:-hAau֞&7 q @_0@봠9ƃq8qYXg9EH`O,% 4\ $`(hPAV* 9(qaȑS6D}4z4&$@&렝%[D"HDpX" -h!`@*g;PSYy_ZZNyN9<[h}0_$@qD AхCEH$uNƃ *naX8 ^Ol;1t,M+@?4{eX :Z&Gԁ#$zC7,@H PFH DƢ@D !$O:$@HPC†@'~@H $(!aBH @?cl $萰a!$@ @1 tHذ@H P[@H D 4}@H ~-hL $Љ 4^H @6`@(x $LJڤBH @50)hN v $@HPM:1-$hÄ@&! iI&D]x] $LJڤBH @50)hN v $@LdQ" 7Y8]LH @Ga} nvn(v(>N::Z;mv{[ h' Q&L4uxK}Yv]'nks'aw"m}Kci8$ hoƚyoH !46'@3WS$ tM8 !=s=EH @لp(3WS$]22ma_ng"$LD+la$m; t癨$@Rz;ሑ@}C@}ZlX|o&[EH "to0)hN v $@HXQi&Ig 4DIt;{?5+XĔdŪm1Koד' t= bx{86"^i觓$m6^_} 0@{ٗ8{ȳ {m'Z#5ǂj}}o&$)`;?0ʫ/^H7S_M5џbC:R_)l D<W_)Kb (N`'6^emЗA"7Ӡ)?1DtB6^H}$61`5{@ӈnV`FbNخS %v Qϱ5Kݏ428ˍ68vvZ~ܼ6qh7;k8ƷEq]Eh tOs$`R/ߨ[;;nkn{ 浇0u7}n|ӼnI( *-T(j7o&b ^㕅#"̀HEwYҕW=%@׭]dž5뭨;Ρ{ +*گ vܺFnA'K;~ag V zP{f9 . ]Y9ZM?qk7<4q-_:`A8޺ʷLK%g6㝉s_AvCog{N>wؙEC98zzP{D9 cBnY㵛AÁ\{8zuq9[CuΊ;Zy'Qз5{y=e7u@@9\+$;3NϜ埕'{`^^9w-5aLsh {uyKuCKKCK >n!r,?I hIػF%`qսɃ! :D-Y6]@no_.㸆 ܰEqV1<|9yܮ6J=l.tq3 sO6O[6d2ۧqXuػ{sɭ0|!⠃ZMʠDӇ7&^mwůn(Tzn |Ƭ:Ed$fd 13Be< |L#V0dln"ug!c2ߊ ".& =p/`]Ħ %D,:C2Kf:OpR}ufp0HIY吝ё˷C, ! Fhyƺ)=;K:I X&D?*D ptTv2.Fid:Q c,3wEMBll%oA Ech%^c%YK;i &D@D@ŁKLK`,!z)aYܷ=JiXHtFHLI]$|@zq[!sLo rd{&ܼb"crG*#zAe+)aoُVJgjfh1h5_Y3D_KNБIT>[ LYZ!>PÖ$[eii276={vSϛI8[$*@yFpQVb1R'കؿS_}ѦWCJM$j(] " @(0qIf[U=V z|-VF#l L/킽0Px۾]Qc#[|-.E[b9f?Lי%KcPԋz[| "" @!::ඐ}|u¯|򱻈 2#pW _oK5Mj޺EHHB0B殩X 5}y\rG9IO ξ)kv)1G =T"&}7LV=q*(h]1">Ɏ'YĽ"m։"x\A(b:oUΟO *V|'-se4_qۥ`j0JjO_?)ϝY쒒瑰`-` k5ESmoB}*W/Aoo:uNwM.,k=RmD;ҥۿ4zzT|Kcx'EDD@ oZ, &[bq+? +d%[3!GG!d#KP7ٱ;fO Ub6Q_=A&:}2wjj}#:Dđ oK_8zGj]KI#nkqDT qO%T4yLJrMt5_{ߓVu T2άϢ_mLT>̶v),他Ĵ:xRYO _6V0-d:+ " @'!'@>z!bIP0!b-7֫pVl:j0C }B7 N3sa%9KOB L3TZ޾e7JXZ` AZ dEi! at2qWduA2! 0l&Cq7)W201߇Ǎ-YkxC>lpZ>ꓛ39jx|ћv-X@v7[p:7?[L=˃А٢#U|%Թh;Ƈ ?#GCzrTc$?Я`B+V\VNZD@n@lQl V3!4<@dW':%0R$=|h1F!! ˇO_Z[KFEBR(ZPNM)8rN&ƌH?uG25]5wL|eT7t@ezmxcabekSKz3I]Bzȳ~@XKLLmb i潞̫`P7T+]2~[z4=QTd=c,/튝7s~ھ w  "0*6(O- wfA ߔ?_hzJ$-XWlI3E:6cf_v, %[*持Ӆ Vч7PJ2_,D$آ*t 97}o0*T{x\;:urf Ǫj^Q1iԽSp4&qqT/d^]<M2.YOˊPfq4!ud;EkWsPpcbHK9 (.@_;(bċ=-EcCn z>kNA)1ҙ zn -<ঐavS-X¸{]?䵩"%>ON8JbOkP6UUNy"ZۢneVEtG/MTuBX}L'TimW (2$Aw$/m9LUӢzx9~D@|}0} &yhR}ߥ<0d'B-p%=cDrKf^!fJ4 嵾dWN~ly[wzyu!!j4E8v`iÏl6dsc渷jȵ5+Ԓ_Ô&/T}`<֠lՊ#;uP6wǶQYTy>Qn%f2lↃ /ڜY|Ň혥W.fo\m+Rǻ83/W-=d^F z7H@EIG@Dc)EJتfb3XFgU3xU}ׅ߼]S0p Bp(ґ?I#M:/O97b1"D :- |P }9HmxA ̈́Mj}BZ2nd4R6@H &ubLX:u ~KiC9|^ssT+I1\$w7Toy~ u,l89sJo^.:'[>FIA9f¨CJ2vş"t (L@ (ly/~A"a:pʤa/5Y/ޠ3"pt)kO4w^`AA!lB\`2."/h,,6 oL" ܒMqtզE5%DlJA 7p N ܇3A†DS_]w 9} cED@D7"'xX!" " 򭀺8XD@Dou$" "[kg߹3p꼚;X'" " pɷ HnwvיƑ)\JgpU:ЄTQ@D@+mٷR*b>0-ԙ{cumOR;fTWmu, " @[| ;XLEqhHl6Ѷ.$d+tpK'_Uږg) uY@RUbn:;>Y.EƳNNՎJ""  btGcDĚd;ѥgu)ܝ4>kHېVOIJ0տnΊY0 UsF}KмŇoKxۣ Gg]?U @D@ ŷ5!gr6v)l$u0;IyZJWFaC%N<Ƭ},^Ŏ,/%޾`9D@D4[pƺHjۦRɍ汞_B[ɛ)Ŵ3y @D@-oRw%OؑGIٌO,Nk)B2c;K]j,&;1_U͢<J3#Y`҈" "toػt,ٻK O8ڏ_nԂqGRoяWq!" @LRXt h, " WP " ݌@GZLjZB9D@Dou nX)" " Z@)CD@D}P}a)D@D@\!S#DS_]_" " @XOW/Ic :CcaD@D@!-KD@D@Ds@չb" " B@D@Ds@չb݅@XАAn#ތ-o:7D@DoU1 " 7#|˛ @D@Mb$Xq @MU2Dpfb15%Z8,  j<-ł"ތNDe-}CرQD?{toI$WKG'PJrfڰळZ홺V%!q_k#g!:eN 1rz%r*daw*3i ߨ ]osA6o-Y'EB1d܋ Uk"Z*yaZJ/#'2>/jL=g3kh TLq(ܟEAVU3bn('CUikUyj X~(P"LΪȷP;?PQy|⻆]]PmaQ}bcc##Vc=t$M6D :giƲwfR=8dޫf_ΚaeÐP {c'TYq@ئ[T}E#b##42;Qj #ă*sdd$*Ӈ@|Z69o5(Hk|;ekR+.,fI* x:EB"EEGg ѽrf dE5s6 zTV(4IT6<R4x{58O*IYk%6TrZi at2!-¬Q+kwn]y8KW K1s? k22TvfDLؓAy?nOBx3 0(Q 35lT_/rC*|c3TUB+黌q zTJx>!s0 \ 1f&-hzG8)4$yO+B].3=0FSU)opS$Q-벪x*U F ,J'ɬχ֨ f_u[t:˯Lg¶֪)s;,1U!<铰pxJy7³g֟=r̷̓OB.< OB#̮kרk Z8v0IȨ}k^[.?޾uO {=YzvY?9P[fs;Xqȟv䗽󇇷|PR. Vk;b|1a8bيzƤMdc bNi'tDy8cpj[T#V)bbl-P?^)ÊfI^?kÌrSPB6^nBdȦ2±(0&QG b8-K@x@MZ9Awnu1TŔb0A*{NR*jM󇇾^? d.{R} $wMk L TxCԲ-D|~#)1hi* 9z8:9#%V^wʘQxKnY7!K}=$xP2SyʎOZmY-LN/T<g(S?L)TO<?TyTU~ TE?}`wJUxebûȡi(g+ߟhH6vOZ'!k]̷p53g̾,] ?p PI4dd =0K#SU ,'8u>Q\Qٻi}/jd34JGEp?xKĬ 7aL4?Bzi2BAR% c4NaB@mQBd%+ Y%nJ̒7b0yQ vyS`*TN@UXW"Q3 ԠolNlԉU2YJo2sFid(A 80qÍ0w裫m'%<^"4C2yF U3>oa|D!$ҿJ}j! ~o ")/ϡZ LZi]+OWWF'3R?-KDyB'!xҎOgI;$w)I]qo ~Q z{[uI3B Bvz'p,"U})-Jg@*VDgߓo_ʴMƍYIsQ4l;qqئXDUB'h2'S3>_ɭCr/?fGSrd'J{'N?e;@^T\&F)F*|t+sB&ޤ kxηl0Kvl[? D>H_}d 9vP?'_Nd% jSv*ϐtyȯ?r }b<+S<0ar~$& ;1%EMUJ=z0`U'SzVzžB'3@`D EE#t/K|&5@|K̐WAEH+__eON8ڬKbXJ'|bOZp'rໆ鮼>d˃o5@77b2KW=;{`~M@6ĞA.<6˥Ic0tǃCME VB~}b%!>/NBU7( Rc 2*%_p q^pP1u(*5)/d ]j ÖȌ)R:Z՛2yݢ y lV[T\KT띕Mv'5-{N?@b8LQW9(68R`>i}ZV1iP B-nA2 -Men c韈@9MܧW=%??W<tG%Sܛ:SwcAOAj,oqx>1wxҊ,LR߸HbCeqAkcEQ j/ʲcꕄ}lmXj2XU9eHUǭ+!:b krDg;ÇcP Rݮݩ<>=cUv> ާ,~8> -˖wos|N7l0h[%%% Y0{;NNƙVs_;ꬢ,+V=8>fPY t*18CxuÎ|~,CSͶW" ͐Tm)kKڬT(k[S@Z]~ݩ m@yosZ·aK(6 2L9 nli~KpC3xAnb4+,'m]G^I,5J?܄$w۔D%$"QJ{}jb0ڬVαxlL wJ,̀lBP,꣪#Gj[l}\P^|\pN:#G&xҾu! 7`0 !T1K?LYAŕY9$>*$J&52 )BF?❵:Ag<ʬQPF>x1P$g8rz'rƺ씠27n7£.o2 -FeO ݅.DfTpIa _<ǾUTTr P<[6fs̻ۗ8Q(1^;[9sR<8-!{N)%c@ds/iSzXjVőɈ4{Sjɞc2C£ "LgNLLDe7*3}7k^,Uo#Q~K`0M^NQΓ:Z\6x),ɒ*ۘ~VRvWF20ך _<#뫕֨ CGZvlhuHUW\MR=x"lEϘ1c4-Tfgwf@+Ѩ<> ;WFxq˦|۽}:ʷ f ^Fuy<^p "1-_Efb15ImPy܆ 3[Z"" " CVpR" "hEVP@D@!@ kBiYjR@W"ÕZsAe+CmiQJW=,j"~`yD"Vٗ|Vi];lhϮެ | ]s!&$WtJ "f?P@5S}b;}B/tl c "5]ͷ6N7b~ ; :ovԼqަo?ݍuH*:{CP'Q; <)3ۤ5U,0h9ȀlTIjD D`Zo^/#;j{7շE/%e^@D[L`̰"I:D$dtf37L}GhrOlN'4*z*OW:hmu>)]-dfN[˽2=$(g$}YwJ$ rҟ`DZ >]x@z׻Nmlqh޹|bL҇iW<-1sR-lܪH0-XZd&D"8%Y 7\u]oNԸg*)]uǹȂ"@t!VON0!!Pyl6?\$OoQ[9nZ|Ebb\me31f6㝂?P;עSuRI VYg2[fZ0qIQGDW7׳prڅ7o2-1'K ڙUnzÅ%N ѹqU8~s4֦B~jE'OAd˾'Q y/&GZGv[Bst\ή$ .?&((q7o.-ա↻ɷWW"_&|>ɎEaOTwiJ}pPU]C%}Ig2lH؞YN!68_]{ͷ޽DD>{9/XE":kXa%Y C:tQ #FGDD e*UZt+N1P,`6RNLQ(ŧp4+jsD/oG-ce bGaߒV2AoQ\^Z?A^D e4XjpLHH.ȑtOqqt?lkH{]l]5{SgICfլbVAZcʥi2laBW}tL~裭Z4tEDI Z0qt2E7.& ?N n[V%]&|">NJ @|-0nEDDEDDݫw?neСbIǰo}|?Y=۷ƁQ);"E9M&&'J,ł5k59PnX1EJ&e=~Iġ$i G+_ Xb`O=t&cc%i렁$yzFЧ#ӓ^/YP(@H) y NRsKR1'FCh9*6HWrԃwҴla" E|l69SS[[YS}TUEEAFEt4z?#X|:Ç'E.66v`قС[/QOl˛W sѾKhCɛ)ɳ >s `ӈ D"U\\-B8g{|cllT||4(61W~/AEo洷HJEYa).l(LIH \yq吀lůM,vMaV D@:ꚓ'ʫ+࠮E r@1싊o} `߂ƽN`m_rjH*Xغ|\#MeW͢EJHarp'2A1 DNG ,u+,\Qgԟ?l4'|==4A`bl`D$bchЛfd=,Ԟ2lm۰Ȣֲ7֣䡞Ɏ""Oz]?W꯹xy"y4GSBZZAF@pڜAopt" Ӡ֫njwAwBy@%}OmnhOC"$XAt؝ O{oNxȷ<$փƷ:ͻK-&`nhĶڬ[5W_-Fᘴ@ϽD?xN'[aWq/#;jFҁ6 Ο*̧C`xむ@N&rI|A'O8pWFVcccM-AG>v}kǷֳsU"މAI'7]^M5.:ByͰWn!dOwϐ޽Bo=agXG*J%ZܪYvt7ߎRg G߲FKm(^-$ܕX-!"'B'qF+j wR~]`aD|prvYl BG>etZ[|lI'd-TvުRY`IdC}U\V؏4ben:o<^AzE][}XLL߿L}"pG} ZoeCx<j]brա]XqpKM]qeKS]%DHsI8Et.8&NeVy7 VtJiv5k59PNTJXTԔܾ5nq>(M*n& @O-L3''9A X|!C}Ku ܺ}˯vpK}+gNTw>xu3^68 dk\̽v4~,[t{|t; $jI@KAX„vB&rݡQ[Iji%;ʄ+% }(l쟞}о }>yqFZE@fU˷9&O6&q.g*";xo$ഉCX67ދcϼci F%[ORe'dK1mFcF|&/W v뤦Q(vfpR(8?L.Y!@eO~ Xp>'VMZp#mn s;yhW~+Ê׿7z'ו/_y?۝I@DW|SK$ЩS / zC@W Т7m&ΟpJ?p?vYG=}Ϙٿ 6 "By۷x`Sm1^-V#ž21medq$9PC&GHY]<<*tz6#"O--&=j o BxQEH%}-:)AlBn|XT-<уPXbV% E*Ȅx,.&D@D@G sBcoO˞3G[+NHH`S! =!M ^.A?~t|-BL&F25CFv"ԝ>y4Xaa`p (,Aitɳ7?|psaQC%s6lĈ'*3l47XJ3o-_`?CsAs+vidԀoAwR4Dvu1,QyUV4ˁ=bB@rQwͧA}Hc5) {O-0 hqS r&c!?KN#*ml#l7%8-0:,Kٖ6{%dCzNW#O߂+'[zs%n$X0tղSiШEf1Yʜc%$.U)U٭zW O!I)8,ȋ-¤!ً|PKK髼‹p^v6Y㸩i9k!)]xVpT R蠥G<{$iHګ+K%9oуBe_$O#F45[]:=/F.u!/8S۱!"xoi1 8yp wԎ̾-_.'v }w1cAIno;?T@kg9*Ό\裏=b0y7J\uꡬiND@𤿼w ^Y&1s<[0;y|jL&RyoY{'L+/i/|(CE Z:Y!rø>M"ڂx(ӈܸI6;~Q)BPzSNtL˃#&md֕Doza_|>l9 |keVA0D8Y}'TwEo[ZTOoo/|)''O >^˹}D!|wt݅ǖ =%D{Q5cA-ǰcriE6y<`o:pC قa+##,[l]@PD@![yI]S0SOD;0j+I-Md'l]-Npo_N V-[Oϻͻo]Wϼ>Oe<ɣӈ`töiVQ@DO-?p<,oOg|ql|"*"7'j1 8ODB\#nD`D@G<95Ԃw}.mn UPs">I|`NgY`mb$-:9vkg߹ ="gxo$ЩS / zC@. g԰a:.KCӢZ]p!| ɷ.d:k[sUoˡ<; |3 [k@w`.ClK_sf I:\f|uϔ|wRNL"X oX=9tWͪmFEL*.%|dϓBaHٷv/A~ka[RҦ.N²҄/~"iS1n_zⱂZYS]5UEt[7j=tsx d[}vs /;rbyCN$ehȓsBm5gfIg? $ľ52جӁd6$Ilpl6\5гz9NǮ WiЭ8Řj?6`>RH͜լ@9L)K'ǎ쪢|3WQJՒiW}8`DO-./v肂 NeG/^r !"tf0M!v)_Œ$֩΃%iFXٺ 3h)I[;-.H 8o,-R 7=]]骏gMבW{glesXr @D$hmrD b ր ^ϟ6++>w_)++sf߲Njl1M1;{ƹqjf ?S>ի `o'>+'lye6V}+eY'JbDU<ɷپZu3ng fav5o%~kE`$ *:b/CDy<ɷ:L>X^w& d澃?!J&\̬L[b>1q]g=BaT2? pbցmROqQooo՛yGXPlMjȥJ>*?LGǤQyx3*+&;8T[V6/]bj{߭% +D'GN-yw67֫#@M,¤!*]S- %} 8-ʌ:mW  @g#I[yqM! Xcu24Lj O--;E >ŶX ڕuPcqD@|O--; 11pLY0ScB+ՇnQ[9nڰگ\2k,WY@@Aމxn8!!=>h[B!;DcTLݲj 3dwr摕Uƞ}':|GDpׂ4KD yڸn>rۧ_;޷'^d漘ؓ ~!nC֓WuE!N#zz"DԂݦq`9E)A=Xomn4]:- oK*%O"VC)q5N"*cTL)7[ t` >VWtv`}bf| 3h_ԧ$mUp"0q%i*j]%?I,^^4], p6nT^X43>=)U0vUe;]"`4Xj+]WFڻajd}.쉡|j^>,[Me.v=wX@D@#[8$ޢ=P+&,ڱK{ډ/NsԿNk%L.Z H!a X(JK @35?Yn6/KMMKP`WVUE.G@LQѰEFF`a8'Ld"$վc˝iWdfsv d:QQB&[{,s.ݵHd|l ""`xou]igVGB.0^ (99ӃkӸPIn]pf355'NUUT4 | 0MX40S Nh,7ң%.1ǂ "I]"7Rf)1.ndR!thn-^[2.,7e3'=6 kNVT(,ʆ:='dfr9 lZN%dCjzq}֮1acWNPz D@Ooy5|v}=}3UZ_`aoz0mwR LCVwԯO(!"qs%𤷷o9= QUqJԏ>l/"zVޢMt}"DL%Lt!zG|Z'JN/9u(tͷX: -[1n}?}ǃxb(Ě^86zT? \Lgcw#w6)vbDp'Dxl`N3+OԠ:AHgkra^=fI}b;tc'],> O֍||wouم 7S*sl"hCO8iǂ[?aK(8AH}pܜ-^u5.iDjMUQޥ))KAUɖ$y dX^)zm51 ue~L7 smᅣCD|wo%}wMaO _?!~P¨$4ᒝԲus] )mp]suMh+gb(u@w]$1f:ǰ@g[pZeb8Ġq!MÃ-"'Fk#dZp!i r'=Y.`v3V8qw;p)jƠq1[0"Lwڷ<5:Tڼ}5SG@dE~z&o[1b>ʽe[(b#@B|STN]߁{ru؎&h3BN]6P\jXtXۇ/ _!uQx☣$49AӀ+cD%ꍆQ@xozkwj߼&C@-w*s7^.m:vؘŹtr99Նص`1&>aZc܈4t1.Mb!~'?НTbqL,'Wh {s Ajjli@z.`ي!DFF`_o84&طJ21,HXHNuBx@D@ |ȞW{贌M"oI?]KnKmmxZO0EazIydr%槭M/׮^IYeL@u[*UF%H\0nIѰ01X&ɪ^)]$Iiľ}hijlnP˰/K{6{ɯZ}ע =}Ӄ?n⦦06m%a땈$ Vqs%96*\ uSUB5 %-™C=c3_?sWBf=m>yרg :X[^*uĩ%lguelsW`Tn*͕y [ >6֩3"ZoTsPWTI["}ke$xi[Jg&+.Qyo=Dy #;-4c͜Ī71eK+}W*оe9Q| \Iy\^bg UNo9%[T &"Ogl^w& 7%JRKg1XXmcD@Ieng7" @{|b{23Kps>A DF2߾ՍWF#ž6<DթΫkF@T-'֘<ɷw}@LQ *.3Ci'j|OD8jf< vR֛W1Ȏgげ^@`']Ѝ|"ʓtaOL"3Ίwکs&SFGpa;XgL. /I;2"xDL7oĸÝ֜w4/~z`7D 6-4BlW{XEnUȗI%$,yr+W,5#p٪Rvtղ8DGK{ "IVfI'8%{\C /)R//Ƒ'qzYIii,7})찿W%jS࿷A7L FԻVKWKcSݸn _FiD@|O--X2 ,@&7=]]τGx{XWlԸ;**ȤTvMg99E/1v߫P:.*)vRQ),2755b87.{bCN"Ph+7WcCD{$r׾GDDEDD<ѽz39T*s֡CŰ^} %OzӓIBB)և!YKq8jG=S XHi F&QmflDoJ(ݚ.tz8D@O-w[f̙Zj:UUQQzd4{ a`X"X.KJo*K+(wAM w?Kn0|$gSEA*wFl 8nD<ɷܵoUל>Q#ʆ:4ȁŰ/**[`܋{q`CT_y0\[%wP2wً|ZUtXWInjӲn!5R4 دggI1*jb" ʷ,nģwSK^65vv,؃M 8XM C;W991;y"D% ;&ԉRw۾|wAHBڴC \a] 75-55m*PDQ@@F@p,_>lPdW{?-{vδ6 ["9 pa3''9w_f5_ (?YNۼR^.8N.%l}\E<=O;+KKr*Wrwɒܬ{,B&fgXW"*ǺmY҂T"7S=1Dﴆ퀽'Vb | lLbf4"}C W~tuof@6LWO5ߖo߲[gA߲&]GH=ɠ c[,|K&acm|{x;n |-L-a!ۼyIMضX@7"|5.$toC=$lW/j֚7_d5+,!۷NE-Im򤿼[JmnH4 "xxU;~^HFT^PM.EMbe64: @|AcBi[~%Eo.9:x@M SP}yh4iotݘd),(lۖR25B" 13[8$'vgpdjm ;s";iӭDLlma=fWQw4>eT^-ApgX<,^]j' _ǡ嵸a9Z Wq/#;j_[Po/>f+{u[ L)„ [|˓ZܰBj\l;yٱED$wz8FȄ@WH#>>!vc͝ V @"Il`f35Ԧuh*~»X|  ,[]<LP$E.GQr6m:rk77c[A:'`26վ}D `$r׾U_W]s u5 u.7ȁŰ/**ط`-``j5'zA^EKFsW9U X̯a0!l4B[0D-[$G%oq=HR5w*LX9" ݊''N(9ud[?+k Xp,fq0-|wN'W?/vmkS?.jKO:ݼ$:7ߺi+Kw:hD -ݟ^MDru@q;}( i-dFv,5do)ݲo?B,xZC`"h2n(;wƇ=BD[O'j#qyI]S0SOD;0j+I-Md'l]-1,yD]>U+__-~i/|dâb$`wGyD@4!@Fп޲?-{v4M"ap>b!҈"6XMʾ$k|ƾ@mFD@om]jm&-f=(Ѝ}3gpvDwF_[4>prӷ{Vh/v!,&@0Ǭ[7 1D ',X"нh׷7!tȇSz [gh'={LM"/w,~к$Ytbӟ>P69{H7@Y?c AsSwMd:lh-D-I9lq8&,F[Z<"-iCMGȶ28w!OuDQ{r(s״9 ϕ*8˺k.vN?cpsub;VtQc ϭ&N86*"|×Ν7{g`&ƺt^w=r)Ileɷ>s 5p/#$&,ɭ\ԌeTjYa˯?4Zf(# @M<Αl0&2b5Yf-1eblź?uL ޥ))KQ<>kC$wzfIz86M 5A{X9|OLFJ+ғX+Ԏ%) 6lXVLf ,hm|5Uv3Vyyyt ۮ~?Zvr DOشFSl ߢa2Ёn^vZH賣~+9t5RL |[jؽO8KyhQlD#c3VfN80kaNzHAc,[FnxA/pX1dYǺ6:`WL2 CUe%g|W8<ɷ!@&7=]݆sCB #G}|<=ڰa]$XrORl Q!'cKVAf|"fR^aJ%\G7|Hh{n/4c0m[j_?%cIBV pNO --_Jjo J!\-lwҋAese|z 5kjO>bٓ a26zr =YYG ^>4s b9OLJ..Y7gŬ,^~Zw288AiD5<ı\ZӐ&72NLwdA&se>Tƪ~曚^{oi;[QlEDDEDDCfddt ΫRyAn:tJckoA@~࡯U4.J'H!X(Pj8x$* I PQ?SrCq#h%gű1!NpYs8v9%vNr*ݲW_45ŶVrDw >[M;y䩪u^O_Mt?L4UOY>NNMke rMIV)ʁ(({/ZM%gˎl{؀9)o(κ8D&&'J.( /UlkL Y RŇyoi;[ l>sڴNUUT4 \WOx1|x,KWQa]E"y>amG8jnje_.w~Vڴ3̱}Tv>cns(08,9oHȖ{@=[m*6[Zd~7W^_%ܾ:4uAB}CWog-}c^Cw/fj˾R HOwpk>穘d `LcWf I}dE Jᠮŵ0ȁŰ/**ط`-``j5i{$0%O`mcsn% r `2~̱UtXLdnuHl=HHl9&.f⦦4ߩbkkħ 5Зz{[8g윞=l+^GqS]' ;K1sQŎd-SYj7w|)wL"5a V(.u{*]0@Һ9*Q)mcFQTI}tS'JN/ٖ2o; YܦL!_ȅ$Nt%da&{Qldd<^Qa.dP덫I8Vn_Y,B@Ms[ȷ_&9Ul{lY/|o(_|`24"'[k6} g[2?~ɺ9l]pz֒bPã-FYPOL)O-G0gW|1l"szo4^* ORqEϱ*3 4 JQܠ\Ɠ}K;8[NC?\=fIj/ ^@FO%x0L+tc0~"xBퟞ%L)z^.nS!qcBS{eOh@B,lgW(XBCA|g d뚋ԱSV0'] _#ӈ)LR~hM:?iGmUk'[0^ UNo9%[`T`{XCbdۮz#1(6a@|1>ɡJ{l, [^Y G 8Zl| ,HJ-\oiGgX>~4*?C۲!璘DdӉO@M/#>9g;V}`Vܵԯ&&ni/s ,=Ƞ}a"{]ݯg^9<2Wn!<97n+߹ i+9N :t&}Ņl>3u\0՛y2ȁX-Rd}yP}XpkhT^XeAZ Hտ :kɑȠ/ +[' ]w!*$/}uMz%[gMpCYT`p𮟏I] Ƒ8GbZ s r}ItԾ]Oϻͻo]Wϼ>Oe<ɣ2""0؛;pFuepV=8εbܙF]΋(>s0P)_6|:aGj>J[ZO?y{x҅9r[_yrB˖v8y#e˨3+>i27AN \2 3I6α*ZORh7CŦ}V+@M<βV~%Mej05Vk  t&[Z[9@D`ӷ4W ׶||~>9 g 7O 2J wg|(1-0 H3w1;ʚ%sNr|Mc$^\YH鬬\;hԱqiDlq0ۂ=+-FEC%+" / ^3,ʷtϸpjo=tШp[/1t+l8w" >ރU.i5Oolln1措@FWlܨÔo|!wtAUQ l{SgŇo'!wg/MIY9#X%%|Uђ$\~\nԂ{|@u+.lّ-L `NӺc>^>4s Ċ'omr搔]2+^w '}Za嘹{Z[2)eqx_z?/uXpkGo '`ǰ*D@q wdnvSUg< dbiRI0FI@+}gsά@y`]I~8Z- wi 4 xNNMP'6+iĎ%?¼ jA|K}kw9K>brU%G~Ivٰps#G~o#ߵʈ5" /%M]PUۙ}K j}jI"#пwċL8[;~,O#rfӷpdl SM&4~ޥgNHh J[ p(ˢD|VEڂ‡ã|ݾ%,('Zl9^x]8j}#iO/_e_ 0]BO-#NFп}N4}y[%ntoVXXo۲#GzR_͛wP S,D<lCrr PKqo8z4M%ˬ&{Yv~9w귗[x˟+!4~|`1@xًIV0'] _#ӈ&PpڧNINzQTg4Xj+] 3::ٳ 0|H^ȟ9aiii wRHajTJDעfR&V\>.HRE=$m-^)$_ȲM&L2XdgXDpS|3.\'GV0Vor6- Q{ߒ$SDDTDD4lѽz3=3ppܹ㥥%o⋢!@2O@]VJ%U gUֵv;( ̅͘)_~;~1rg;h"e6Ϝ>qh#_,`=/3ꖛ<Ա{EEoW$+f_~VS]mfb%SN&ƹƖٮE񵫧o쌲.L" "xꚓ'ʫ+࠮5558Ш3fDyo߽/Sc=pݟ~PC|>](N\a:`U^d$h+ ,`6ItU&OFQ; " @"uZ'JN/9u(t"##Gy1/ʱ#5--_^o]G/|t^X" uy<~hcJ.-::l)9Ԋ7wQsq !jV2zL" "x~q~z̰\tPW^zo_0:]kr5n>c*eLXK 'v ؈~"@ Х'r5قAWzr%>(Cd NR&Qy)"Х`@.C%z`>QK3Ne.ekcgm{WǶ w{WPX " QUӽDaԀ2" "t1G}2Zq^=C{?a߱Xv1**R+v"Ņ @D@@-7=)[9n =9_OՑsgșd C wʵj'a%" "t} : 4zHp0?K7sMhk5D byD@Dp@-l$llnjh*AL]'?s@:d44ʌ^aHUV,6ȂB2OKWKc+$R" "[Fo8{NږGʒ+rA?R]CJʪc#_|o}C te|W^aJT \sikZ1<$"[f̙ʚ**J>Ţz_Uuz-~-}ZI*v%᣿K/u[kȀ~gýCB.lWrf< " m#dkWd{A5tӏy_rEx}/Ƕ]7J o#Н|dE28lk Ψ3t5y MD i8wG˖pجčLK_Q@3V1]MsT¢QZ$ G!>yA:$_DNݽ (" <ӑ,Yeʰ :_,+F)0()WjsԒK]H>?EĂU%eu_AJ.f kh;^yHуW fvt)a" 66Uo/xc}VKc4)/?09Tfd}5<؄~zaBnEҞ|otaBDKłAЍ4BP Wҩr< !28'RaBAf@_EG?ڴUnYy\wOHc^; n8 " "|oioe_w5W~scZnHҥo_{/s gkC|[Z[K{Qذ]KxE}/J<"iiW{ B.\3Pb-"  |K}|5d3MGnHocN;x9S­%a " !|K}+fw-DN/k |e " ~o--~R]9˷u=udib47 DΟ"[BN\afY,G(-Jhx8'7 @Dhͷطl*.2`' Lݩ> ~vo49P2KEj6^nAžENyB"X̠9-Ȗ.ab&s߯qvDH0yU|zȷd'3Fep2Ӭ?4<·Z{e"BsD| ^^`0AU[^#Y!C{_'ِaDn-ߞO}"߼J_^F̦, Wwu>ՑlAl.1;{#7R F -~Mr^1gH' "F U}ڊ#tۭnF@8@^:d]c$– j;6^T[[%BuW[WK9twƐ#Eϛ'CU/ߪ+poݻWgt?L TNDp}M^C\t7@Ne!xd:ޢ%Z }qQ v|K}y-7ѽ6waΌH7Vۮx1Uu``n4"~K9Zwd/šwk. C(OFǺqWfQ[[N,ׯᄍ)$$D3J(DF7*OdT^ѡaQa!:]0ߺs":܄c3;̡"$k[`0|` 8Xqm+%CpdOgw.\xl[T(WI,ěuEQE65]u6r˾IbЩ:ovԼqަo?ݍuH%],#Ƅxɖ#ߚ {.c}70׺9+^_.{L6&h9yc$Gd05.EȂLghI&j.M@GP[Q+9+7\ *C1\f;0G-X@vH)ZQY).7 _4e>ˇ/5\͠":z*KzΉCZYQA pݻq|K}l6hӮWmeqYEC 3a}zBfG*(:|K(5l9oMbo 9YAL9SSZࡒ R~xԴ9#ʌf3_:E9DՐ@@1"-^Y;J"q$[Jw2k59PNY#2# CoRPRWɋ¹Uֺ_z"+]?[6uwmž~/icN^}/Ij=r#Ie>?tMZ-&"%Yg&l1,f"]8?0!^:z-G!:=qߚO4Brb#Ny`g17HMq 4NT,[0|gL3'vF|б'on־/2%pQy@[[sKX.o--w]=(|ZlU.饋J"ITؾ%i4qtujJ5nA` FŬ32fK4u-@$Jihr[8J-dˑmVfvNCIga1dՊ3&Ē!Sf͟ [EUbRl6Emu*q ~vdYb\8"c3ҊYsQ`][^IDɋЭv[+]qkṗ?Pokx;((yB36bj>e 9LFDkxX>>}‚r/iRa`%0eH؀`czM-v-քpW XvfW8t%&;k7gѩQ}c|2s2u#+ೇ7E>IG8*=~ 7{m9[V /r0a.tX[|w[pqTT)wLpݻ4[B4 !R3R+*JOmZ\btÅ&!<{ٿ,[h QL xcC=NmWD7L"*tU_5*|~~-[.vBxwwӈ 3o0Wc6Ҳ~℥۾62 Ѝ"c N3[Z -[*P$C(E#teG)WI-7znB~<ȷt¿V! ߈ddoih7u a681| [lm;{m*TyW۷ҋD!UE,Jb9ֵ$U} Yg +%q<$5O|Kˍ2.BD pojm?D5`h0)Aes6DKL'F,E l9` Zf ݞȠl߲ܲ xC%D _vuKc%/Ce]ը<;EBFua|#lS~qjʛu4٦{n! -~>ӽ AIlS$gzfA89˛X7: ;k8n6~t C7cY ogf$f$3?=l- -姹lnA3d9X27LgMpl6 TI us|sdkDpDUf2M ~FLFHBYYVdl*6|@B&Q 9&@jTК.c U/2 ; bttcF`Z@Y,J)́h[ _"&;۲Gꀮ~rK+IQ=g#`)D etR*R)au[ϼF~($'ˡeفN@ zYvD}9Flv7aADh5VCc-RĬwCѕ=VЬl[`FWNB}Kk .)eXe_^"tz>:`"*ȷP9#.~ׇ coSI|+ǜՒ+%DMzFND8~^Hy|/6e9,'GA OA:XG#0LPP(< ׄc"o3d lR1Gɶ*9U |Q@: A粭VOTiƊ!PSUԅ5*rk>&[D~(3<9Lё 6oX9ԃ<,!"^?cp_DxO -Zˡ"xD[rH,:pzRU}qxt$2)v svNNɹ6r J!vq юMaBX"LS!ӑlyU^!po aQ8#"pRP2v^pΕQQMSJŭJnڄn0brvZ<2mVkD#rr!˪cU%*$A3vZ <Ђ!Š1]ӌ0∀#0)M?GD |KM;2ա܇.ٞ'!.s"*k|?A]8GS!'1ڀrYhx)CWJSybX Su:N"-܊qb|P]R Bodr6uchD@ |3A8Ϲ=\!$xcaՁ5JX)IX" !|Ya"mZf:=LapR1!* Vp߂αVD29'jfyM XO"BJ9%D;_ݗ8Eb+ӭcuouDB4-+,G:G%G TE8a &1"Ȝ8͸N^jD)I2nL9Fd~EGG"_Юr"IZ bk(e%N0F(8Nh\V2",T{݅]BD@8{ %$ եtLTfÌQJ%udfc\W)˜鏠h~0sMؑ{^LVݾ̩F-{nF゜Meȶ+QYA] ye0]0҈" "&b& J <STdہPG%ƽb@BFrĤAJ{UVlڬ8c*~6#2C(X 5j]ڤ > @0n}8+s< j9u>D__Î!" ZTw~}jX@مb|EؗHNV$6 KrbR,:ljb x 1*Nt!Ilac-_7K&=1*S,C:WҊ=a1*=*$",#73" "h[+ rTuLd<"MÊQ}}R@"e>1om> ڳOuu5{I[tXs{y񣻇 -_s :)/Qܪ~VU?{ -sk%.i-Be^ ̧X_8o)Ψ6TPv4fUpiQ̧hTs޲IZz8CVei^q$&ZZ4)#GO<ȷ`[Ι#{>{>(Ԑe4b޻=ydɽ/'ٿ o/Ĭ/*XR^[U[u$E_㔘c >1&{i;4%'1&٤!uc3^̫7e;@>)Dko+&&iAX" ׇŶcD@|Ka<_$[xww,YC^$r`z|b%KϜbk_&?JF? \E*\@I5L )AK,Bf/wBu tdZg.V/všn'ÇG< lWoLb xUթݔyz;ʷJJJdĹ9Vm_jwowΞTGY}#EqVU~,*W{Md(j/N`r*&"@W |]֞`Y_$g9[ba!c6Οje\{,O0+Pn 8敽w+Q qƷ 2u)9`F%; 󔿼VueW=`XH|00fF&[a$jc6nobg,'$2/g&j˥L-!6%Q0|(wDX(*,^+]h3n=2>ld?dq"nG| M>OK7Pd" }dw)zz> v:P  +s*/I}VU0?? )*]uc|"o`\[nbj wAH%xC| pWT89'_F+NxbC2pۋ9&NNM9P^k 7Dpڱw]Ym 6dLOyqSR o,վUTTvR y7U ^X]N3SwRrW)f\+F*fR,K*+޲~:m/0јMm:nDE{A!Nxu#N"LѾ_蓧[Yڷ^X/}D--]'VI^rOLyyw Q`R[ >N=eʷo3\5r` gOp&"fԛLZwjU LEd~dKԣ`7Z%RAgTކᵦ3fZ&cƌA՝$_nOfe; `÷G.l րDT(D@;{y}CGO<z)Ciwg>މ h;Hkyydƹq't}˓Ǻ.A $b̖kXJϏ!lĊyhuю[#kW|tس)_^ DP]˳ qG:Σ_]w " ]wɬĘcZDލe,8ϯN]dk. e1/; 1k|<2b?) s:AR}K')ž.>=)+Ax 9'zA,OZ9w#^`+%UE0] :j?q #@OwBb>Vllkɿ!ȷھ( x:"O@G<|pe!1yn|24o{q<` @@!]/`DeFi*+q7me{:g=?l'Ȟ[Ogրԝ>!IF8vaDD@amu >݇ Etsn3uSgl0H&A1HtIñI\2rPhiEy\0o6tɨ4*ڷ\_ ?*yp۾%xGQ;js XMJw՞[`ߺ߷{X9k׆D\5|V킜oPjo1Vѵ2%/κfol6>% o_?F,Aˈ"`[|˓&[_۞ӇXn" qho\U-Vn +ñRo_]݂Q-d` t-D{59# @DB`]:ګ; |3 ]7t}py-'=ZyͼL\a: F&uriۗwn0I`j1L@,b$F] P.PK4]j " "q:ʷv/Aa\~.SC[ $hP 0`gl(pj-avn%<_ՀAd" gK-9˅ mjξX?" @(߂f˒ ñllnjpMFO]UKXdShd}Hdmpb"z"'ҙV[ḤSff'*,`ơUrEMY+#^ z df};z?EHmPuwljuaS#6-H: /XE":kX'FD@:h`: gOWWpHƨNRK,54&lKS-g-7)$8qGJ̓ET~RQiE`CNdh6/h:YX}NAf|"TIyJ)-k286N4bNj W 弟> NF*7a\I.INvXC'-0he˔r9/&D6%D>=yoe+""*""Zջ{#r)cyb%jb%FNUY N[tHd`ZbWFnĈ0Vr6]}I1(l(SzrJJXOϣaP sEI'qhڱiS&Uء>8֣4awa忦]ܔDE?-{xq~uJsڴNUUT4 yŢz?KMQIei8ݚa_)Ξ>[V"×r%fRJK-h&5DĪq*IvR,jKK urn5#^.E>X4"tE0@MC@BϺ7d@I2<&DP*O՘xhGoݘ+ &㿾7~l\su۷NQ\C=-Ɔ3斦]Sכ~5;̲I>4{({pM DRUcJDZV^m%}Z= OzӠ*XTZ n)x!$%wl6{&ds;>.3<~}>%!Lz:Xj Y_S!~$m17VRY@J0nKZ޻TiF;we-JK+Kfkg֟>蝞`O;w!*$xo?A7'gpNJk]17 H :܌N[wi}7&:>339b=79zL_u/6=-qVL~֞YQXJ/CHEUQ R Rp.顳Wֲ)7et;ז&)I* BzKxwz&X-`5Ifzk Wf-#z"z9xڇAQm/V1So-M+|k&ffjؼ3LA{kOw)l/AmnT9UZE7v. 2Yzmɉ,fxI0"XE5c5Q^z["b$[CJV,8n-".›ϾwOy۞ܳ?eY}@U(қ fʃoyH|S/Ap%$$GW.jR%OqCH $0 UoCԳm-v5^zϤ}} 4>˥犌4/ ~E!~}i[֠_3 -22ۏMBH $0}b-ܐ@$w>|UVb)߸)VfavgB%gW?r 6 $PO#ܿEsA"~b+â0/o&9Yf3_l=d_a uNyFcʏZt<#Ѿ&~ǜʆ86B@<˫) ѾloiÿJY=nH DLx@!蝡2P \2x'hLf[-icCr#zU>gx/+BW_ GV$yJAzwp͘mC+:fp%\ MFhPґ7Q!&AcP~c:җ+ltzK7>zV`QzApigqrң@xUdQ2RFLN2y)ӓ'OKJ:iRJB䄄IVk՚lLVFcH@g̷ȧn)!{H5*6ݟJR!HS*?']%xwŭS1K#ONv%*J5D< nnU#C͖ "T)̅t,|!B`@iip;+S*GO[|+n!i$?@X/4 ` yrhs;uv;7-Ҧ \QvmQf32tN[&JZ7Gz>YdeP*_ -(YA$MwHh#c*~fq)SN(eTss (.Vaݒ~n./(vE3JIJIvn(lᇤ:WgdU.:!1C`06~(˰y}1ĿEMGߩcIgdMOL+uz&)} VOz> tъ}yyp`AX'6 ˉSCCKUUzBUsՕpp[aiTҲPKKij>6qP8<9>ȲJ;bkd7ܿ|PE2Gqų/f@ bun/ED5IU Mi% kKn"T釣H*EPа1lW"`FB!30=$H\lh  0]mZ&G@r°t\}$>͘("509;`jx3Aї:E>yYqu[7[ U1;1,bgƢ? B/ ~l [I&/ͯ<`[aKUS`ߺkG hюySZXQ`FLNV_P`aͧ-l-l@] G 5XE:¨ls%(nMGi%L(M)Wͩg`k JaB &0/YeE!jzq_w*[VWGKeGKyhuFg(*< XfXzhطo U0fM5E$Q` 0R5Tyt@)).=*&Ѫ\bT~r^W v<8Xpr*FP u B$sASW j *-(4%+C=,L'xd>l%èf5JaJGQk@V;/776>@"!V W.;]ޱ+UI|rÚp,)8@'/QU$b}dmE}P*0U.ejlF2(5=PJ :RcpCH $$0&sЅP@x? $!0&@[՟z?vřjAH $1tڷWVo<_Yb̞Mo=[?<0?P/QU{Qtq*g 0xF/o GH 4ˁ:zІ%SmIӻ'_Vf`:|w7m Feg`Rk‡ض &tUV(',hn4@"oYgO|"[w !4< !7fE$kߧ֨ǟ}vEw V|ˋf\kI^WVww[j~MjLu/wҕNOvUQo 0[X)l[mE5`zKGYaA Ԁh'QAHfK6\NGr{Mɩ>rז`,XK"H!;({ K5VXJWa씅Yx /K,|=A[`LH0c7$@ch-G7/ =gLbfIS-IYYKl ) 5z\NYtyI;bt JQSZXƔ( 1dzI:ҨP,gH e5nBiJ٬}2M4 |M:|Z:x$@$@h49))Brri>zXTE$#=}yvjXbL Ħ+y `Gl g+>4]X5Do?GٗrmqJc`ї@&tZyaY?%[A [=I`@HFӾ \imks4679 ?zXT~ }>AQ,[ +PS7) Yo !FH %0zB- $0dX|$ $~e zS n%z Lbٌ̺y-Qu2ˇo<}yt/r[MWC۳QX.ׂw[uo XE*lf#+#a#p7P:GUɚ֓OUZrcH Q[+{Ou7kԣ&CfV>RhwA#g6XbbʌW.ż%IAF&=oY D]΍^GvM{N>Y`u3a'#ѹJ[GnqU[=>VbСlQ`Zۚ W3h\,; g`a#ÔM0焿y@ Uo1An㒀 z >0}u($jdR&u+c@r[,q|tzU+u[&zRΖb2$%`lt{#d:}EbJO9U0n6 R ;Ve ss!,ִNl =-22c뭁ڷ??ngs_7^{3o*ncL$(`EEBP@ca'Skɚ=dւw=~HAѹn%o$̒[<{P.lu.ٵ j1xu*y:1#ykgᝍ^ nOOHNYV3$sBt]`Mi_8a9mőPc:Ϙ󗓽S]DXZ ? G^VA%Ë&ѻ/w7\mR$zYTf qXg_t\nwӮaE mֻa Cevթs#,مuq/k3q&\/7HbL>_#/oHVZ?sffs V4O~w͵׬n {zZ]f|DlBG_ PoZPRPO_Yd V<[Lo}qk ®_ k[d%{[DK4ynot?H 'B:ZZ/;Zyhu:b BaW6fbb T=]޾@}lkAl*+)"HG෯*+1Քoܔ%!oNcU[RAlK+TL@H` yKX|D[%'`\1$-xDoؒ@lM[u[+>!͗[w.sY*y[$DžX_{pO___WUڗf."$O?[V.֜h'?xYӦ^o ,vw_xee$Kg~:w=s(0h&AD]"ث zu x"qt<,c#H BߧOlܭƳo)߸kO=U?E=K,[)UO<^bk|7H $F[jL=s\hC /IsoodBM[|?Q?+L9n Dn27;&z &zK?p SC^?Ѱq9H $8&`[1q|!kH $%`lDS>V6n{8S !&FH $JzK}({uoUI]߼+Ii9ms|=gWZ7gNV?vN^G7EL蓀JB]:toDdGywZ" aajO+5D͖l \%S}\S-&Y,iyV;87|t9$ivV;yzvפּ=CH 6B frD]] #gkE"U$C-G7/\qu8c^uҤ뤬%^ׅΎf=.,0D DӓmZA(-Hw%ʾ?]iZKk l F ۗ:'ܱ*[6e9^*LC ٷK#gR,B8: A|TV4#ò,=(VzH#Mxa@ Roe+)irRR HNN:-02E(ZK$˳W`XMb"2 >rk(+SEˇtujkMPyb4d`D|e'CHK-mvGK4մ6'u.lߩhĭ'!{޲rvDW]:#,?qf*$2!b#Ro+WZڈMh } <{cQE+^F@H @l$}k %U_X<@꼇]R}W@' m[v?veM~.k̾5 Rds\"'ʕxr; g`a#eyUpMB"Ґh*?rs"^73C꭮ˎFV#_P\'$-Uɥa߲- aLpvx], qHJ?rM^HW 7!DE῾̾EJ ¼Gǫ^]ǹen.*v!:v [-͍͗Oy[~\X )~\nbKi+.}5|BcNDR8Ε7-y^t:23M 7:烺;> Ҿ) ߆Oٷ]տ~bJjۿ7g}gGY?}̦Ce/ $'`lsD5ȞgOdՖG˃CH $c-qp H $A [o ¾eFH $K5 Uڏ~7[*O6/yo^tReq/xj9ΗOW}/̗ןS"AȀ鼐FGG/e^'$, GU]]]Kk9C.0moTglX VXx4[xW $0[OՌeWŔښeejkOed\eJL XBXD6\zcH $Mxz냪 ҬIi~#W۞˫W3'hoxBwKF/X=h $@![vNCyW =XWU6[)ru: lJNsO=d0'[NpӴVI{\-ΘIZRz]:;j.%de5B9_g_^9UdrI*Qfv>9I5lӐ\fd+'" Y1?^ra;aAI ,4LH mƛ/3u?L&[p?5^d^W0iu {~1zK- EO SzĮˎF2Av:ZX|>At1L ZLl+rJaCYI鎍yznEktUO5 z4H $ `[-͍͗Oy[~\| )~\nbK5me!*(3y[קܢSȈ4$c`JΗl@H =7 li~Xl[s|򃷜=ey?mz-bw\.ў+M/]y0Q»a x~8&x"*M[b .+/.tS3ZZD$"\t[^ $@#`DN)koކߜSyng 3{,11Qg!zٷCo zaa:$0 8JġfMHOȥ3ľ{$0Lݔրf@?YiiKKGH`"{ҴP(<&&+@Q۷#$N7մP|W $`[o`;0<:wh7z~tRlS `eiMb[x%'tqCSv bIӠ}7 v`L0}S>V6n{8S 猩KAHʟ^Odʟ8Z_K?iy}$Tr}sۙd1O,#yjQe!e ljtFX8Oj4ҨH` 0ir6:^[U;u7|e3{RZ7@_nc|gc2aӐ0xd8qSi˳rP}h5t15T6qJxn3So`͂xQJq…3K?ꍏHki4 XFf CpaCxz o>5sh-_ͨ\xEPL9ZVvTFu_!{^fڬ4{aK0&[7n>ePln g^8/{w疭I;@5&el5٩-M'q9˿zպ9szˍ/tw`>ca06ٚcash`y\W!'/`~_Uw!CX9[?XM87~,0 H,{p$ZmdSt$'.ٔ-皝z|m 6bf;r>} 9v IANZg,&$F@=KsyvkYG\)n(uӞOU}Kv0Afݴ|HbByUjL(6:"l2j.6nǂ胀ɣ]Rncgꗗ_ducߺgp]"`aEjuk`EzjA.I^)HFVRd эlw?=`~d~Vr|z>Ր-l%%M299etî+{cQ) Ibzբ(X,V)`J⇘#*le>?-/:Zr 9+er֥5 F^ $@C&`H \imksBڀ@/]/'h55 GIDATBb+ v"l@H 0hihi$MNGJ &`O` Fɥa+PXf_SUccJY~$@H  [/՟(}< $~e zS n%z ĖVFo=P\aJ|޾z~HfmEBgɐ"Θ}!$02͗?[V.֜kq򃷜=ey?mz-W.^rYBPD{sc8ڎ4Bgp'ƔH`|5;r죏i[xOxNrf}MY@H tƑ=~wɪ-HKKO S"$@H`p۷Gs!$@H`a:2, $@rd@c뭁ڷ??ngs_7^{3)n㎀Ġ(7vht h/:mڑy< tڷWVo<_Yb̞Mo=[?<0?Y_.M"V_v !OƦ +AH`p61ÕzK}C,ojF+bJmѲC22f 2f%\'2LD&07#&76Ndw$0 8[ax0oռhnƵuouw&Iפ=^b{g{/]_Qر mG `(e*ZWZJ[GH@M`@XƋ˰ +bDH`Bed}y:eXVz [)Vt7H^I$, ,\-\6$XioQz ԂR 谚$Rbder&Өtd"0$12xbb\EuҤ뤬%^ׅΎf=.,T 6]^k|NP"̧| bjvdUZK"-q|waא@H H[lVߟh, $/^-b5,"#婢!F( Xݫvƾ Dl}@H L$[̾g .aĠO  &BN!`̐ٷȶO-b6 5|Dr"XW$@H@!`lD_P\'['ɥa߲/)-)HL ٱ(0sm!w@H $0 [o陿%DxlA/|$MɃ%`ⴕQ?o_yNx s}ŕ|@dbJYӂz0xٷr嘔^.#$طV]g{TֶQ,.lW=]xu{I-`M`H 0!5H=Aіpw>FG=Z8G1 SQ= Xp4P}4u(Xan!lṼc-=-<%5u𛳾q3#Սv>rf}%&&EQ[zw|$({,/ZZLkN΋?E*IŇg6 ?1gh8a!mNM3v8gط"Z<]}'w)AEFXbnL^CzT[e`"2xT ^-o15.ExK(YZR @]@_^[, 2)|h1{ocÆ`pA"$0lyy!U ff=pNpbf'V>`k2o GVҳ35ʎlX $!Фһ0&=ȅB&4#GK#JF^ul> gMs;ewpSGpi"и-kn;' 6PmlVT~緿܊mogSܐ@\|l̙+uh0b-"\yȅdZ K4sr zoSA1 m },Y(IM{,:q: l,4؆j`: dJXi3=$#z+N)W:o9e*ɝߺy|=)-z/~x`>4 f~-:&>5a)H mYz+ȹV+Sb]B.;,Oj- 4Y!Kv q:6@TU6rnf)r{xɤ# jSG'k˯_)"=&q7y?T p kt6 [fdG]ݣfٷ]G;6X>ՌeWŔښeejkOed\eJL.j N@S2)"wP{ޢs(p !؅0evPlvS/- ".-E:8ȶ٦ MCOGdX|~) )_A8'PnK2uz7K`@cd)һZ:.Ư٭x#=lnL͸֒8$)=ԙ^r_ll+;7CM8-:fȕpcw/6!mSTb0et6>~ӡTO>)>X$3/6ߧAw2wP6|Ͼ$;<8,o~0bD͖l \%S}\S-&Y,1FUA*qGt jJvf#G#J{BH`7=_̔qKU"L̃X<*0}t2qu~l4i:)+k-!uAi1K&ZV jv{ Jk6ҘE{ILhEX$e]ZT,\d*mT9VQǡԇ[F6:N^/%!Ckz !X&'%@gSNKrk8[)ũaʣ K )*4k4ڂ|$*mW #$@F$`H \imk#6&6S@/]/'h5Bb+ vg+SKZ ZPRsF4#Af$@H?[]--q t:]]z J>+|@aj~"4[E9|/54<ٱ1E, @H 0joilnoT-p؇-_0OQr-[ &N[uWE)«WQ[w.jr}W(4>`$@H@?[TPrټͷDwo9?{>~[{\䲘$tO箿G.L2HP:TFGHƹ?U+:h-7ڦ￸uGOhmkEVpW2m=@H $0v rJEva&K$% f-1} R#r  k2Dc-o\zV/EI zk,} D<ԉ=b 'H $<,'%K֨?q)b ??ngs_7^{3)nH $8'`<֎ Z[/8 \\_oB¤$ +B4iIMc#Ͼ ^;6X>ՌeWŔښeejkOed\eJLybQH $$ 23V+,1$^io% FPg44kmm_~|Ǖo,U.7^ V@H V = ,aP4~w(9AҌg߂FS($؇o^W,(hْMӑ^dSrjO6kv~%$jCt1ACi;g|Oo\6肋?%ސza S aųoV?2A{x}ʗ}[)Ƕ>Y:e?oKrl>~6 P $@ ȿŋRs1㉜[s4oAq6}w=z~Fk[(z`XzS.x:w=qX@H $0f (*4C[5Fs<`<_?1%5u𛳾q3#Սv>rf}%&&{@H đk;w-:Uq=Ok9ȶ[o\?Q&{>qU[=>Hl $0 ifxI x@L4R ^O2zOs~o l2@H $OGMj9s\$>Cʺzʔ3gN~6}+($@H@O]SG{?Q'sSl"c뭁ڷ??ngs_7^{3@76 $D! sZz9W]nWn\|m7߼ªUV̿HJJ6sNQުy+W,ٓrr۟?(w $YƳoyg_C,ojF+bJmѲC22f 2f%<>ަ5>c)H $Oo}PuAkO&٦%ǧ|\Foo{/^nΜ^r ݝ.!'gjH $00M`G6[)ru: lJNsO=d*YQbZS$Tm•XŚM/ $XlOOWWkG嶶֋--/Cp:]Tru@c^wdH_\imk#6&61(Eg `xu H-QWՕb,>Pq%X@n+b(D J XY̚PS}TNjE!$`|^0h%&&'&&䤤T@4iIM#C꭮ˎF2Av:Z.Fs%xA>Ib^5 ~?\-Qҡ~6ڂʣ;VdT+0gtj(-0A魮y$@H ~bK!cHzR߷8azKX`u$/|$ B@l4y+<]U$jW'p v[jr@d>œR[K@H [ZY ,j: >a]UxtR5LPz~s!^ +}:l^w Y%z+_jdrc[j_rf}%&&B06?3DH $N$rU[[]`&'`^zKgϳ'jˣBH $8fꥬ_||;W.\fĽ[[q"$@#djĖ⩺a2ܝ FH $G8`) ,R,ÈJjߪԫoǟ}x/T0~@H č"@uAXx1hBFxbm-gսU%[w}:WX<'p[=?χ}1Uvͱ $@H` (IE-/4.&.ٷ]G׼d`|W3*-^Sjk=1soȞ6+1Z+vdk cs]7$@H`l`~M'NPxz냪 ^J66/Y?>}7z{syusdm/^t A-1K֐fHqCH $ O`ڴY8`? ЩG)SfB?.xz P"$h+bhْMӑ^dSrjO6kv~%$ESV\+}n;xx(`JeVdLmdV@jy8'im;wESe $Cs\H }u)igΜ86ݐz (FloqƄbN4bĖQ崘%Ǽlh D)-Ab%`0:ƾ{(iBѢtʥh ;ր.!WBH $g|G{OjT8}Iܹ[ސz ,[IIR)SIGE(ZK}KO_[,V)ش?G `5 1wuF&HK/X 68%T*H $@L1'%eҥ7púnm;nQaUX_a`H_i6۔1u3+f~yX?/:Yg@H E}KL"Կ [v^{s'N0>iꭿ=%+|>w z fƑ-[mw>c&XbZbt edQ~ DS[,s&KoRZ$F![/՟(}<:b1&I |oxS`s@lGV\d^W%EO71`' Qo_[ "-2l܈*Aw0!@H $0 Oo\6肋?%ސza S V + -(MW;.s,86$@H@7ͷh߂x^߸kO=U?E=0,[)UO<^Py1q1@H $`X[jOLIM]{6kbɚpyCH LH~@tEᨪkiu-^8C2'tHY4dzq[q{ijjW]H ![GޮB4NCvOOͶ%Mnw46l8 9!+( ez8.slp65_g-Y$f#=*QȱК=9` 1Fxzz=ci$Jz ,[IIRzrri>zdx`HwCKlHzHRV#V}AsO W͂O$}+oҒ2 ʾ(1tFn*!%7H_N\HNHs!"Y`$"iJZ8La!DN,e4xk rz#ir|^,M{ LLH?»ddbˡ XdDP$0h~Xg?F()B)Ap12A>*c1 C(D)S g0yaf*[&O[ͣ@$<=K4}%UYZNXUSiI4WAn+RWoyP4Jr66@~0 +P.SWN(bS6ɭhDz)w$7t2TW:v  IU"ZSW], P& ]"C'iP/uk =7Y]|B xĦ+f3LD>HL0mU!J;Y*r~m|VQ\\Y",D^mo߱C\ώ0J=q?a_e){_58Eˠe+Qރ}"ERD!=4ԗ 8%<5|lYwd8K,6T7]9C"uLN_~zNNIN #aO)W6[z[[Ρ Kffےw;O6432҂hos\ݹ/7ՃzkP([oޠDC$[ʜgdgEhG*jJ-h^oHy$[xJC1I5FҢxJN<,dE{̺fRUGhnu@j mBXРG=${bz k_Zվݖ$_:sx_i)DV&[B z 4 O1J&K$% `TZq̤rNquM<x,E]VsR(EV|L)U\f/hRD%{rdZ׭̈́O5IV]j=/8S]X/{8⛢zڄ;0sj[|?, F<[w."p: K6%fDks˹f_[ 6mt9z|ΝrIA2lJ̠D !Z߻yN|yS-=}~N";{Ȓ C1+8AC|,貶i$+Ot,GKP+/KYXUټ^~.k#+z)/_|e1&ZvAKj?=sH ݬxG>%g! C-G7/t>{\-Θ6['MjNZbKHu]iv~rZ̡?=փع0>,Y5x_Ou-Tš4|Gxz`˂S>>yRE$/Az0U6MKUzޡ) RoUW%Z*`Q(%})Wl:̄OS/&PBV1 kw\]"8"PbdKlݢ':WR\쩡ڨRrc6UΔ>TK\SP4XJSU.kQXBn*#kCS6CZ&=iHX!fUS"\RsmHEWVsPW3~W0  Z ~1;>(ZPRPnI >   n K$tW{X~j"ڣ|ㅆpʀχHq'$T!)2|fF5 O34ZyV"\L?Ytx n&SJ xyإOƤ, ${L 2Df @"az_=O x3SBIbHzx:;NWWG < $/2VX$ ~?\-QUMf5D*EKdŤ0H+flEU|&݈ ?YoVvu]GaelpⲉF˓B'\,M&a\d #R%6R0nbl`"2ogjآ: ՄdacG+cv.n*( EqyHNBx >%ۨzXO =[-͍͗Oy[~\X )~݂KKi(dy`b:}Aao%VbMkc[:/&"@6M=f/H/S~!"Aks={`Y^sT'@[oꙆs|¿L2_Jtlj:,? x"{L )\lhM6gb 1qe\TlQn|d%6+%.ISi\-#'ԲEu~\LR%FC7fa&0zs_jАGP`|Ry:wNMǍA= #~ oF2 kO>u['?xYӦ^o}%,/uhZt{BVtt#%{C:o1*Ԅew1 ,3u7N?W~gC~mmm&{@qGJ'{&ApX/#lɆb^,.Kۗ4płW=udr.H\ew!Y&%E4Bv%h`Py8 )7RhRÜf( caKU$5q*9H #aVaFqrDxQ }T($9 DS)nWy`'z411Q3, ~Q[6wTS  $Wѯ>?ѳƔꭖ*=[)<ǖ ,Hr?#;HL68[y,.f,)?*u?PU8USj숋}p4;s[xg'd?$]T4 mK×ڃ)ܥ8,;aQ\FVg/P?Vx2$e!UD) Sb֬t=zːo{QϖmxY8F{r9b-(6ow@[Aj%y.+LlQ (: d(6l˫~z`>$ dMGAщP^2dA=!=#fO^njL|l&2fqBry04I 䣉,y::&qԴ<Z8纳A;^dcyr١1y% `|0D84bxQMN7VjLN=Î| (_#a䋈0>%*Ox(HDHa|JG)q0?W:d[#"x9\-II\?]6f&1@q ҐIҙl*öo9<#%?hUi؟.34Qoā6땷S&'Z[Ư3hJ|Ce0ݱ:?kϗ?%i<ϟwwط4Xڏ~7[*O6/yo^tR2e1C?pNN0[+ZA4aJe7N|zo]ʽF}gfy8P0 5TQ *'\Aϰ?Ϲ݇egFK3,-$PIx^^+o")BXW-[!C#rh, w势H)9!m80߰2m0n=OjUSoy*Y>b[l[s9all[vGcɆW!3s~FFZ0q\mK;Ey!z4(HN?,Г6]#>ӯ@j+c:TiP@ Lh0~$9OWTXy%)\)RE)\ \V0>>}W>B:1$dhwD&wNR*3)^'# #E2`\F"a g:^mV&07/ܰç~/Yx|ǟ}?K+Es3$N}-5IJO&5u\;~JΧ"p=ZJObL@oI)eۛ;=.7,臵}`8mg$9fVMM/2&Lq!ˠ.$rS!OR"9XTzHi>fyc9ʌ3f)0=bEŧrƕ0w:_?çDW/]:>j$I@}*V\ܩQy%=Fs)ʸ`S$1У2HUX(ERT? a!CLDEHXer(x}9!@4.E=d] SB4!^lY<#OWiH_i6۔K~GH $` q[36 09IHB $HHN"Pw:԰.c|b A @H $zk4cGxzz=W @H@[z(ahommohopb$_Po뉽 ̟@H`t ]X;@H $0 {@H .[kGH $?yzRFrkFRWKKtAŌH $W֕ $[޲2YRmϣ,0.!/ :y_f_!T Yl"`U=ZXheA{(Ūx i(P* -C|Cz~ž P%`Ѝ*&V)4Y#L(ڐԗy(c(C_bs6fOʗv(ϩ!>"ty{ؐ.Ј )PCxhI!Cj B}Ĺ* fQOIH{V\@H $ Q͋6IENDB`F3~I)hn?JFIF``C     C   " P$ p  <7<V<^@ na71GYpy:Lm ax 67g_&AbA+9|y`Mjvx|ej6(41R:}K<͌]1R:y] f9CQ#ef_y1ՏolzOr}/p溚㕙/c*n\wLs^} lv.Ce-n+Jȳb˞Op6mZXޏ^L[z}'qȊ ( (Ip:nK+@Gd* )zo?3nYiXZkX7ySrۜ;tP:.W-]MzǗv v<<*흽E]f>7<]ܽG7OPׄ~Gz{FyJIԴv23ך|o;0=?[}G3^>oo9lz#{ko+neEmjN\{!;U ]}D:kѸ#9a$rGe 8D"YӃ^G*!ܥv^+dfB#lgAYBHeِ m tG,VBP@^ خcn?Ϧ>LJalH'ͼS&<H*(R =r 2wpΧ84 P4+H+#F5AP@HnBzBS|}!]mZv+SuX]!fee=G3Ԟy'侥G#H1Bj1SrrUqmdZi1" 8PDPSYBXDF״c^ѨA@. 繓fkyh*eTZi m3g(5z[={cH3X{>=Ь*OK/-zc;gC^v[GWCZoѳd;W.myGIJEZKsFBc#d#k5A*"^W9pb+Jִu1N:Ze)m;9mu\zcgyC$r#$ FHdJ, E"gDƲK DJ(G eF^nWpUP@A@SX"(刎9#ǰk\Ѩ4TӼNXRWdN˟ SoYJ2UettS}f> GٝG ~&SF|~k$iyIBvO|^]l; n'κ]0=B[W,X2M" R$_wa+Ny9PMyԓ/S[`l( ( *M E,DqIrF1`ֹQZ}W}Zoѐ$\u|A˗%!rzZinvk\vs?J\t7{N7; !?/ϱ3q.׃w1EgdxڸSߥbw</s'OQ{=/;E<Ǣn=.?;I\Ύ0t8obdecֱv|W]aeomQP6q|NĠh@QPPQN)"#HE$dl|c k"+D.zOC~/Ѽtиt|E)r=F6--g[p#?ynѾov|wduQ>yj؝t#z x18=Wcjfپ_ca|h9'}Pѓ(m-o Ifg:U/SJ֯C>Vj`qӦ ҈%d44<{`;EPAEG 8EU6"871`9Z5ECA=} Nc ^69"{tgץ^Y׳ NZzsy+ |WȞ{ov<^t,97O: c-_|Լ./aKm鵣&CklzPkf}gCMjݘQu<)j)RiZP (  ((AUAUMhe9"#H14k\PDT;?HQ0Y&33e&IaXd'ۥu/`n*qݗpzF]}ӝ, y"bIM :^]ffiq( = e5--x輮>*LʋϽ15[5YCŠ ((p88цhb2(䌍`ƹZ戊"螱B;CHN#Yc֬gT_ķ񽷟ͮ^/opz[64rgν4--yG!,M3IBJ( (<'7>yŹ99* itXmthzG#lBWxH"8a^sDEAˇ{g{+|[#7:9MţaVg)yCM8ygx~sT>/t=O3Zy'=w<(D-+:fnMk|4xz`iy=cթl'<0TD@QD@QUEd*G}[YٌKȸl((( 888+Z H""I^эsF&O@uG<_}4[ZavIYG׃S^a`Cb+/y O{t:..j#r"fӇ9jEr_$QKhaz>>O#/$;(%QUTT ;-TpGxxyvJ+CbF1hֹw\/ü1^7n2Eos;:6(mشP3y7|C0J"f?~>.t;Ŝ\z.vHh "(z/!0 ǽ˧~ii/,빿Wǹ{qnB <}L_v)ϴf=ȈWOMLyO==~O㥫o>{.x*!H7wFṞ41%Tr?`D$IBB{5ʵ+AfSE}3=6Ghh&Vݑ R-63 +f/Swok*Ǒ717Nsp+S(v$ֹPAPD}mggscږ95|9DzH5F\4@Y\;^/ܤT=:؞OOU.<ռtѷCfR %@ (<`z?IDx$Ȓ !!-{uJ+Abf9c#c1iw8^ǟ8&'GX]z|95k\D8{fO?Kwk3WV,G{K.^Yɨ }yX)Ͼ<'jsgM6xl fikI d:rhuʸӜycr8X^=OL,BM %\Fj $ y|?˽mEz˔t=_5ϑdzY2ztɹtZy%z7hkrF GEޗ}}9fL:fN:vN`Ԛy$DprF5%Ha?zא[fέ-ޣkᠢ%Ӽ9|^Ks  k^[UKTc :  F *(/ J>96[lMsUg&1Ίz-lDM)2snxsy5jcgװ;jDu5c$rEf^XP}䴷C`~Hs#^>FJ:VJ>VL>h$O+!"tcXAwpzavfWG ,6;XCrt3͛a]^ξnѳD{0hٮnt zҖviAbHQ%ȀTT$A J^߄41:WO_u.3G[SιL9)!{AWkuE 9k=#$,r9I&bI✖x%ɣc ѲF+DbFDEhzD;Ñ}2]:,'u6lҹB`j 5z3R*_8m}?VX(ejd{ rF (( *UrUr&/|+w?z=hTUDp<{2BIch%)griMf 0`4`4AAP@BuR|3Ba IyZWjztʒT!9~"ȽC J0QU*z8Wz؞\ teLuc}zv1T@B-GYqZYlddQÜttttt0$L$0 !q:%ZVe¬v+Gf2V+Ef"Vb+2W"l uվ*XثQ)zuY[͵a܊5;=df&9 VUD",V =''I|^6XvՃ$Ë|ܩ_Gl\"f6W Ѳ_J>[I,}qO`Fb$$Td@n֖"Y-bҶ6[)j6ZVe=>ZChx6R_& N{%?kOay-_u^c(2 ؊VJQי&K^ieLg޹iub>L7'0JB܈e2O%[zI1"%/.CFvVֵ^g*>+953{ zߤds함QεL/FT8O]r6CۖogD" Ѝ4+DAP#DT8oR#M ӈ*:&&&h*N&hЭ8DAPqCDgƨ??ý}R9GF̖ +eJpJ&) o8]mZley:QF);J:يϵV,oHޫu?e|qLQE'܄)awk!w-H,::h+eSks\:cw;WOS-[+U`իSU͑~j=[g+*WY֣3 A R *wZDUZb:l,KGF&B&TK&rcݱWRE1C~[r71LF"_~((p J _$ewgV3VĽ:Ig%߬v5dLk譋1.[oނC&[5[_5lwDmӵuh;wi:%z(L^Lz%}~t2zXHrr h̅#ylllVIhW P+n;$aOX{!1iQG!Bc!k¥ϺۿѣF4hѣF5*ݛzJ\b~ŠIǡBۨ4 &g5(n8 rɮ^_Vyczt-w"1]YŠM !ˮdP"rZ}y|ԍ$zꩪ(\C]S/1yH:Y9 o7F18QK/8xTxNUSߎܮyOxR0L x/Nmw6c|;=+Y*cE5z61]ޖ:exwc XQLlGzI*W,,diBZڧwO=~H2MlKZuA;:l-j^JM0$.jԻl3ѣ]j152u`8G~uNɺ"o'bωшgHM_\%F]w>_;UsШmgAl8ٮ#bMLyfXن.R m,mbA{*eO~VkW6!qf2ueZJ&Ō}dǘ,V3.kF?hqW2-M?FGȎeC4=լIWj&-4bBT$'PQw>[?8N'Gq4q8N'[q4q8N'_Ƒ23)R͙-Ϗ%ixK'oe4hыOJHq=pJ"/_BR##Yy_(nfF"cX1.ܵ;XeNyFJT%lDB£?Q~j= -SFt7 ҾDNEUr!f~N^SU%BT%'_?T%-ܒ}ڔdTf*xc ɺ;%i&:BQE_w(SW&BNʞ3_Z9[׭']diIIIQyRH.+])V5.đB$$>5HY¤𺼿TQE_ 4_Hfρʮ\un9bgf͛FQDb8J^U<_7 Ndi?zA9i Uв Lf9.X8IG"J(^' 'iAfJ{< ("TV9;Z7H.Rr<$ Am~S軵tf&:AB#ѭD'm/rH[3?y*bJ$GnhCo_UNr 㴄g͊{>AhNнoq8H׆C z?EQEtی3;ڏ:prf=)KM.c}QEQ~]?UfUj@I%lL؆rƻD1?xp/ꀭX}|_;i5%78mҫbH捻#Fey<̢(Z$寖:ЍE!*YK}yQ_?v⨢pM³!7 |'z;oW(/',y:}7kҞM&wA8pEC䂏3_oЕ|gVJ٨^Mdt}S k]D8NfNri~~/R1)ƏCY' yHRo#aܬ !M?/J3BU7ّu:W{tTOz:%8Km% sJMaүh3\w^RN4zΫJ Yrubdmr?JdyQJuZ2bjf|XX{yĎ"#NH/vGCTy_yZ'*kz S))Psm=`__ieVMG1Y^G1EQElNOyfptnãJ7!^}'cn`}lCmF I:2?8yYdf(p8MTeAl8k"yܹǹs;aF~[é oAa{F\F..n&ړѪᔚck?!EQET#; F WczqWLuqHzf>VxJtG\wf0P(~d*SRދs(Xt{.;kd|X thѯw4 k6Vyl5ќS Mл,%B"Zsj((G*~"롋wsVDA (yQUq [#$fW{}+B-e(k{% q;8? #F3H1v3$])K= HGkPvf,$1'U>oO'yK x극xYp3Iu;;BjUltbqczV/QEQE8VF0tNy5Ej/zwwR!ަc6 I_[!|}|GZU~!5~ds/JwvUdlkRR*Ѳr}:lm%ɋt*A5jw(cawg,K9բ6 ƈÉ~r,v/r9g3QEQEyA|fd;v*㣜oF9]?# (I i"?'A:}w4E(42ި'kt1/c`سu*Ǫ MPZ!PW9uU*;)~[`ޞt{,v̓ʺ;qk/:v~Fvj1:;%q5O^7.}sf̫{J?UÅQESo]gfdXs+ݑ7$qv#[`=:ԁ\#zu):z"c^(fbrxRUs0!PBդ7 +,h>$%[^+rVw5JA(WQ4?U"hC23tl6@]媊[߁%+چ=ޙ=^Z_8QEQEcxE6꜏㰼eF[}5FHh# =ƶApWJZ_gBA% _QwLP54DS޾*͜Cđ vU6U.cTQD7<{+ybN. -PZqyF(CVB)Ϋ ^^ ((m#3/-'eΟEF- =/He"ý._Jt?!LP.ȋ?ĖNvjh3Usx;'qQ49_`O>:te =GddpOp9M6r6HAAA( y O1X3BxESաȳ- HHeWXBa /Nn,ɒz:(*6r9b}{zHWO3 rofD۔ӱi!(N bO}AAQE~ټS|hmRgqK"bw,sy!!_Eb#%'._ZQiMuy;'*prJQ)U5h:m&f+V$Q'Y}lM'9f   *(/n304$w|^4All|;!QHdCXR /H>9R2çKfMy |G3v(qaeAAAUEQTQM`|U<2pN'[˲AAk6-{qTz)"WBDV"pCR2x-OX(cBzcuc',1uw;fІՅAAAATUE_z:Ҋ/E/ >{_ (D   }X[U0r;n'1u!]Qډ]##G(l؊T_Դ-<(>wհH,8LT7񸆍ѵbhlٳf͛6lت9G)i| Wn_ѣF4hѣF r-HZ1)f{.3q̌lG;HwhF#:AAAXXevj–-ew6lٳf͜G!Tr E[hѣF4hѣF4hѣF4hѯNAAA>Mzlٳf͛6lٳf͛9EQKyBF4oE=4hѣF4hѣF4hѣF4h H  'Ճᬪlٳf͛6lٳ}[6lٳf͊)88HYQF4hѣF4hѣF4hѣF4kAAA_KvlV E' uQF4hѣF4hѣF4hѣF4h   'ԉ9J6lٳfE& /(F4hѣF4hѣF4hѣF5կAAATMz7տ|! UE uhD4hѣF4hѣF4hѣF4hѣ_  'Ԭi/0Kw;NӶi! L7ǻ^?E CF4hѣF4hѣF4hѣ_O[UY(}$AAO5N`vOCRD;ÐJ%-lGy;hrC~ FGx (YAD4"!ѣF4hѣF4hѣFCF}t6}!-fΐ*蠂  ~'Si4wu;D6;e;u;vnvlvī<#p|Q~  " hѣFM4hѣF4hШ* Cz^ {%&y~7UZ/eQ[aLN=.BkѬ%h׎vuz?&GR`tgnl~oذ;v/8= js͒`%MUAADADCF4hѣF4hѣF *u/C^V:e -̔EܳVz/y:Qe#Na CYAF\u\MY1١.N)0uC_3TOtvM;Nj"'#Q:AADADAѣF4hѣF4hШ* (3A 6_ zռ5ΒKnYFfUlV$Y3H;ﳫW=NG5Ȋs7^)  " " hѣFM4hѣF (/K%5`_tg  'H   " "4hѣF4hѡPTAPTQEPAAAAADAD4hѣF4hѣF * ((/  71!@A 2Q"03Pa#`q4BR$Cp?V~&JSOVloVUl318ecao6bV6Djjiq2%%e7SHS71l#]='Ua6W.Rl;ǪQ.uW59 I9q_1Q)rZOX=MZ-1P(Z *v#aWrle#q/iX EJ9sD*^Օi"Ne-B![9I0;9[, JBII?1Tq/hS06{8-J"0XJJLU<%:g13ӸPh"/(߻3eVT?{CP8hW@UFݕ ( *ѹg^^DZkQXa=%*Ѐu@@ߥlG8*2ⷦZ?ByX,]⹅܂bf@c~Bn廔 XKuݢtE ] &w.見5̩)u@Aqx>_1;cyL,ݦW[SZu(RM E[twiM6T2C>q :yI lKl>aۖ⡹3Kqx:mC-~8iSC0L]|M#CLF= jnðهRwƈ\L.iD-O*e|a!-x)&Fu[xQL^laQoLj|XN0q)VZY;B)6שэ]~ʨض11\k f3+&Az˟?7T]"33t}2L<=,;Uh>(uet6 ̄[~XFɼ@Ku 9UL 18m#Qqסv3!@TkU_y %1)ImwWRfٶJ;7( anQxWS.Z?b&;cV!`!7}mWDpbhӧ@n^gS Ɣty>A#H*zt'vc6p%8aF()`#s2m*MPW9n:LSNrݳ鱛DЁaOCQv/gP97hčKK mԼ/@Bnwa T-ܙ%JըB#Y }%LMu//_/84ߍ|oY>B&.%Z1"`!!}gF204!q'g240hJBFڌb?qA?6ѪEןibxi]Lx~qyyy~A:|?ߢ EoÎ!F&?8υa*mS;Oo4i./Akû/N3 |/iA3BְČH,_8|;t+y"`Z=f# v# .8BH})䋐:W|+e S(lO 4 e t/bJce%lҖS@YʆbeR"ikyyyR׻%SKd _/nʚ: (!RFBS6P,69UQhgt)*hbGUplVs4={gavT %+ *puF'X*K\ VR:vk_U2;Zc(V|S )#J@_*44w=ӌTTKt68>< >ukd! JgZ)€$8(6ṄC\È[(4Xu2V#{r%OBOfKFd0N͋FGI=BSbԔPA(8si3\ɫ,SGZPhNrR`U " I=RG>zH =dFmMt]r&P!O&HmU_$›MzNVO,IHC1ikNSk 1xCwoM):rL{pTB#(՛)L39̋. sOT/dġֳeCj͊I>0XM c T0L H $m0kahmدtۀNsQGVV:ǡq7;či#IJgtT ʳX"<]6ڜ͙&ŸǶUάj5 ;Nϊ *ZC-U!6q1zQ⭗E>WŇb(,9Igi )BǂǴՕʼ9Ֆ25WzkRW:Qc;aNBwXMS'p)IjHl2U`ȏL\9+lNkZJ׋-'z, ~ *x=6NaUWU=!ޫ|XU%Lz{d.񤂖ݽQ?sgB29Du XLtCD|># s(^ZTt3Ŀꎈdr soqܚրU 4df.TkS6lM&B PF~(ۆNj귂*3zEXpuUHM{HɢjZ,13.hRt&LL&0]*tU :1hφ؂wPFfEZ-b6'6g,+5M*3g!l7ZH|yv eeU CKDS0|4Q4n7!]ͭV8 dcQ\d-,&vn;à9B ^XqU8Q "ydívFM/h3F@X~>yVLԧbc%m$\H2ySZD*S2RSJv+Lg\R]Ta#T7I;f*]vb99Mn$>9 xz؞@2?>}auC}Ȕ \un`0^EњZH%Z i$IhK9F7(sX3'4:  Τp 1{r,ƘNUQֲEv^mLm=*ث,e" 1>B9ϊ1ǂdVG=ҨMM^eRF)<\.Q`Ɖ̗8p"V-6z48Ed &#TǾ R!D!׸HkɊe1%c- F > mr6=n*8 X&=|3`=UT<!q2kp?L&l ։6{Nn2Mn;3X~70ⶫL|9:)ũs 8L6as; uZ^Ok`")Mڏ926>-i]ڍU!P˷ou( '$4mw;*<ȵVFg8n`NV s>"JDH|Tp֓/Jv"9:pyv sQEZ?(HlB׆0%JF4&V϶[{+V kT?n%Bk4Z PX~ɽ: h.͜H%Jtj΃ޢR(MNsTX(.PCa`|ӚvќʂgL*{'FAt73s* ے?"X26 ۔Z+hiXRLvMEpv(t/ֹ@G5'> %X2$>w30ߑ5.rW<ȇ@21xL{>͚eZTa%8&BQˤT*A(p`BCf ֖+UMflӄ:])+J5C4B2Thq"ߤ5JIA26kMVR5h1M^C 72j7 ҍ .ܩxQ( smCp2BvSMSim(!Q*^$^JB{KY %C[5auXWo9ygT랊=Pv5gj0t QT)>wh?@2}Z;)Mn%>,SYVnUhW7`2kVxd-x(B%Aeڬoa Ė&ߕb:&J1cnl8PޛOS6m UZk}{7s[ Jei1? 6Mݛq? u.iOveUצ)`mE·❝$ҰMؕR[҆ћx-l2xZw\nhp]}%g{wS g;(QQ3CX;(Y!%nZLZ3a܋x$c&d߫z$j8fn9FB{w$[5)V @r:+%:,C79s=*g'q9nC< d11ܮɁ\kٿEZ"72l@ l ,̊Z2hVu<hMZ PX+, RlUv)MfFNcB9D/d#̫b;\ 2kѝ [T$w%TTg75w(QZ-Y?N9Wg'RIoE [EQ&b,]cngpxM¥6G6bB`1AJtl\{$\TC  )r 'pB%uخZJB̑xfV"N+[R%+SdG0Ч@9TŇHt;^y6'5>zE %5g%FD-^y>7Aah RwŽi5"XÙR oyF h#>Fk!iQ;iQeV#U-Z4~6-prgZ<27-VEBъB歩-:+' O7ЫVBq}{.\: J7Tg8dh^2@wD2:7!P@v䳨G\; n3RoH;q MQ݃J'6;S'~g`ω6V'i^ȶ񩰍*$xqM\z+\;ZO'԰ۃBOR"v!LI)YNe^-r 7V%̸NBjmZO':bJ,YqZF|%ԍh\Qvef>`t1!o8q6iv_U̇ãVxX{Z&dV8)|ˈŶl_%c*֕-ҢAcJl23 xMBRjfhO2QG ŭcq*#OщTqTHhU̇0=5kk욛kAv0bKP1fU+T*Ly:&O 0dhdž;U #}Z5lhG5E{e+V|zrBge(,Fc$_h7rU +7pPRh.;*hfX!M! vϱ۴]%|kEo&CU\ E~Dڨa0r.+{Id51G6M(G]%_"Ѝ l^ƿtY7QG3 \Yv#e6NYeb SrKk55\0FT0&FDm_>+JJZZxثnR4ta@R-vNbH86"c.U]P4~W8GK>PyR-çA^5=(Qe},*;,/2iMHjg`7(樏i#I J*P`C>V^/vD:u\bT$p>(_,#a"0Gr87=@ ^QgO(PfAMB.)-)?&KU]bZ]& a; |͑* Y8*s(q~'rR"W%o)ׯRڇY9n)[Н?ņn]J[#|^wybZSF+̂e!bJ5iWf9Im;y*#WCn.Tdg(VEM.jȇ^¶ i!v39lSD!8$%=S )yBeL<pZnKF+kBeZPC?)T}7)zTG% UQlRЪܟO<9oЩB8t!U_7 rtZڥNf ZU?ˊtEnXTv^)60, C(B njB`~'o@Q|aaR_)ODqV.:i1N;Ԗգ#xLd1?i{?B` m(9pq=j,QnX"ⴴ l6}q׭0eZ$."k)tF5UPz^U~nd jh vt7J]'wS*b+Z/ʼ̌a~X_/sD;~;pQݿ#x5nZϰ #b gmrvG9DmF~J4k2 -X%Sx VRSuB RCo TM 8/SI4W*|(z Yjm%DVÈm-*Z֞ 1%R݄'}S!#NVA[kslT?$Cs=Ff%>f>^xF `q pw\0}6Bp^h;Zw+s/3" Lc:vނ'djK됏GhMYsW~ Uv(U )#}ɹ9+ǞK%ܵUG,1⭎R;1{(b,~_?ׁweߢ2a׈DY殉?%|\2aaV;&,!k| lF?ԅ"!sKݴt{7O$&2xQ#Dهw74 9PlhΐR1sS[H v`}ePr\r!6~xM+ IZ/j<[K7ȯjy>[R#ӿ}txxNo+NdDNJu218994sZ[`uj!?|*C6/(FDG|w/_YcG@DjZ6TklR(Tg:Dv }Jn!rdh|4\い4nR='=.Ǻ@Y5ix%ϪtËE)fӣRa„F|Ơ@Ҝ ڶ.VM1>kȵVZL|HlQZMʋLEm6K.Țhmu$~CFsEvǢW{U% XC&ΕU5Ԩ0H*=8 uay*DIAJC\$8u& E6ޝܣG}"Z3]ry*!Ƕ?JPТ>I7-*M?h-cR\h1&NuÈ6D59)N^"JSڋgcWoH z&lrFV24:Q x+!1AQa q0@P`?!gПC/UH"גW8Tw\fLZYd%gĒq%DΟk1671鬚GBVD#FSm~cB!?V. AOY. mz|Z ԹъRw +bƛIXŢ, PzOG L%;cc$ei"TݎcRT/ndaʆ{F4ZI4Vb'09,pm?CJ8$/BAY{r`1~>dMy"b!1CEyeDÚQ2!(d la̡# (6]A"{i.%"cb8_>)"&,a)ԆfsQX"MI *zRJQo"|g]ܺ+>ټԵib`'2 .sn)k\ȥmSA ռ!O6/DKqSc59^S*̂-ՆfPYd;3ocWQȢ“؋ 24oS&N J%*ۊ̮JW:n=\ΆFO$NO6?k _{|>b.KXr%IQ1BKEdȑ#d-^QTG:N$]^luŸ;*ƢC&E)Whm2JQ;IZ;Eʲ܅mCpGj!ol)h&&lA< ?~b5\B$pb DӑGvM\HؓXGVjToD%'H8B5veRR5٥Bc5;vEe _d57D?JWɂRBWh!lRvÉ؞uQt0еgk5{#xdLy|`A$^U~PS,O pEDB܊(F%ZGwK_ TY7&Ovb8S=0,AdR&ߍ'8ER%jVx*($LQJQT8}QDm"niK:@Z 1l$e4P̮FbBU4>k)OQ_(UYA.IdM- tX0J6~3:6r2YRJ"t!:K;QP$JE@#"5]$ϰvG]tT2m9͌U&>we@NLP}BCNJ6SFlNJlr^mBHDm (АH|d]$*%#J<#R:EV&Qhrb3cJ2( z VV7LkpBRH&U1AaAAaApAAAAAFAcFGR%$%ya6Q FMqJ*LMlBцAIvw)l{iX\S-ѷ@ذ 6*U 'QAQd7QJE5pT<ֲ҅䴛|ēؼ,eVEp܎Fq̕.\`֑5A;>Gv*D^ZtsgN4q‰)HnC9 ՊUd?S3IYT9r67ҳVٱ:#TꖫT!ulȍ*S~GNߑ|[L?{@fJ:ImȍlإdZ3Qk42$cKͽ.Sz䙠%J@Qu,6/nsBIFS7$ӠbtM|;!H+. ·>nq“<_&ytdoGI;!i&hzUvc=H"jRDyQ GI?b!6r/oHeBYެx2eŐkԽaiHôvi_J{.&5Yڿ\ʡ{XΨvZ,|w *!$ 8؟Q_mv F,b2K/!lߡ6jZakO?z-D"< ff*ٙk'J+"ɡeW _J Uo0T:5z0lVYEd_/q+\§fK 1rRtE3dI*<(3m "^JcLikXrf#dyfIzQDDN<j7"oݔY!G* J"sZϝ Q:Gjj6&\TW} ̝̚ŅdL _:ՓEi2E2Ђ@B엕݊ nYs!H @=']4_A3-T1c+$d.~dfrVU}T]F^0׏Q׫~WEcF*:٫GH;i ֖JG&răzVY,dmVfIEBSD:m"q$*I-[I@Tq<$K&ɿl2ldn9!=aqR+ CI+ZMtT$P!: -B"S 0 ` R?#@h#Zl!40:mscѫqHL9K%BZTn?*F֣‚\;Fȃ2 CgHS-$]!su, ;|J[yhPh%KZw\BDՑWn%Z.]eCeD`ק>J"0)CRv|6M 0RgJoLd%n))zYBZC}Z?'@=Fde(RG.۠Bnka\MIg(w S6PJF)7hUo/)fO -$5< D4444@|jT$W)Q>)%e6,59z2KdJSyEtIڅZ% Kw='[\J AU09~cCCCCCA!)--\afOVߝ"N3O)&BP hRrwe%5cQ#9H,f$dr;92IKvHWy SR~AXf8# X1G x> ,%55#dhd[b-GRT1RgHT y Y6R׵5\SL(u>&J{NLNL3^pW*_ЃCcҪwͲd[UcB:y2TT"DMs_N)RqLx ~.p l(: 9)ǗMhhhhcxs%K-I(Jajxe2ꎭsbwͷ&E?In0( eHDU_i˔$gH0r DX#lωCe%Kw|g0A1| x)=.͉ SDo|ܴ͢,P#8(vTJ,)bhC_l. DX:J^_J(CԸ]Z[WQ-ݧG.xO#A cNj KV̗Q`'US#DHrD6m8T]Q1An-ƞ~Priإ. sbI* "aSJdr&<]Cb#ԏB8#1W_!PF4٩mvīWeSHΤzA$&\i-it[F4| `Ky$5TUl-a !š|,kWpG z>1c /eڌV UŮQέh>WB[J)$3'+!1b$nsCU (5g~IJ}%B8kV%%: ,/T>i}ɞ1OUBM95KSd gEFIo#6U _Gq:2}5%~M"Hiz=5o`<0]zUBY.ű QNF>41!6XZgb\Jur:HNȖ=݆`+9jц;E~J$]n ʂ,7jl(1lGF՛Dcb\2pDa& Xk9v'_VEwKU_Rgb GlViSЛQglqt.\9\*t w=cc:?pS}nXDCuÀ #J[b,dXKN=(2+G ʉٛ㍀.{3eW{(\ V2!]ǩ4k ҜM-@&!삈2:.b~O!>r+?"۷XN2G;jp(Ud=/LJ7wC# 011Ŀ(3CM2Mg"a4&#n)9n[ jl6ׄ #71NpP=_[`(.CDfr4a^mSiV(|{ٯn '['r1\1G1c's |`ݘ"F a)aȨJw 1|oj # B/f1UQЂ Zm-ˇKEC=ʯV/j{~ D pcN}SY|h!aihV#j &+ #=>_ˁ$ I|v] F&c\<4ꈿ{ dWWW (!P eIhF Ӂ!!,G1c0J|p?X+4"=9<$n @BQ҂j,a.ԊQ Ap hPlcSrKP%.f<Б@RDh $#M0oe2$A$zh#1|zh/aKɞ -f`VBh$im;bu-auLݮcP A`'H$yT'Lt-Z~V[6n]C*g$S=˅FHvJ:>?02BHjռ BX$$$$%1x1͐ V?l[{vFeM6N_QqA ˪r![BR7 %xY*uUeU!-X{v3-B8b6endNj!Z$1 wH!Z/Rw s& A"ft,7++ރ lOa(!6 H1c;2,?`v_EQ|%*-z& KH>X-'BnLZYf$(XZ݁ذ)x&CAPҷ%BY\Yl<xF,d R \{1g!ScjMgY4TTCQ;Mv6!!!!!!0'c1u!Wee2ʃx)}@lAu`K]I::B.H}2i!L0xl@R_q^/%Q!"1h3݇MBIHvgv8a>%Hjt/l@9wMjI B, 01c,L (.v͚5Bw>QR)%Y,!]ii,=r3aK V/Cx,OI$B h"dgB"Tu.bk|}4g)/̬Ćt듺12P|7uCEd}*1d_'s|aς-Af烒7yFwL4_0uֽ|B_= *ws8)}dm4w1)pK|!u AʝJOq%4yH~:Y2cLiC&<5 -gwT%<Ɉ7ӧyIboW>s֡Y|d}k/| j{E($\Fpu.hQ#%ݖWOnw/y, BQhGn*ׁFRɈBBBBBBBBBBB (&#fy{RNnHky9fk&q9I㾟Q=}(57i`}!4[h;pO PYꞨP݅vtSPID" 2Rblt Z܈=眃s*)zيQ QM,'Qɞ@,H8s tVq7qV$/up Y{I$I'ٲ! bQpcdž+nngKbH^:wpl5fXB$Z#q]vlkg9c8\^q0$?\l˪Ttm W BƃL&[䨯f1c3#}0OC2Iن :iQuЛa.M&dWT6"rAWS'}j ܯ`2xjfBBBBBBBBB`'^cdžŋ |wKE{O(O|ίW5$O |=#!ȹ#O8\Q`<>8> ^ ㍂uV 60B'G a k!2 ~(gZsD4yWlPIJ]$!!!!!!!!_C2 ZS_S0ވJƓo^UATB oؓ'IHwP811،= l1W0Z,EiK~ pO =cvR [WCy,0@r_Ktϡd"TEP:RSSdVBkiit%S@s˫U9`Mn1c|1w*EBzЍ2WRhQ= !!!!!!!!)n<&ZZa^W"zDK܀ԟ94"H6k35JGDSBeQj~eՁtc%pv|Xzyx+ET1˄j@V٪>r'O6+.L7 T2'ɉ [S0 n&,G:E|1–炠_ #6L%BqIKgM  71Tm9_ҩIV": _FD{ȳ"Q2Ob?8HME7,)!aFF72X2X'n"<C1&uLbh?Ц[b>ȳ<|^2$vsͶ2+\>A;H蹶K&gDw=y:AڃyP$I&"BBBB &!q1>QCz\skE"pd>-m#iNEB-ם t2LGj!n*0ש `"<,7j x4\8W7BUFo<-3;*PCTI$]1!!!AN17lcdhቐn%U^wnJM6MɁQFҧ$jryapID+6!(2a3XxEX.T6666Ik3#1 cMdͶJ_B@5um؈S\[vj>G-g4Eb(T  G$$$$  `'<$8#7.YZ\%wsA~YCج)T%*!p^3Ͱd-CfV\^=z,jOc=S}6\-Ηw> EYR׸kbrCE; Q?B   y1#_zI'0"J ygZ~VFU"4d k$+W)09Lµ Fp. Wq,΄ʤJȝyűO:&;-[\w%zQKĉD:6G9.먔Мf15,vȆ'jydl|+ N ]HHAAqۋx44A߀@7dFlW If}WZ9/@ !`qߖahSX'MX‚VE I X&f%Ԏ(e̾=]da7MPPJ Y>N/>05A4 OsVLu19rrg$#ۢ41S!AAa>3 f{lQ< _5rFKBB!u 9`&Aba؄2 "d ;oAIRPB{8LRbYʢnԊeV5!~JyPvjnf>^P%CI ܠy-x6(MF}IKz! BAAD\J3`TI.w/r%z d ՈB RƖa I]`_n$3% -܌\! 747 r3 fɫĿ)>MېF0ZiΛ̊s6׈U]Iy4ZI$I$! A0  .46ȏ"EQA̍"F*D)MI"uca4ysI2b+ I'8`< pDEF@`_[TAaĩq,HH%/_v&:4Wm}MyyBH]X'B!HX  / S 0)HQG34-+SZo-,#y鏄?t\$S 3>(XG 5@&8x1JYCX$V145ihA,LRm9,j!աB#p!HB&QE^ ac$O`ʿIM/oIYZtN|$lx AȡP> P1aa$ bb MSݺkmXX%A-)TܺjdR@8B! &AEQxto~ :Mɤ2V$ )[b88`ע(򆒖2o~F+  &׆$2! cɬ#@|*z`F(&6Ԓz15!\QEQpla6<N&BJ?,ҙF1AA@ԇ7):%s*Nn+nJ M"màc`!X"p(<&V"E$鷁$8 l'$oea^0K Qb#  !ԛu֬IJ-7 bYPZ+!BPQFH7Ԉ9/&hPJ`8xU߉OȴXY=#Ђ#  gFa111d^[pAĥ\ 8!BQE>Wȗ@0ßݛ#;Gb~ƨd/EY4+0   HH|zĶz 4!Bpccccx>?jF5gݟW1K; \ pV>4VݷnRZ-,z9W Ђ    bh$\$Kw X!B`8>O#z{HҹH'a>%~/"Q.E£Ќ   K\`A 2 <ʜ8EApB`_666HÒ5]!+*_}?Hb!B&%ߨj>u,*\"ZZ1qAD * ;_q\2&܃ZF7!܂ B! FO$9п,/K{6! fclK@(0,.Ejpz $ @$7/}1B]~Ga|+AA!`^_H 셶,H I8I$d/FA8x8@  sj78yKєa$iKĐ /^a  B,E;} ~>q냔az Y4[   XLjahh #,/H I$I$I$I$8xKÌfGrAAPXkaa #B>* I$I$I$I$8x9p5GpK$$$$$$$$  "?<a =!B?8$I$I$I$H2jb)>B "(&Xaa1P!\ ؎8㏃\ Rc, `&dx$I$I$F9 P¤)1|BXAE~ 0 4444444F)%Baqc˫a䠚#9ΦihE xxpccc qB*> $$$$$$ ¢(~eXaa <-:ؒҙ*]DBLiXщx%a !XqrLyNxɧ3?! pysz"5φ>2B!!!A=QEQ\7xl,0 JWVe3:!nHzmBO '25Vm<75 qYfU%r_;Y4d-ǭ J6R-FI]fI3Hgu9Zqx7<!HBBB "+ pYeahhhhhg "f6ٷVe cjst)UA-%E"3mZStE-CczEfs QsgGF]-}z ;8 HÒd +X]pL_  TW5]G NҡjTVX/๑1Tq*p*sh1o~dCeDJ^ڔj Ίo)Z$v]%`R4CPd)RFL"6gm9o41xUa-c pI>,{ j*=tR3I2[+2< 5 CS6>l8.x*⬂ 4R&d3/%v*2b(効٧@, $# 6 unVh`䶹 +) H(c F6 纺&h٦MdjdkШf $ ,BKhIF0fJm[;{8 CJ$c`0dc #2zKi`[&nd,##訒'{Bbihi!(KP$8e(j'ӓv? a:mx"(K82L<ь<"Go+i:He8)"ۡ8p4>%{/-檺)#ڠ0N,EqB rǎke*I9:$nhgI{:a0 (qB駦kj(膚邫+jJ/*pE!,˭#m`#*Za" 厉J&'jeK+ルk%+zm m*fl.-!1AQa0@q P`p?6n's.F&s\A.@@t t(:.&cR_C}j(<([8\3^Q-:4~ @# ؚyY' >kZ9&tg#1`yTUhK6ƐKt"Jۅ`=/@Rc7 l @8#l؎cDR H%ˌ1(1a2s&B[/uXk)sWKP7-rܡ: Is]N}j`f@no޾1[ 03Qk)%-(RCNc_e|ݐ̮1T:y]]erq]`6Yy v4s\V6i KC+_YՠՕED 5/e(";`}`ʳ Ą_%phZ巤i6>2fOYUأC1U9 L˚2hcqӆ⸎2@,|xqSYGNttSIS$d9( |*RRo-Y#RWЁ7W ₾#\how_SJ3._ U N 0{xd"UW XFi.KS@xTRŏи@ :qdU!s >&][0&(G U5fzFe{~ͧ7Y_΄. :Á ]¥%~#YVH 5ϡ{g.\(zJ.8.fఝ|-+T`ܢ?nr&XM7w0tW$_$Dy"Lh ;.!&90M*DڎUR [wCco 6KKKKa|j 75]x.\| QZ@DymTOZ|* ++"j:%fQ:Y#Q:g ۧ R;0b_ɧ}%ʸw9 0& [rX1H-,CADV^VrMP+$=N_7)D(E2,#I{FG^5P J&5( 8tP,!1AQaq @0P`p? Xg1MUM^ Zo<{߁Z:B۞!n h7 w1h4ξ 0tM^ЅVXb/^4X|SNPzcA@kV6 tઽc{BgѸ ZeTU踌*%rҖwb˛49[ al{ʫ8͹Ig!}aaD*B0UyƑ' _1b:wI#/V*{uKǶѻZTN1򠼽b%@CJ}J̙[\UTs@M Le:kF>5+F*Si}/[h  B䈭,hڀ ^p9#usMlvGULU-ցTPUqy4:ZrƐYt=Dί;W;\[Q`MJG{ϖFU?>]e81tHԃV 6e6I'h.5/ ]yQ o{?LwcJ{o7Ua;hR=>> / 8X4 Jƒ9-+f 5Mr mp(P\sY(2 ZP-@j0(^i 4pj{`%k6:Xn`'^e:>Y֞Y?l ˜FA3ONP&7E.h FZ$LVUa.{:!UX}e]e6TiZ"*)937z-S F:MO:d@'5*dUuYh@k.;BmYX:CkWҪ ~/E.TcH ]+ R jK6L*ot(年n[cQAC * @,H:``>,jo آn} ;wSAGDU EZКM'Ip cb&IQKiE#RJMCe'>%Ccܲ:PM bZpy7ƲB 譠[5i_ɻ t7^8 I[4&"L{^2[RG,tY`Ǧ> kE.5Rܹr@Ny XK/ɾ,b> B061bQpKCgP?/~IVd?i{*N{Jk@⡎ =>+ɾGa/6hx4jꊉYϹ?QFhC"\-)ίc%hv$ rk,k4?]sDy5TBc֦3)|6.L`*BrCTM:$zg [#4vd;tup .֎ܠzQ[R˖xoc5˄,MXv|č%L]"Xi"߬qG2W SycSAEm-Н쟸yx7K]9z !|xjV(~ےܸ3 jK }}'+kB gAJ:+k. =J}SrMOx܍8mXvE?ܠ*r157ݜ!l}WTÒߐ .R! eXeJ.+Ϲ~a dc2%sRSЈΡܖfRN<\%HC} p|*a atb:1F Er~@:K-K`=_&2mZ-?_b:KLŨ{LȝZ5c)_]oࢽߧ.vJvvm7칝 {'.]Dj" cB_m'RJ5N?p :D*&#auTRJOJ]"6-7xԂ-Կ t{`hQ.52 R;Db},˾DgQīs`c˿ԭ6-KˇB+(-+k ۞֊j_N!^@!WJ*W}bZ ∋VhXPa[|P]^ޱvvK:L5lEXVub_,!1AQaq 0@P`p?`Y,}?}C < zCX%+Rdh}8K>݀T -]8zEr26@TCHX,$s7<V,I+Peh:Nyq*a:h͠wa̪kF[ c\GsCᛴU$":c(aAJ6A8+rc)tkߴ=?Gye,\/@AUP]apl箥pi܂aqibijN0 *>d_} UzHeo Xl7 l_}+G1fd`)x!,JsJ-$Y|ʼn!?q-XSѽ0u(ݿt8'2:M{bai> YYdr˴}WAO?Z&nxgqJI)ʍ:^{c/ c%kag"^ IclNHZ`aE@ Ce":E@k; =H$i6Q}jYEVٝR,"4Ơ Zbhz &A\0C+= .9:{7lx g-X(Ȅ;r~%>ϱ*&nHLSp[ξqL!f%5rW^T/ɧYC$%ͥeVdt<+IJR=q%wa`QUYn& enya 6Pub`"!N2>nIr~{&5\GR2 \?a Û/BZU1YbAMȻ YY]Γz/#v^<@Is gH/is^A@_Vi5f)Z*YjbKfܣg Rw$A+򇼫A;Sp?lu㴩+AxhZ}Uئu_y*Cٖ]U֟EկQ{к gQVϾVs(4i}S]pаW,٫vnU.R] o~!'a}ɉßOOLg"v+ rEGEg?-p%0uXp"huUx9t.|W:: \sY􇀕F1c8-YϮfhHU.KCs* 򒐘&KLډn[0C8lk-ľD™Zjz{khV;{)drFBc}3 N|w+RS֫2Et %/=}riG:J5_y]Nx9z JA#*XFmT]U]bÓCg+s rjrYp`y".d\IXק11Ȍ_L lf/܎W%@M7BWQo]$ YO=ab*DFs!~Qxp+A(* k/{PR@ 2!Ha'ZߓO+N(xR-H97L.(߀OZ݃g5N6ReGQEt0]2ZCuo?i:s,_1V]_Ae08 '|kPԑ[L]0Q;Qκec[ JP^E9+Rt҅ gFf2*ٮck sdmOe^:>]>6hjDX"_(=_oX`ʘmLHjQm_ (d||B>hG59_?3Snowp 'fG\`=/9EC9^bu{SY/;Q0;pJ4Luצ8AJVC]YIb7*# l\A)C7#0RKrG]cD+%p9RS&FE-9 Et214E"eH/iCGDPD*~Q/*Q+IN Mxie` DG @JL%i)%J8GG.88QA2OG|:cszx&=L<.].9K@B@sruĪ㟂fFQ{̀/!ٴ%RHŹtiǓM9Q7uf!}Q@MYxwx/0T->N['/2[ݔ4V|D`Z_l,7םYn>C/^ba+ Ů Sjl>*<Š|ךQT;3_}D>]z?ĵy폫g6}j=@UavUk, W$sAXj\1oU۫*aMG0 3KE94fQO:GҥlEEa5ϱ\_"Cec#Z,Uiig>(Tn>=DU7f|V?Ԅ*8W}\\Qmw&\͏IJoRJq w~L:14Bѳ6i9(СXpYS`ٕU9b=/Ԭeq< LPoËb> ^V_aKE$Gcş[FuuAn3In,UYvEWI^%{{}B7 (Cguj4}HVݶe@hx'@-"G fC(_敋n BU?#8ge9y*6їm1J9@JtMJryJh)5c'r5@2o4n]ҡe|QG^H.N/DӖ{,%S_{jcC rQWry=2OLJDJwBHtM@ &*Nwwܜ]idNj7fU8\rz%>s@%M(I R\m <H2~J]ුRah{̽s*s('*{o6}cdY,|Ϣd=c%Ĩ%&Ohܜx^_(안GTvܴFT>޽R/w`@}T y'y/w /6{SO毬1ae)PCz̏s.IRͰZ#hi!J݁[Ы|Z߬f C\s4Wu5 e\XS^#I,VWX\iWj."F2_q@zBe ]>şbϱgGaxH_PUU7dl5D\tN~(͗,>2M hL&󯘽&Rdjq }0) KXuu)봁ktrK1t{EjKcQ~::*vC_l?HDW`6/!eG/5{Y*mAݎe^ ( PtLm:q*XVWDl- mfd7Eb$nyhud]Xn5Vi9ݹ. t[Q5T<h,PT ң{c9㔦زō=*Xw^GwuAN6ۻ]+_`eIAT)NkbQ`~eC~ʛ3RcM2)vZ *letGV_Co@/|L9Fcv% >tT0&鴨;5 VeTtcBE`;L\5U W9;%HӔ( uQ"Gq#N5teltb51:H;r<כ *7 D`]G㋍3z%E"Kv.ʩl^+!cҟZІi̾tYe6M\}؈EO>+C0<H"Y!ۏr{xx.p CAp4pmUI:g*ZF rb(l#r(:h r&R뚬_mtwaPCHayx wPY1K~%zÌ.E݄Q wftӉO)̹t+r(LNMci[+BSDY~CWt.^l%CsmC|4 @p8iӁYw?hі_Yr02a U:u^jrX2}3)}:GVc{hǻPPkjYTr,J:"|;l+V !l|ONG:Icw`Y|=RWAcϵBmz'Xz~øk&M,݅OF:JoM A_vY]P!EJm]q v'h*% @p?[Ŵ|~ fr~'%K7M)=45h FmBxRX?Xk8zŜjLg_:jD˱ 㺟QxXXSoۧWoQjH3ӂJ0K.'ɳ4lFxir/@P.@p8S.7m4m}Zhщs$ d>p}p{DV-(d=JR\̿S@0"AV,sUa7rOYeղfy*0yp!p1XǕFbD"N+qrT"%~㶇^~Ib0d e7Md,~ULŞeiuyV1 SvbD łnzJY0y_7!Һ ˻e(Ce!(`y"!~.'S )b3]7qtB{K[Bgkc]My 0P= QS|Ӓ$M>{bm q@ P.(\.86@^D8c4bֿ1jh>%ywH6}w ߩ7e*&8FWbc.h̰eO_t."9@F&\KV'>`;JCZ=itT}IG g]ాox UJT0^ HPdU\b4(!^ 9-W|a: >ω(%-K|Q T. !TQEqcnM 1.õUQ-^SKM`?RBt2zU} isGuɣ<@ F/@uaE RhLx{q~kjJ *58(s.-t? * +炊LÀ#oF:xYI u؟ 9er]+n4]Um &EL "2;bTyf1A>/qSr\"s70]u =beXјXY rz>+"z'W\(0Xs0m @0?4OFW.p \!C(8u.Y/I1*7g AF=&T'U\VSSzŗ@Wx;;323J5 B1E;ߪQʕ\:f 9c\-˥#M:i"66%XU]_&U_peLj*t*<ؼ._X_g@jT@\>"8:ŎBNV^ uYA/5G\@嶤;ߘԊ<ާ+"՝V]>`E`w+3Q&IV[d7"ȑV:HNow\M8qa0 ѯqAJλn`   6zQohȷnyc3XZiU5e}>xUh#ϒ,U㤵) ]/̡kp'DKf HFi)Ha2 !262ԳPsJU,(E/jἦ $sy`^p8E9wO74p+@ owm4p:c?K>JeQ|?^m,Ⱦj.B wJ-+UM]K ;X 8eoBm@`ӎ 6NtV Dm5|0ٹUcaEg9$-(nc9`5 IbBԈK%I{[2%FKcE<."!PzJ@6 þ #JC% ·bçX6UI#iol*8:m BwE\L*7 {G!&gD5P~5,jfX+_ \8ZG0\`Eh"JaPT.$GHHO$rr  ^b-9'_2—X7ug K!+Rg<}A U:qh-yJWeR3߁@TFA 0A 3^6N\?Qj*(X%*h댫ĥW?f:7** P! fh 4u< Ȋ&ovsT?Ew{@~DNID?JK%LJuv FL , 1"hcw1[W'@Q46@P A>a~;KXR"c)+Hgg?X#nL_x7|NǘP!B\8x ԠWGJE?,RW_[#n(L 5(#0f4[/ .0 gAU (f8qޕH`մGT?1k([l>LzaW{tw< wx\"BlDQ(J> +H%G-ܖ# QkoҦi6@p T P xϢP7!eg8Sm'*&B*#6YO;|+&Mpco)hA*YF/&,EV,^h/.eB:sAc9GY^\nDSPǧ 8s\%YD /OŽpc v6J#:Jl\6{7YInbQfGhF*OQXqh)lb,,8[ {ݲ&ni 9\GV@6y&2ETLngH:"6y 10:/8o  {JM| D#hP. p bw0; A\*kQ]z&?|C"g?q֡緃S#}\WFhWٿ_.apY_bTݧ؇1D4Gy%{nB:bT Ha W0sl?@ +餣9 )4Pe%bއhY*R:(3rׄ>z#-yf=1DXh}};kGy$Xn ݇/W^E>L%Ќ ;)qP{B*XXz Ies0޻/=0!%gCB 16k/ 3@ 'Eˣ^h]|1#A c4M8NY~| =w7( q#)&g0EcN?+J  {U/ EbP `nE(nY{x D!-xg![)EOهH,k0Ta:xj Ą 6>bW¸ęq>EP"Wޡ!zP۶.KWOtnx%. ު #SsIbPjye_ (fa鯠-i7lߎSF;mtd{|h5eՐ3$.| Gױ_ (P0L9Jj:B_U` +wn!h] y  npcGS,S|s x9Kh0,$jmIX }Z0q Y [~3Q L.V*^VD2Խt.~&tEDw~%Ϻ3(^"$~Rdu6p0V L?X( t޹ҠV9cD\/P(g= + O0Yߔ`nW)J"L+W!Z_LV'L3qܢ0C3z w%|rrp lo2kF2t+|O*B3КvQ4 ׸QPEt?6N=rT'T6K;RN)2q-WٶoGpA 0}& Nr,V8286iG$eݷĴ#!U-=4>~a`MY>'7>BoʊHx9b•h&< ];P&Zi}XK ĩS(I!ȈJ*hlYÔZv&\&#nzKGϨa pG}T}r뛸C|# `*N/?%Vܺn Рo*#+s~m ŻgeګZwk(#!$-GO>7iQ4Gw&['$ZE.Zhea3uNn+Os~v-rmF) @7Gvit Se2( &=6 yDr,+{nUrˀXfPp8 Q,ݔOԧ\8Gcِ{D:E\(F4{K1sxLeBL8&%rZU?TEa5E%&_3l <5te, *±jenՔ1˕栠c^o%|Blow"mX KcƷJ`%S.Y:ǹT)Z 1^8l }fl&ʬ/LFP2008< ePo/s57ߖ!SYs?$}mLV鈟_eFe -U/J˹^#b,ݳ.)Z-H2WW%TBG_ .=c0ӔiF~!;kGtԚF-ZzNZ#S"<cjW;J\nl8ˉ6ă4~8gs 1ml6>@!=?2o OkP`G?K9nŵr0LL*{*&7Jí+t#8g+kֿRTt!0jߖ`A6gEG=Q_xB#J4ۉB7Up=.DD01?Jp~Xh81}yG/}J%fx0s9Bf£,az \J-5T-TGW^Zna!:ljʞn57W; ,]Ie(PHj|Q% DU_nnY(ji;/.¯"gãv;TETm]U$(!4[9|{Qm9`+}YUEh>s+aM\fb,ZnRCO$ (OK9 Խ_}6|q!ؼ`< V]z>RyG;SD l 9*>vlKkhBrreoA#+1o93`˼/>bO$;@-&[U[+=[,\:'* T#gsJ瓕u1AH\ЕrW=3^ʘt) 2,xAJ'W]e Z)oޘ_@Ni+)l8ngx25#'VcEuBi L/yXa12zȝ̼syeטGH<M<_Qŵ^/*mD eâWs(_O,7/\qr6 90ܐ8;F[mJNvSJFMvL⣁QL_zB_z8@]mNM+zH(Ne]LdA@"T0Q/sOXy;]z̢3n pG88B[Lua~WMUSduqWtBE9:?s B%0YOvچesd|ų hu=D'4Q(m`x1NT*g<6}>@XiA|+pEX y|9ͰgR²;aUtT<hfӫ꾸UyOAF`yא,jƗStWꆄ]9].cQ0LZEРوV#|y fBr>Is~&1ZqǖYw[9?q_LОKaP0~dv+pUoahs," 1Bs_ɔm p>-z%,SKKCrh"> lP>!"cf]`ܜA Ty'=_Cpdz՟6v🹵-/W;G@yQfloM s2KmT'\ZA%;QIw*^-̙X4J`c^p<ɍ(ڽ<M?~Ҩ`y ys C`q=#=H-_(AGnax`\3O w呒gYaIhh1]o- _:3\'uԁ>`) (=`7D7F|7MO;wu58W_c Q}zh%3-Rm{JٶV8 Dr?ALn^wbՑe?QPC*éVNЬ+9dme ^A* Wa p^NoInH !xF>vMmŠb8jXS݃iK ^5w">geD˹tU<7SBE ~e98ٲV)֙g͂0 U } _2j'ZHf21hVV߹viHb8iRP9pJ,YY-샥4CϽaYd F 7!el28P8\ ƞ4~4qmsne:⩄Rz-Iw?g:Bl͇%RKt~!/lMe_Lvp{OwkO? ۊ~ئqOGN2eX.c=j>&_, X TsQPLS(MtkRw-A A8hx%/g'Zx݅9@?7aKiV.vn4^Yjf_S~wc013dR F J׷OysMU?Kh.@z9 0}c}3br3W]uшZ7X#z oT&s~: \&A0 C.h4pM| ze-p:4EhX ɰ@Oz3䋯9ycL^uD32qv9ne9'70jp8'*0%2+:A5#,y3d-w״dZYAQ(@ a !> STF<Qsn~^R2|t!~PNOĭzs.ma7\љkEdwI|7Ќ{6XόK+qu s+V~h \ BAA|4)Ur&GS @vWp b<w(;j'゙L.  a `q}ˀQX6g8 JDPt.%r{]q/ImMD6L$3Rc{&U<ʎߙ CDU ?s;O/TB !A߄BL nzeNlTXu9JWq p ACa j&Dp(-E1(v \fto~dSE\ndٝԲ{e,w ¥kN6ʻ0b0s`\ӎ*\ p BAA$p~6 yQјhv+Ւ7Ÿ)uR:*  0A C CaP0},QbWCIMG2%+5*Qh() 1i^dĊT72ՙ}_e*..GTrFU@@  I$I*°B֙{/U78;*3">3+G @p. 0xD8Pu0E &7]/gfrI!eєp\]CX]̏< 6M_S~" exT   $Np YJq||]Vbe%# SʥOT@CaHg0M9_B"8lCՄR;8-rMn"  ˏ`1IR@)TdC&<-25yW™DP.0A$AN|'<8wk!_G XbpaugGhގfܡ{2X/sh !m8Ro9fVan,ukh_` J\">WJ,Q4ѯMWsMv%DK黅3>ac 1g--^7xw(* }BP-$(I$qį&S{Ò@C8 =)olϘVz5i~fuFYaꞮC <Xf:Mg/,<Ÿkj[)u,'+(b m:q]c Q8z)NwzfWߙo/xKP9?,;<;`W@}vöIC,~QaYa @ >98uM.0qb %&4T;Dc 0,/tߎ/v. ,~fw7shHxUvxA;FYe팲 Ye=S)P.@&wܚ\.8ŋ\tNK-̎0 0 0c[w-LN@p k@NH# ^QYg+ 0 \Qj((b %H]VA\*fc ,=YeY.%;(XqG. ~p} ³Va@pۃ((qZ8ZůoИa,,xa8[GܕTLO]GAP. _vC0bʑNϔ~fS)yA˴YN: ǜ?6(u BU(Wy{@k ~_~V'bv8$vx1a}"=THjTѥ̴p8.%d>4}A4Q̅''^"sOY NfoDM""Yf^%~DQYΪaҩ邌k9Ǎ)١bA=:&{& {-0CfvFd ƅݲRBN1u #-P(.xҶPWNDF>6 ,]UP1ʄ SbS ޘiˋԭ;- U -/\tzp]>r Wj<[a3@sCVybKpAhxp{;\`8olbjv@*T=7UfVrVqxsuU1Aܧ+^/q:.GL <`WsSᮍսE출2AdU; .͡<`P K,$8CR)UTVRk(@p( T"4T[/WJE>E0T[%וC5R2ڀy n= 3BpPҦё[$`0 #0 ,Q꯯61 !a_jx濨 gs T<kwt.`C'6Vc s#Wk5QVX  snAC @(   060@0 E0 I0J0L0R0S0T0V0PW0X0[0]0a0g0i0k0m0q04t06|07`/ 0DArialUnicode MShh 0DArial Unicode MSh 0"@ .  @n?" dd@  @@`` x|    !"#$%&'()*+,-./0@12345678:<=>?@ABDEFGHIJK  OPQRS   XYZ\^_`bdefikmoqrstvwx yz{  ~eFxR$؛ Rz 8ݎb$= y]vƈ@b$\:1r5Fb$DUMi$rNy$h? b$6pl;P8M;';Lb$pjDb5xS"sb$fY1hVC.ߖb$i%/!ɷ!!b$(6<0`:z"b$.Q cyy( b$}Eu@+ M3b$FS?ƊGTb$heia*mb$ˆGDƣ#+Eb$hȕ=֔e**0qb$|&y#zsHb$̕T;c&á!4b$ViӤkO}_5Vb$er.`J3b$虲NÛ,]b"Y?b$ŷ\XH({;c_NRab$xu\~*yE!:l.>b$:6$9J.Z@b$m+eu-,m%H3Gn<$R$~I)hn?36 0e0e    ̙ A@ A5% 8c8c     ?1 d0u0@Ty2 NP'p<'pA)BCD|E||s " 0e@        @ABC DEEFGHIJK5%LMNOPQRSTUWYZ[ \]^_ `abN E5%  N E5%  N F   5%    !"?N@ABC DEFFGHIJK5%LMNOPQRSTUWYZ[ \]^_ `abp̙@8ʚ;ʚ;g4\d\d' 04ppp@ <4dddd4w 0h <4KdKd4x 0h(0___PPT10 f___PPT9H@?(?  %O  =0ik4What We re Going To Cover& `The MVC programming model Creating Traits UI Views Creating Traits UI Handlers Defining Editors 4GUI Design 101: The Model, View, Controller ApproachThe Traits UI supports, and is based on, the MVC design pattern. The MVC pattern defines a UI in terms of three components: Models Views Controllers&||GUI Design 101: ModelsA model is the data and behavior that represents (i.e. models) some aspect of a particular problem domain. For example: A well log contains measurements that model a particular physical property of a lithological column. Models do not have an inherent visual representation.$v ?GUI Design 101: ViewsA view is the visual representation of some aspects of a model. For example: A line plot can be used as a view of a well log model. It s possible, and common, for a model to have more than one view (e.g. a plot and spreadsheet view of a well log model). GUI Design 101: ControllersA controller defines behavior that mediates and controls the flow of information between the user, the view and the model. Having a controller helps prevent the model from becoming cluttered with view specific details and code.  Defining a ModeljDefining a model using Traits is easy& Any object with traits is a model that can be used with the Traits UI. The object s traits define the data and events that the model provides. Defining a ViewA Traits UI defines an MVC view using View objects. A View object defines the general characteristics of a particular user interface view. A View also contains content which describes the individual items displayed in the view. A View does not reference a model directly. In general, a View is a reusable object that can be used to create multiple, simultaneous views for different model object instances.Z The Kinds of ViewstThere are seven basic types of views supported by the Traits UI: Modal Live Livemodal Nonmodal Wizard Panel Subpanel*AZ4ZA4>L  Modal Views&  Suspend the application until the user dismisses them. Are displayed in a separate dialog window. Always make a copy of the model, interact with the copy, then update the original model from the copy when the user clicks OK. If the user cancels, no changes are made to the original model. Live Views& Allow the user to continue working with other parts of the application (they are not modal). Are always displayed in a separate window. Interact directly with the specified model. Changes made to the model in a view are immediately seen by other parts of the application.Z  Livemodal Views&  QAre a cross between live and modal views. Suspend the application until the user dismisses them (i.e. they are modal). Always appear in a separate window. Do not make copies of the model. Changes made to the model by the view are immediately seen by other parts of the application (even though the user cannot interact with those parts).RZR Nonmodal Views& Are the inverse of livemodal views& Allow the user to continue working with other parts of the application (they are not modal). Are always displayed in a separate window. Always make a copy of the model, interact with the copy, then update the original model from the copy when the user clicks OK. If the user cancels, no changes are made to the original model.kk O Wizard Views& Organize their contents into a series of  wizard pages which the user must process sequentially. Suspend the application until the user dismisses them (i.e. they are modal). Are displayed in a separate window. Operate directly on the model.Panel Views& Are displayed as part of a containing window or panel. Allow a non-Traits UI window to intermix Traits UI and non-Traits UI elements together (e.g. within a wx.Frame window). Can contain the normal buttons that the other View kinds allow. Operate directly on the model.68-iSubpanel Views& Are nearly identical to panel views. The only difference is that a subpanel view never displays any of the standard Traits UI buttons, even if the View object specifies them.6Q=CdjVET: View Editing Tool VET is a tool for building Traits user interfaces. We ll be using it today to interactively illustrate many of the Traits UI features&  View ButtonsdViews (except for subpanel) support a standard set of optional buttons: OK: Allows the user to close a view after having successfully edited the model. Cancel: Allows the user to close a view, discarding any changes made to the model. Undo/Redo: Allows the user to undo or redo any or all changes made to the model. Revert: Allows a user to undo and discard all changes made to the model without closing the View window. Apply: Allows the user to apply all changes made to a copy of the model to the original model without closing the View window. Help: Allows the user to display View specific help information.HZZ.NM HV m KLControlling a View Window s AppearanceA View defines several traits that can be used to control the appearance of a window: width, height: Window size. It can be: an absolute pixel value (e.g. width = 400 means width is 400 pixels) a fraction of the screen size (e.g. width = 0.5 means 0.5 * screen width) x, y: Window position. It can be: an absolute pixel value (e.g. x = 50 means left edge is 50 pixels from the left edge of the display, and x= -50 means the right edge is 50 pixels from the right edge of the display) a fraction of the screen size (e.g. x = 0.1 means the left edge is at 0.1 * screen width, and x = -0.1 means the right edge is 0.1 * screen width from the right edge of the display).VP'PP"PmPP m  u\Controlling a View Window s Appearance (cont.)Additional View traits that affect the window s appearance are: title: Specifies the contents of the window s title bar. resizable: If False (the default), the window has a fixed size. If True, the window will have a sizing border. @ 14 0(8Specifying a View s ContentsA View has three primary types of content: The actual editors (i.e. widgets) that appear in the view, specified using Item, Group and Include objects. A menu bar, specified using Menu, Action and Separator objects. A tool bar, specified using Action and Separator objects. It can also have various optional buttons (e.g. Undo, OK, Cancel) specified using the buttons trait on the View itself.4+ZZxZ%K& &  V The Item ObjectAn Item defines a single editor or control that appears in a view. In some cases, an Item corresponds to a single object trait to be edited. In other cases, an Item represents a non-editable, visual element in the view, such as a separator line, or extra space between fields. The type of Item is determined by the value of its traits, which can be divided up into several categories& nZNG}\8Specifying an Item s Content<name: A string that specifies the name of the trait the Item will edit. If empty, the Item defines a label only (using the label trait). If =   (a blank), the Item simply inserts extra space into the view. If =  _ , the Item inserts a separator line into the view. If =  nn , the Item inserts nn pixels of space into the view. object: A string that specifies the name of the view context object the name trait belongs to. Unless you are editing multiple objects in a single View, this is typically left to its default value of  object .6IZZZ4 !":9  / G;,\Controlling an Item s Presentation and Editingeditor: The editor (factory) used to edit the contents of the trait. If not specified, the editor will be obtained from the trait itself. format_str: A string containing standard Python formatting sequences (e.g.  %5d ) that can be used in conjunction with most text-based trait editors to format the trait value for editing. format_func: An alternative to format_str that specifies a callable that can be used with most text-based trait editors to format the trait value for editing.Z Ek  \>   v@Controlling an Item s Appearancelabel: A string specifying the label to display next to the editor. The default is to use the trait name to automatically define the label (e.g. a trait name of employee_name becomes a label of Employee name). style: A string specifying the style of editor to use. The possible values are: simple: A property sheet style editor, fits on a single line custom: A custom editor that usually presents a more elaborate UI that may require a larger amount of screen real estate. text: A single line text editor (i.e. the user must always type in a value) readonly: A non-editable (i.e. display only) editor. The default is to use the style specified by the containing Group or View.&#Z8ZKZ  L%tHi, xxvPControlling an Item s Appearance (cont.)Cwidth/height: An integer value (default: -1) specifying the desired width/height of an item. If the value is positive, max( value, minimum_needed ) is used. If the value is < -1, abs( value ) is used, even if it is less than what the item says it needs. A value of -1 means use the size requested by the item itself. resizable: A boolean (default False) specifying whether the item benefits from extra space (e.g. lists, tables, trees, multi-line text editors). padding: An integer value (default 0) specifying the amount of extra padding that should be added around an item. ^ZZZ R!  nl,VControlling an Item s Visibility and Statusdefined_when: A Python expression evaluated when the UI for a View is created. If the value of the expression is true, the item is included in the UI; otherwise the item is omitted. visible_when: A Python expression evaluated when the UI for a View is created, and also whenever any trait belonging to any object in the UI s context is changed. If the value of the expression is true, the editor for the item is visible; otherwise the editor is hidden. enabled_when: A Python expression evaluated when the UI for a View is created, and also whenever any trait belonging to any object in the UI s context is changed. If the value of the expression is true, the editor for the item is enabled; otherwise the editor is disabled. Note: These expressions are useful for relatively simple cases. For more complex cases, a Handler subclass should be used.P{P 2t 2My 2M{V6   %Providing User Assistance for an Itemtooltip: A string specifying information that should be displayed as a tooltip whenever the mouse pointer is positioned over the item s editor. The default is that no tooltip is displayed. help: A string specifying a complete help description of the item. This description is used when the Help button is clicked to automatically synthesize a complete help page for the UI.bv@oaP6@YThe Group Object{The Group object is used to organize Item or other Group objects visually and logically. Groups can be nested to any depth.H| D 8Specifying a Group s ContentfThe contents of a group are specified as any number of positional arguments to the Group constructor, or by assigning a list of values to the group s content trait. Each item added to a group can be an: Item Group Include The contents of the group are laid out in the same order they are added to the group.pZZVZS>.VNOrganizing a View s Layout using Groupsorientation: A string specifying the layout orientation used by the group. The possible values are: vertical: The contents of the group are laid out in a single column. This is the default. horizontal: The contents of the group are laid out in a single row. layout: A string specifying the layout method used by the group. The possible values are: normal: The contents of the group are laid out normally, with no special handling. This is the default. split: Similar to normal, but splitter bars are inserted between group items to allow the user to adjust the space devoted to each item. Note: the position of the splitter bars can be made a user preference item by assigning a value to the group s id trait. tabbed: Each item contained in the group is displayed on its own separate notebook page. More complex layouts are accomplished by appropriate nesting of groups.4dPPZPPHP YR :Tb qkSH!@Controlling a Group s Appearance$show_labels: A boolean (default: True) specifying whether or not labels should be displayed next to each group item. show_left: A boolean (default: True) specifying whether labels, if shown, should be displayed to the left (True) or right (False) of the group s items. show_borders: A boolean (default: False) specifying whether or not a border should be drawn around the contents of the group. label: A string specifying a label used to describe the entire group. If the value is the empty string (the default), no label is displayed. Otherwise. if show_borders is True, the label is displayed as part of the border drawn around the contents of the group. If show_borders is False, the label is displayed as a fancy text label if style is  custom , or a simple text label if it is not.P P u W Z j _   b swPControlling a Group s Appearance (cont.)style: A string specifying the default style to use for each item in the group. As with an Item, the possible values are: simple, custom, text, readonly. The group s style value is only used for items contained in the group that do not explicitly specify their own style value. padding: An integer value (default: 0) in the range from 0 to 15, specifying the amount of extra padding to insert between each group item as well as around the outside of the group. selected: A boolean (default: False) specifying whether the group should be the selected notebook page when the containing View is displayed. Obviously, this only applies when the group represents a page within a notebook, and only one group at most within the notebook should have a True value. PV~X ,A"VControlling a Group s Visibility and Statusdefined_when: A Python expression evaluated when the UI for a View is created. If the value of the expression is True, the group and its contents are included in the UI. Otherwise the group and its contents are omitted. visible_when: A Python expression evaluated when the UI for a View is created, and also whenever any trait belonging to any object in the UI s context is changed. If the value of the expression is True, the group and its contents are visible. Otherwise they are hidden.PZZZkZ 2"g 2M"E$  xfControlling a Group s Visibility and Status (cont.)enabled_when: A Python expression evaluated when the UI for a View is created, and also whenever any trait belonging to any object in the UI s context is changed. If the value of the expression is True, the group and all editors for items contained in the group are enabled Otherwise the group and all contained editors are disabled. Note that this can be used to control a user s progress through a wizard View, by enabling and disabling the groups defining each wizard page. These expressions are useful for relatively simple cases. For more complex cases, a Handler subclass should be used. Z;ZvZZ 2M"BU K#%Providing User Assistance for a Grouphelp: A string (default   ) specifying a user-oriented description of the group s contents. This information is used to automatically create a help page for the containing View when the Help button is clicked. The help information for the group will be combined with the information provided by the help traits of the group s content items.n^ m&zSpecial Group SubtypesHGroup: A group of horizontally laid out items VGroup: A group of vertically laid out items HSplit: A group of horizontally split items VSplit: A group of vertically split items Tabbed: A group of tabbed notebook itemsd)'&$#H)'&M$The Include ObjectInclude objects are references to other view elements, namely Items and Groups. Include objects allow for factoring views into smaller pieces that are dynamically included when a user interface is constructed from a View. This allows for several interesting capabilities, including: Parameterized views  Visual inheritanceZ)Z7L-?)% How Include Objects are Handled When a user interface is being constructed from a View, any imbedded Include objects are logically replaced by the Item or Group object they refer to. For example: The process is recursive, and will continue until no Include objects remain in the resulting View. PPeP2'^!&!!Creating Implicit Include ObjectsA class View containing Group or Item objects with non-default id traits is automatically refactored into an equivalent View using Include objects. For example:P 7Z ='"!Using Include Objects EffectivelyThere are several possible uses for Include objects. One example is creating  parameterized views. For example, the traits TableFilter class contains the following view: This allows TableFilter subclasses to define a new version of the filter_view Group containing their custom content without having to redefine the main TableFilter view. ZZ$R 3 + E P} 3 + K (#*View Objects as Part of a Class DefinitionJView elements, like View, Group and Item objects, can be created and used in any context, such as module level variables or dynamically created within methods or functions. However, there are some additional semantics that apply when they are created statically as part of a class definition& J&Z)$/Defining Views, Groups and Items within a ClassViews elements created within a class definition have semantics similar to methods. In particular: They are inherited by subclasses They can be overridden by subclasses This leads to a feature referred to as  visual inheritance & 6cF=cF=*%( Visual InheritanceJust like methods can be overridden in subclasses to customize behavior without rewriting an entire class, so to can view elements be overridden. For example:P.)( Visual Inheritance +&The trait_view Method$ The trait_view method allows you to get or set view element related information on an object. For example: obj.trait_view() returns the default View associated with obj. obj.trait_view(  my_view ) returns the view element named my_view (or none if my_view is not defined). obj.trait_view(  my_group , Group(  a ,  b ) ) defines a Group with the name my_group. This group can either be retrieved using trait_view or as the view element referred to by an Include object imbedded within a View.XlZZ ^  / + * ^,# 5+ Q,'The trait_views Method$  #The trait_views method can be used to return the list of names of some or all view elements associated with a class. For example: obj.trait_views() returns the names of all View objects associated with obj. obj_trait_views( Group ) returns the names of all Group objects associated with obj. sb s9AlEventsnIn the context of the Traits UI and user interface creation, an event is something that happens while a user is interacting with a user interface. More specifically, events include: Button clicks. Menu selections. Window/Dialogs being opened or closed. Changes made to a field or value by the user. Changes made to a field or value by some other part of the program.@@qmEvent HandlersOAn event handler is a method or function that is called whenever a specific event occurs (e.g. the OK button being pressed). Proper event handling is the key to writing flexible and powerful user interfaces. In a traits UI, event handlers can either be written: As methods on the model. As methods on a special object called a Handler.XJ AnThe Handler ClassnIn the MVC programming model, a Handler class instance is a controller. If you are using the VET tool, it automatically builds a Handler for you. The main purpose of a Handler subclass is: To handle events common to every traits UI view. To handle events specific to a particular model and view. To help keep model code separate from user interface specific details.  ; o The Handler Class: Common EventsJThe events (and methods) common to every Handler subclass are: init ( info ): Handle view initialization close (info, is_ok ): Handle a user request to close a dialog or window. closed ( info, is_ok ): Handles a dialog or window being closed. setattr ( info, object, name, value ): Handles a request to change a model trait value.~? ) 5+%3>vF-Qp'The Handler Class: View Specific EventsEvent handlers specific to a particular View fall into the following categories: Trait change handlers. Menu and toolbar action handlers.8Q9(%9q(The Handler Class: Trait Change HandlersA trait change handler is called for each model trait when a view is initialized or when the trait changes value. A trait change handler is optional. If one is not defined, its corresponding event is ignored. A handler always has the following method signature: object_trait_changed ( info ) where: object: The name of the context object containing the trait. trait: The name of the trait. info: A UIInfo object containing information about the current state of the user interface.ZZZZ7N,tNr/The Handler Class: Menu/Toolbar Action HandlerskMenu and toolbar action handlers are not optional. They are explicitly referenced by Action objects specified in a View. The signature for an action handler is always: method_name( info ) where: method_name: The method name specified in the corresponding Action object. info: A UIInfo object containing information about the current state of the user interface.ZZZZ%.1   1 N>  HNsThe UIInfo ObjecthA UIInfo object is automatically created whenever a View is displayed. The UIInfo object is passed on every call to a Handler method (referred to as the info argument). The UIInfo object contains all the View specific information defined by the View. It is basically a namespace containing: Each context object, referenced using its context name. Each trait editor, referenced using its Item name or id. The traits UI created UI object, referenced using the name  ui . It is your responsibility to ensure that context objects and editors don t use duplicate names.v#ZZ`Z,%%  `$`PC\ct The UI ObjectZA UI object is also created automatically each time a traits UI View is displayed. The UI object contains all the traits UI information common to every View. The UI object is returned as the result of a call to the edit_traits, configure_traits or ui method (on a View object). Although the UI object contains lots of information, the parts of most interest to a traits UI developer are: result: A boolean value indicating the result of a modal dialog (i.e. True = user clicked OK; False = user clicked Cancel). dispose(): A method that can be used to close the dialog or window under program control.^ZZ<@3 _@ QP -(The Traits UI Object Model 2-What Editors DoEditors are the heart of the traits UI. Editors create a UI toolkit specific user interface for displaying and entering a specific type of data (e.g. floats, colors, fonts, file names, & ) Every trait has a default editor associated with it. However, the default editor can be overridden either in the trait definition or in a view Item definition.*\K 3.What Editors DoOEditors and traits are loosely coupled: the editor only ensures that the type of data it understands is entered, and relies on the associated trait to actually validate the data entered. In some cases, the data allowed by the editor is a subset of the data allowed by the trait, so no user errors can occur. In other cases, the editor allows a superset of the data allowed by the trait, and catches exceptions thrown by the trait when invalid values are entered. The editor then provides feedback to the user to indicate that the entered value is not valid (e.g. the entry field turns red). PZP4/Editors and Editor FactoriesWhat we call an editor is in fact an editor factory (but editor is a less intimidating term). An editor factory can be thought of as a template for creating the real editors when needed (i.e. when a View is displayed). Because they are templates, the same editor factory object can often be re-used in multiple views, or even multiple times within the same view. When a View is displayed, the editor factory for each Item in the View is called to create an editor for that Item.BP50The Basic Editor StylesEditor factories can create any one of four different editor styles, based on the value of the corresponding Item s  style trait. The four editor styles are: simple: Fits on a single line. Can be used to create Visual Basic style property sheets. custom: Provides the richest user experience, and can use as much screen real estate as necessary. text: Fits on a single line, and is always a text entry field. readonly: Displays the current value of a trait, but does not allow the user to edit it.PTPm,S];QQ71The Basic Editor Styles82The Standard Trait EditorsThe Traits UI package comes with a large set of predefined editor factories, and an open architecture that allows for creating new ones as needed. The current set of predefined editor factories are: 93The Standard Trait EditorsIn this presentation we ll focus on six of the predefined editor factories& Three that are simple, yet very useful: ButtonEditor CustomEditor EnumEditor And three that are extremely useful, but require more setup to use properly: InstanceEditor TableEditor TreeEditor^tP%PMP&Pt%M&tt   N  :4The ButtonEditor Editor Factory The  buttons trait of a View object allows you to define standard and custom buttons along the bottom edge of a window or dialog. However, there may be other cases where it would be useful to define buttons at other points in a view. This is where the ButtonEditor comes in handy. Traits defines a Button trait, which is an Event trait combined with a ButtonEditor. It is a parameterized type whose argument is the label you want to appear on the button in a view. Z " f, X f?9The ButtonEditor Editor Factory  For example:  A:The ButtonEditor Editor Factory There are several ways to handle the button being clicked. Here s one that treats  spell check as a model function:uZuB;The ButtonEditor Editor Factory xHere s another that treats it as a view/controller function:=Z=;5The CustomEditor Editor Factory :While the Traits UI can handle most user interface requirements, occasionally there are cases where it is useful to imbed a non-traits widget in the middle of a traits View. One solution is to write a new traits EditorFactory subclass that creates the needed widget. However, in many  one of cases it may be faster and easier to simply use a CustomEditor to imbed the  foreign control into a particular View. Z, x 9C<The CustomEditor Editor Factory Using a CustomEditor requires specifying a callable function plus any additional arguments the function may require. The signature for the function must be:,P  D=The CustomEditor Editor Factory EThe following is an example of using a CustomEditor to create a view:,FP' ' F>The CustomEditor Editor Factory Which results in the following display& Note that in practice, more code is required than this, since among other things, event handlers to handle input from the control and set the appropriate trait value also need to be set up.sYThe EnumEditor Editor Factory Let s start with a trivial example of using an EnumEditor: Fruit = Enum(  apple ,  pear ,  peach ) Unsurprisingly, the EnumEditor is the default editor for the Enum trait, and will automatically yield the following results when used in a traits UI:r;Z)ZZ/ ) UP/  1 UuZThe EnumEditor Editor Factory 4Now, let s make the example a little more  real world & We re doing an interactive menu, and fruit is a trait in an Order object that represents the diner s choice from among the fruit currently on hand. Current stock is maintained in a separate Stock class instance that has a fruits trait that lists the fruit currently available. The diner should only be able to choose a fruit that is currently available. nP]}v[The EnumEditor Editor Factory We can still use the EnumEditor to create the UI, but we ll have to provide more information to help it tie things together. In this case, we ll focus on three of the EnumEditor traits that are of interest for this example: values: The values to enumerate (can be a list, tuple, dict, or a CTrait or TraitHandler than is mapped). name: Extended trait name of the trait containing the enumeration data. The values and name traits provide complementary means of accomplishing the same task: providing the set of enumeration values independently of the trait being edited. In this case, we ll use the name trait because we have access to a Stock object whose fruits trait contains the enumeration of available fruit. dPP8PP  /<  D#4t  _ w\The EnumEditor Editor Factory 8The resulting Order view would then look something like:J9Z &<6!The InstanceEditor Editor Factory;The following type of trait declaration occurs frequently: manager = Instance( Employee ) Amazingly enough, the InstanceEditor is designed to edit these types of traits. There are multiple usage scenarios for editing this type of trait though: The instance is fixed, but the user needs to edit the contents of the instance. The user needs to select from a fixed or varying set of instances, but does not need to modify the contents of the instance once selected. The user needs to select or create an instance, and then be able to edit the contents of the selected instance. The InstanceEditor is designed to handle all of these scenarios, along with several variations on how the editing should be performed. However, in order to do this, the InstanceEditor requires a more complex definition than do most other trait editors.;PPPKPP;vKF>pFG?!The InstanceEditor Editor FactoryLet s start with the easiest case: The user only needs to edit the contents of the current instance object. In this case, there are two choices: Allow the user to edit the object contents in a separate pop-up dialog. Edit the contents of the instance object  in-line , as if it were part of the main object being edited.R$I% $I%H@!The InstanceEditor Editor FactorynFor case 1, use the  simple editor style and specify some or all of the following traits: label: The label on the button that displays the pop-up editor dialog. It defaults to the trait name. view: The View object or name to display in the pop-up editor dialog. It defaults to the default View for the instance object. kind: How the pop-up editor should be displayed (e.g.  modal ). It defaults to the value specified on the view itself. [][aS3<KA!The InstanceEditor Editor Factory For example:  =7!The InstanceEditor Editor FactoryFor case 2, use the  custom editor style and ignore the label trait:.FZ9NC!The InstanceEditor Editor Factory6Now let s move on to the next case: The user needs to select from a fixed or varying set of instances, but does not need to modify the contents of the instance once selected. Within this case there are several important sub-cases: The user must select from a known set of existing instances. The set may change over time. The user must select from several different types (i.e. classes) of objects, which are only created once the user selects them. The user must select from an unknown set of existing instances (e.g. by drag and drop). t$PP8P4PP$84OD!The InstanceEditor Editor FactoryThe InstanceEditor supports all of these sub-cases, and in fact allows any combination of them to be used together in the same editor. It does this by allowing you to specify one or more InstanceChoiceItem subclasses as part of the InstanceEditor definition. There are three predefined InstanceChoiceItem subclasses, each handling one of the three previously described sub-cases: InstanceChoice: Describes a single instance object the user can select. Note: If an instance has a suitable name trait, the instance can be used instead of an InstanceChoice object. InstanceFactoryChoice: Describes a  factory (e.g. a class) which can create instance objects the user can select. InstanceDropChoice: Describes a class of object the user can drag and drop on the editor to select it. |PP(L^/ HU(L ^UPE!The InstanceEditor Editor FactorybThe list of InstanceChoiceItems can either be specified as part of the InstanceEditor itself, using the values trait, or as an external model, specified using the name trait. Or they can be used together to create a composite set. In any case, changes made to the set of InstanceChoiceItems are immediately reflected in the InstanceEditor user interface.c (5h"P ("QF!The InstanceEditor Editor Factory For example: P MB!The InstanceEditor Editor FactoryHAnd a slightly more complex example& %P%ZH!The InstanceEditor Editor FactorylAnd here s an example showing  drag and drop support:7P7\I!The InstanceEditor Editor FactoryWhich looks like:P^J!The InstanceEditor Editor FactoryFinally, it is possible to combine instance selection and editing in a single editor by simply combining the editing and selection traits:PYGThe TableEditor Editor Factory TAnother common type of trait declaration is: department = List( Employee ) In the case of a list of objects with traits, the TableEditor can be used to display the list as a table, with one object per row, and one object trait per column. In fact, the TableEditor is the default editor for a List trait whose values are objects with traits.r-ZZ Z-2 t -,} t N_KThe TableEditor Editor Factory Some of the features of the TableEditor are: Supports  editable and  read-only modes. Allows object editing either in-place within the table, or separately, in an external  inspector view. In-place editing supports many of the common trait editors, including drag and drop. Supports ascending/descending sorting on any column. Sorting can either affect the underlying model or just the view. Allows the user re-order/include/exclude any of the object columns, and persist the resulting set across application sessions. Allows searching the table contents in a wide variety of ways. Allows filtering the table contents using a wide variety of user customizable and persistable filters. Table/column/cell level context menus All changes made to the table are fully undoable/redoable. Colors, fonts and grid lines are fully customizable. R-PPP > t a9bMThe TableEditor Editor Factory An example of a TableEditor:&  `LThe TableEditor Editor Factory 0All of these features and flexibility come at a price& in this case, the amount of work needed to correctly define a TableEditor. Out of the box, a TableEditor will display many lists of objects without any extra work& but the results will often be non-optimal. The traits that can be defined for a TableEditor include: Table Attributes: Colors, fonts, sorting rules, & Table Columns: What object traits can be displayed as columns and how. Table Filters: What standard and custom filters can be applied to the table. Table Search: What filter can be used to search the table. Table Factory: An optional callable that can be used to add new object rows to the table.>P[Pa      " : @ / M>t   ecN0The TableEditor Editor Factory: Table Attributes " >8-The TableEditor Editor Factory: Table Columns fYou define the content, appearance and behavior of a table by providing ordered sets of TableColumn objects. Each TableColumn object describes a single column/object trait. You can provide two sets of columns: columns: The columns you see initially other_columns: The remaining columns These are the default columns, the user s most recent preference setting overrides them. There are two basic types of TableColumn: ObjectColumn: Used for objects with traits ListColumn: For lists and tuples You can also define subclasses to get state dependent column behavior PLPPLPGPX  U  v   GX  |    HdO-The TableEditor Editor Factory: Table Columns ObjectColumn traits: name: Name of the object trait to display/edit label: Column label to use for the column type: The type of data contained by the column text_color: Text color for this column text_font: Text font for this column cell_color: Cell background color for this column read_only_cell_color: Cell background color for non-editable columns horizontal_alignment: Horizontal alignment of text in the column vertical_alignment: Vertical alignment of text in the column visible: Is the table column visible (i.e. viewable)? editable: Is this column editable? droppable: Can external objects be dropped on the column? editor: Editor factory to use when editing the column  in-place menu: Context menu to display when this column is right-clickeddPP  +%,   (1-+/ 4;<~    (1-BeP-The TableEditor Editor Factory: Table Columns For almost every ObjectColumn trait there is a corresponding  get or  is method. For example,  editor and  get_editor() ,  editable and  is_editable() . Defining a method overrides the corresponding trait. This allows subclasses to define values that are dependent upon the state of each table object or other values.RTJ 7J> R  fQ-The TableEditor Editor Factory: Table Filters When applied to a table, a filter reduces the set of visible rows to only those objects which match the filter s criteria. A TableEditor defines two filter related traits: filter: The filter initially in effect (defaults to None =  No filter ) filters: A list of TableFilter objects that the user can choose from using the  View drop down list. ~} $.  I,}  Iy-The TableEditor Editor Factory: Table Filters There are two basic types of filters: Normal filter: An actual filter that can be applied and modified. Template filter: A filter which cannot be applied or modified, but which is used to create new normal filter objects of the same type as the template and with the same initial filter values. A template filter is simply a normal filter with its template trait set to True. User created filters are automatically persisted across application sessions as part of the TableEditor s user preference handling. You can create your own TableFilter subclasses, or use any of the standard subclasses: EvalTableFilter RuleTableFilter MenuTableFilter &PP,P0PP& 55^ 5 40b 3 4hR-The TableEditor Editor Factory: Table Filters (The EvalTableFilter: Allows a user to enter a Python expression whose value determines whether or not an object meets the filter criteria. Its use is obviously best suited to users already familiar with Python. Trait references on the object being tested do not need to be explicitly qualified. BjS-The TableEditor Editor Factory: Table Filters The RuleTableFilter: Allows users to define  rules using drop down value entry for trait names and operations. Rules can be  and ed or  or ed together. Rules can be added, deleted and modified. Introspection based& requires no set-up by the developer.:ZZ>knlT-The TableEditor Editor Factory: Table Filters The MenuTableFilter: Is similar to the RuleTableFilter The differences are: A rule is automatically created for each object trait. Rules cannot be added or deleted. Rules are implicitly  and ed together. Rules can be turned on and off.hZ7ZZ>+nU,The TableEditor Editor Factory: Table Search VMaking a table searchable allows the user to search for (and optionally select) object rows which match a specified search criteria. A table is made searchable by setting the TableEditor s search trait to a TableFilter object. Doing so adds a  search icon to the table s toolbar, which displays a pop-up search dialog. The search dialog allows the user to search for the next or previous match, or to select all matching rows.BP  ,  oV-The TableEditor Editor Factory: Table Factory If users can add new rows to a table, then a factory must be provided to create the new table objects. The TableEditor traits that specify the object factory are: row_factory: A callable that creates and returns a new object instance when the user adds a new row to the table. row_factory_args: An optional tuple that contains any positional arguments that need to be passed to the factory. row_factory_kw: An optional dictionary that contains any keyword arguments that need to be passed to the factory. PWP-7 - gbebk - gOepW*The TableEditor Editor Factory: An Example  rX*The TableEditor Editor Factory: An Example The resulting view looks like:x]The TreeEditor Editor Factory RObjects often are connected together in such a way that a hierarchical or tree view of them is a useful user interface feature. Common examples: File system explorer: files are contained in directories, which are contained in other directories& Organizational chart: Employees belong to departments, which in turn belong to the company itself. A TreeEditor allows interconnected objects with traits to be displayed as a tree.XZZRZ FZ Fy^The TreeEditor Editor Factory DUsing a TreeEditor, each connected object in the graph of objects to be displayed becomes a separate tree item. Some of the features supported by the TreeEditor include: Full drag and drop support: Objects can be dragged into the tree. Objects can be dragged out of the tree. Objects can be dragged within the tree. Structural relationships between objects are enforced. Objects can be: Added Deleted Renamed The contents of objects can be edited in a separate  inspector view if desired. Each object can have a standard or custom context menu. PPPPPPP     ,  {_The TreeEditor Editor Factory AHere are some examples of TreeEditors being used in the VET tool:.BZ  }`The TreeEditor Editor Factory hLike the TableEditor, in order to provide such a rich set of user interactions, the TreeEditor needs additional information to perform its task. The extra information is divided into two parts: General information about the editor s behavior defined by traits on the TreeEditor itself. Specific information about each of the object types that can appear in the tree, provided by a set of TreeNode objects associated with the TreeEditor.  @ dI o b @  o ~aThe TreeEditor Editor Factory "The general TreeEditor traits are:.#P     cThe TreeEditor Editor Factory \A TreeNode provides information about one or more types (i.e. classes) of object that can appear in the tree: The object classes the TreeNode applies to. Which object trait (if any) contains the children of the object. Can the object s children be renamed, copied deleted or inserted? What object class instances can be added to, copied to or moved to the children of the object. The icons used to represent the object in the tree. The context menu to display when the object is right-clicked on. The view to display when the object is selected for editing. tnZZd6d,{bThe TreeEditor Editor Factory The traits for a TreeNode are:.PdThe TreeEditor Editor Factory In addition, there are several different types of and ways to use TreeNodes: If all the information about an object type is static, simply use a TreeNode and initialize its traits. If some of the information is not known until run-time, create a subclass of TreeNode and override the necessary methods. Each trait has a corresponding method that can be used to override the trait value (e.g.  get_children() overrides  children and  can_delete() overrides  delete ). Sometimes you have data that is not explicitly or conveniently hierarchical, so you need to build a model that exposes the hierarchy. In this case, you can create your model classes as subclasses of TreeNodeObject and create corresponding ObjectTreeNodes for use with the model s TreeEditor. An ObjectTreeNode simply delegates all its methods to the object it describes.4MPPB Di   >B Fi   >eThe TreeEditor Editor Factory An example (Part 1):PfThe TreeEditor Editor Factory An example (Part 2): "PgThe TreeEditor Editor Factory An example (Part 3):hThe TreeEditor Editor Factory The resulting view looks like:P/*)Saving and Restoring User GUI PreferenceseThe Traits UI allows some user preference settings to be saved without writing any code. The preferences that can be saved automatically are defined by a View and the individual editors contained in a View. Some of the user preference settings that can be saved currently are: Window/Dialog size and position Splitter bar position User defined table filtersZZQZ+HQ0+)Saving and Restoring User GUI PreferencesUser preferences are only saved when you request them to be saved. You request a preference to be saved simply by assigning a non-empty  id trait to the corresponding View, Group or Item object. In order for any preferences to be saved, a View must have a non-empty  id . The user preference values for a View are saved in a global  database under the view s  id , so the View  id should also be unique across applications and views. For example: View( & , id =  enthought.graph.vpl.graph_canvas , & )Z> ~ 1,)Saving and Restoring User GUI PreferencesNGroup and Item  id values only need to be unique within the containing View. The currently supported preference items are: View (Window/Dialog size and position) Group (Splitter bar position when layout =  split ) Item (Splitter bar position when editor = TreeEditor) Item (User defined filters when editor = TableEditor) New editors can save their preferences by implementing the  save_prefs and  restore_prefs methods.|ZZeZH0#/& % eP + >     0` 33` Sf3f` 33g` f` www3PP` ZXdbmo` \ғ3y`Ӣ` 3f3ff` 3f3FKf` hk]wwwfܹ` ff>>\`Y{ff` R>&- {p_/̴>?" dd@|?" dd@   " @ ` n?" dd@   @@``PR    @ ` ` p>> f(  t  C >A&blue_blue_gradient"  6t 0@  T Click to edit Master title style! !  0w  `  RClick to edit Master text styles Second level Third level Fourth level Fifth level!     S  0|~     B*H  0޽h ? 3380___PPT10.'{O Default Design 0 zr@ (    0 P    P*    0ܡ     R*  d  c $ ?    0  0  RClick to edit Master text styles Second level Third level Fourth level Fifth level!     S  6 _P   P*    68 _   R*  H  0޽h ? 3380___PPT10. u 0 f^4(  4  4 NN̙ ?"6@ NNN?N4  MTraits User Interface Class<E 4 NX̙ ?"6@ NNN?N@   7David C. Morrill Enthought, Inc. dmorrill@enthought.com88!` 4 C 8A traits_ui_logo2H 4 0޽h ? 3380___PPT10.S0a$  0 <$(  <r < S 0,V0@  V r < S -V ` V H < 0޽h ? 3380___PPT10.˸>$  0 ` $(   r  S T V@  V r  S ,V ` V H  0޽h ? 3380___PPT10. $  0 p$$(  $r $ S V0@  V r $ S t V ` V H $ 0޽h ? 3380___PPT10.&Qb$  0 ($(  (r ( S JV0@  V r ( S `KV ` V H ( 0޽h ? 3380___PPT10.( @$  0 ,$(  ,r , S  MV0@  V r , S |V ` V H , 0޽h ? 3380___PPT10.),  0   0 (  0 0 S |ZV@`  V 7#GUI Design 101: The MVC Big Picture 0 0\V̙"`  P  5Model 0 0("`p @ : Controller   0 0_V"`p@ @ 4ViewR 0 s *0 0L 0@ c $  0 # lGmH9Im?"0@NNN?N@h  0  fGHI?"0@NNN?N@  0  fGHI?"0@NNN?N  0 NdV̙ ?"6@ NNN?N` X  AData and Events  0 N,jV̙ ?"6@ NNN?N` H  AData and Events  0 NmV̙ ?"6@ NNN?Np X   9Control  0 NoV̙ ?"6@ NNN?N 8 ] AData and Events H 0 0޽h ?_0 000000000000 3380___PPT10.*`uf$  0 8$(  8r 8 S dvV0@  V r 8 S tfV ` V H 8 0޽h ? 3380___PPT10.-슎$  0 <$(  <r < S V0@  V r < S V ` V H < 0޽h ? 3380___PPT10..@}}$  0 @$(  @r @ S V0@  V r @ S 0V ` V H @ 0޽h ? 3380___PPT10./@:`$  0 D$(  Dr D S 0V0@  V r D S V ` V H D 0޽h ? 3380___PPT10.0P"$  0 H$(  Hr H S PV0@  V r H S (V ` V H H 0޽h ? 3380___PPT10.0hW$  0  L$(  Lr L S ؽV0@  V r L S V ` V H L 0޽h ? 3380___PPT10.1 }$  0 0P$(  Pr P S V0@  V r P S V ` V H P 0޽h ? 3380___PPT10.1$  0 @T$(  Tr T S V0@  V r T S V ` V H T 0޽h ? 3380___PPT10.2  $  0 PX$(  Xr X S X0@   r X S  `  H X 0޽h ? 3380___PPT10.2 $  0 `\$(  \r \ S 0@   r \ S  `  H \ 0޽h ? 3380___PPT10.3@ه$  0 8$(  8r 8 S x0@   r 8 S P `  H 8 0޽h ? 3380___PPT10.[@H$  0 p`$(  `r ` S (0@   r ` S ) `  H ` 0޽h ? 3380___PPT10.4p\n_$  0 d$(  dr d S 0@   r d S Ȧ `  H d 0޽h ? 3380___PPT10.5@e$  0 p d$(  dr d S ,L0@   r d S M `  H d 0޽h ? 3380___PPT10.ڸ}$O$  0 h$(  hr h S 8R0@   r h S R `  H h 0޽h ? 3380___PPT10.$  0 l$(  lr l S c0@   r l S d `  H l 0޽h ? 3380___PPT10.lH$  0 p$(  pr p S tq0@   r p S Lr `V  H p 0޽h ? 3380___PPT10.`{ $  0 t$(  tr t S P0@   r t S ( `  H t 0޽h ? 3380___PPT10. $  0 x$(  xr x S 00@   r x S  `  H x 0޽h ? 3380___PPT10.z`G$  0  h$(  hr h S 0@   r h S  `  H h 0޽h ? 3380___PPT10.ڸ`$  0 |$(  |r | S {0@   r | S D| `c  H | 0޽h ? 3380___PPT10.}^"&$  0 $(  r  S l0@   r  S D `  H  0޽h ? 3380___PPT10.}Ul$  0 $(  r  S L0@   r  S $ `  H  0޽h ? 3380___PPT10.~iH$  0  $(  r  S  0@   r  S  `  H  0޽h ? 3380___PPT10.ip$  0 $(  r  S 0@   r  S  `  H  0޽h ? 3380___PPT10.$  0 0$(  r  S  0@   r  S  `  H  0޽h ? 3380___PPT10.Z$  0  l$(  lr l S 4 0@   r l S   `  H l 0޽h ? 3380___PPT10.ڸ($  0 @$(  r  S 0@   r  S o[/  H  0޽h ? 3380___PPT10.0>$  0  p$(  pr p S )0@   r p S * `  H p 0޽h ? 3380___PPT10.۸fX$  0 P$(  r  S :0@   r  S t; `  H  0޽h ? 3380___PPT10.0/$  0  x$(  xr x S ,Ej0@  j r x S lj ` j H x 0޽h ? 3380___PPT10.ԨI$  0 `$(  r  S I0@   r  S \J `  H  0޽h ? 3380___PPT10.pl  0 pl(  r  S W   r  S hX0@     B[̙ ?"6@ NNN?N 0g  (`  ND?̙ ?"6@ NNN?NR  $my_view = View(  a , Include(  my_group ),  e ) my_group = Group(  b ,  c ,  d ) is equivalent to: my_view = View(  a ,  b ,  c ,  d ,  e )H -#H  0޽h ? 3380___PPT10.JE3  0 XP(  r  S Xp0@   r  S q `    Bhr̙ ?"6@ NNN?N` Dmy_view = View( Group(  a ,  b , id =  my_group ), Group(  x , Item(  y , id =  my_item ) ) ) is equivalent to: my_view = View( Include(  my_group ), Group(  x , Include(  my_item ) ) ) my_group = Group(  a ,  b ) my_item = Item(  y )## ?.H  0޽h ? 3380___PPT10./;D  0 D(  r  S 0@   r  S ܈ `0    B0̙ ?"6@ NNN?N0{  htraits_view = View( 'name{Filter name}', '_', Include( 'filter_view' ), title = 'Edit filter', & ) filter_view = Group() $MH  7 \ $H  0޽h ? 3380___PPT10.VB$  0 $(  r  S h0@   r  S @ `  H  0޽h ? 3380___PPT10.9$  0 $(  r  S 0@   r  S  `  H  0޽h ? 3380___PPT10.п2|  0 |(  r  S $0@   r  S 谍0 `  P  N8̙ ?"6@ NNN?Nx@ class Camera ( HasTraits ): manufacturer = Str price = Float traits_view = View(  manufacturer,  price , Include(  other ) ) other = Group() class FilmCamera ( Camera ): film_type = Enum(  35mm ,  16mm ,  8mm ,  Polaroid ) other = Group(  film_type ) class DigitalCamera ( Camera ): storage_type = Enum(  CompactFlash ,  SD ,  xD ) other = Group(  storage_type )  $ b  @     $ H  0޽h ? 3380___PPT10.PpU#  0 D#<#4?@!(  r  S ˍ0@   `   + # #"    C ̍"`  [ b ViewElements  B    C Ӎ"` [ + (`   +  # #"      C  ֍ "`  [ c ViewIElements  B     C ۍ "` [ + (`   +  # #" t   C Xލ "`  [ H Camera class  B   C "` [ + (`   + # #"     C D"`  [ fFilmCamera class B    C "` [ + (`   + # #" |u  C $"`  [ @View B   C d"` [ + Omanufacturer, price B `   + # #" 0|p  C "`  [ AGroup B   C "` [ + (`   + # #"  wu   C \"`  [ AGroup B   C |"` [ + ` film_type   B    <?"0@NNN?Nftf  <?"0@NNN?N^ b   <?"0@NNN?Nf |v ! <?"0@NNN?NO | # <?"0@NNN?Nu w~  $ 6P $"`k  @parentB  % 6%"`A M a traits_view B   & 6&"``  Bother  B  ( 6d("` q*  Aother B  * 6*"` v_ a view_elements B   , 6|","` w} a view_elements B  " .  fGH;I`C?"0@NNN?Nh " /@  fG`H>I]j?"0@NNN?N h  " 0@  fGH?I?"0@NNN?NOu `   + 1# #"   e 2 C (2"`  [ c ViewIElements  B   3 C ,/3"` [ + (`   + 4# #"  b 5 C 15"`  [ iDigitalCamera class B   6 C  86"` [ + (`   + 7# #"  o 8 C :8"`  [ AGroup B  9 C T?9"` [ + c storage_type   B   : 6?"0@NNN?N   ; 6?"0@NNN?N    < 0D<"`,   Aother B  = 0I="`    a view_elements B  " >@  fG`HWI@i?"0@NNN?N {  " ?  fGHqIS?"0@NNN?NO H  0޽h ?   ! # .  / 063:28;82>2? 3380___PPT10.C $  0 $(  r  S $Q0@   r  S Q `  H  0޽h ? 3380___PPT10.g$  0 $(  r  S |h0@   r  S Ti `  H  0޽h ? 3380___PPT10.К$  0 @$(  @r @ S n0@   r @ S ^ `  H @ 0޽h ? 3380___PPT10.͸ VZ$  0 D$(  Dr D S 0z0@   r D S } `  H D 0޽h ? 3380___PPT10.θڙf$  0  H$(  Hr H S 0@   r H S x `  H H 0޽h ? 3380___PPT10.ϸ0$  0  L$(  Lr L S P0@   r L S ( `  H L 0޽h ? 3380___PPT10.Ѹ,$  0  P$(  Pr P S \0@   r P S   `  H P 0޽h ? 3380___PPT10.Ӹ5$  0 0 T$(  Tr T S 0@   r T S ̧ `  H T 0޽h ? 3380___PPT10.Ը`d7$  0 @ X$(  Xr X S (0@   r X S  `  H X 0޽h ? 3380___PPT10.ո$  0 P \$(  \r \ S $Ǝ0@   r \ S Ǝ `  H \ 0޽h ? 3380___PPT10.ָH<$  0 ` `$(  `r ` S ю0@   r ` S Վ `  H ` 0޽h ? 3380___PPT10.׸%8;  0 ~:v:V7(  r  S 0@   L  c $X99?6L d.# # (    3 l"`d.# b fooB (  Rl(   R l!   3 $"`R! =barB    3 "`!# ewxPython controlsB  ~L   +  #    3 "`  [ Bobject B   3 x"` [ + (`   + # #" d   3 ̙"`  [ ATrait B   3 0̙"` [ + (L   + # <   3 "`  [ c EditorFactory  B    3 "` [ + (~L   + # py  3 "`  [ BEditor B   3 "` [ + (:  3 ``:  3 `d < `F  S 8 4`   + # #" @    3 "`  [ @View B   3 "` [ + (`   + # #" @    3 !"`  [ AGroup B    3 &"` [ + (`   + !# #" @ p  " 3 ("`  [ @Item B  # 3 x-"` [ + tname =  foo  B `   + $# #" (  % 3 x2"`  [ >UI B  & 3 `8"` [ + (: ' 3  : ( 3   : ) 3 l  @ `   + *# #" @   + 3 p;"`  [ CHandler B  , 3 A"` [ + (: - 3  @ F . S   : / 3 l  l : 0@ 3 y4,p 1 C D"`H @   B.control B  2 C I"` 0 B.control B  3 0,N"` p h  ?.viewB  4 0hR"`   B.handler B  5 0V"`p  b.foo B L n * 6# PO 7 3 ["`n * \UIInfo B  8 3 b"`n  ( 9 <?"0@NNN?NO( : 0d"` ?.infoB  ; 0 <?"0@NNN?N P " ?@ NG@WHvI?"0@NNN?NP @ 0|s"` `   a.ui()B  A 0x"`T  l.simple_editor()B  `   + B# #" (  C 3 d~"`  [ b ViewElements  B   D 3 "` [ + ( E <?"0@NNN?N  F 0`"`  j.view_elementsB  " G@ TGH(4Ip?"0@NNN?N (TkL -$2 H#  p I 0?"6@ NNN?N-$2J J # "`t.@/J K # "`C0@0 L s *"`t.$/ penthought.traits.ui subclassB   M s *ܒ"`C0$w1 menthought.traits.ui classB `   + O# #"  @ p P 3 d"`  [ CToolkit B  Q 3 "` [ + ( R B?"0@NNN?N  S B?"0@NNN?Np l  T B?"0@NNN?N l   s *"`h L.trait(& ) B   s *t"`g 9  i .get_editor() B     |0e0e    BPCDE(F̙ A@  A5% 8c8c     ?1 d0u0@Ty2 NP'p<'pA)BCD|E|| p@Php\P @   s " 0e@        @ABC DEEFGHIJK5%LMNOPQRSTUWYZ[ \]^_ `abN E5%  N E5%  N F   5%    !"?N@ABC DEFFGHIJK5%LMNOPQRSTUWYZ[ \]^_ `ab`@ B @  `D?"0@NNN?N    s *"` Kp  B.handler B H  0޽h ??` '"(&)&+-&. &/ 0 %89 7< 7>8%?CEDGPRQS&QT 3380___PPT10.$  0 @$(  r  S 0@   r  S \ `  H  0޽h ? 3380___PPT10.ۯp!<$  0 P$(  r  S @0@   r  S  `  H  0޽h ? 3380___PPT10.ݯ@$  0 `$(  r  S Ю0@   r  S @/K `  H  0޽h ? 3380___PPT10.ޯ$  0 p$(  r  S ݏ0@   r  S `ޏ `  H  0޽h ? 3380___PPT10.߯е   0    (  r  S \0@   | 0 S 0e0eA     ?̙ A@  A5% 8c8c     ?1 d0u0@Ty2 NP'p<'pA)BCD|E||s " 0e@        @ABC DEEFGHIJK5%LMNOPQRSTUWYZ[ \]^_ `abN E5%  N E5%  N F   5%    !"?N@ABC DEFFGHIJK5%LMNOPQRSTUWYZ[ \]^_ `abk4  c  N`̙ ?"6@ NNN?NQx8 CFor example, these are the four styles supported by the EnumEditor:&D8 8 H  0޽h ? 3380___PPT10.ȣH>>  0 ==A>=(  r  S 0@   x  c $    < gr^  #":. rn    HJ?"6@`NNN?N  MFlash @`   H~L?"6@`NNN?N  MValue @`   H|V?"6@`NNN?N  MShell @`   H`?"6@`NNN?Ng  LPlot @`*  H  ?"6@`NNN?N   l KeyBinding    @`   H ?"6@`NNN?N   LDrop @`   H ?"6@`NNN?N  KDND @`   H4?"6@`NNN?Ng   MImage @`+  H@v?"6@`NNN?N(   m AnimatedGIF    @`   Hj?"6@`NNN?N (   KLED @`   H(%??"6@`NNN?N(  NIEHTML @`   H`??"6@`NNN?Ng(   LHTML @` [ H4??"6@`NNN?N^ @ @`% Y H ?"6@`NNN?N ^ gTuple @`  W HXX?"6@`NNN?N ^ LTree @`  U Hl|J?"6@`NNN?Ng^ LText @`   H(?"6@ NNN?N_ (  OTabular @`   H01?"6@ NNN?N _ (  MTable @`   H:?"6@ NNN?N_ (  KSet @`)  HC?"6@ NNN?Ng_ (  k RGBAColor    @`(  H4?"6@ NNN?N _  jRGBColor   @`   HU?"6@ NNN?N _  MRange @`   H^?"6@ NNN?N _  LPlot @`   Hh?"6@ NNN?Ng _  LList @`  HLY?"6@ NNN?N   PInstance   @`)  HTz?"6@ NNN?N   k ImageEnum    @`(  HЃ?"6@ NNN?N  jKivaFont   @`   H?"6@ NNN?Ng   LFont @`   H?"6@ NNN?N   LFile @`$  H4?"6@ NNN?N    fEnum @`*  Hh?"6@ NNN?N  l EnableRGBA    @`    Hx?"6@ NNN?Ng   LDrop @`   H?"6@ NNN?N;  Q Directory   @`    HÒ?"6@ NNN?N ;  NCustom @`   H ͒?"6@ NNN?N;   PCompound   @`    H?"6@ NNN?Ng;  MColor @`   Hޒ?"6@ NNN?Nr; LCode @`)  H0?"6@ NNN?N r; k CheckList    @`   H@?"6@ NNN?Nr ; NButton @`   H?"6@ NNN?Ngr; OBoolean @`B ! No ?"0@NNN?NgrrB " H1 ?"0@NNN?Ng;;B # H1 ?"0@NNN?Ng  B $ H1 ?"0@NNN?Ng  B % H1 ?"0@NNN?Ng  B & H1 ?"0@NNN?Ng_ _ B ' N1 ?"0@NNN?Ng( ( B ( No ?"0@NNN?Ng^^B * H1 ?"0@NNN?Nr( B + H1 ?"0@NNN?N r ( B , H1 ?"0@NNN?Nr( B l No ?"0@NNN?Ng( g^B ) No ?"0@NNN?Ngrg( B n N1 ?"0@NNN?N( ^B r N1 ?"0@NNN?N ( ^B v N1 ?"0@NNN?N( ^B x No ?"0@NNN?N( ^B - No ?"0@NNN?Nr( B  H1 ?"0@NNN?Ng  B  H1 ?"0@NNN?Ng  B  H1 ?"0@NNN?NgH  0޽h ? 3380___PPT10.$  0 $(  r  S \0@   r  S Ա `  H  0޽h ? 3380___PPT10.Жo$  0 $(  r  S '0@   r  S |( `  H  0޽h ? 3380___PPT10.)h  0 f^  (   r   S 90@   F   B,;̙ ?"6@ NNN?N  class EMail ( HasTraits ): msg = Str spell_check = Button( 'Spell Check' ) view = View(Group( Group ( Item('msg', style='custom', resizable=True), Item('spell_check'), show_labels=False)), height = .3 ) results in this display&   ' H  D|  0 S 0e0eA     ?̙ A@  A5% 8c8c     ?1 d0u0@Ty2 NP'p<'pA)BCD|E||s " 0e@        @ABC DEEFGHIJK5%LMNOPQRSTUWYZ[ \]^_ `abN E5%  N E5%  N F   5%    !"?N@ABC DEFFGHIJK5%LMNOPQRSTUWYZ[ \]^_ `ab    r   S I~   H   0޽h ? 3380___PPT10.k  0 @(  r  S O0@   r  S O `  g  N ) def _spell_check_fired ( self ): # Perform spell checking...,uM  +#/H  0޽h ? 3380___PPT10.K  0 rjP(  r  S g0@   r  S h=    Bi̙ ?"6@ NNN?N|~ &.class EMailHandler ( Handler ): spell_check = Button( 'Spell Check' ) def handler_spell_check_changed ( self, info ): if info.initialized: # Perform spell checking... view = View( ) class EMail ( HasTraits ): msg = Str */6  (B' H  0޽h ? 3380___PPT10.P ($  0 $(  r  S 0@   r  S Ԁ `  H  0޽h ? 3380___PPT10.o  0 vn`(  r  S 0@   r  S | `    B|̙ ?"6@ NNN?NK * function( parent, editor, args, & ) where: parent: The parent window for the custom widget editor: The CustomEditor instance being used to create the custom widget args: Any additional arguments needed by the function to create the custom widget The function must return the custom widget it creates, created as a child of the parent window.6 m  F z - + A>$L AH  0޽h ? 3380___PPT10.@Q  0 OGp (   r   S 0@   r   S /$     B̙ ?"6@ NNN?NZ`h def make_calendar ( parent, editor ): import wx import wx.calendar return wx.calendar.CalendarCtrl( parent, -1, wx.DateTime_Now() ) class Appointment ( HasTraits ): description = Str date = Str view = View(Group (Group (Group (Item( name='description', style='custom', resizable=True), show_labels=False), Group (Item( name='date', editor = CustomEditor( make_calendar )), show_labels=False), orientation='horizontal')), height = 0.18) % "       C H   0޽h ? 3380___PPT10.0s   0   $ (  $r $ S ߓ0@   x $ c $ܳ    | $0 S 0e0eA     ?̙ A@  A5% 8c8c     ?1 d0u0@Ty2 NP'p<'pA)BCD|E||s " 0e@        @ABC DEEFGHIJK5%LMNOPQRSTUWYZ[ \]^_ `abN E5%  N E5%  N F   5%    !"?N@ABC DEFFGHIJK5%LMNOPQRSTUWYZ[ \]^_ `ab/   H $ 0޽h ? 3380___PPT10.0lf   0   @ (  r  S 0@   x  c $ %z   | 0 S 0e0eA 4    ?̙ A@  A5% 8c8c     ?1 d0u0@Ty2 NP'p<'pA)BCD|E||s " 0e@        @ABC DEEFGHIJK5%LMNOPQRSTUWYZ[ \]^_ `abN E5%  N E5%  N F   5%    !"?N@ABC DEFFGHIJK5%LMNOPQRSTUWYZ[ \]^_ `ab~ %x 4 H  0޽h ? 3380___PPT10. !Q  0 LD`(  r  S 0@   r  S  `     Nc̙ ?"6@ NNN?N _ Zclass Order ( HasTraits ): fruit = Str # A simple Enum won t work anymore & class Stock ( HasTraits ): fruits = List( Str ) # List of fruits on hand & b ) %H  0޽h ? 3380___PPT10.p#b}$  0 p$(  r  S  0@   r  S  [  H  0޽h ? 3380___PPT10.֨   0    (  r  S @0@   r  S F J    N4"̙ ?"6@ NNN?N>3  class Order ( HasTraits ): fruit = Str & view = View( & , Item(  fruit , editor = EnumEditor(name =  stock.fruits ) ), & )b O   N(̙ ?"6@ NNN?N S &order.edit_traits( context = {  object : order,  stock : current_stock, view =  view )$( .   0d.  M  VThis view relies on two objects: the Order being edited, and a Stock object containing the available fruits, referred to as  stock in the above view. This requires providing a context containing both objects when the Order view is displayed:V%H  0޽h ? 3380___PPT10..Y$  0 $(  r  S 0@   r  S ? ` L H  0޽h ? 3380___PPT10. DTv:  0 ,:(  ,r , S N0@    , S DU `  "p`PpH , 0޽h ? 3380___PPT10.0b$  0 0$(  0r 0 S @`0@   r 0 S a `  H 0 0޽h ? 3380___PPT10. #  0 `X 4(  4r 4 S \k0@   x 4 c $4l> a   | 40 S 0e0eA     ?̙ A@  A5% 8c8c     ?1 d0u0@Ty2 NP'p<'pA)BCD|E||s " 0e@        @ABC DEEFGHIJK5%LMNOPQRSTUWYZ[ \]^_ `abN E5%  N E5%  N F   5%    !"?N@ABC DEFFGHIJK5%LMNOPQRSTUWYZ[ \]^_ `ab ` r    4 Bq̙ ?"6@ NNN?N x class Address ( HasTraits ): street = Str city = Str state = Str zip = Str view = View( [ [ 'street' ], [ 'city', 'state', 'zip', orientation='horizontal'] ], buttons = [ 'OK', 'Cancel' ] ) class Person ( HasTraits ): name = Str age = Int sex = Enum( 'male', 'female' ) address = Instance( Address, () ) view = View( [ [ 'name' ], [ [ 'age', 'sex', orientation='horizontal' ], [ 'address', show_labels=False], orientation='horizontal' ] ], buttons = [ 'OK', 'Cancel' ] )&)  L | 40 S 0e0eA     ?̙ A@  A5% 8c8c     ?1 d0u0@Ty2 NP'p<'pA)BCD|E||s " 0e@        @ABC DEEFGHIJK5%LMNOPQRSTUWYZ[ \]^_ `abN E5%  N E5%  N F   5%    !"?N@ABC DEFFGHIJK5%LMNOPQRSTUWYZ[ \]^_ `abP @%  "  4  `GHI?"0@NNN?N@ H 4 0޽h ? 44 4 3380___PPT10.0;[  0 h` (  r  S 0@   x  c $Ȑ s  | 0 S 0e0eA     ?̙ A@  A5% 8c8c     ?1 d0u0@Ty2 NP'p<'pA)BCD|E||s " 0e@        @ABC DEEFGHIJK5%LMNOPQRSTUWYZ[ \]^_ `abN E5%  N E5%  N F   5%    !"?N@ABC DEFFGHIJK5%LMNOPQRSTUWYZ[ \]^_ `abV F   B  B̙ ?"6@ NNN?N' N class Address ( HasTraits ): street = Str city = Str state = Str zip = Str view = View( [ [ 'street' ], [ '13', 'city', 'state', 'zip', '-' ] ], buttons = [ 'OK', 'Cancel' ] ) class Person ( HasTraits ): name = Str age = Int sex = Enum( 'male', 'female' ) address = Instance( Address, () ) view = View( [ [ '9', 'name', '-' ], [ '17', 'age', 'sex', '-' ], [ Item( 'address', style = 'custom' ), '-<>' ] ], buttons = [ 'OK', 'Cancel' ] )  MH  0޽h ? 3380___PPT10.E}$  0 H$(  Hr H S 0@   r H S 0 `  H H 0޽h ? 3380___PPT10.Fц$  0 L$(  Lr L S 0@   r L S P  H L 0޽h ? 3380___PPT10.$  0  P$(  Pr P S 4̘0@   r P S  ͘ `  H P 0޽h ? 3380___PPT10.! q`8  0 0T8(  Tr T S ۘ0@   x T c $ۘ<   | T0 S 0e0eA     ?̙ A@  A5% 8c8c     ?1 d0u0@Ty2 NP'p<'pA)BCD|E||s " 0e@        @ABC DEEFGHIJK5%LMNOPQRSTUWYZ[ \]^_ `abN E5%  N E5%  N F   5%    !"?N@ABC DEFFGHIJK5%LMNOPQRSTUWYZ[ \]^_ `abXxG   T Nݘ̙ ?"6@ NNN?N l BPclass Person ( HasTraits ): name = Str age = Int phone = Regex( value = '000-0000', regex = '\d\d\d[-]\d\d\d\d' ) view = View( 'name', 'age', 'phone' ) class Team ( HasTraits ): name = Str captain = Instance( Person ) roster = List( Person ) view = View( 'name', '_', Item( 'captain', editor = InstanceEditor( name = 'roster', editable = False ) ), buttons = [  OK ,  Cancel ] )$)@9 6G b| T0 S 0e0eA     ?̙ A@  A5% 8c8c     ?1 d0u0@Ty2 NP'p<'pA)BCD|E||s " 0e@        @ABC DEEFGHIJK5%LMNOPQRSTUWYZ[ \]^_ `abN E5%  N E5%  N F   5%    !"?N@ABC DEFFGHIJK5%LMNOPQRSTUWYZ[ \]^_ `ab Xx   H T 0޽h ? 3380___PPT10." Ytr  0  D (  Dr D S 0@   x D c $] 7  | D0 S 0e0eA     ?̙ A@  A5% 8c8c     ?1 d0u0@Ty2 NP'p<'pA)BCD|E||s " 0e@        @ABC DEEFGHIJK5%LMNOPQRSTUWYZ[ \]^_ `abN E5%  N E5%  N F   5%    !"?N@ABC DEFFGHIJK5%LMNOPQRSTUWYZ[ \]^_ `ab' m   D B̙ ?"6@ NNN?Nw Bclass Person ( HasStrictTraits ): name = Str age = Int phone = Regex( value = '000-0000', regex = '\d\d\d[-]\d\d\d\d' ) traits_view = View( ['name', 'age', 'phone', style='readonly'] ) edit_view = View( ['name', 'age', 'phone'], buttons = [ 'OK', 'Cancel' ] ) class Team ( HasStrictTraits ): name = Str captain = Instance( Person ) roster = List( Person ) traits_view = View( [ [ Item('name'), Item('_'), Item( 'captain', editor = InstanceEditor( name = 'roster', editable = False, values = [ InstanceFactoryChoice( klass = Person, name = 'Non player', view = 'edit_view' ) ] ) ), Item( '_') ], [ Item('captain', style='custom') ], buttons = [ 'OK', 'Cancel' ] )*C   L ) yO ' A S N  D ZA ?̙ ?"6@ NNN?N     D ZA P?̙ ?"6@ NNN?N#  8i P"  D  `GHIS?"0@NNN?N   D@ N?"0@NNN?N r   D N?"0@NNN?N   D ZA ?̙ ?"6@ NNN?N&rl H D 0޽h ??`DD DD D D D D D 3380___PPT10.}  0 2*l(  lr l S 0@   r l S l;E   l N-̙ ?"6@ NNN?N)v ` view = View( Group( Group( Item( 'company', editor = tree_editor, resizable = True ) show_labels=False), Group( Group( Item( label ='Employee of the Month', style = 'custom'), Item( 'eom', editor = InstanceEditor( values = [ InstanceDropChoice( klass = Employee, selectable = True ) ] ), style='custom', resizable = True ) show_labels = False), Group( Item( label = 'Department of the Month}', style='custom'), Item( 'dom', editor = InstanceEditor( values = [ InstanceDropChoice( klass = Department ) ] ), style='custom', resizable = True )), show_labels = False, layout = 'split' ), orientation = 'horizontal', show_labels = False, layout = 'split' ), title = 'Company Structure', handler = TreeHandler(), buttons = [  OK ,  Cancel ], resizable = True, width = .5, height = .5 )@ 7 5   y a 8f 6d N V uH l 0޽h ? 3380___PPT10.-^   0   p (  pr p S P0@   x p c $XVe I  | p0 S 0e0eA     ?̙ A@  A5% 8c8c     ?1 d0u0@Ty2 NP'p<'pA)BCD|E||s " 0e@        @ABC DEEFGHIJK5%LMNOPQRSTUWYZ[ \]^_ `abN E5%  N E5%  N F   5%    !"?N@ABC DEFFGHIJK5%LMNOPQRSTUWYZ[ \]^_ `ab8  VH p 0޽h ? 3380___PPT10..-e  0 xe(  xr x S Z0@   x x c $Z 5i   x N\̙ ?"6@ NNN?Np class Person ( HasTraits ): name = Str age = Int phone = Regex( value = '000-0000', regex = '\d\d\d[-]\d\d\d\d' ) traits_view = View( 'name', 'age', 'phone' ) class Team ( HasTraits ): name = Str captain = Instance( Person ) roster = List( Person ) traits_view = View( Item('name'), Item('_'), Item( 'captain', editor = InstanceEditor( name = 'roster' ), style='custom'), buttons = [ 'Undo', 'OK', 'Cancel' ] )** 7 1 P  | x0 S 0e0eA     ?̙ A@  A5% 8c8c     ?1 d0u0@Ty2 NP'p<'pA)BCD|E||s " 0e@        @ABC DEEFGHIJK5%LMNOPQRSTUWYZ[ \]^_ `abN E5%  N E5%  N F   5%    !"?N@ABC DEFFGHIJK5%LMNOPQRSTUWYZ[ \]^_ `ab)    H x 0޽h ? 3380___PPT10.3Rt_$  0 h$(  hr h S x{0@   r h S P| `  H h 0޽h ? 3380___PPT10.,p$  0 $(  r  S 0@   r  S le%e  H  0޽h ? 3380___PPT10.ͳ9t   0    (  r  S 0@   x  c $/g   | 0 S 0e0eA     ?̙ A@  A5% 8c8c     ?1 d0u0@Ty2 NP'p<'pA)BCD|E||s " 0e@        @ABC DEEFGHIJK5%LMNOPQRSTUWYZ[ \]^_ `abN E5%  N E5%  N F   5%    !"?N@ABC DEFFGHIJK5%LMNOPQRSTUWYZ[ \]^_ `ab_ 5?  H  0޽h ? 3380___PPT10.Գ@$  0 $(  r  S 0@   r  S ܢ `  H  0޽h ? 3380___PPT10.ϳV1B  0 AA @1A(  r  S ,0@   @ Z  #">2 Z *  HP̙ ?"6@ NNN?N1  l row_height    @`,  H?"6@ NNN?N 1 n columns_name    @`   H?"6@ NNN?NF  Lrows @`+  H̙?"6@ NNN?NZ F m reorderable    @` , Hܻ̙ ?"6@ NNN?N1 @ @`  + Hģ?"6@ NNN?N 1 Nsearch @`* * H,Σ?"6@ NNN?NF  l line_color    @`) ) Hգ?"6@ NNN?NZF k edit_view    @` ( Hޣ̙ ?"6@ NNN?N1   Pselected   @`/ ' H̙ ?"6@ NNN?N 1  qrow_label_width @`* & H,?"6@ NNN?NF  l label_font    @`) % Hh̙?"6@ NNN?NZ F  k deletable    @`  $ H̙?"6@ NNN?N1   Oreverse @`. # H ?"6@ NNN?N 1  prow_factory_kw @`+ " H?"6@ NNN?NF  m label_color    @` ! H!̙?"6@ NNN?NZ F  T configurable   @`(   H*̙?"6@ NNN?N1   jauto_add   @`0  H3?"6@ NNN?N 1  rrow_factory_args @`.  H\=?"6@ NNN?NF  plabel_bg_color @`   HdF?"6@ NNN?NZ F  Ocolumns @`(  HO̙?"6@ NNN?N1   jsortable   @`+  HY?"6@ NNN?N 1  m row_factory    @`   H$b?"6@ NNN?NF  Ofilters @`3  H`k̙ ?"6@ NNN?NZ F  ucolumn_label_height @`*  HHu̙?"6@ NNN?N1  l sort_model    @`-  H~?"6@ NNN?N 1  o other_columns  @`   H?"6@ NNN?NF  Nfilter @`7  HȐ?"6@ NNN?NZF  ycell_read_only_bg_color @`*  H̙?"6@ NNN?N1 l show_lines    @`  H̙ ?"6@ NNN?N 1 S orientation   @`  H̙?"6@ NNN?NF  Peditable   @`)  Hȶ?"6@ NNN?NZF k cell_font    @`2  H̙?"6@ NNN?N1 tshow_column_labels @`)  HHɬ?"6@ NNN?N 1 k on_select    @`/  HӬ?"6@ NNN?NF  qedit_view_width @`*   Hͬ?"6@ NNN?NZF l cell_color    @`/   Hx?"6@ NNN?N1 qselection_color @`)   H?"6@ NNN?N 1 k on_dclick    @`0   H?"6@ NNN?NF  redit_view_height @`-   H?"6@ NNN?NZF o cell_bg_color  @`2  H<?"6@ NNN?N1 tselection_bg_color @`   H?"6@ NNN?N 1 Mmenu  @`1  H$?"6@ NNN?NF  sedit_view_handler @`*  Hd(̙?"6@ NNN?NZF l auto_size     @`B - No ?"0@NNN?NZB . H1 ?"0@NNN?NZB / H1 ?"0@NNN?NZB 0 H1 ?"0@NNN?NZB 1 H1 ?"0@NNN?NZB 2 H1 ?"0@NNN?NZ  B 3 H1 ?"0@NNN?NZ  B 4 H1 ?"0@NNN?NZ  B 5 H1 ?"0@NNN?NZ  B 6 H1 ?"0@NNN?NZ  B 7 No ?"0@NNN?NZB 8 No ?"0@NNN?NZZB 9 H1 ?"0@NNN?NFFB : H1 ?"0@NNN?N  B ; H1 ?"0@NNN?N11B < No ?"0@NNN?NB  H1 ?"0@NNN?NZH  0޽h ? 3380___PPT10.Գ$  0 $(  r  S 0@   r  S  `  H  0޽h ? 3380___PPT10..$  0 @$(  r  S G0@   r  S `Hu[p  H  0޽h ? 3380___PPT10.߳`$  0 P$(  r  S ^0@   r  S lP `  H  0޽h ? 3380___PPT10.{$  0 `$(  r  S xj0@   r  S 2 CIC +  Hd,?"6@ NNN?NpZC m%Layout orientation of tree and editor&& @`  H0?"6@ NNN?NIZpC S orientation   @`*  H<:̙ ?"6@ NNN?Npr Z l$Called when a node is double clicked%% @`)  HJ̙ ?"6@ NNN?NIr pZ k on_dclick    @`$  HS̙ ?"6@ NNN?Np r  fCalled when a node is selected @`)  H]̙ ?"6@ NNN?NI pr  k on_select    @`!  HN?"6@ NNN?Np   cSize of the tree node icons @`)  Ho?"6@ NNN?NI p  k icon_size    @`*  H$r̙?"6@ NNN?Np   l$Should the tree root node be hidden?%% @`)  HH̙?"6@ NNN?NI p  k hide_root    @`#  Hp̙?"6@ NNN?Np   eShould tree nodes have icons? @`*  Hx̙?"6@ NNN?NI p  l show_icons    @`#  Hd̙ ?"6@ NNN?Np  eRef to a shared object editor @`    H4̙ ?"6@ NNN?NIp  Neditor @`(   H̙?"6@ NNN?Np j"Is the editor shared across trees?## @`-   H ̙?"6@ NNN?NIp o shared_editor  @`0   H(̙?"6@ NNN?Np r"Are the individual nodes editable?#" @`   H$β̙?"6@ NNN?NIp Peditable   @`]  Hϲ̙ ?"6@ NNN?Np, #(TreeNode,...) -> MultiTreeNode map$$,  @`+  H̙ ?"6@ NNN?NI,p m multi_nodes    @`B  H?"6@ NNN?NpC, Supported TreeNode objects   @`   Hd?"6@ NNN?NICp, O nodes  @`B  No ?"0@NNN?NICCB  H1 ?"0@NNN?NI,,B  H1 ?"0@NNN?NIB  H1 ?"0@NNN?NIB  H1 ?"0@NNN?NIB   H1 ?"0@NNN?NI  B ! H1 ?"0@NNN?NI  B " H1 ?"0@NNN?NI  B # H1 ?"0@NNN?NI  B $ H1 ?"0@NNN?NIr r B % H1 ?"0@NNN?NIZZB & No ?"0@NNN?NICCB ' No ?"0@NNN?NICICB ( H1 ?"0@NNN?NpCpCB ) No ?"0@NNN?NCCH  0޽h ? 3380___PPT10.0L$  0 0$(  r  S 0@   r  S ^ `  H  0޽h ? 3380___PPT10.`X /#  0 ""%E/"(  r  S 0@   x  c $< H    k[  E #"."&$&&&$&k[     H̙ ?"6@ NNN?N [  Lview @`   H)̙ ?"6@ NNN?N  Lmenu @`  H9?"6@ NNN?Nk  Q formatter   @`   H(2̙?"6@ NNN?N [  Nrename @`   HDK?"6@ NNN?N  Mlabel @`   HLT̙?"6@ NNN?Nk  Ndelete @`)  H]?"6@ NNN?N [  k on_select    @`   Hf̙?"6@ NNN?N  Ninsert @`   Hlo̙?"6@ NNN?Nk  Lcopy @`)  HTy?"6@ NNN?N c [  k on_dclick    @`)  H?"6@ NNN?N c  k icon_path    @`  H?"6@ NNN?Nkc  Pchildren   @`(   H?"6@ NNN?N =[c  jnode_for   @`)   H?"6@ NNN?N = c  k icon_open    @`)   H̙?"6@ NNN?Nk= c  k auto_open    @`    Hذ?"6@ NNN?N [= Lname @`*   H?"6@ NNN?N  = l icon_group    @`*  Hö̙?"6@ NNN?Nk = l auto_close    @`  H̶?"6@ NNN?N [ Tmove @`)  H$ֶ?"6@ NNN?N   k icon_item    @`   H߶?"6@ NNN?Nk  Kadd @`B  No ?"0@NNN?Nk[B  H1 ?"0@NNN?Nk[B  H1 ?"0@NNN?Nk=[=B  H1 ?"0@NNN?Nkc [c B  H1 ?"0@NNN?Nk [ B  H1 ?"0@NNN?Nk [ B   H1 ?"0@NNN?Nk [ B ! No ?"0@NNN?Nk [ B " No ?"0@NNN?Nkk B # H1 ?"0@NNN?N  B $ H1 ?"0@NNN?N  B % No ?"0@NNN?N[[ H  0޽h ? 3380___PPT10.@:p$  0 @$(  r  S 0@   r  S 0Ͷ `  H  0޽h ? 3380___PPT10.7  0 P (   r   S 0@   r   S  `  r   N, ̙ ?"6@ NNN?Nb  zclass Employee ( HasTraits ): name = Str( '<unknown>' ) title = Str phone = Regex( regex = r'\d\d\d-\d\d\d\d' ) def default_title ( self ): self.title = 'Senior Engineer class Department ( HasTraits ): name = Str( '<unknown>' ) employees = List( Employee ) class Company ( HasTraits ): name = Str( '<unknown>' ) departments = List( Department ) employees = List( Employee ) class Partner ( HasTraits ): name = Str( '<unknown>' ) company = Instance( Company )>> !  ) C s 3H   0޽h ? 3380___PPT10.@K   0 J B `$ (  $r $ S $0@   r $ S  `   $ NH̙ ?"6@ NNN?N R  (*no_view = View() tree_editor = TreeEditor( nodes = [ TreeNode( node_for = [ Company ], auto_open = True, children = '', label = 'name', view = View( [ 'name' ] ), TreeNode( node_for = [ Company ], auto_open = True, children = 'departments', label = '=Departments', view = no_view, add = [ Department ] ), ++  # |# ? $ N0̙ ?"6@ NNN?Nu    TreeNode( node_for = [ Company ], auto_open = True, children = 'employees', label = '=Employees', view = no_view, add = [ Employee ] ), TreeNode( node_for = [ Department ], auto_open = True, children = 'employees', label = 'name', view = View( [ 'name' ] ), add = [ Employee ] ), TreeNode( node_for = [ Employee ], auto_open = True, label = 'name', view = View( [ 'name', 'title', 'phone' ] ) ) ] ) # <& J$ W(H $ 0޽h ? 3380___PPT10.  0 `Xp((  (r ( S L0@   r ( S 8M `   ( NO̙ ?"6@ NNN?N>/:  view = View( Group( Item( name = 'company', editor = tree_editor, resizable = True ), show_labels = False), title = 'Company Structure', buttons = [  OK ,  Cancel ], resizable = True, width = .3, height = .3 ) >b d H ( 0޽h ? 3380___PPT10.O    0   , (  ,r , S a0@   x , c $b &  | ,0 S 0e0eA 7    ?̙ A@  A5% 8c8c     ?1 d0u0@Ty2 NP'p<'pA)BCD|E||s " 0e@        @ABC DEEFGHIJK5%LMNOPQRSTUWYZ[ \]^_ `abN E5%  N E5%  N F   5%    !"?N@ABC DEFFGHIJK5%LMNOPQRSTUWYZ[ \]^_ `ab'  7 H , 0޽h ? 3380___PPT10.0]f$  0 $(  r  S m0@   r  S n `  H  0޽h ? 3380___PPT10.ׯ$  0  $(  r  S y0@   r  S y `  H  0޽h ? 3380___PPT10.د z@$  0 0$(  r  S 0@   r  S x `  H  0޽h ? 3380___PPT10.گPFO"p>x @e [SS24MN 52Pn:^]Jijky eBw*,ð,* |>wcqcOXn.ρFǼc^ pcr1gba$a,t8GQx4b#<=jvPZmK4N3ZP!(m;gs{+m{zU|U3|n2ܸ,粋λuŤa-}ZqOw8Ҩf&=׭aƭ n}oA"M;P˼ߎۋ?ԼݝzK3; oa1w>±؛F<O“<O <̓l<|/ċb/EN ^Wx^x6f06°(0Cø[c4ބ1x3x x+v2N`Wݱގ=ށ~wb4āx 88p(ϜD|/4#(>$>Op# y|_ėeLWU| _7MoG|q,C??OS '$~_ Noq*Np:1g,??p?|\ qbLt_0p fRe;9f{U1 `㟸_7F܄q nſqnX;qzzXpl 1ă0CP< #H< cXlx'x xgxx^x ^aclx%^W5x-^M6([& [[v۰v.aw쁷cOw`o}@ n`}8D|/|GQ| 'I| 8G>/˘o8 ·/1.X~ 9NI8 ¯Ttc Y898< "LŘ阁`&fƥ+ws0 \0Wc>`!",?q-ÿp=n 7܊6܎;w.v8zXpl 1ă0CP< #H< cXlx'x xgxx^x ^aclx%^W5x-^M6([& [[v۰v.aw쁷cOw`o}@ n`}8D|/|GQ| 'I| 8G>/˘o8 ·/1.X~ 9NI8 ¯Ttc Y898< "LŘ阁`&fƥ+ws0 \0Wc>`!",?q-ÿp=n 7܊6܎;w.0 #@<#`<p<ģh<Fx'xxgxxx^x6&x9^WUx5^uas[`Kވ1o`[a{;`G ;ag]vx;^x>a,މqĻ0xLAx!x/އC~Lp>‡a|q|ħi#p$>/I -|h{>q~ ~xD1/+)-NiN=LsGßg p!.T\i fb.l\o ?0sq9 p5c,b: ܈p3n7nKp'BaX !FxFxxGx 8<O$<OS4<3,<s<</ "/K2lMrīj)6x=7`+[c4ބ1x3x x+vxvb7=v쉽}/Xwaލ񘀃C^0|>>O8GH7>g9|_%||_ |G[68}??8?lj8 'c2~_W5~S[;3{L8 g8??8B\03,\ٸp`r\+qj,5X'u 7f܂[o܆qN܅4Oԅa=`86A[cp;O“<O <³</‹//+J kZb3lc s l7bkƛ0o6ovooN`Wݱގ=ށ~wb.û1pރqދP!|G1|'}W}/sekh.M%BXbgƷCt+E(](](](](](]8?Br[!܅r[!܅r[!܅r[!܅r[!>ŋSBf椧G!Μ 5ȅ:gVh !D17#cfp_BC%{wBCBr[!EO+"(](](](](](](](](](](](](](](](](](](](](](]SBzBۆef1bR҈Tؚnr@l|sF,H 8' 2%}܎5ߚiϱkمD3#*{ARS&ިB#!m(do,!Yܙ~=4'%fkִkEk2=mpp7[Q ]]Wܚ;oH 9`WM7[Q 5u5 gZ;GQ#ބߜ?BZ@ ߶cTN*jIJ@3ð&Xr\aj`89rb $~q79BԴd%9xěeX`Ƥ#*Z2ݵޚu>i];W$K:'~7pB;5'3sB2N{OPB`n](](](](](](](](](](](](](](](](](](](](](](](](](](](](](](](3G&gOKn!D(gم!!vV\YcSh8?82ZSncSkHM{1k:+=՞ܓ$nڷ: DGQݹ=36{dla2(d{foZscmmبJbeB`R҂Yls;-mvzz|g+' ˧oG\fϹ4Vs% 539]9o<$krXpvط<+=E}aN !j>s22?i/-Iq`,7Nn;E/i8Rm߷ܶio<;8IJB`ip=*퀔;3kwmvg,Sܥ3+'d/)L͌K^WBAs{϶POd0+ !D-:r\ڑSƯ}C6Qu*B!*C-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-bs{)B!3HOnsssC#ngNF{3f+13^v/ B!!ђB!!\Un !D A-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B-B]ULBT!555*jm嶚r[殦Vn)jjjj53 #(m cĤQQم\5bA5Tk(XjͷpNeKn+>ٹk5Ӟco!0 -;fFT$嶚Z\uf=M!i I ٚ5mmZx-̸xcsHL^#cFx<9hPSSsCsonW6/zfmz"G,Ha綝1sFsr(Յv3u՝(՚1F'g4s '(v&5k"vRVϙ5 SckDřΑ oTx'۟ IgÈջ8'GZm#>737D%I FTGm幽5$}~ӺvQI~g*tOv!rn)Dcs6W~&=ldtᑊsvjfn0`'v?vUVjs;[QnUsSn+Քm555w5r[MM]MVSSsWSn+Ք' Qn !D@-B-B-B-B-B-B-B-B-B-B-B-B-B-B-b/r{im!vs}BB.B.B.B.B.B.B.B.B.B.B.B.BYYqQمh% ̫gEمLgLf%cգӓB^F!oTwn :ȥ)m̬%ٗWn ! )ii,6;=k.[fZջB5fd̬vT~m$"YcSBs22?i/-Iq`'1C|k$'K*'qvˏ!!5A\OJr2*;/ivӓo ̸$CBOnW*BQܶs0k)"-Pn !pvvBpB.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.1g.^"b04-mr{i{ܜ!ۙA{3f+13^v/ B!!ђB!!\Un !D A-B-B-B].͚2ݷt34sBW\)UȒ5OT'<8s͛6dϟ>{| >TsQQnW!اz.͛lmw(ٹs˵΅ #X.LlΈ(椆y3j ɚ;@GREG]Usx g}n7Vuݎr ՞qFQgk>I L4c›]()ٸuxg{yg #$s{L'NpV|(EG]UX+(,FOg{y v Q(}Wj.DBwBwvof#&%UZScYۀ{[\񻃬{ =Uc"$Mn7;w_1'^G+q*ۚMg+ϒW܂Nm!D$^ܮl_nWЊ Q !Dͤs%0]8gBv&5bWRjYkqF5L򊟉 $B;8hDQim#>)GFK|iƤ#*ݣ^ښu>i];W$3K:'Ke\5SԜTЇٽϓg4mK[Ռ~_R5ԐqͥOP69h=+}7֗?o۾}GIJ~ﻠ_ ~EA0GCǚ_k6r~yb߶!G#]˰./oܸxvFwE%)'&]A<ߗΠOA8Q53/{=E]ULm}o-x7[n\kEo:;~pQ߯UߗsuJI~q)Ǻ~u<\pڸ3Q޲zK~41?)^ӚK= !/naOkMiPӢkU]Yz6)ZpÕS9}gy5`eFo/f˱~a_Q{myF+Q53{FU}Ư'?Zi.-~hu'翵xi_?.lw<ޯ;Uߗ S :/YM59iUmק!vU1e<3py^G ^^[`~w=ǚ٥gĜZs:A*A]|?}GUT=C|ͫ%jU98w9wsd}Iռܮr y]@5!m!pm!pm!pm!pm!pm!p{m!{'+"(](](](](](](]6ƦfFKF9Y#⢖r1XߏfL.fgFG GEV.L <qB확owq$lwymd[KD09Dzkab_- vZWeԎYi++T2cyJ1s;ۥ(+&jܶIu˕BʜOKng{GKRX3!Z6r22^E-APM-Pn !Pn !Pn !Pn !Pn !Pn !( BQ1BB B B B B B B B B B B B B B B}홋! MK?IOKB9$j unLKB*bnFz{A4! GK: ! sU-5B suؓBzB.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.U1O!DRP0=jjjjUԪ Vne{oo74Ն}iiL0wK=m嶚ZۦY͟c틦Hc7;~'o&r[MM-m,Vk#cFIƔiߘޓnzr[MM-m:cI_&i_O4 OMmÈ2J[31)iDTTva*WXPlM7{9Z 6>9#ZGDۊOvnǚoʹ[>&[v͌Im#1źĘ11ON9:xBjGn;sՙ4KH&3w_n+$'%fkִkEk2⍽9;cF猎1FQnյfbg͵ٙ~ms7ܮl_n+nۀEX0+Ù1F'g4m9m5ֶ$sBbG E_okOmKa8SZ9RaX7g+ );Șe/mzjjn;a5R;oNWK+L5g;GN,X~\Qpo߶[b'%55ж$?=% X8uӂiF|foJ`$kIgs{kIFu ^5T=:rQ_~$!04vv@̸3ҧ%X.%XZs%BT_n{uy2aW;r%[26jOsX-:r{Qn !npWJ ! 65>=]-A-B-B-B-™۩'M5R[Y-Kzro'[(}E'L:e Ojo8g1, `lgcyi BT- 5V |ղVƲ^ҋ-}Xs:k4'KD#IQw~@}Mqel0?v03kOp !?TDP>X{o76v7t3v7abScSҿD)u4bxɺ kz[E%|H_]`jeg7zOp3s{#7 # ۽MJd]5 c+21QDQtnՅ G \>l‘#/&j'rYA|qW .H^rع_gM<ل_֬m, m+_bJ@%=w-9EB~ Q+;;G]~c7sSYѩg޴SZ:2juh:̰Ҍ fl<mMhH}V8C;}a];|ߜ]׵_o,6yNYݹ0O?n+awDLlŞRvN;M6ڞ+^ռϪW];yMX}QڹG) zg3ur;Ld~[=$Vn. :GwNϥ7$i\a ))h[5|mc|0V2 ^{ݭ(rGp'e,OUEoovȒG".g#gp?S`Fndx}s+=ݜ*ޔEu"ɿ{'!Fk%_k 9y7[pA³zaoSx`˼;wQfnϻ\nEܶX:1fuGw{dݚa\5=~Ø=# 7=ioM2%O2b;p(]D6z`]_^X2w{ۺF7uS/2X=w, bIAζ1;ۦcEkK S읱n7o4BXzv[wι BgQw7elŽrrȦK\E^Ѵ8 Nx=VtvH;Ǒofn]|/'wkf;86[':-ʖ΋v֒du1[0f7k Ksoo.sHg~۴cؖfۂ[-Ëkýaݩ n!wA6y1w=툾!.ـb 9w(W{M,$ov|s7I sʼn1m =cEE؉WGb[x oiH~e|@5~;ءvǵYu Kk}y4sc$=Q$FzEl}'އEsۣ:Hn{3F6u۬a!6hQz1r76}FM0Kn"^2 ojMn%_m/s{mMBa5u,0iyEۻ:ߛ..a%OjvOeIYG^noWc>@gn)ro}N^F.sz a^^bonY9 Ѱ|3ga#{-F ljZ1E 0,ٵqrF0EK3+[ݚo-aV̊Loܱ_rϛ _lv3O7Fmv-Zq vfn_ce{ -qAo]cu;SNiwjۯ8c4Ob}Q r{ FU`~3IAt"e;miF}CV۳g z$҉];,~ϚG l^ֵr.fTnVj9iO;YlKb-bث؋ !#m75s+{$` z 4duжڹWynYyFgߺ6_m6MJ;\n/k㽹.ft۹Gˈ;ECKw 7QZkdgm򺄳ZoK?jYSn::˱%܎G 3|;Ҟ>݊3ڮ8݊;/'^;mB{ifbnl.rEEZ]xG=7;)YѰ .1/`yv>+U@iOw:r;k<^w귪^_qAu̽]I~6қyrف_m?2=[=C_!xq7tn"`n_={+"\mwSU-+_|ۊKn˹]r{Efnt/g~v2"t6sQdM0 +Bۤ [X_#\!BB?"cmCz׊{hs|;(ot_u]V\)mYM_Yrk'#vc9\>ܶ&Hloo_m嶢E-\5zvnwO,xvǮ{??V_=<$=嵉˻U- nI? ;m+Gn;Xߢankf6 DA[s,kFxpԧ3a=+C/g䚸 <^haG xGbmCVUWX~^c.7fnO=, 2䳝NVt[hąBמ 7q8o|s.Sq1a:f/Yq)2W*՘XkO\/\p#n͸߸ , =h400 #@<#`<p<ģh<Fx'xxgxxx^x6&x9^WUx5^uas[`Kވ1o`[a{;`G ;ag]vx;^x>a,މqĻ0xLAx!x/އC~Lp>‡a|q|ħi#p$>/I -|h{>q~ ~xD1/+)-NiN=LsGßg p!.T\i fb.l\o ?0sq9 p5c,b: ܈p3n7nKp'B yc=`86A!x(x$G1x,6x<Oēd<Ot<ijl<|/ċb/˰16 «æ [bހFlx-;m ;cݰ;۱';7cNp ޅqx7c{p0{>c">A>#(>$>Op# y|_ėeLWU| _7MoG|q,C??OS '$~_ Noq*Np:1g,??p?|\ qbLt_0p fRe;9qU1 `㟸_7F܄q nſqnX;qzЈ>ba$xGx<O“<O <³</‹//+J kZb3lc lQx5FM7cl`;lb숷a']+voǞ b?;?x 88p(ޏ_>>O>q3||_—1 _W5|7qo;_c]|DZ8?#?O3sp2&%~_78ũ8 8p6sp.yq.E1 1L%KW `..Wa|,B\EXZ\z܀qn-mw` ]A@X !FxFxxGx 8<O$<OS4<3,<s<</ "/K2lMrīj)6x=7`+[c4ބ1x3x x+vxvb7=v쉽}/Xwaލ񘀃C^0|>>O8GH7>g9|_%||_ |G[68}??8?lj8 'c2~_W5~S[;3{L8 g8??8B\03,\ٸp`r\+qj,5X'u 7f܂[o܆qN܅4>ba$xGx<O“ҘsMj6"Gi>va=3Կ|]œO6k7nۜ_]v_GǭMz:2z[1z ͉^t/cW*{65='6bn~`/ekL;0lkWX2Bkz[b+7)3m֛YٷcQ_U9_ ~;+Z*U36Wy5(({rkn=b}6ߵ[gQ=bnJIxL.ۦ7/k}h3ӆ>|CnZ"Maxd<̙cD#V<3_|u|kȇ ?[m6N/c9b"]潭XV=C[xbF6kS<(hBĀ1SvF},ۦn=,2;xh͈XͭYD{*&~~admӘ%x.X>|h /m 7w>iSUn4_fֿKil0;{c~mo-|Nxxxd<b[]zܗ =9߇`8yF\"_ZKz{S9(]G.n]ۧ 7sS9~4wlSi?p 17.o/Uo_axu"[P|g tŘiV.WJ rejued̔]dck k\ۯ07]xxڕi1{Koo -߲0~w0ѱ*9ӮLA]v4T>h7TYŘﹽL 6l ɓ%7{o.pu۪m~-ƈrl8dgĐfSw"]hݗIvn]-1uGr̲*KyFoG:-/ZG8*լ!X ;V__lQUeTxizVT\VjSLK%{\O߶nM/Ids+7!|R$L[]kwI-t>JPs6\8ƚ<[4ȷonZaO8JIX)W筻=?ϩtGq9Ĭy4=)@rp{^ii3gbcx_^$OeWEUL o'//΍+RUIqea2^3J6QU3^Ψ5_ҰqYTտ.u_˨]FW2_QUeTտ.u_˨]FWk OP+g4_A?ܯK7KZ+`DTԈTD]U*{ {>$L*_"ke-0#)tIkSlkɅ٩/7+DK-{"晫2猎)9焾jkI9o}'e%XE+d֜|rǿo-7,?A׿$)0'TtW8+7Qv~\-8oo AU;w^qN-flaoL3Yq[_*f&tkE`Qa_+Ω N pM߫d0җѲWҙݛ{3ޗ4V+ yk2T_Wk}#TJPCeTտ.u_˨]FW2_QUeTտ.uJa+S?Ww/EEu?݋BZ Oh1Jx.LPR!U: }%]BFBuB!BJB8^x]Bnbw!aE(K:KP.DSU"v+E qq0ZX!B! 8!?B!B!B!B!B!B! O*BGMMMMMMMMMMMMMMMMMMMMMMMMMMMZOqB!B!B!B!B!BG8!?BZУbZ˅I"^W%WPy 贼ڪ5W'?б JQw ~}c"&BHX`-ԋU1쬭B:K@pX][sk-Rk>aX!B! 8!?B!B!B!B!B!B! O*BGMMMMMMMMMMMMMMMMMMMMMMMMMMMZOqB!B!B!B!B!BG8!?BGA{/-̿my .z]iD2a¼oΏ^cH|k6bT9s+VF9sQ{ *nF]5Eӧ?[f:/t9(E!;h;5qN&kހm6>fvߞw^_tY{^3:4Ze͗Q4Sؤ_QX5(|j.y>E&r!2 d7-1a]=8nͽSGy>k׾yvm!MrHMdPip־?%uhxf1V?js~wOr|iyg Z͙fixֆFڠ/0*{ i_+ 4;H=;'}@ӬI%`Ac/kp&|o㾶skjCdf}T<4J:GECϛwwPKw܅{sUw^\xW izeZfJxJ뚞tߝ8k>vG0M{% z_Po *%ۍ&5 ϝ2 uM}&5}w,L3>5e]4qP5?oǜU}ꔴ!ժ)i3=|]`yw'kuoՌg|&4~@Ýjn9gPnޣ]SI3!IFNvN}llwn|bBX-M3FgƝpGڛ* %nJ~,sxЂ. ;_ې}o~snoz kZ]vo;憿+iJژۈ ~in#Oʎx=^! vxJelƭ3a-S/G*h%_ _[I〒6E qEڌ4W';kBLnxxtôӮNM\rq mJ5w P}UKzҤ4ygs?0KzޮqC?YWM.kx{&_Q5ᾋ&\U~[l˿i;4}{ƛmZ2_ɍ6K︤tEew )3U[u97Xu˯qt`v:lmC|eW~y𾯎8+.?3W\qƟ/S4촢󥽖_-uAJg-LɧYH'' ok/I0l'vȡg~1Ɣ#u*dB2~&2w@֟zW0Lic2OݺS70@#坦0x)[4кm 4Ba6UOlߒ4iHCcAzH iHC17YR\^Qt*+7tHx\^^D"J-iHC҂ DҐ44!ͱ iHs,HC Ґ4ǂ4!ͱ iHs,HC z@/vۦo MqGy]_km4m7Vi*ownk/z|rHK"D \ۆ .@GRz])^{Xѻ4#n8j﷫7JVrfbloVC{?]n[}&PҾJcbl#'TPۧ9wjp6 iHCAҐX49! iiHCcAҐX49!YF" i]f M77_jZ iHs,ӇמO.7ɝnw3ǿ? f7w1ǿ? 3jmLT-!âino aM~^<5|οH@dޚD\zb|LϘ M/f4`^u% GIԿ,RQ)r~4+4,VXD>*!>@U&_2Ol矼}\Tc2O,ne]^[Osg5:\Hu?~w3ǿ? w-ǿ? z{o__5_}-2=@KSo4ot{v/{/A|y݊H27~Դ7)}pby݇$< y6"hg~BW?*%}swR[Ç=zdVkR&dOvgT~ Oj%5_gU{;7}폗T?v5UK" Gy+9G3"ATd#vM#W_3`%"?v)cYD_rav$3s?~nhGv/^+Ѿv}qYef2;\v.E/?O-*K˖[APSF;z]ڒaSŹ::c=5-Qd/|jFʟ`I?E$}rjO0PSF;JΗmZƀY/Zq7ڲeCjZp j(c9ISMB͈|lu&7(%#k0ʫ%e"'>McN؄uئW9\ *wq*x,=K6zL?kp@9}D? odL&F33??t0>?ڰc玥kђԾ,Drֳ/-YzڼböoC\GE3RMeaZ?q$Kډ*Y Y?&GZ=zd*m#)G]hG:XC-'m@{'_ ƒ~|?PO2Ԍ%#%?<dU~ߐy7'8_hwMe2ڑWr~k'? f*8oé_ f7nw3ǿ? f7{I&*oz듐_n$e[]ߍva|{M~dзw?cEaE{u_p8!'*v  ?UykIIk"|Q^ÿK? f7/˱d0K)zo9ohiYA=?ڰc玥k#Y۷0YϾd?z}>okk W ھ$hmk;rS< 53r۾ iyI;Qwq:N v (@-zʹ<)NM?A:kZ.\ͦ' @w` ]/t9W0lLc{0USߗ2-sl*7T|ۃ&{XaK׼%2G˳oaf#}iuu|=0@} 3I2R#8v`2y֚4-Ș^$4k2)c/< DQyo#]X=zK,"~T~|g~8"%=T;FhG:XCuճ.h] #u[F;䷷_6׶fkDAr 5cxjQ5ݮ#GɠdUڒa@+F @/GF2Ηf H5jH|+CMH+9_{>x. i@+Fh~bHC Ґ4ǂ4!ͱ iHs, iHs HC Ґ4bJoXlkׂnw3ǿ? f_^3?=ǿ?O?KzX|g~umS)"L36Pfw9Nklh^a"}Z{%֦\[vQsmQ XV“l-92 lHCҐ iHs,HC Ґ4ǂ4!ͱ iHs,HC Ґ4ǂ49SZ'kW W?3{4k/)/N )o^nkPE JM)҅B'7;yj(cT#^"gݭƜHHsBYK )X)8X,8!k0+oR&r{%Dm1'l"Xu8,X ZOas2k3+m }vc{orl݄7`w9Qn*%{n8ߓ.y@Ɲ*Pi49! iiHCcAҐX49ҿ vHC Ґ4ǂ4!ͱ iHs,HC Ґ4ǂ4!ͱ 'Nr%Feb%blS3~sB[)aRӒiHCcAҐX_AҐ@49S KoRxGۦEZ 6֓VNM?ߞ+M=Qۨ 45Ζǵg'˵zPzE_1 ۲AdpS*E2~[̷~W>0{ߙqŷyF=;2,ë)|/9Ao<>h.G]ڈL՞x`mgK_ ? ؟?wZʏ,9p ΒIeT.=m}9v9}; {5<2}ib__CweGsCW|FQT7ͽ_6iG\7}}{KG}{iChG֥onz_\^sgiG9%1Isx^GCGIsԺUG%rUt^;sFU29,wek~E{P:|cZՋ>kYG/r^ڿsX &_/f͹Zz3BQ'k<_,<_6Q+T`mUܿ`Փb8*yNKՉgMO?&|?Δrj8Q?2Bs꥖w;_[_UVQ1ڱZ~ }/-P^kezuz oDyA:o<#x&0jp[vI_ix @TJѪffK*.+b⾠ v]3K+bi%+M DPDuaD{μaЀÙa<А[b#Nr"Ym:YZ_#IN8YdXM.$W(_1t;l`; l*a7H)-JABicTJ3<*)~UJ?~uS?~u>d_|Oͥ߷SWg$}m ]t7_j"9;ɟ=U]K=ܬ'yWux5gNN^_N~N^727›$! lj[m{Ix' -ὰ l =|vÎ(ϩ3Ga7=cZaozH$cp|\Ap0a>p|B?I~I(81p, p"')p* t$GL8 ΆO9p.  B(?s%p)\y\ E|Wku|߆p \ p|nM} Gc~?/+5p n=># x7;G<O` 'a<a< HxFs0` w;aG;.+|va>{ް}a?COAp0a>p|B?8?qp<'Ip28 NO0΄lyp> i.b.3p9\Wgsy|_+U|߄o;p5\up=߅{p|~7-CnOgs % ~ ov-w.~?_~x0 GQ'</CIOpO30Qca 0&dh)0t0flsaa eXk8p F1t;o7- l of9low;]nxl }5m|a>;ΰ `w^7=`_zp páhp'p 0Np 3,8>p`0|. ".K2 \WY|_/*/ 7|_o7[m\ p\7wF߇p ~?['S/~ _m~ w; =p/?!+< ?x  PxS0F ga<yxXaL:hI0` Li0f@3̄Y0\/|X/BxA hr^]a#ku^o7›6`3;.x7V>>Ç`0`gvn;{`//q @8CP8 zO@_GQp4cX8D8 NSTI8™p s\8·A0> p\ p|.+J,|>_/—p| _7-6|kZp#|nf~?í) ~~_6 ;NwOg < qxC`(< )#ixF³0 <c`,0&BC4$ M043f, s`.̃a>,`! /;Agl :7Mfx l[ml[Nx[{a+x55*?;ΰ `w^7=`_O~ COAp0a>p|B?8?qp<'Ip28 NO0΄lyp> i.bD~m .p\ k?{9ySgW̳ Gk yVkַ.Nn[/"޹[Ϯ7ky|*_|}UyՍ5"|_oVͦ 0LfzDuekRK}Ī ak^UU>x/W5UUULu ak^ˏvm z;>]:M7Iڜfݒh1ah闇C>9\4ydR 0 SJg3 h sam}0 a9Ӑn0ge^ȫ\\7]6^]c?qT396MϭfqIyާgoKNzzt䅤m$>5 +)Tސ8ǯ\`zphį!{\47昲sޫs ڟX{Bvc p?,:ęs?қޫs՟5JMz]zSd&E_%b]ifA}^L*sSFFVbLK3&Oĺ2^Ωw<=3Nz?߹^ͤ>O1<5dӹx[Aq禌S^QrnݱvVFl9cN;r>;!(ܹf4Op 'k;ܺCY> FBwEQLD<1օ+:ew7L1NYByVS>єz3HJ)h8;7[QY/N&Favd^}NY*bݵp!xoݏ'ek>6*a<ӱe-DW.UgCcfK[oר;/>ʿ+iH\AᩝjO-u1[ny֞v'kWZ{Ė^RXV^lQF!G jmDøz˝}unWVD[KR%ֵ>۵iJi`Eu/z* eGv!QC5 Y_-ٝ)gޠlY{:[~>-nj ƴX}R%vu=Eym({=7dI{J bc`1I V`Q>][6S9[rp/Po 6_ŗMzbWqջ^|ʹ>1Y&9ӻsrfz; qn>n~PZIJ׋EIXlPe,umΊn?Y?\/+Gʡx-Xm*Xk>E2;^F*_̱e}dz/r=󇧫)a3*^q?-UmK][o%O׫ϟ;׫Tٹ֧QS9~kyuUysI%}wbVf'Vo\oM+m}^L*󂂂|bAA&֛QIq7}^L](|YNa%Mҥ\+߯z5J{}cZc"X6m6/JNzz߯ކ^<߿ذχhcLV冕$A*gF 0aFQ<3?0L=|+a}0 \iG%ƤY9y3$aEm&r1ߜwBjzy^ G_mzNKayf9/9;;-7z<$N3-{faj(C#~ سw!1ǔS}~B>Y1b#.0 SAEǜ8sxcq7L&kR 0L gLO ?O3D22Ωw<=3N~KvbLK3&ODƥeDZaj3MT% S;IJOOH6סxckS33 SC 1%unuY<Ŗbލ7VoSW8`]T iVQN;\uAbmRP:Oէh;DSJtEyZf&j63LE3S9t9[i;R{IRy8;/h>Re-9E"vEݡ!躔󉆚lD:tɒ$iW&"kWZV6Y/I^ʫ(8_PD/~8K{m׃=-kcaBPԴ :cyFv605)hhrqvm:+=b=Nߓ53_ J#޻kmD6=+B|\кrN$m-²"$bQ&iHM>7 ;;{Wٲt|//+X?g A'ހr>٧Oeg{zm{_)o͐$G\!X\ SsAcI5癹JgO)|]qzwppU.L:/ug9猲3AE~gXw}xWt'A'gkϳrsLᬏU^׫Y>2o3s#COKbO}rWt'A'g㌦lk3L]}gF힕/0$99 s|Myŋ 0L ''//͜ON>/((gaj8 2s2ϫ<-|YNa%a&SpRfv.7>W&EBjEEڏJN>bÊO?rB!1Drܰ2T}WLbhο0 S yާhD ѱ Srt4ԋ(Z (j?>gaf 0aFa3 h#sam}0 asa+}[^`aTIڿ̀B"sBkRҲ9{o>]J}N!u*|"*}N!u9ަffz'lG"Lf3<faBHC9㓓LĔ'lMJ1/ hxT:q Bqק*ѕnuTD칏}N!uᆴ4%Q: !"t翄XR}NJ̴sS"J:u>'sCZ9''#;wPsУ9!=DP(QJXR}FoMh(~s-gQ$ !>/(,rRˠSY)촬윌ܬy/]ʷKEE"xJ}~7Bj9!h9!h9!h9!h9!h9!h9!h9!h9!h9!hhi+ !"sBsBsBsBsBsBsBsB5nsB           j>'ڃ}N!ڀ}N!ڀ}N!ڀ}N!ڀ}N!ڀ}N!ڀ}N!ڀ}N!ڀ}N!ڀ}N!ڠ~K_BU                                                  j#R+ !D !D !D !D !D !D !D !D !D !DoҘ}N!@M1Bj9!h9!h9!h9!h9!h9!h9!h9!h9!hsB         !DPgBH>'m>'m>'m>'m>'m>'m>'m>'m>'mP}B!B9! sBsBsBsBsBsBsBsB5sBjfBH>'m>'m>'m>'m>'m>'m>'m>'m>'mP}ޘ}N!@ yi=sB=         j[!6WE!BBBBBBBBA9?!5-R !D !D !D !D !D !D !D !D !D !D !D !D !D !D !D !D !D !D !Dt>'Zn9!sBsB紬#gxGw۷;dû~}h9'GbaBH}~&>;bBHD~yNE@LH0`X}N!u8DONN0SR@%6))h`0Q-sB{>8j\DWQg>9!I>GҔ8PWұ}N!uz=:<)=ѣx+*}2Q>'z(sQ麔e *`0$gd JSSU> !v}c4Mf3ԸR"| B*q-(]|KT}Ӊ9!=>O1SJWJDbaBHC9;-++53SsDN !!ܐfF+GI]Ϣ !!JGJW<,&>'' ߗ>'̕y*90 J*җa906>gF 0aFa3 h#sam}0 a906yRlokOP/k:W/>Y쯜`]wʼno;tR}~C~v0I$I$WJ}mUrZe;WW[o؂g{ɉi}M>hrQ||n>NFKqrL㤔IRZ9U2d.I2!Nr$oQ1\Y&YIR)k;V''lDq2[ެr;l2'ޚ\iΟHp-溔Mg@=SO t?O;5ݙWt St33p|P>'x~3R`mrrRB[l^9Ӷ&˗M:}ٴ˶]:wnn~KN޲϶dp>G>mM^L*KŦ uW #?l_Nյziw=+CzphA'vfG4Fk;}MN'Z88G_R,(r2[^,`Ë3 TWʖ9NG] ? ]c?؎cǷ7ẦCt7xMt+=rRjCM kizT)i~!g52=H?U7)9򉙮e(yNr_X:%H)ESL۷8=|;J=mK]!+Uy1w)Wr;׉fZmV~ aj/3Woj[_?G'|Σ1%cjb)M2YaXcI&2,SoqY;}~P3-5ֻ뽚}JZsrhCʽNV0cm.{ \oj>\TWT"ZX;?߂hBG^l {n`l?)ؾ$]_;D}~CIM~rTr^Xn\L/p,p9KWelB'7_ֽQl7|wi{Ϛ|ЂqBcL~qSS\Da⬸ͅ/{ B+7a 4L*Iۏ,HD30xY:ce=m)vw}C;qՍ>]z <GϜ2wX n)Ga},>5 5aXbSG3Abv&G(xzLI2K7bw^gO7*[nMj6tp"{XsQm}!_~b=,J>]pV V2[DI&:W8 6^^[,n4wi;,srY$Rש5yHw%dq L?܉>7Nu/#K1]S\ròq6[BʹۇK!ka>Fi ?9芇z2q\`è`_PI{ sNQ;}-| -%6{M/Ƚ?U8>GnY#[^ꛏpm4+Z>챶>06NR\ngc(6{G91B*1$z=}G̪n*.v>{@ nq6,w-{ vV__4f몬;05GP >r70vq"Az9vwk;Jw]K]񭆞nM\B;/{sg69WR樅f4ҕۖnsq8_l^ es|H^9qYq)7JS: X,nsr~n 0wV+񋍓'/5_h1%~" $y"Ͱ{}2Gq|܍%}=L@ WIˇV(P8Y#N\ldPjפ>yǷ7w>]9ȽC'yكsee[OsN&*ↈC9wZ,7_nLE?D ͪ6aGKc>RҜUɁ'MYV,=&'vWRo/ϩ[}!t:0AяIbօ>ǑnfsqӮrmf4?^>z&TR>ug$kb£c82ϩ{H?_[P4w+b}蘿Ά:/J=,&Ȑ=gO ٝU[=Qq0 SWQ|dagץ,xtxȯ7H`o?Ө#\v2љR(\\)4H:9_ [rr )d$ t̑r?82Ξ%%M*L= fQg-6%/lH]`=J\ҔgFgy=/ $Ƕ֢6\Xs\mV\n疻E!=$juQϸE.5\$VJ3KܾU3zA1W3֚h'tr IxbM7L_IRR&M[4yqb`9:'{k7,춮W9ޢ wB#1DT)iSCiNISUۉҨNE|[)?M_y+-y*SgIJn.k/ 0JTa踂EoV&/0{|Zד}=):&4*Olˁя Lyu?M>=L:-2/ϕ|$ݞ LbY(/bؿ!wפu3/8%'@QϱsQe.*=ڣW?GdjG-[V4r^k%,*ζoda)bֶനY%hVT+^ndAë1t.`+e.>֛^K9USRɽͨa4eAQۊu,iFaZk'%Qʋ3"֟?(~^q)%/_+(4qx9>}o3x[+͑Y] E;T>#Z!EWc)$Y Q*/ 7|_o7[m\ p\7wF߇p ~?['S/~ _m~ w; =p/?!+< ?x  PxS0F ga<yxXaL:hI0` Li0f@3̄Y0\/|X/BxA \% :Cx t`cAwx=o7[` o`sw» [`kx?l`; lð#|va>  `ozǡ' 8C0 C8>} Gc88N$8NSa' gYp6| ΁s<8`4\Ep1\e+9<|_/U_o*| ߀o·k:n= ?!~ O3_9?~7p;;wp {^?/p?<CWx#(  $ `8 (xF0uP `24 `:̀f `6́0^^2,(5:Cx t`cAwx=o7[` o`sw» [`kx?l`; lð#|va>  `ozǡ' 8C0 C8>} Gc88N$8NSa' gYp6| ΁s<8`4\Ep1\e+9<|_/U_o*| ߀o·k:n= ?!~ O3_9?~7p;;wp {^?/p?<CWx#(  $ `8 (xF0uP `24 `:̀f `6́0^^2,(5:Cx t`cAwx=o7[` o`sw» [`kx?l`; lð#|va>  `ozǡ' 8C0 C8>} Gc88N$8NSa' gYp6| ΁s<8`4\Ep1\e+9<|_/U_o*| ߀o·k:n= ?!~ O3_9?~7p;;wp {^?/p?<CWx#(  $ `8 (xF0uP `24 `:̀f `6́0^^2,( F1t;o7- l of9low;]nxl }5m|a>;ΰ `w^7=`_zp pvkeO7G4/y=`< -*h拸d^cEO;xJ^l:luۋ73H-V?hͳm5G= -$/n|2̽7KŗG>4<3,XiT4!Qbo%KS iR|bRqƙG{Yٍ^nrrZby-K7-[zANFT1''a̍a]59Z]"9|QQN&D*%(%B "N㭲Q-(GT%{&Ĕ%?=ID]@3SH]Jâ.P[,qVO@-R+ S>`Jf.o@Hpg?/o_ #RC똪=;3}s.? +o|6s[L0Ѳ(iQ ͌,y?G'0W_m?4*?0uNoCoIsB>ɽ<#JN9?W0οKD ;TԾ( ;'$rɳC" KV'掟ǤaQШ8WcU_?w+=Y1_͈ٕd\ڼL>v]$1aRhyşk $Wx-~u-V)quӶnp.rvi]ź Coa+]s;29? `+lwyEYGVkIۏkmXնI976W}!/()P*s6j^$dm6Rw/.vx s.)i..<9ˊKc/]i]g >mR[3R?Ϳ\A˨P1]~6/:Vܤ%m:QŒHۜ _5ɸ߆5q|Zu*[ W5G;rÞ1;~wk.>_ܺ]⬼kʹaoXxm.Ƴ;X%h^o u=`Fr/ֽF ٶݛ:6mB2[۳e HR|n/ٯFX/rp81d9{*yϱ+Cyu(}ƖfB\ٰd|]{YNٴ <+dw;"N9҄iem}lXJle\2\PRYrdUyK1:?͵w܋/9bqDoXm^R5 ٞi;kⰖr?b)\|q ҋ{DD,_-:n6ls /^ .^:Φf-Lif4-GWNK*Cdy{8J0)68k/=QsXNHO[,LPm<&rm_{ .p .p[糜p .p .pKΑp .p .p .p .p .q .p .p _P_]8uՅW_]8uՅW_]8u? .p .p . .p .pK.p .8SHZ鷱ՌqYȨ@3bI)u I 7ש NT7ǿgaI2f٤Ԝ7LdTS@&43*if1LKE>ev/7ܨ}fMaÍObBU`S=3 0 0 06–}QB!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!&ҸzFmFK}ՌqYX/4Hq 43*FĨqzF͌N>Iο>FUWu sJT$èdiQ24 9 gTӌz)PqST#^FT$0 6`CW'> 2b5ϐ'$%)aaaa4cTB!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!5DƙVIo : nN% A>(Y0O %6 ZSmEcZ" Kyweny-[ϊ 8RFw\*Hˈ4.Km{:+jqY(TZt'VӜ|.fij4vb&ڶ2)E~-ɶdtyJ#'0Ǥ_˟&%5`\uLuIKW|뱮OHav9(綏m<xx\c(6(iea~ni'>8/07?Qb}El:Ȱ<{yGrÉO^Ÿda}nĀ~]BIo}?n|NZ/dRg _n4o{?mk)kVXfHVN3.l\<^ĸx& /^_jNs3L1,o率=Ln~ zŎy4lxm[DybS\a$)!xdʚ)0,o?J7'qƠĩ&J۳MQNMyvyN$KL^Lӷu0+.pR~?h\6E]4 㺗 sc:icw`hSTKYjF|6 A-Ks}>mb} -<PGA<}[$t2S/)\ҥc;FާG2~DC[}ۭ<^gmQ<>a}1a\O]tOymX0?>8<> m #[Gܥ+a]ݵkycy>-?>yf5L5Lxǖ#0IC(}_=ĉqt+Zywo?Nihy_jh)=U$ֻMݬ!y#}K9qC`I7K4;N;d "L?Lb?{u*h50qz)t-zvP#ym#r:†1RQ\"ί#0Ҝ 0Li 4}=ICnLw8.ϳg|Ty^npQl*frϭxǍ0)S=MyL7~rƱmFēN{߶uQ̳󜢆rD]燷0c;sܘGIm~nHS }t>UkI,yU.lz!^B 6d[*l=xM#- 09scV} :u&_vNMuiM;߼ unn;7eNi2sa귙 Y꓾ܙfZ]Jf'2KSS#Z;^9],'w98'l[qB o{hH( "P+,>F)[,g3#ǜfRR,Y*޼Fjfzo/^lh)?3s=>Y,S|O] >u.S|O] >u.S|>ۋO| >u.S|O]K`7;gS|O] >u.S u.S|O] >u.ԅO] >u.S|O]|,|_g"k_ۂ[o mYs -ۂ[o m-ۂ[o m-ۂ[-ۂ[o m-X[o m-ۂ[o m-ۂ[o m-ۂ[o m-ۂ[o m-ۂ[o m-ۂ[o m-ۂ[o m-ۂ[o m-ۂ[Vۂ[o m-ۂ[o m-(=p_<6#щdTʕə+kצ_"V?|myu.S||x >u.S|O] >u.S|O] >u.A|X|'>S|O] >u.S|O] >u.S|O] >u.S|O] >u.S|O] >u.S|O] >u.S|O] >u.S|O]K`>;ugS|O] >u.S|>w|*O] >u.S|O] >u.S|O] >u gb.%hg"k_ۂ[o m-ۂ[o m-ۂ[o m-'A@$㿒WrS<|LO 'b /{ξs#+/迷CK5vZdEQYt\U /{~X]*I2CT_O\!Yɩ eH$'ZYVcD+?6>.,˿wD"J,MQeen26&ZY1D+o[wb#D+$&ZYMbdxO2⦟_:uc/7|pBWSOW!ŧ@}=Ojx{D+$/~?-x}4 L''F&SD!'㿒Wr_&7)}|_Pf _M俭OY1i>wv5Z{eF2/_ք$ߋHe8b+ȼ Wc؁2,؛ʾ/8^֓kwY s)I2Ԍ1eԾGo>[?s#-Eo(S/9挹lzs/R{3}V'b'lh>>۹Ub3q~;0_@%B!,:NEc+<ֿt)WLO_! ՆBmi!=S"ENЮBo2UGgߞ3># R٩՚>[քB5iF{*ǩ>xds>D,t8eG(isz|8ݘjP{۱s{x|,Lè>jiUgS}P{69Կ+nzbLRh moN!'^y=# $oV;n mkky̖d>MYM3O,Fi[UUUkES]7VY=iyDźuiw,4nv5߯e6Snar%'&KkUU·I׿~bbØZᙚdzzbјB!B)A~71+ B!4<|LOJ{e2_sŝC%K$rR$/]*听}%5|QҾ矯7pCrQnd=]Z&42Oe\&86OL$V{Swz@o*eq?6dEރε(hsOqޢIw[G)w>rԍP߭N ^Ƴ=s:s-=xso?ZyDhz͝т>őꓽd'ꝵ {# fv?oBzNiod "t3af;.E:46<Iw-1DmnOjdQ3"si8z0?_gW<"s۬;s &~M-{^rmY}G| kY_?)ThtLSGKGB!T` 1b{ݬ۳tKgYwr? U)dTp wJ c]7_ B!]b?^GsLzufz 11DՆBmv&XAI/3)8! IkM(TZ`gRp|8HD-;BGΖdKnsټsG(Eo@M~?Tl%ͮڐS]lFTҼ=,N&x$%acB42ִ-䝎d$/]S}p,).mUUۚb.9[Sђvjft#%%v=~Tפ%TUMc=OM4:LL3D 32O B r=b@+<0_!B!BJ_M cJ|$B*0:N yKg.4gMSZ]:|?;{?3x$˿96c/h|}]|k]˵3j__tX0k׮&->331٨GYe/2ry^cȐxF.,\_䊭"<&ǹ7a]Xtxx7dim(.8mB#BXthx'Ⱥe7rjVv81YYW i"`_wZW=or%+SUkY7Q͂֬a7jb_ɾVv, u?z#]dRd ͯ^z^7rvmh__Xq,6ԙǿ7/qa UՋYf[TH|ջˇ *ёdoluufrFKzkY5Ѧ 뒍~@*K;|3'%ԥ_VUjfP-(nڶbJGG/]8,yUQϢp}7Ű7eW~&w=.YVnl^ [Ld>n=]X]დ67ު3->g77=},}=Ojmyh15|?O$&'"ٟ7K,N''F&S&ڌ2565 we㱁ro!Q!Bn 1bu{zJy;^%iⱑ$ONG''WWLL\\6}?+Kt'>S|O]իӅ) )Xl8]z%]K>#ҳY|)2e3y_Jt~tr%*=37O1}6-3eғ>N37Ok7Fҹ$<Y|);me+o9gV&H&w񲃽xm)d=d:yiLyu*=ϝ,>s#>e,s{B_W>{kdC>q?9Ξm3 )=I!)gnN+ggY,3 i&M!Ӽ@Ϲ|Z3.k9O99Ȝ˧9y˧~8i[\>[@>bŹ|w$s л+# g@G]@>9: HġnWF7O֮?on]1@lux7Z>Z\>ZY|@<is4? jyfiM9'cs H7i 9l磼H'>9 'ߧg,&Efvvi{@ۻHVFzug kZ(Ia)Tg%ۃ/G%ϧ?bӲc8rْnwO7mN_p)ʑ2}6PGRl}oiav6?ujOH>7P9*Qj>oE9xc>Yˑ2|nk <鏤4m7NbVGj/G}VUmk <)ۈDiۼq.+nAu;ߧ~yNgj匿&3וPyIIsΗ)g 9HJ^:Yr$g0ϧS2ƾ(r$g@9NI{'&o^Rh93򜾞Ƨ_s5oUg^LTr$g*Ϲ$/~s}~kπsCxl`b<<91:5͸~ˑ枏淓 >Y'>9s6H_<)ͺ{[>jq[E|y|yPru{U߾ҹ+7>i2 XEJ|-&{/=| ;_ϻ>wo>N7S?~O.:_^}ʹOM^>{ۓ ٶA06swn{产牌۸n_޺}[ڒ?v͸[Kwou2x7;27_^|uͼo'|%< ݷ`-\|ιڑroTRsoSuՅ#[2Ǔ~Ay>q'WO2w*?wewn?ȺSOi[]^8^:ao,wǼFogIǮɟ}m/#scrA0*[w֭ޡ8_ŽΠ'}۽ΙR[._"K?9 o#M~\?-GV%X^ŻÇom>G&yWj*'ۥVF~o`pQ(&M<~m%c9mIs x] `U[**xA(V.Cxwpoy9vL6 ~#t!t'AԦOmMnzB7B7Alg O}}P8zz  o#||zL` D@CaP$4QГP44Z`ǐ B18(M&Bh*4 == ̀؞8 ́BCh!Z #'Z U5u Л_BAނz.>Oh9 Z 7} } /-;{h-#Zm6B?Ah+ ~vBB @A{}~w(J@CP2tJR#P2LPt:i\uAE2@P dJ2: *J jZ: C P#5C- ( B]0|+GB"O%ХP72r ;   nnnnzCw@wBwAwC@B}}P8zz BGУc( "'h$Sh,bih"4 MBӠ3г h&4 ́BCh!Z AKWЫkП7@-6]=}rh!1 )9o(Z Z } }_[5wZGhm~6A-Vh~vA( ~BP"Bd0BG4(: e@1( :eC'$t BP@**J #T Ai TUBUP5TBuYj&j{C!P t]u]] ]]]uz@WBWAWC@BAC7@=^-ЭmPoN.n^z~ЃCPh04=Уc( "'h$Sh,bih"4 MBӠ3г h&4 ́BCh!Z AKWЫkП7@-6]=}rh!1 )9o(Z2lq\y~B?Bh# mB۠h'+ @ nh~$t:%C(:AQ(ʄAYq(:@'Sʅ|*tP P1TR *NCg BP5AwH؛&7۱H`ٟSmx5M+!Aah_Wi6݇SS&VճB{H4V0e݈D" W_gW;Aoޣ^V{*g6͵tbLX>弹^a:$bHyʕ>a.-{ɘ';'+""H$v vź|s9OR"H$v:")ωD"HyN$As"HRD.)ӖWTԞ;S{L];(J%x쩲ހj{y{FΤ;~OMˠ`{X+a?+:jo@u9YKJkehQ[ZLذڀ 0ʧ7fy6K7Rٝ"ߔM>d+O567 7jAYѮl)ﶗe ?G?>*ߏt8ZbȐҊXQ! R>!_h,)(roW٨ XT 6/֭8zTn^L_V("(hURj<ʅϣ}}-y<_y 򱟲kmT0t|lTͷ͓&mӵ6[|. gyN V㽼,"{8*;!<P!Ļ/ 93ton'Qy 68Hn2O3^ۛZq-ۼ/ݐʳE:T{hF^s>\! }s>mX)Y^Y/+:7ڋFǚWmik[6->!*CVzQedXkethݦ |Ap`J49l?6^mv:F y6y&TgK55 ?Cg2?K>ʬfxf&đCP~:At4*Si-~ l] r \Lufj-S~j9CB};T;y|kk6tun㽲R:!8Ir ӛkjfG?X("g}QZŧKEh6tm'mhum'񰽖<r[ |^7|U`YaOj?DlEy8KT͓+무zڞ4vu|v(:j#j̜*hhm<'D 9H$)ωD"?HyN$A9ϝH$' _WkD"snH$nH$D"T9]H$sD"؉IyN$As"HRDH$D"$49H$vbRDн<߾M":sĩ}>hc"HP򼡩Ʌ~@yN ҊҊ5gjjןmls@1( sǠ<'( C<Bm<56!2^+(ԊH^g`Ui]OF_y)@ĉ'HrhVQnCdKg8T$UWĚh_TqhAyN ꎷhDH@Adrɩi)3z+!i1^Y:]ڢ]3<'| 5"n(܍޵&BݨĪJjWÚ֧>nP ''+@1TsKdpMc7QN+јǫ]?풃]b?_+J)@p 9Gy5hDۨЍM=r{]t^cͽ ^j{@-?B6/q9@yN v + /N<'| u\y\Qc"՛(/5qWӶv ݫnnc{]걾 JP>sq\E=uv(ۺϭ_]Nc) Lкx\t5B5mwדz^حٽYNcBG@se -W|[DeZzr_Yj\&Bݻm=%^UskͤtsPy?iQd*‰Z73]н~YC[&dkN tt<*Xܟ֓g\ksV-q<'::-y.օVK8-dRӓj9@yN v9cP AyNh'P>9@yN v9ct˵[ F}emqᄇ~EԪ䞬Vʕ җLTOP>sۯeQǽЅј)O8ҥ+4ܪӶDyN ~碻7!GKm\ؽ*ifs<ݍtFUr=Z Ѵss%v<'| ? ]G}eDk OGK?'sW6s 9cwk=Pj\U=<=s7nok[Q>\:voQm3{uPݻ qH7oѸr,l[) CFgQ܍ֽ֣q뾲@4x`}\j}K14|v@1Ts@1( sǠ<'( N<'| sB;@1( sǠ<',sty`>v~HyN sAy)ݽ[ k,I<.η5-P>yg'_ygyG/]ܧt( +yn鞬s@s>RP\o\+ݵ i7@yYg5FUﴲ -[( @nT-Xsh^Ay '<'As^@97@yNh'P><<'| sB;@1( sǠ<'~\R\0GrG?D—LXG~Z֙Uy.o{H} ?M} ܽgwqU'!vup K%L.*UynW"Wd[m2%JrSy̷k vVd9F.uyZiZA%j||9cP AyNh'P><'|sb St9zE}k0g?'<9QuR^9QuR^9QuR^9QuR^A9f @eKrcs1zE}w>_ÍϫwPwp[wrb1yKC 7 %n'"9C Ϗ;9srvv9Xpؘ ֘B,Ǻu<>k1y{Sƴ# l"}[ӣln<JڷQ<'|>~RVYyB)*2RNwjJ!n4ǗW[ӟ omJ ̸D"=Vuq"ҕ Ӭk޺D(^rW\k0 ̍rs"Ew\c;bȗ1KG"A`ST硶AiN,,U^.+?x 9ϕaxx\y.ksyD{ƞm ~ByN kDnyM,8pS 7Ewrѝb ׏-2]#  e=ayy3><7g/:ag O[F|%bz_B4Rg2ݗf*]en0Y8ū`_w 6"*+ƟunKS5XYA$,yt""qzPm|urSl15D.Gˆuc#",-Bc5#*cbO^L˒vzg9{ VxV' kFB^UkNccf-k˂VuOy@W>'j.Emѫj3k9ϭoR)CCyt#X9ϱj kph͵jNH `E^#rN)5(z~ݏ?uLHd3' 5K-]bx ʥ BZ/rx(~ )l\%=1>]=qK8"U혲jClزtSXW|a|τ|bA; u\xj^皥54n{b ̾/_Z}16TnK%;Hlo*cDD7`|}bÄ O-([b,X-ct7F뮋]9*WlFR?8OLcws?G~B‘‘B#B,R q[98ePus4yP)&P?z~ш9st>2$ts{Lg?y:4y9o^~?Xza9]E'޸4{ٯe-_MȚe se~O*s[FgĜ d7W~w拵HW?,]q[%sZ<φg^/Z  O-,9W7~nv}<~)jnQ,c #-4qqcoʽ~hcRӲNkߞ|ko6~l:g.Y_ :'rߝ<8@v"#Q9Ǹ2yW Y9!2+fD"M>h7&/؎W[ Cg gWH"#GjPgx_isO _Hl~I7L sg>pʹʩ솺xh5gL+>ӝk>"=g+RGsD.pIJj7ƿ]NOnWa'}LTD"іONӷn2Z-C/Bq%eh)*:gM/_AˠCoA zzzz'Z}}} }} }}}VAVC_C@?h =Z6@Mfgh mv@@;_]JvC{ߠ>h?;%A!(: @( JBP&t ʂC (: P.CP! =dBeP9t:U@PT @PtF jZ {P0 @AaPWЅEПKKnePwt%tt5t t-tt=t  @}p = A@GǠ!P4=EBO@áH( = EC1X(B Dh4MAӡggLh4=ͅABhz@/A/C@KWנס7?CoB Zz m;л{? C#cS3h%/s P< %/зAkЏ:h=m6C?C[6h; 4PAߡD( :Aa(J@iP:tʀ2cPtʆN@9Ir<(* !T!T @F*ʡj꠳P=5BMP3 B?@P<( : t1t t) nzB7B7A7C[[۠ۡН]=нP/tt?C h0(4BB} ݑ#-9&i $ \O'қ4р>FcL溃Mu3`/>sУ|g|:[W#OmH Ø>oٓ.*!H cebt0&OxPAK)zaR1dx#ysۻ̮>oqsWūx[}|"qৌl|\ UMFl;VX,$A91A30"dAMl"ȧ( ^eQ >',<!L1 l[A9ά :InaxLM oP.]VnR X eZyJ0.C"[{_\a^[9#:?0 '_z"l _˹K8qWY]^^^ ,;r[@tfٻ-?",H YG)qa:anJ׵sSaLQ}\} 79ӎoOޞgUzńiu6U l߃VͱpS0(L5o;@h /L w8dN64^Xdnknf#kx|Thq 涬 &Mf ,(/:"%ݗ >m*CSʖa9]/>*-+ff/ahWUY)Yz9;56*V {гs+xw.޽a%߱e^ < oѶHm l(HhU,-?u?!3T%̂E^gXfTwykm-%=a_gkζ5(V6}9'_ad炩A'LӇTڈ˜޾·Emt:>t<<c-9gҊr  iU)#89 !7vYp.L*erGi ,t.Q6oG/Z7NCyMqq7ȃ_T|z뭰tDev{pqjVĉt%;D'i?J81'Lcgdˇ+4>f9q$m\)ؐࡌŇAQ9*Dl|Y9WKT?$/my+%Q_ ywsbNg}Od W'?t7Wm'za}(O@ q=W俺8O"uA _]W俺 .-W俺#U.uA _]W俺 .uAOuA _]W俺 }N]W俺 .K _]W俺  _]W俺 ..uA _]WT俺 .uA M]W俺 .uA _]W俺 .uA _]ˁ󑕁;VdbYAT¤"ѩϱD:T}_uD"KjRg&c͉D4Fu O0Ud B$,CSuː9 ST&)pU@TAStg"H$D"H$Db囫U߿'@ @ @ @ @ @ @ @ @ @ @ @ @ @ @ >坒 GV?ޱ&CwJk̬ HaR1QM/"ɱc;IwF#]hNjH \>X)9Ot QMN'Ƞ´&`ܖHafPu'DbR tpwèNa~!)A,"H$D"H$DUb_=P;ZkYP^kjjp~RH7m>U7NzpݎCn=Pyuur=5 JJ -ןN*ǜ: 1y%-E-G؆SO6>|xsbVsa~]]UMML,(h)i_FӾ&a_]}lyn~YYVVH#v| s&f4Jmps;=9)ٮ3A9m|ddK2s=v]{qL. Rg6ʄ;?FcON)&&.N?z;5-ɍsՁ|syNC;D71rDH~1Eܭh{8olVe̯6τa>FpFL{xk#??B*cEf-`*k{~6yu=I˞z VOa]psS'Hf_r@waKnJ.t0Մ|pZ7Yr˶z fs`8|\ 퍶wGkYW_A_ӽxWs>?Oh|.G=O57Tmo^k9k7˴ D;6M6<"dq(,<.+#(s[%yb>ojssj&`̰ocw5nPAAj[xC oIy Gs&؝r"a#NΜh?z~ƝdnOiܒUU;`IJڲoƽ{pRS555[WlKܞT%O7%ր(kO֜?[]__xlnnhiiy87fILdvp׮ܿ_pS .:krQ;5fcE!-=.5퐱!Ͱ|I W.1Wb9W9gUmմZyKYL^-7 "ҦTl2Ĵ%5%YS+GJg߼o d]P:r rduv;[LnkA/Ƃ*ydyhuqQTo3X3y/o[bӪVN_W俺 EcW俺 .uA _]W俺 .uA _]W8A5̹zK5Y:0?.cjR(G:8݇CEoy(CVl 6vn,Yh;oܿ2h~|ci[CKPd3DܱT?>zǶ K ]O{ D۾u]}\^d~~>5 5 OszZcm2@ufɈ9{pZ'ߓ+{Z/fřo?)-KJ^P9o*~ҩS K&+ZDGrciˈ{u%&?o.p7gdov2_CY3߭XEwJ?|Ⓑu3aik /O6M(ZngM6ﻜ&314yd0ӫ?(M㻋J-~c)'-?Z7gnp)?wi#{ DxM~2&(͌*`4_TKK?~fJOU8cXG &/ ʫ~1?v̽4O[9/`ϔOߒN 3/?uӣl m?u3!-a癆NR8y`pn͏;?>tS--3[ixugssW0?7?' c*,T}uύп0VhEY[O,uMQ5#v͆.e~e~ޔOgU=yEϏc8s h0iZգpxc]S?1?1Ka~^ 4vU0envdѼQE-fyL?a3{qW>-둋7uQ0 $eWcAxz]g~BhPG3yd]K_Rq]7х9diݒMAnlS+{'S{䍾]#XZgf!E3-1P̃i}'.p3붭.H7cn f~>~` ϙGdUxrpS0) ,2@7!ݔ~E'iU|*f)wۨ'n;`CNxoIvs73muCx2^ȽA{z ?<|Sisʪԟ#n {}.e{ھ~m]7{Ow_l-dAn>|}єYWX~Nkg}V)]iӬOVZzOg%~9wbkqrg:NM|B&#OGW|܀ J*!9`mz:L^G[2mgА~73Ia@;$?;2O#^I~vLgG&N~j-]n X[W9] ?XIC)TӁiu ;8T`5ωuk6ѱO\Ӵ5UՋ'+i.j9tD pN͉}M{a*E?M;7O0Xs6r'e4Mgܝ֤9wZE?33w2?~Գt >5);y͜/~"33q\0sF ~ڹٗ| J6m)im[~bޞܨܽͻ[ȷ-i;D9S1!f/u똟X|d);J۷2XyF5ѣlGmKD/6~bSÏ~.}?ۉK~*=qx.:m< bbV;'/4`]J~n䆟՟S#/9T>yO)6MWws*'K^m O^趟[ӛ6iZܸ`On ~Ӟ'Og6Yy;IMʞ̒fK۰R ?ޮ&fi,Htƍy!':uE gb|WL ӻP5k[5Ű^a{iQ} yd+Vȓ'[!Obpş/_kQ|rY;ke.&X<g*R6q^ܔi8낧/E7}{,88(x. cS1^j >5Dqq>,qUx?G?ĉ3aϤ>:vخkP]^gM_eJɱ!R; Zݤb}˱}[ UUmJѮ}돿@Ian_JDkuVŲI+]H#*S3tJp7=ڒ<'NwrhcY_Uv}Mq5>s5W &^G?׳?g#]Oң񻑊ShfSt]6nw[ٙ+aѼP( BP( BP( BP( BP( BP( BP( BP( BP( BZ_9h4Fh4F9k{Dh4^/gBW'.v}/б4@.&m}G׸JZ)H%m=puttZxaպz'7OS %MϜ8q&?pׁ.G̳- 35_09#`ԭ.jږ/ƨ94r6cg!^9!9q\.%Ws 0|t?-5݁GN1B6!x8<#˞6 ӚTSWwY9)]XB<:U0z_0m^P-L&.g(hFT!ny<71,R%55Pu|[Kax)חuy ~tϿtUm ԢOSɨOSsk\xlʂ?;=~y.\Z ^*_N=Fc/w} 9IB\Z,do\ZY). 5/{fgx<~K{%kXȟ?_!B|bi1t(!Ze5`Бfi+A.U9NęfB[*6bC9YxA@LY )6o_J-`$V閝ڶT8cE +pFޏceP$ABGNUV·nMGPE6e7uߩG|r,D8f^_zCpo'Q ZҶ~YB| +Wȟx/] Eybd-A5nxJw;p|[47;e,G󢳻9*G0Q _MiF$'*{3 0M+c2o`Wo?r?7v ;\ ӱTjQt4$ q9CkEN?lR/c9"g'"Y30A>;[DDÀs)vŔ_"g'(ų:L_q:PSJ_?;Q6{!PÇBϿȟ(`Kv vHI? יCة&5D]- 8p+] Nh.5P bfz?556T@p.(.#1e k[D<2rي  ,/?}|ⷿ?˥d*1Ul?fRuفFh4Fh4^>~0yջw@4Fgge/c? ]]„H ~k_ZkϽs:xf`(ԾCzZx,2b遫k-Q+5|6 : ]^Y+.d< ce"ԸP׆rT<_(,q|6Ԁst*,)q!4)IhjN@4KhxҒ}b%?l=jC4 M՞]! l 43rl2XOXO%WO*-{AZsvU) *us&H sV#Пj2F?1%%:QMh͙9H$~"%#n_Zxl><)AAzw -ل^9p$((ԠVԴ?It߱Cпt, ώ[O$(9tTg˺ ZsvnP 75@ǣBK7=JNc3c#5(4=(}lwLF3sӣcU]Rz Ɩ6k5 *=d5Db!a_9R~r6 u)΂֯!dbl)WN'&ǃ~ ^1tO6?Z&5?=~.-w???M:Fug'}-^w^6Y }[\l)(䓅*zy9_=vYHRظ,22yk3*h4FZhNyzkWocNv6yJ%DNxdti)Vȓ'[1i|v"ϩ6Sdla&ϯ*O.OK19|֮O`wU<^lm"ϒur/˸)=H5੫kUI{G+(LuJy= Ocvmӭ\tvhZLy Ϫ”^pF<ϽC4׆BGZUϦ]ꗪ9DXi.qwdu>^Bl< 12<-< yd+f<ٜ\[ͳ96^n+ǙϏ,&=DrێT<]NԷVmO!V{*UKJ\ܻ[bͳ\i1(Wa܊kLڹ-1婅u*UqcK8:s6mg[_#1WKlڔϮZȓ'[!OBl< ycNi-Vȓ'[!OBl6YAȓ'[!OBlO7;3as:IU)^& wC?7/8^=7,Ux~I7"#F:|l"Ory֊k,iXHW> 5z ,^cx7ݺ˦PyDUx yw^ZeRXd΂g|:^gSSp>w\.JF) |Vxu8L;KhxҒ'5@YxʥrΝ&%OFEzSZ1%`6uL&x*5z* }HA9޹K~aI{g08w:ó! JM:pEaW)o#(6 _S }lZ5 >HYd%?K_.rIk?zs)_>uY2qO!e1Zp̉nAyO!u$$t=}ʶcySP_l.hi$w#C/=!M_ ܯE=g`u:iw6Ѷ=@OxL>CO鈗O2 _l? }w M{y;~/!M[=TvQd#Hmd ɓᇴ#m9,~ ml'/ ˿S>p0 7pܰ7tws얯m.rv7g\Hx`e$vQP'X@ H z H3@"`lgx?"Q,GOIHݒlڦwwvI6&d/'̼;3;33ϔݝ)RU̼XZAQ y{ndc 43xadҪKTꙠ2-ƿpv{lu,]+g8vgoi;w{S37}wcأ=[1Α.kӃyؓyB{Su#6M{?A_7>}L~x|R#^󁮕X'O Пt bj-|ycV6vN.nt/tW^PoA!aQ1/zzz z@A/6=:=zȘ z h$^ьoCAxh4M@Sitḧ́fA/A!&΅A󡗡PhZAW%Ro9rUhķUju M-m@kwwރ}}}} Bh# } m>mA>C_A7зwh' EB?B{('h/~ CGЯocqt:@P tAqP< E]@P Ӡt(RCH L( CP A* "*JPTU@PT IA!O :@!Z:'zЍMPg t3t unnnz@BA=^PoA!aQ1/P/$8ƨʵAC}=C*yh(4 ^C#P 4 z FCc8(M&Bh*4 ̀B,%h64 ̓C/Ch! C@K2(Z ^VBЛ["mLV# {b_^5/G:$»ϫ{!|ŬȧZ:kK]z!WVe.Auvve_.SG8;DVlzi P{5elysմ :}2->4i1}%uv)#oet z9'Ŏa`AI?="Hl b2 z A؂2 [2pY99yZCaNqI^Ii~fߥ\-3^ %Nmyc̈́^XhaVQQnIW};RFM :U{s/c:w_dDXCEnޤ;]D9u%{=w%%J*:.ؤ/< ݼU>[Kdk2hB.bZF+- El3.7/Uu!-Jw*2YMBl3K_JS])d> El39@l9No}|0D" q4 ^7fNJGګlTd%zuqqrCTGXgQ^Q6[Pr 'm k!.16GsdٗmfDۋF-dhT]%Z$7YlF7Dr<Ź Ŵwu ~ 65q*~T8 q ;ekUg\ʈ&vDJTZRYdDbfI48kUxfOaB6~?S-ܰa)_u"l49W:Ѵn\/n̉v(kg-3aKSvȈ/)#GL~Q+,t שTyr 2b [PyvJpMMk/s^-I7LԬSx jd+tQrV{)#Gی-)D u E|cHHW6]n^&FF4(ڳ1A3WEK⍢2ba0PB9J~QKA8f JJ Ɖo:^ߐf3#Z[{EF$:mՒBqiiPc##ܧʌDSLyyyY{jyyAQqVnp"#DS8q9VeU]P^QQPTv%׺/2pWLtPu;*U՗B.fy{)#G6U}^.9-vxm2p31l6_m^ly{[~EA4y,xRJ p4!U{n A؂2 [\ ~(#EOjPҊeZ PwF؆ eA {QFa eA t_l lAA-(#eA ~  2 bVNrNPS\WR_r5))/o>w)W WzF8-Nh8ݟ8 w[hgG rKJ1!ipEϷҒ64͟T]dxί~Ihkt}a? SFQq~Ǿ Ao=c?Y ƦsJ:'{(!9-JJTt]0Iɧ_:xp/ڥ1RFQq(:}}gE"@'#ˎPzl'bT5l^/iˠ ̋iqSЮ\Ckɤ2ȶFnQOET;Xyn_ٽh$.&e>??Ke]H@Rk="e!3kWP_1# r݃(? 'F2"`Hv@f^^zRJqIF痘-gfb OE ㇌~jj1? :_ll/BX=qVoόfXR{ .ƭFcr~HL<<<5[ /m `ir{[2#r H3DgDo²/2/XD)GtDHCca7z?&sDe賓5.bUkXDRU!\#-yȈ+I(6~@lόT.e=QsޒFtH]*wg"#Y-(9=`_&zFȉ[quֈ1Hɂ'#EF01}?Q땽b:g_vaF $)ODR s*ZyayĮI^X3gس xTd=,2;`蓇Kɱߕ r*<ԛ@M؃߆8VAWRUѭ$ٱڽC uv 5NN7 Fn252 A^#6 "`{(Sh(xF>3Btxľc&R@pN-u7륜 qHME.GH+WDmg18א_}xGxEUU'2&*O8}϶i0#@^a"T7,[N&7 GjOaUͺxԨD _W *_]WEa{U{I6'7م(펰/z)B)jW(#)69d9. ɈHOC>[dG QH{P^Ya(.")c¹*xu E#(f]B-޸}M(ݪCLrR4G䷠\bc/Cn/8k_c9Xy4'8<2~OQPRR ń?_RozP|FMOf2#Jn)F5K6SuD1n韑(,)!6mP!_^ڐXAR׮i>YTޕ\O;KkUG25*8TbB/gDQIINA$BaID|CZ*KkΈ(-WKKs +e'5+tsO+ "/_,///k/\-//(*ͧpn#T?#"_8Ѣo7f 섖9ALY~y:2 \S'G]]>ЗN5I  2 [PFa KF5K jCA-(#eAkA2eA6 ABt͒ Z$QFaV.AfD+~āy#*TP+#B] e*Tl*T*ʈV*T4}-+#;kWx/ 9-{TvbaOAJ f̈`;>VXev [)#Pqaiƌqq o" eй*4*#fY6oua## 432 Yf_6s ͳH2 :kWP&>w,u ;p1 R.(5PqUi+Aq! D"~[0tGPҨz6A~ W쿾X(#PiҨkؕ8 8阂2 6^- e*](#PbPFPBVBBA [2 *J#2gIIqgk \eA 䵔AXAA-(#2#Z#p9o{PFQA؂2 [X2"62PbxĨ$i ,;{0[Mԇa?!1v/[wK͌8_!q8$zRXz K 2:-8)CGR?K"k`s/ $>;՟gćq~l1D~"˞rCX f%(ozXQ506M\S%XdV8L`9( fEE,o$+^-fM;L15x8( \hbWmC=AH&SpH)]inc-^6D-xћКȈDCO P#g%dKLID~tqњ32 7ύI|so;?m;>;<~y4C^#=b=w=hGt\a\qXQwF DF}U:Tעp&x)}B'l|" 3*G]}^âsh}bz ={?.Cnkx,{݃E!"8w(_3BAQ@8јiN/KG^˘+O'?9!OpJ)O}(8،2n_qpg2{\c˜⡙ ҽɜ!k^4s:h^ޠ !Ba|`u2bZngQ.tzc]cxM5Պ\W^L3c}lXOČCgy J !v^4_v~˽F̔t32NxftuiGh{M=.̛֠gvR}3;@9ϵP[~4qM>q+2ʫXSӟӑb{hjfIYr Q{?}"#t~<#=Ć~4m4V h]i,GoSFdDy7O5xYw߶Lmc;iyځO=:=Kǡ*M;<^2s dD-w"S `cEP2KPnޞӇ˟b+&*GJm+1gCxiʽ9挈}SԂK)#^4g߿-(NVӑgĜgvVS#~:;hX5dF &DwzzSb UEeO<#6m+cnL1e^0[^cr~)#vCq۫}J2B7S-:2};YMSLG"];DoX0%@~JO؉9X~1URƨ1ckGYbwVt{>m㊱gm>dctr$מ!Ϙt:l<A4&#̿A'릭M{U7i)N74XBFgb=# Lbj@& #p HIdD9|9#22$KF$ Q:k4n ڦɇYq`,ҧoܖ'WJ ܪp_F+~/;4Eʈs!t^pݸ0 =+0GNa8:#Ǚ2A\S%}%y=3y"5VyquW@kTX͘r]>o[c>zEFkf蚬9ofN_afﴌ'ZbQi=2:sw<jAD8ُ:O8"Yd&yJ({zV;8vM[6h^̈PM{W>#&1pz!32LIr|\蘴$?x8ψ{J}wgdRXR .;pQ=w}Q}DSfpEn:n$gĘڕk__SW%iCggI1?߅}(0G #w:?]N.`g0vv]uv0񿋙zPV]XhzOeSkdńഎi X`/gpr?2כֿ9KodNM7ivbEU/e<1`*+R'"#bDFĿv][\ZK+'iIpW^w5ĥ˘v5Kk eF|".)5o"|[lIjm͚9of9suI15#C/e{x-O}q^sF?d ?3' lY,~>kGt>882EȎ)2Տ#u.X"k[+uW&-׍_ Ӽ0_C) y|޲,52`Έz2"gByÄ́ʽ ڹI>ԇ ^ U?73ggpNMOOMrIOMK~oȈ}_"eDpvzQgFȹP aDdy3ϭȶT%價xuo6""!SPUxUylVA/q34ݥڧVgs%$)qqΟy>2(8:Pث:c2&I'D0UJw fD6(6@AyGO.(<֢Fy/l%8E &|3OѼlU]8s0F2`㻑z =:Wyxp,hbHL8&'[@KAE=WYc =†'q^4XR0rr^&$l̇+]dK;Ȗ%Z67Ѳ+yyʄ=g[Xd βX%>E󿋣lVhƞ#s\j =+Nr$'p_^ {]lzX JG$ˏƦJXw׬S4L{bW}&~5hMj n]^RӪ |/1>5g,2uM! [wٶ {}дz?D/t+ؔRec;u M_}֩wr*/傶hf_0|mc+7~3Jnӻ:S.9ºG΁362RCjMebkX>ϼZͩݱ7,o3ٖl:YKD[vxyQ1%s+Dta^Vs5;S, 3 ͧ[Mgׇ^Pw T}D.oi!L>kY 恕o=5Q)X=,OAဲ!nG.!y/ZPaqyU>U9ʈzGialc ˱Go?JYZUۋYx`Aɛ :Y/->󝿆H[tW`Go?E_gU҆PdZ SmŶC؆ͩ2!(}`Eϯ'=z7旋c%inTE?Px>ϑ|$Bb J316-DPD WH4t|b\ٙDC Z%7w->}.BVбOb+-k B-vǘ'M{'wFY E"\|]Xvџ 2ߜHZ4/u0a^d!M5n3#C%?kbȖWCn_fEZe/ForbUo5|{O#ߴ#s|"Zs`/g0 QL;49=l7:rmsK7S!][ߵ>u-w-BL++M?\6 `klj,?К?;v -B*NWb7_a+0#.Ҽ/h(>JgyY6 G>wY~sj{F ?E<p}~F_Dݐ#:\C;/k jwZO3?ΐ;ӑ'wgߝwp7-?$\>' O3?ΐ;C Z_ߝ!]K+|[A K$]f#Qߍ-+ZJԁkp!lj&J&jW2.-[:!`5A:F.o)A,p_\~͙R@br1JB1R2xVasZ łѷ5Z40)-4Q_&   rs\}W*TPB *TPB *TPB *T@     h+.PL8MϛZ-ʳ)U'~;Wz(*8xSEO;Q ~:VŻ~/JҔgU}QS\yRՉ U+ GUrB#5'WRۅ+'H; vĚR%l>S%9րfiKzǏ'ۇ,~B #L)I[́ml20_j7&a(.ɤ]9 ~8^\n#c?t&-d~*T*".ёRvqjի%m%%Em!%qJŒjSLܠRmHC+F.a TϛzKzDt9r_(yp u*պիr_0iskT cz!yU&* rkh:RzlhWfgc߮Y|7.nj>|d}r2vXX X?d0Q؄W5@t\\B6д:y,nx-5/[V-S5k#(`S k 515EMpi E 1$X^{ d-M킱ĆD6<I{XĦfaTgW4Rf?}pndr[D^GP֊kIe. քd|.%Uƌ }@6 S{'=w'c羗<ݿ[$ַ6H`?~5靖7~Yeu~[s3_[9Crn$ 2BM 3#Wg,5 7xIe5'͆n{?{*K]73u+'iQx?uR὿{-zX{d6f'œ/?%YkB3ߘ{mv$qEG^ȳS2vC;-B{,́e?Ec׮^:)=u,]4V=?0cЌ~SO'yF=À;EOǚ,B"qdަԴ/L+XϰCO'1&y\`-ZTE9C<|zsntٍ|'>mgiA~\C?۹EO%ִ(m#K8U7}6;,zuRHxz(Ōdx_{M}W^jHH84jkW*nѤ~EuK' [2A6@fɥ ޯWx:Q=^멮ܢL+֢.JWZ, 4Wi׽faZ _;f;Gޑ0Ot Lݗ"nQa{bT>@3S_|<`vXMh3s|EGuA7.vm`?> I.=-ePi2Wt_QEA?3H7˲G U7kư.u"?f(2UlTp@3+mS{AvC3yP=~i}SM9nleXtN OxdV$X[yVi4 Lw%;.}e_HdJp}R?P^AwGު>cpǔg¾qFr`: OrjѪzE?zhϘa#⟿= Cސ̵O]sqmmQ]@gch܄T~};凾]v1|캨G}"+=َAwgE]o1R2wSE]97b%E.w;O(G^ūXgjclД ?O%$6D!fD O4qtm?šq"\V xusj!"%,/","ȢVlyjo.[+e]dYdE B5XȢ Y`!, [4_EdB5XȢ.,UȢ Y`E B5X[,jn.EdYDk,"ZdYDܢ.hNڕhZgEĵ:_mFk.#8nQx|UO֡E7~딵}<}Q5{윷lZtLۅr"a LXX^yE4Yj[mo l}&=ɹoeik4YԌ Eβ([ i ܟ)֑EWNu |O%'\K ?9){D -RF}K3*!N|oѿF"ej-ߵk ?WQQViId]I.4hKsJK_-mFK]-Zj˹bE/=!"'Xk+,"ȢVYDE-be#f Q([B]},"ۢ}{-+~"n_-:wwJ?v-wwJl_qwwwJl_qwK+Qүޯ;~3o1Of?^"KX~sŖnp'+_+MJĹ*ӷ/j&?/RQ-+MJ.ba{ 7 vJn=_7RnlQ>]Cs}/w6G4+>}.BLǾ?ミ;C_ߝ!w'ߵ[:QŬ`tɿ&M&ф;_6qzzy "\M8k=d{7lXȬ_uamSԼ[X6:#of[Yn>`?Ûkr1w~%,]Bi]6:[mt~:mxɴ&>nrLOml2&.  4SE>l}ic&OW6Sppnq:>ԫmT꛲Ï4"j#~Hn7Ҟgxzx#?5>Ye [xnQO22u|(R]7R}|k־53)Rο'ƿOz>->D͇4WWx3l ޽q>SM?@I]sω6y]x Qj#c[3iu4{cw@wBwAݠ{{P>'W^ЃPo!0(z u BIh(4 0oSLӌC( C@h" 3 1MB)Th4̈́fA9\( CB!&.BHh1Z EAˠ o9h-ķh#"2 &h3*?kПס77-Пhh+ vB;]=h/ >!+A@BAC//!(t:::NB~~  /3 t : Bq( J$, C"t J eBYʆC9ʅ|*b*ʠr2t U@נJ:TIF!wA!/F&t3t {V6u@];;n=нPwt==@C@B}Ǡ~Ph84 @OBCap=? _iFA1P4&@D( &A!d(MAӡLh4ͅ yP8,4@ EsP$Z-enb_ʆk/@h#"2qx0m0 pT[#K:fCsv| w-|Jw2Ǟ[ `O3·úp»0Et| u:pꦮL%8܄V7fx-at4]#c`{i&uȏ|1+S 0)>쟏#aAMGA؁< >A!${# ќK+䕕_.,Rx )h:w)W]r)KIg{^4תmR`翾$4WړGDCM|ڂZ;?%+6ј言oFJ\)## s<)5#RZt ^|J;vex{# 1~lC`n͠ :ihWF~< Cx0/HB ]Jk6pg8G@_PcAx봗kc+.90&:(/(1EEEns6 )ٵx#U6*&-:,.C6ŀ(iSGc/.yEEN^?(!lqg`dm)-,r/ꑍn/Q%QM'ƈ%y\Sy21s۫t> 3JJػr 1žhy ;w&7b6lT{k6J˗Vm9F)?9YG~HIGxFAi)&l/I|UREmM<ر՟)_u"K]-ٸl<^. ښ(O&fQI\%$QXZ JJŶĒm%xR ,HķShm^~jٸQKy{,=RU&Y`(1f?/Id;b9PGc(*+9R?0iA $y$A}# =EK [AT} P>A $y$A}7 CIaH GA؇߇~; 6Ai=zB=Z^h ^Vjq{&򨧜MjuD2\>gG l AzAZ<%DkH|p1oh7Ztp }!ᑾ5{ ˜@|QO9[,o;(Sr`d>C=A#cD?m+j~Il|/Z|V}C.(^/mVD<22F"G}$}Q/8*z$6. X\ͮizF}yN7=EGyM}U߂jz~[B#B=I䍵+7: GrS\6._RQO9<=ydӅz<#"Uc#8:jrP̪:N[H#IE`x c+Ű}?Z1Ul56qEUyWRC=`Թu*7 dLsĆC`k6ʋ4?E}Ш壳:zI>g8Fj~&Z\yZQyGJ[Zb}vB=5|ܹA!o-A<<ydKH -!#]/#[KGhG&G l-A<<ydKD=j-P/jdH Gyf@{H %)>H ېGAGt>  H GA؇< >t͆ ># BIaGH ꤴT hTJm0#)(((GC<%?<)^y7y$kFHjA)((T4#HͤYNEFF`Lxf_d}T.cb; k=/^|eGRPP4u}P/+[pD 1>̏-N>2c1b!b^1LIAAќpxT+9AMAywH U $y$A}y# GA؇< ><~? Bc $ y$A}# ;Y0,O/1.i0^ }D3FDS)0/~#O'a8&H t@d"=2,R&`<o?2R#M1x<70&ѱ=}QwJtbǑI$d a}N;sPb'ce#H_cFc*Lq;NDKA-]=c.=Դi'4WHֽAYwLt i?"}H{ GJ׵Ukenٳݵag9r3<.{fa8|`'čc>&aN"w\/F>uÑ`iLy2=魬PUʉE>u."=m,/AYeC3|$|{O?9ə>s|f 95UwdAu>Y'=p#_xdRO~F;_ˆGna <z ^|o3M]4h7WeqOо^FsF]\y/_>0]V2/z8>~{c oyb;Oܳ.ޕlΎw'2On{e*̹*7yo5n2V%/h~a5i*_2_u䥾Cge>e3?{Hv@,s0o.qsY rG7 #-f4^ +"]ב.\5vڴ#+Mqvj<:`)Ɠ橼_eXn>euH/ VLvS.W0Y>Rx;Ayda|VtqeajH;gߡ^h]JK|bzhˌL,O9󬹄kPMS8TO-M \ 5Xf 73jM_\;)*;02{#S5h 7PcbFIbݝ,~ ڲGgF$ђ&C:?KَPnrvGOc+ ]|Q9oj׵a9k:/;m󊹔>^V/Zs򀜘*sN*KPT &BlB;|ĆΜJ7{n8Ξb" LV fz&׸;sA؏|Go%rSNK9k-We4bNHpZߺ=ƈ`?{dz_|'#~dGH &qzɺjWV-GbUvFr R5L4- ϿaMvH3f~ȹYCgf>1%C褌R &/,xygrior9/覯N^ ^=~f"YOe ʴ>:yq\]c?Rxd(wxd 7]Xwu^)nNx˅;_wWk%d ,y :K͉nᲤUŘ4@7\ݟ{N~k7 K_Y}KyꦯMZ=!Rlwzo=#eq u˂ap! 1>g~CG-5Q*\2fKnG;>.|[ Q sA]N7}n mPTEJM9:#Ws4HX#GȼLFKaAMA6ݺ %b囆 ez\ΰY)_HF{G<\Gt2τAH`aL;P=A8Or4^gHS>>bQW^y;HaJX]PaD g9yv6vͳVgHS)ҏdo~&?GŊeU__o2as b0~1݄h^D TD]p{jeansX<{]V_ 5@Da)>G"&p-]3㝜{p :}} A1ߠ( -ww1q=t#o?O_SiW(@oP%Agdt@KP*CP&ilH =\(ʇ B*JR *.CWPt CUC 'jyA7B7A[CBAP'3  uC=P/A7zzz =Cǡ' h04z C>)h$ = A(h44 B(=A$( BS4h:4 ͂fCsP4 Ch!zCKP zZVBh-Zm6B/B/A/C@m6CB zzzz zB۠h' ޅރB@C@BB }  )9t:bA_A#Q[?c? {$/GB?C@ЯP,ߠ(JB9[/)j Hpen Qe*#luF (bdU|ĔD}0i6#L>\/ }aR ED=agRxCΛPt &+ \ǧ 71+h?ةUL v.vlg٬\sEٵZC5D}9)Q7߭p ^.ܼ!喍)^pӺ^/g+ۭ=V& Z ٲ+əD0ןma_ [|Eűg4&)_zsFų)ʹSQ5:Rd&ը^D[έh8@."1eί\f_.x T۫?z>ɛ%8^G.`#1sήP<\-rYEsUսɂY̵h<-{`ovU{7}2%V=KPfӺ)S2x,[6S>;#Lo0sj=YS>fu(#p[Rl^]m^ ||9x.zHC>)u" 9hz>5cjc:2%/OwVԻ16o(ft$i,[ˬ(Ŧ_;oH^bͷZ.>h:2MPsLߵ߰߃^[LeCg{*RSQSvjًQKSG[LR+ >cVU|@T#Ktj-i-m\W?uKKwTW.KweBOϏ5^7mPՍ~OoҠTueK(έÙ/b"5@έoorʮV4oR:geT[5~yRTzڇ5I/mȟPu~R[T_ho۴yTWOweҞOwaTWFO͏\ODhQ=ׄOweTWOweTWOwe#ߕKKAWOweBTW.tUua #h(>;Dy8PD*f:=`ejq3 A?Aњ!ĉUoKkDbBEʜA4'= \(P-P<U8 qh0ܛ$L`&"nq΂ E/AAAD38j@]տ@AAAA4)mTgϣ^g5_ݠTunPՍj/3Lc|72}-RmE-_̆GG7EZjcEZ6ط7M^Ul;NcDJk~-kpfu0.mw:R7_ݠT]UuFAAAÁO*'W7@        Uæ;thmtDy8Pⶤh4EYzBMej29QB҉C2uL8GjC GY(J3PwVI4*a׉Fx 8C\VL`N#_   P\OAAAAAAAAAAAAAAAAAAAAAAAAAAvB ._     6vIi E3MZoQ AW7_ݠ?ڗ)bx;cNzY+Ogԣc?{JZcb4 Fi :|>f*\jl,<@QXً̛OcW//տ [^孃QK+w?WߨhשP A AW*=+AAAA|P?zAQĬ_/f %d! q k6H&;=nOzMĆjt|i>eŃioɄDEw:hOkM^G5)Um*ڕsy \^ v*Km:# W WJ sЮir+m˗Jrk`K%JeeE.;_,ع$+L#YLM?ߴ0ǠKWJ-F:\3w"gw1gMO/v1oYg@Ml/oea/g7vN?/g4y*-=;^).4ԿEh()w[&V/9(%UQ\\jF;X9s|w$($DG'⼄,*Ʃh(7/WͺXKb,(*s" }_t)2g~L#Ic07נάn/o[rpԒRiq.R:,4_L :%ֹoZXh5degZƷW(ls89X96@AސɸPK^/-$m]zV9^6]HWj` 4JcgY Z>~t{*h] ڣ=eMW9-D 66P>o0j`r_vi%lnK #[d{UEEnaeln1!=,SӘ|r#ƄV3o'b9N\<ۼzfhٴlNZ Jn)lHfcr0º~ ,}AVHxN\]ɽF Hy S\ eq2P[)7W7ifGjd{:Y#@a c㜐~iSFDArRej;kRz2~m˚ ?ޑ-s^" uѭ]1%;*HhlVSiF<2&)enyѡZa-C^Owx7[\R^@ tkgVM^6I9!YNgONД46wѭ >ܒes6E_{avtK5kT次iSM={3&H<áLeD ;)5" bH7..m`׬q]>o3Γ3촍9N<.i{e, ^21{i%EOk#-۲>݄Yc:&?uḳ7 }ulX%ðd9RwIuOƴAYOk^4JW;.|`ΜG-I-ücn3ıH "R+le˥]ӃXd_"#|hÇgə~?_C}-7yAw0ӖĻ\~;::}r̙Ofɚ5gfΓ9g|D7~bPLGV9<.Ƀoޗ&=x'BM>oFh^YAj&ܡ 9kD!gcd< %$=ycs;ه}>^ ;.]@>گÁo}o:WLv1=?{sbl/Ik` sf]&rAt3ŖPdۈMۯؐ9ŀ \}BbhVNk$|7&K~)lMOGcOa0$q<3Ŝ_laMԓFkjذǧ[gBt2 )zfbo&g}$gE22 )Cʰ3?2l\dP/ [9}rO?k^ ] ÖRPNz>vs0gr(Cʐ2 )Cʐ2 )Cʐ2l [qEqլT2t }L[P!e U{¯zΐ3T7rkȰǦ a-(gb/gr?y9Cϼa|[k$3lw3l3t^ʦ;ұRXy eYћ7v݃ F+Sw2ӨeG*;ZϒוMf=E}%ݸE1wo#ߜVyZ7uh ޚ)q2[6&ߣUtw.=FiukP1NaV{{3ouX&i^rSiZgɰ01I)ũw”3lTdB(mE:G{^l|PW?uS]?ߕ #]aFBgrjΤT C|X[z.=\ AAAA4Ꟁrq9QvuuurGjrqm\s r[/h]|;?ҩ΁/Ii/%bSS/=}1Ⱥ2MF_-ї~l$G#_VjMF_|k&u ͹Ѷ䭿\.o6y9 RKey ^܄TT77*z墂KFן  F (9_{k5[8L#}i俐mg [99{VAK{ ~UdlF:-Cwl)C_uH#>p{ԇ2ܙ͸zdأl dOb$ݐ]ݠJm8ܢL`_7B+]FZ$+WWX9<{iNLY]}4g |z~=7:`~.J\w;K M=qyQsq{b[4h2 პi?ou  [+ k{>CmP4ޗ?eޘMr-/ub|9ev˷},yrF^Nl7mݸqWk|FXO=1y|K?H ?/jԻ~i|$iR؁w_ٸ2w >i~}oۤnƸ}bYѣ[7&B|=2y]ԙ֯1v󙇿AQ{oooD[:oaJMm;<5TKUX x`e'(b,$&B %L (Ex*oA1 ʩH(@ ?[Mٰe6 <ΖلKRW^XE/O9[{Fvkq LM~y?$k <h$4 exL@ga1Tsǔh?Kom6#vY欝}|gGK~|gx.i/.QN]7}f_jZ0<6NVn+_${4xiqe:\<#K/5kz0T~2Ggt>F,dM:_?@BAT!nF(JSN)b}/MQ.nn  $ =uz@=@EmEAУ%z B~Ph4  !8e4 FBh,$4M&BS$HS4i(C3hh& ,4 Gh.4zGE%eU_"5ߠ77wCh .Z-ރއ>V@BVBBAC5'п>9% Z}BB wFh=7#  ]n(J@{}~(:Ca A)P*$P eAP APTI*J2NA3P%TUC5YH5  AAP-]]]ju..:BЕU5еu ЍMPfV6vN.nO=PWt/tt?zzz^#Po(z BǠ>P_(@A`q(  Aáph4@c'qxh4&A)Th4 EAӡP44zz͆@sy|h"2 *g/BhWuoЛ[;ߡP zZ -CAC@+@+U?_AB Z }} bo;h#    m  vBq.h7%@{>h?BI!0tJBǠ(Jҡ (ʂ(ʃ:A'P1TBeP9TNCgJ j:X/CmPt>tt!tGb= u:CCW@WBWAWC@BAC7@7B7A][[۠ۡ;;?A@]nн}PwA!a zA1(= C!cP/ C h08 3gmzzz zzzW̯ۈ]BUdl@ sb`$(W,N]DL`Mw9xyT=ĚNUH+=O/BXqvB!uGk1M8p]0xcKꫛ ;+_gc=SpN{ؒOԉ\)4rP׀}/L~~$g&It h`8e3~3]%uQMVqv=;GqQJ&tW~S8YCEv<x[*B?wSKK&BiRBqz)!8B^J!C/%=?rDNqNV>yʅTTVQJ3ŧN;~g+^Z8˜JAS^KZӲ>~}go_t~IHo|M1ѡkފ,(+|饄c)&KDۿ79e#[lD^ť^/X:N T [2H!-7pz+$f/? G{e䦙 e CS"'8=_k/gq [J**JT{q"\: p,=X4$|Ϲ*2Ԝ|^z"hI}/oF^v,Nϗ/%=Ho)%&$UA)Z%U, D@{8Aa/'r lx#͖3SY_K/%=Ho)(Sgt^iJ/-HrzRB܃SOWO**.?nK'_z)!AzKeeʒ6{vM1X]S#jTVUU zי|4+?EK8m.ɻmEQs[^RB\ ּ~4)/$yyRB̄lK+6uof.|饄d`/;Hvڣ ?WqK/%ǡBXy)?E!h/c^ۄB^J!Ә1.hIјl-!{᥆ !QK(Bi6KuBHBK !q襄8RBqz)!8I/=K !K !q襄8RBqz)!8BG|&*^J!A/%i^y+NS-'ڶ/5 ZFeO91\F2^h,-%襞RFcA/m)A/8w/(Q"cEqpVK[J4. Jʋg/81ZF4p߰3-%襞-K{.W̱&R qb,܂9bbܰo(A1;z*Va/""2~O_%H SRc'E,׺Iy<^R "2V@U}cMV}Cin)]V/Ű [^ZK> F RzuWOU۬Y 7 { x,SC~OaYTK4t! RIvK^ȚAQyac߰z!e({){{h(K#pȘޖ{h^Z'M}ac ׈ KÞO 9BK !q襄8RBqz)!83QrK !qZ-'ԇnZZ-#Fz.A/%N^ۼtƑ6}5p|zIoK-CR$襭>K~MU7WQ*~sծU;cթ_NkI(%2VQ#BQbz 3Jm޷jFA<uZz)qң҈uk"f-!G7z)s6A?N{K+w~-8 y颠x9& U̱(^(-AV-= lB9r=?lx#Kj&/^AOJRC=2vehhmmJ eV9sBѲ2%EAQB]+CsRbnRLRJyJGMRahZpJŨ6bMdV'%jM^K5<ϔ-[ʜڭsobU&M/gf*wƖo_o>؏ۼxE[IGUy,/_m9Sx4Eq _>^6R:7T'F*ڷE{#]YB}q|_kIyvRڑ;Cu8N9$[M4*D*|}^Z\^Rl7gHMv`ҝ!`.L8W_#QvFcbt$_i<ԼtnKQhiG(A[pv_}r3XzT=P߉O;N&iЍHiMU6`>؏g\R o0p|I :6BsN ;_ZGsBElKJLh[*WR voZK'(gPT9a+ֈ#+-Gv ~yHAi܏CKk79{3lxɗC^z:akфkpz`;T|pQ9A/%Nĝ^\(;Ó?q_פCSIUN5*wH/%Nx)vx"xmVgv>\TslO݂͑C;&ZO /{Oĉjzi oRH ;UGbz4A:jUv oϗA/mm^Z] 'S`Zߕo}ٯd'K6/mnKSh^J= !륄9RcM!-ymK !ܡBK !q襄8RBqz^DBHꥬK !襄8RBqz)!8NR/т0i- oz)!noK[[K qVRB7@/mA/% 8K%u֟P 9\-=RB܀tM\1 ~9'{.׷Xy. 饎7:/8JB53٘]Iv7"/3w^&^PpK z)!nE^DT]Jވuk"7{0 x,#pfyHK q҈u0$|_5s="(H B˖uQJP &ˤVΙKz)!n^ u? Π6r 9M/L^zӼmK z)!n^^J襭>襄ziz)!nKw>7Т؉EHz)!xRBqz)!8B{"^zRB9w襄8RBqz)!8B^PK|BTmVLVLLPT1| j_UNVʟPJG)#S( Wʆ 3'('ҁ}E1@Dml#n*ʯ>g#}AtZb4xj#H*7W.*^:q}xiK'BL9kf2q6LD\~,P' !-ZbJ[CO/gm_^|ޡݾ{ܵ~ܲAk{ߟ;#Uq0Rr`cgԣ;u2o֦~Qjav,b1|%ģҚY+{]ߥo}oc߄汽W>\xCλ?=ۮ%MzHq^9Sx4q#unj_WjkS`6tpqBH+>IWu? =vox}#Svzӻ ˼6,YB. j+TO{˧K߽L{ 9rMj?Mӂm)<m' ;_!MPd;;;>t?Y7Lr e:=N_4m%g:a n}o  /.RO{hLF=e>4.nOf9&k]wIv!yRߺ /=px)gx^z͇ۋ=-Qw;J3g ҿT[}ʙI>xvEت'jsWsg&bzu7̤PG&T/S ouvUpkh\͹❭+:~!gkkrۭ SaB\ Kϩ]ة_Np*UARm~Z|OGh،G#2-&gN~0"ۄ4:?uQh8{77snpׂ!Kkk?g+ߨ2<9̪pz+'\<)#,^Z9ӿn 4YU,v{wo3uGgFQNcU5x4,ŽsSL_\D0ySns *a1V ʟ0},,\5<0*FojlMcRw140$]m^ ۄ^;LJfb.>S*Z5R`f'{;YjX'F0{Z&!,맛OזNqk.Vn,3{U_+TVrD)ףmXK GZ>P!zࢠ8\'2Bf 6#[G@Dւs;ͼ ^ F|v& / 7}DV6i'gw .*7̋&JP2FT\'XV e*Ƙ?7/- ֩,en䜵spv~JT1yiv .^}H3tkgNmpӼ͵ A,uy&dL>U#xE񴐧2Ge3lfΐhNΑg{eXnA9gv|~+4;K_' %tK1.&=̷xsF)yN?I7GWo0yi`~鹲&/K̃Uih<#|3RT>ʮJ7e@s4y .^M3=fβu6xm33 E~o!h qmx?3ٜgrᨃg֍sse_50>+^/MWztx^V:^MDŅ>2V,[>>f(Ev̅Yf_s9Ke-ڮ@*N͟k~V\0kUj_XV}32`asYoRv e,X{䍟sov ۏm._ UBQ#ʼn=Y#\ z",TziCf䌜;zvgsFg{ΑY7˺!,AYʺ~pt_y۔7 / ea-^ڤ\kHlq~8@HQSm O^Z'ΑOc>GoZ꼏Ο2]rY~Xꮢ)שMhVk9 A6!X` ОOf'= ك,F*!7>yetyMKfb CQKEfG^̛SͲM;)̇d7"]kkhCSꇅH;~z/;/@}D\Y\y͇m>,|77)~=7db;ݭB izK̙ťϾY-Zī3r`}&evh1:ߥ]rTK{(eO왡Y=J Ed;>RXrwd n|^J`QsrXU,?::R޸sG>3gȌӲO y* 05{;?1/u}Ô'/H~# pdG$pay~> irx^J J%ol/zxZ$ƒ6( N~%O~`Iᬷ f?y_΍x1o yO='w쁑YOevvk+xu_zicRiqJD߂>Ӗq#{;0!6B$u.U~;1X>,NA0)H7?wr¢Mд[x}2? F3zxL^AJ@+/gj.GK;͑<3}p'!{ѣuӜ%S*gU0ᅼgsEfNztb&{~kKoXޤ)O楘)x񩊆櫦1 !X6CPiU i\9.yn]^eb:k"A/i VZ4A%A!DE;q֟AK_CVyo$I}E%pT9f1(J t龒h_|~B<§9V/XVgNl^/FV'?+gӶf"IN˟|rԨ2GbLC Ev4+TH3}د|U'1(pӵvhRD@eS?a :rRse]M !ӀwI7_iQSڠo4_j^*NR3RXoa@4>"}H2ocC6{o?I#{]i TYROkȵ:I} /.C ꠰>R̗3-P/'/~Ktufq C) ~ FOi8 ]gF E'r]aĮ0 Zz&6wh1-ޅBˠ{ CJhO#ch5Ч>>B_A_CoX[h=m6C?@~@B?A?C۠B@BACC;P C h/%BPt: 1(JҠt(ʄl(ʅ|*CE $T @PTU@,T+z<@tBP;ЅEKPR2# ]]] ]] ]] ]]unnnnnuABAC@ݡPO(=G`(z B~Ph4  !Ph4 F@#Qh h 4z&@)h4MAOCP4EC3ggYlh4z=͇@/@/B/A/C@B-AA^  Z @Kw2h9>ZZ >)Ϡϡ//W:(Zm6Bп-O6/Яoh'vCP C CGd(t JR4(ʀ2,(ʁr<(* Pt: C%P)TC)4t 1lBr΃6P[(:j#t1t ] ]u:Aˡ++kk.-ЭmН]П{P7^>~; 0 BGP( @A}P( BP4 Ch$4  =BOBh"=M&CS4i(C3hh& ,4 ́BAE%eU_"5ߠ77wCh .Z-ރއ>V@BVBBAC5'п>9y|&AA$aʰ4Le\31_<c͌* U^Բj:,/_ڮov]VAr#7؉V|'P|mE. z sv(aʰ> 2}]7=̮U 4jrB6y,9'SRHȓ}^hq2 (~V';lBZ/xĂ8gB h4R  BrMOfj+{:"ͩS,b/}̺²Z/L̷4wx>?<4sٖZ O?,8r#\BE/&<XfaevB2%1|jY]Sk:EDT( ʌ=~?=ʌxwf|55wN:s;%yC޼+8$ZpsIތWog;{(tXZb~w&t+IRy唄]ކ 06;Cto@ߐ]~Oga[ռmesr lyZt5׿߶\y\Bj*@a%<_G-X89}zս,;]Ţ2Mʥt3o}uJY_:˭6L67}.lpv$O_nWAU?PK'[r*HIs;Qamm!0he@\,:RR2):jyyt'dP<5V<`sHhiE -ܺuٰ\ Iѥc?ʀ\wB߄rAIymy@05قYS%~gk}%SC2Oh5gs8\_NFVT_=eeh>LHhEGL1|g-u= K-B ERΖ?7mOڷ|5 j6 ˁ/Zꏑo{Y}SܾzƟ\yƞh_Yq%~776XcտѲ` a {3?p{3?Ͱ7Ӳ>`YogV3wfololƆC}n:G~|ʾeY 7YD)pV7#17 S}nYJ|c&;,u0m;v"e?Ŭ sJ9oUK7AԱ;so6S)"b"Z'o~թmS9Ֆ?e& \^"y41HfC\L D[2Hӌ&F*gpo'BH#q"0 ogL 1 .By3@|&#?MtH8ZH͎C5ۓqwKkYg|?)zϱ]V_'@ ꏃwvv䞿H5.ٞX{wc)+CCW85ߖT/_n0@U 6朗?k_oh{M|M(>вIm]&J;4o-U3'TeVܐ{Zw;3QI5(}U`*EvϿjƖ=GPE񦲣qKL_qE+Z%eV]M#<&EzAt/ oޫO(#@-9ΰ4ח]+ XN-{7ANv\[Nw 1ס˾-LnWwFicpu ui[էu a$W㿉ˆ~_m|Fk nՆu{D#s"H ^\ i1%.dT)i'ʉL8C g Q&TFub֟Bl`z;}~7~ p!}RIǻ_B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!xL `0 `0 `0 2:*QTf2D%Q' T[d(}27sD{|命.u_<57&谠jtM厘ZWs;&7&L_FШy_,$mgeTA>ϺY̮jDVN>7orτre|wL nZ&[(%<ߴs P)1  |&>'rQق,Hɰ4AX*IJ߃L ;_"el;Z!7ަּrI` $geR ?4uʒªzS{YtMdq&"Y3a$R\&<9(kJhG3  dG+vO[6a}'"M*,.n"]Qp;ϝ$ˊ>|GyZ+S^ȝ?>wܹsfȎ˚/s#ܸq=Y~s[s1mTe%'?xE(\Yܗ'#&{2wC"f>6~qeYrvS.o<!Psɝ3 YXlȼ&>?.g蜙óg ɚ6 kZMx$cé#;tlJMoH$}}Z{лR޽oPCsk$}pt]ɹi918QX|KzC7J`cZFD,. 9crkÒȠܐ>KjmCWr?n.nB Ռ?6%'qd51s-ߘ1A7=%u/"Onͥ.Y"sf ɝ52sj_˱3άa7gݐ5蚬Aצ@Q<|5o'G'؂9 g<;"pZAV~s_=誌Ws7HWz\n< ERV,=~;#òXR('Ζ>7ʜA3w>hoQNܝ,r]qNta{Rt554{aD=3gn.1oG.S.2C( ۓ5Ȍx4kj?m=35(gR܈eI%!.6"'YLGKIUImilϱޝӆ E:?'=9({R`Nă卽=Mh?Ћzon5˃Lq+Zc`{Yc9>0s\qed1w7Z`ܐv]we`k ̗y=ۓ#Wx뱡J 7u}]SGtMqwzúd]5Yfj?)_ܨr us[.:^߭qvue|}9M }o]ؕv<лCbE:?v˞׊\ɥ[$2eEyсBn sɗ]i[uű\l+ 6m뛔=?eiq\~Xܩ)63 %u{ZyS/΢_}O`&Y]SKͷyf y.g^`YgolZb[?Ͱ7 {3?Ͱ7LKykB_ nF_ߋƠx1^oxvMbYg֟f8d֟fXߛn?殺7 ǟ7 {3?Ͱ7ތY >o%8=| :/(6JMz5EѦpʖ4(756O8pƣ\0Ny&+o0 0& c !B!Bq)%_^kWjx]olololتܢ AZۘƽCaQJϘ89&*r Y:-[b,CCvS{uǎE֡)l?6Rm"cFֿhzA_ݳURj}XG%wf}Q yꔽnG%'{E)Q=;ꅍXLR7gXӳ##m؝Xz/c76Xc76X&!B!B!B+X b FaH!B!B!B!B!B!(Hz%md'463p zXp ^4MͰ{#_;@`0 /~H!B!B\/@(Sѯ7:?O` ` ذQ E=c- Z;5E(ͬ ~ iOGk;-Sr ?77_7{g[Ul}y?`?GYMM5PPUUYQVNOq0_7؞JgZ JN#E>}SEm|S2V@yyIɂt?_w_>\sIz/Dd{EcҲeIrN~i6oo?6[l9^憙j\"1wЙ()+;yD^~Nۛ{m@еx7$_{GiEyٶoN#Q9NheF/KtcեxNnV۟9%!!K47_6]i/:uf=׶yF+AZDŽK_D:M/ɓ6oo孀' 3ҏبc0ML??|S‚삂,P(n ï͹O6^\v\tke}캹Ի zhSï~.o~cQs¯Ihʥ5\< s1_NS.x}-/eϕx ʝ?*|"r$v^ʞk^Envb,* ƥler ݯ<}>x ^LwixyoV3d3 F+BXIM|hS~fݑsO|Sg{rx}.SO-\Ty Wsy\ty1uҭ; .So?&%9:u+b^|܇-{ye^Acd&}y]e%/@b&SsC퉀7Sn6h;Wܾnd'Q -yJn˔\1TKQ۫,Z(<vF}EPHbEq_^7' n7!%enj(kW.'=ct{1c oRGTW?붎6.Bp<"Ί0%ZoҖ/Pn^_yG/)!r[*l#]<1ڇ"W݇z ;Og 5n_O=%/wܷmXxonPWnP2nRv7|޲"K?o(5M>yd{%~S r:?H[C}#=n"7mZb"$#seަKyG1k`9?Aߠo {C"OϘ8ul֐"rq=jx} @T)WKefV&h*& *"b*j.z̞Tde`}usϝ;wapa7{9~~;r_́2YJHN!*s#d@jzZD:[ )9-'K/|1ȿ B! A6C@B>',׊xok7]o!_n|GO}!! @C@BA~r$4OH / g! ! !K8H<2$I$CR W 4U5H::$"ЅwDɆ( J h ZɅA!BHR)A!7!JHRC} va7g+\h$p/u7{-\Sjԏz}cs=L4y)iGE=ߛ-&u[nބ[˷\S>=HҼ=Et}"- ݇,1!U# A bH|  bP><>\f sK nFUV>W)nV߼X>$)5xa'BZ/Җ䕕п-|T|q楣6&>L|qɇ Q7}(}kv>\!DJFV YLdZ.BzFkǏƸm|ÅY8J]B㐣l2՚YIeWV^ao+(ж3ڴl+3֓>9 ϗkuײ>6'`V#|7' DItRa_Na gߋDٺt neA"H?.:)I0^dط)ć~Dľm򊊀B;vHs r xmF}/ `Up*<^ jE Cfe%lIlH֊YC8&TFv|1-BItRQ?nQ$\v2*k|hx˗B1Z, C%/M_R0+7' %Mɇ-[6Y;&RPi;(}; ڔ,TcM%f MbϷ>ަ񡠤/.>K.?8Y(P"?y/'&Un^U>4mbh^| $q?J>'  +La,9\oPXZ 0+JJȒBg)%t))#`"<ɔ+|hx1(uۚt,q, ,aaf%BIAI+Qɢ"DvW6W?TZ k$}Jf"J^ܾe^TZ+|hx1HAeK [`}S\V $Ȁ-e[IE>(&{7{QH[PYí/o,6}4>p&j+(̲ʇ6^ƇTWćFo,k-(-/+,Vjs|0ʊւE%ڼ+|h;m,_D?55UUUE%eWF 6!>3҉Vjjk]:q]6m]q'qENdkU6>Y6RFv|&je' j|`"̪e*U~ikm,$n\ Đ A ĸcTۿ#m"$8GI| A $>Hߧк!A$!ACsHE2>8mݖ$>tS~#E;&g2E1iz=‘K*/.*XU؟ *T~v/(ʇ\Ow1=_TMG?:SxeJ<^xa8b((8x"Y_A  0qLJ! ?UAPB"9`{G.Us5dՎ[X$0 !7b>гvp;X9: vrADݶ;BS2]<'{~|سsyv<9 'n?%. ؑ!(+;y!eBJ?7LaVX[;b1?=Ģ-BzpGFF+ PqBbG8aְct/z;>a0uP_}{N3D Q @.cTai<O d)"pcz;zBP. } fFzC 4 \N(ls5Qd8%Du쑪c%ka9B__⻐DZfXO֭/-25_sx)^IC >@qPb>YOZ fs}B-,/Kz>ǥ@@ P|w7͞7oMMI'\Tv޸H9 JbXƾ|h&ޏ2Kg3jdY`J>[(!Bl4TzVyZZsr͵Ki)+cNד"C6R4P`9*,@ߴL(>HE&>H} A 0'mX%n4sк!ASZ?HhIѤդ[7=k&؅1K|  b3D$>H0EKӿL ZǤZjH|h[I⃔6>$>b‡>Zb"z>|L[al16"iɑ|إgdۘv9d!ءm|HDl`*-I5rPDR?&n@yor+uFx\*5TahۖpKIEv3ヘ9/rvQa7txSpJ.tz=C}H;~c o|m\ 7wNK3 ey12u Iz>a|a/fV/`8Ш'd!w.w:)^b~VsűMZml1a0"XT,lm d>lF`|G](^-ܾ]>`x 2!kB ?5d:,! wרXlD:ÁvNa|xV}aAzt ſ[RkC# $>4[HOb AlC~-ڲ-wK|h;A-5A/)A bH| - WK|C1$>HCCCD6ak2/d3p%:=+0!u4aHtay 9gٶc |*ݏP0i(Rr/ ^}@ʇ A7DBBrf0R41,0p1CM8BFj]w9N#SHdR>Rlxe IXi|țBan@l ՋxT-tWű8l{Vu0z^k #L%Ci hP 0&5KQ,QC~HvęYd}gOO4oVHmSzrӻ﷧};ӡOyァ߁!>zpyybo!{⒴pa ̘PUPž]},gjPh:`F Ƈ\EQ^|xq=GĈ#㻏'wz5ð{}|9]]&}Nw#u>2 W.|`N`ߢC[OZן&˼Cdޓd}'e 9![Pc) v(#]&=~0/YD3E9U~B3C;Crb Ԁ\( y}0GE٫vOyC>uM 왧CB}g^b <4Wf4'E3k}A(3Ӎ#=ӛv;VՆ|=ȼ'f<]3+{phˡ3LW6Q`/O).~˛!]Og aӰN nu[H[=_ԾG/^T|.O z<iz++溗bn2ץzIz+vyS䗼ʺ/Ps''굞BZ{{ZSX+s{8֎3})>c |0RuZן۶$n->fT U4 UVHχIF>T#?ktEɃ>+ѕz>"'D5e{ULUnZNl/͋)=*a:",*5cLjz =Tş13->o &{dOpǣ3^2|4|wj\Ջsφjr{^x<}p=9B/lD82XݲA|7&~0w-`֧pkC‹^4R{( ,^1fOԩ\7aTGԖߋﳿ9*s4-áי]ά!9_ƨ/|+C+֕&!qA_]ziZ(i^IYFH>:e蹰 %PKcy20GWkNš_(, dJ}~JAg% ={{+Tw` \2_P9~jUp>*),>QpKN^(ƿ_p1%C0χ } W^j۶^yyed:X 1p(+Y8*HE͒<yZl^T%,gXd"茁_. ƭ~n6[@\Ĭ1o(&T\ԛ^!U])*wy~R_ϛb>hC/3kk?TЭq6,zIHf? Զu^|8 <u.x{́RSOtvr.@W?s}JE( 12gZ,4.Y5hI.>LxKX"xKW`~2DbZ]wX^eʃ&/SO]T5>R)ZK<3Yk ţn㲺J"}`d?E|!#+~r!AV\l$|W7AQPJs|_(X-sp4Ӯڡz֖Wn;a٩u2b(6$b E0Çkcˆ̔OR\R=u 帅F2dpvײ+^32 ]D=ȇAXX<~kNXZgsC?s"ĽG3Ř3X1ÈpEujNROT 4C"01Y= =562> & npJjm]]53]b` 1p!EHW8f0SL6C C^wM*ӄl/M1RqY} LO(aȦ H`ʇ ,>d};|PM# kWg$ q2g(v?AcFe+{/ q)-cWk4 55p#q ?$}2|pZ--|H(VoY9g釺QBWUĈپ%NQߊCMxf9X|Nߌ2\@.,$Hry1IXvyH%DmX\)7Vb>8 R{hn^Sw.ܷ5oqC5q*xr ׳_ ƊI>cDGNf!~+]tkV3}=vg2ruGrZKR 惃]8;2.i;m|X)gGXQL%c] cɆCf. \;EJQ8{h |`a'9o]˼"7 yh@YաSW'-SE*G-P Do |> _!w> p!^(?jӼjB xuv6f(ϐOM(6< 1>C_wyi#xJ}ćz@I Ň̕t`ߗ.Bߐ4M@ 7@v9oDՇb+Up0s;ƈ>}f`,ZӡzG+ XH0b {eϡޜƭvBjG^1G6`-`[})|Jp_i!=5~Id0#U)ƮԪ !QwgPQJNH.7wr'.n={!#3 AC!]!@t<y'IHoS>!@<<"Ų7;BŐ~SC>%΢b ,Py~{IJ1؜|oWoK^M먮:=UU|3Wу#Dĺ+SyȄL2-ثl- Րi*2CC33 sj{A<3vj:?OO~XE?hVW V5:S.*lU .tpPB@cyE&\u d~.|Y궤!kܖǫP2ci-nVeQL,a @}Q%FJ)2:U"^FB\Z',njg@R隧 09-AbK ,)J ݖmEfWq+RCDCGjéz+;wvkݳ6u߾v꫞o]%R=V]%SZj$6SpO@$2,,})8$n6UVdBxt{E^I`2ҏ%Kz,*}H%8LH;zrڡ>I"AyZ: @'UЄLi̦)653L81\*j*E([1uV{) K~^bwexj6_՗wuY/sPJ 9%mel\gײEu%V[pf68tnK 3>Ag{?( 1`W9MHy;TⰔ3YfBJMcb;UH-[ʷeDOlTC'J1;:^o,s} 1m)}-g+t+{*P3c_ggv&2o/g֤_O<\b%2l9Wh{?Egow :VEŃ F ҫUsǩB/ KNauLi79;TF_nX1*>p[Io>0K?3 p +%JJ~C3yfS'׬g.1Ge0{.4dXWaҧP۪G avbgva'1W̨Kz?TUL.&S?X_µi_[κNs `.Ȼ# d?-CrsR5 0OMz1y?P- * CWyx?`ZY$m{ 36t o/ԏ)$XGf|GS}Җo;:ۂJp[AW"aT!VpoTi^0.Oؐû>Y݊=,bI*7a:hL/TiHgrz)cf K`ݬN6AAa!b|`:=5p{N8ZI2W~Ҥ4XP?I d.&(荙M z)X P'۽:o\[_sqkO{>mOUm9:" FQh jZ?Yd "יJ0jcc <|J Ғ5nz}GYg<;ܒ#t<"M\KY(y>>wΉd>SgX -ܨ0}3z9PY kM`bk$s:W2hgjVP`RqT-XRnIRSEVnT.̏nٟAǢj؟bYM][wRQ9Vc%.02אiM6-6we+{n uۜ!?dEGO3z7T5_3X_qX]cӜٟ@F?swN!|%0~ n 1!Әgٶ2Al8j,U:Ls~hNy!s42$;wJ߆!߹N/XC˲-?IwnjxHbQ.C%l{c#} 8x=_n6ϼmsPV&-eW͈| ~uv'dV坋\j!ta5n 3k%|=i0цD}̮_ύ siaZ YdC"&{޺5"8{?s`R ZsB2Y@oufqUmZ .gbCC2+7o' ew]`[&^hbOVߘd~XA὞:;bg b Kd;>`bv6X?ׄL#hYm7$rYchy`q67{ QN|쉘cu#U#h4O;[SW-&MZ_-%e/_ۅd[%;x6i&V4h'>6Mn_s!Ϳ2$;Rߖ!_pg%mw%;Iwn$߹IsM[1$S#[`M;D?ۈ:Lbj܏L9Tnȶ?`Go.hѾov#T-!neM/:±Q,o$iAZY/`5_ h)0s8'5l1_QZ(&f V _L`-)rUjE7qPCRbyFi|8nH)٤_t0EPTT+nXkaPr<)( "$QIRt{-MK"< srsVP(c_ܳ@aaٗE'Мm/L 7q%v(PPS(AE "20dc_p)Wk*0]RnMxPQrȰ \$ ktZ";`6h[Ԫ38g:kd&Lщgz# :Fe\\9M =TZJ>[m+LAL^豁ǢjDy:&< !@&@0[R)d0o(EmI W.n J ]Jɬ"2{^C$,nj-h/CDC1[2[:Si*2EI 1LȤ.d4JF^@ @} ]}|f"P>,\?Ek~D BxAYMtG5kTKCyٳ_~?{P@>c05y dӇwB~j¼ 3դkՇYv甁1ҜOV]{KޗtncyusԫgWWLU- R,,Sh+x}?FM}Pg4}4|pϗy;?ٴF2Ś,P=*iV\2^16u̩F0癳ևA C>QSI7n}GRsoOU-\X0F`4`+d^HgK]> y,p/XX@9AՒ9Vl^e/%˦OP,̞;"{| ԁ(/ =ӠG>/%?Їv41m}&,#>2#g 2Y^ʳ?1ob`}kQ[^*\:{_Lʌ{2+,>?ܕx}lGʨ>5ajMx(( |"kY=eAO%}jS}^L5GVmЊ^t>&Z9Q.X8,e?Z䁏g3yt}a&Bj>:SPsQ}P-V/ t2rkTiJ{ :VߡOm`U7&R>o 6T*= U&O룚3P_3v(/?&^Ű;IW|@-'Bׇ<eNO9;'{Ov`EˊʙUӟQO ΂q^>)ϻAL?sB7?l o$I}BdOM1AE@=C^~ЃP}SFcQ%EnMv88q#{ƍ7=.0')eXd{S^3;.s9݇8>>j2}m+KſӿO;@{~{סg=8Г.{ {t&\hOcrӹO/yIS=/"#>> 72KW963}FlOa| z?f++f+``*?m!Wg>.~q6>0WIIO7#_K8}}M4v$sK<*##6O:yTGҧ4Fԧmf>-I>-J?!A}m鞒>xևNפ\c} o>ʼ˲gO_*b eGΗ-?}1% e2WIT1 zk5jΦV1)էTy\eL49Z\HehnbV 5&WA.>_t}> 0%u0)Uï*q>`f} PrS p>\TbpRPTr }TP̑ !(.:[FC2'[C!! 3:פPyl2\>l9Hqrت}*>4C}ҩ@hrrgAUTɑ .Ucqe-S}o",'e`(&/kH>fS_̞$}$}Z>NpJv_V=eWӧY(c>d?anJi& 82XoVvwjG*Li&U 4nC~A=_|Ә=u?CA'lh}.7YrDOTBw32.6w'#vH%l'|5x8 g7Adbf6YM'.a&[meVb=fY}M\ѶZv/K|3J? RCa &d}(AfHfFSt Br!hqʮ'}5^/q;"y# 蟑pJ1Bkq6~=zoJiH?#"#>UZsxmOLheˢ[R-/sxm?PV\*+-/˿YVp6AtE7 so8k?\Hߖ!_[y0.h?^5P(ᶣ^7L}Fzf~_ i^I/(> ,.\i`-yMwezu$mZԻ:ro}ksmOE:/@Q^_yGvMۏpn d",Ꭳ}i=6Ahaay[2a5Ӑp]z|~ԣ?tamHqڣ#yv|%Y焋,=yM>ȸUCzKL.0qՖ<hꍿz>qsYОxƗ] hc;BG \ǯ:Bۺq\|eh?rdӺd.><;.hg?a=IqCRܨ7lMyc kkKF{.'?j =jx} @TxJs4M$Pq@E\MP1u\Z3/MYjfee A6AQؔUY;ܹsgAƙ=s}sWT|b&È'BEePl2h^7,oK"Zj#$qL KON$/#SAҙxSog={w;2/8ﵿ%Fs睄t!?$}}|Y N.o>=gпq2Yߨ܊FPx>ߟgt{A߰=&x}~{n zv 7 3b@HG~: {j!wC z?hwhОPJ^Ї}@B>}:$)gBC@B a >O( CGC@BAC/@CaCLNC'C#SSӠӡ33Y(lйPyЗ1ЅEXХePzȡ++@Ѽ*57&t@߂ }.=~1r|WFYt;?ϡ_@~/B?7o;AwA   g!/_ACC@BA = ? I)ih,4=M@Sityh4zz ͆*t UB*j:h>Z-C@BK2h9Z VCk:((d7iF1~`FL_n.Kpė[Nw5ޝ\hK=vT!I2.GUlQ?t&_O-|)jنj_lc%&&ll5{\dg}n}+nR>$M2|T:tB{%DB[@?qz cBPB(!A"I)t%1>>\/.))+Ryjn"*-O^ lvJ*V@Q0׫J]\t|HUs۫#zɇ,?u>DQ/G^(D,p__^^\y&9/ޚy?|u<)%0@\0(_P"'B$b7x/œ-pΧzYv9N|: q'" qQ]RL>.(Tp(T;V`0r p`%[\>\:XbxRsJ8_Ɠ%%X⃋B|hCQi)X@lN(٘Z10${KJM(!'K6U,ځ|(.-JJac )*I-2>is  P%Ett=Y^j~M?,K8{KKHlQdcjƠ-*M ؒ7K)y[||R^0V86 %MiIТ-[6aćf xYu W> R&IGCP(q%mHC3v(J** `yy Yr5cr0t JK%>4S@Z04,,(@~r~sv+*YIP P'%tiBp2ޖ ||4i*+RG# |d@ɖ-AtIҟ_n<Sҽ-9򡼲K`vBCp\|:yڲ kׯWf|@%r3>w to Pa>TWWWb>Dnm3RGtoK$p`~UԥS[WGQ[[ ([zv3K%W"G@~X+l|D| QvhI#χo>^KG\;zÐ r`b\e; ~40~]|8%I"yZ|@ "Nf)cYO6S@yı [$IaH||OWXk 0E)DʅzLo`u*uzVAw&h?~|qqa寑B1]rܥ-$H|v I3Ŗo/5C_L2>܄mH$>nXғ?<$'1쯽T*3Z&&PM{N~A>d sx3od%>8S*6ڤk◡&pms(ݠ^Ckp Eէw;C?LNXvsΉ ت(>^ f_0DJ UoAzR|Kg2O'@ z*0M8nz\K6'NqI&-WG*TB2򹺋g)2OQVMa8nO$> 2C}~%hpcEM ^L9FI]pH|0b58,cKgH88uv⧊+?J Ç Dk⃄Đ A xҾ*u]B b4~>Xj|p,wZ: mxR$>HA1D3D$>H0EK&ih-!yI#|OC>>) ᒿć"N5mVƾa9!nę|A7Af_30,d16hM #| }Y..;[@\6Wjsl{B԰4OÅ,ژij! _~}YN:zkߝC8:NK Fqژ%jfl8#s1c_X@oIsx}iA' 8_Ui|hT$X6IIbZQh{wK|h; hM|p SH| A$!C mxH|  b|H(pKdIAFxD_Y}a%0X4\;~V?rt ӥ2"(CHn(i,m Pt:X닲Ip<. 3J9"c4/?=C~($BQ0 Qt)d(_`D5#3C]4+"NFsmw>TL#eSHe6<& Fli8+aɇ)t:[ TC_PGBOKxՌ-`ӽJ?{[J_di‡\*dAU-iOGRoe{e']%ta ;̘P/ J8z>Wm-ߢFc3J0>N8̽J5*ćF&cG$;"iv˳N?G{`wH %z  >&wme|$>0[>.=1OE(~& 51мǩ:n T1HA8Gz4/nL=C}B7;wKy^((|g7cPgD–_"PcB#@DVWf4& +b6E{!(CEP2%N7}j7cQk? w koRγӕyD=0StMtw zy<. ㇿ({f,=6 ΐ.~^xWtcMVr.ʏWm۫qz]VVsy\Yz6o\#{Ӟ*|J>GjX][*cMasͻ*jlWS\~}}xFSk:Ĺ// ?{LUɉ6є61p>vOj*v}샭\G}^+գ2VfWE3SmU,J 5I1fhoSNvFp?") *!F#k<=GxdPq[wyGbGN9#C@['NL;p64jh(K > ^i.(z`Gzf |H~ڗ֜FӼ:kkv.#rme>gPzA6͙VtWcקR`-֔&%N/ZR>|#?I`W6m[<އ/J^y>: ڼ<0|<vOp9wfyχk|^gem71$6cG,[Z+߆xNs @.[0)wKI/k&/Մ+B;\cxuuqn#;|Ṡ&! &z4j Vǁ`Ŝ^+@$ROBz%7]Vj(뻌A~5s”c+AeK_"YRIS޳t#t;+g3`EpyfbR0\˲}ډ|7]{B !8UXL;u6bfB:$F=J4x,B{P!BT=iz~nd$=Bv| ّJ\|hbŒd@ο0GmW8>|Q_q\$A/^NX 寊=[%5˶lS 'șr-T@xhn!:S9UJ;sv2t d`pX^S>BN1iw|@ۍ|C7P˹2@.g jC`FGP^qv8Zg^_#9si9WUub!f1]cg6XzSad*jv:-~˵b5 p*L?^!*z?0> &29%u6${G0L043qCnȽ_wY bTWf03Ll 3C C>?5]*D|w]s/P}63ЅCoʡL 7#@湃;S?x*<^aV;՛ m.\n3PBG5ȹy%MY_sO~l9X~OFE.L$s IR,9$/<\,I\L:<1TSل#1\E taW|yrYbWpDX=vjUЋyEaDdEq]Y~`|H>rk.շ\\퓵u_|Åշ^x'c;c9Ѭ%dɡq @aCV 1~]۫*+l*\^ QDAnZN=p2az\*żSsI$|8 H8dO#yq$͡(ϖ"i5 Wm ">pWW|}ug+>(} dȟdZZ;uv2MhzRĀpEϑIW L[!71(, @E1%4eT/ j.|cygw6b %\>!Fd=51)9J[/:iY$% V p%#̸QE g6! 1d/y5Ż{a!K ʑF1Jy0TzɖpP"ElOg AY' 9(p`"%R#IS`^Y/o_4{d {]+<6μP#``Et!_h4+nE~8{eW7>V>@Xk:RwzP|~Fl!.p3g7i&(ϲP `]ӑ=/]6^4M@ @oL?lUp2f%,¯- |f`,Zӱvws􂤭1B |y(7qHGUL8;!ܲqvܭO(- Ki,]4>$ 2XGXoXYV%2B<9Ʀ{]AEI\ 2J' m 6пC  z7nCv> } 0h_ǠCAA@IF.P5ȏԑt^k^,ҎDB ^Co )zdsy=ǂqZqUM먭V*W,yl~1+26A6. S sȴ<a$RGi aWةu3{/o=Az~[7QLV`p=f|E%P n4`JМp撉d_ĀXxVx.FD:ezMW(d{i=VCQ?6L6I~Q`tA%pɢx(BxTjP8։*1еT@):f>%Bl0E-^<5Ys5܈Tcp1IT`((t[_Iz\eEo[u^uW.eޫ.d0^y'% g[ d9D\D$qVI QYdb|tEKf'g%gJp(Ȥ%M;[2L*[ы18%;Џ*Ӆ;m̵)䴕G-CT/>{VTf>]VGŻ||9&V~!'M {"%.`j{ϱ7^Mx[G ϨL/X}M]|WvQ?pq빠!dsZs4$ʀ \|&WW7M˸"7mU VtY3iBM.̶r]`}e aT 47Ld39+-$Ո1s50nVi: yw; yP11]_Sbf}iqA@O.žU*x{T5O=_b dig`r2O.&Z).,<^\Gd%-}9>צﳙF'69{m3`stBLJ=OZ'Q?)8M =x/n{)WsʍwbLdqtNYT{/)Y8 ^Y"]@C1UQXx vlNB?egU܁PGaQ-%Xq2ɱ !ܝ6JE{dz ٘G Əq48p<g9?  L%y>d1Ч\s X0R0Hυ@U B}ъi9ퟺ9'R.C!_[0$>~%ۃ׷j}hY7 Ek_Jv\pp\Mtä%_[>!gϼfѧv0gaЍgStBd6͗?%r:qr,dzBC]VϢ=f9$f5| -G݇7k%iۙmƁ ]/jd)_/7, |2p? R 掅d^eywGޘ%&_BrBqo3A!=K<IG1r )3^n(WI3ӻ:L'ow8 H&lgAV;vI1ؐ1ipz7uN>i o%ϿZHw4LZZiYZZ[%$Koh?@ E J4]ls pn&T4%7OZH %eHo'\~y]("ߵ"ߵ"ߵ"ߵb{+aك£7Ō7}]妿r3Qs/sL[*t7}u冠Qo 4~oޭ߳# leNpB"cx_95-?ײްU n7q#7}F\`\OYx3}k49v;I@} %o8Gt%xΪmwoZQ&ˍ agII}or1(*4 \.zҋĞǟVް37g Vd-sK1_7oE"ߵ"]pHwHw,> (-~1[$KooR)?z9딑~.-:-_+ Donegcj P )C/4owVi\yi(PRB:898u[ K2B*M4jx c7lD Dy2G- %v;Ӥe͹tJu J?f8_ozE'C宁=w';{4#.;S=Cgzǟͪw/~T?2?2@]]-I!?lD- fܺc`?_MU?=ٜmyvI+]S4E݃=pn&vd,Po?^[r^,M?sEcI@РORiaƖ-ϱ(Rs bC8J܎"iK+*'$hy~v.7BLOӥMvο?y.s[ML~m}s@q{Q-L"~ <.<,ktwLB=4,ah SQEsIad1U =KdQdV)N/,_UcF!EIx>h$0gsxbvlvL@i5E601"TB :O 34 mkrfҼw^j̀Q{*\MꜬFicBTf?bPެar w+Bdx iSW2罕 2SK$wQ{'8{Z+_m6|",н>Onv,H튩eձSH*ޞ&Khs d=ף~dg)ܴe@Z4Lҭ]5S+^2A3.d'J؉& @ZXr>~ݥctվY>UdzqjXՂ14Q)g VL~*y\]t< XhȷbcB{4K&nZ]yv-Y6UxjAHܑy+ByٯeO2Gy&=,f=p[ g̨YaL䧄 gObaOScUHhHayf+:t=M%tFgC3Ͳ_^y/T y0^iczx7osRP)0ug@0- 4+eRcUBW<;GLɻ7%F4@X˓4K'k_^bMxö́!ݔ㺥Ԟ! jOtjOYa*6s^xEp<,, 3&+JzhCՄt;gx5_GtxTZ6c{)#UՋƫY&zv҅ޭ9oTnjԞ-k'.A*@#ϝLޜUG V/;D;Ǎ&St!{`L;쩵̰Z^'Sûá *DTGk F ?!_K]ᷜkԞQW=iV=uM`$gڼ4.,gryy""UET6n Jcwoo\{бv#~X mf b`K\Dv~~9͛+/ոUU kq '=_#ʨIWj.at3:vobPQGNPҨFHqڈ{Ӟ>cޒtse>`nOn='Go:|;ow5:w뽷e?{3?t 30&CY{r`̨=V{<DӜ` $L0gڃ'pFl` 3D%M5"N9SBONɇ{W$,4_RkLtN?*jqyX` žsjv3 4'36=ߟ3򃧫=#0pڞNJ~>Ŷ <c2sɽq3o!Ҩ=eC|i5غJ?slU؎sdO8qwC{r/>ӤY7\p? m^2&cߺ^(ӯžR2T~(MZO;Qp{neO6צ=N'ǭ(چ=.{l7[٣ɻV >Yne*[ٓٓce]i *Bd?m07W^>9NW\N͹ 'úfponNrŘazq wo΋ԩ}uN7/'&H?qRVV(Vyzn"+-a??1~[Zw/]+-OZ[%$DB 7F(4L—"بsmتf엶W67kZTCjzѧ$kW\J߱/5Ox8|ske%j7'8vc{;* ĞEss{\?@`42F:(jpWtD;z]ЗrQ2bg dF" )oHy2o+yi cN)1Gx}`TE$rzH"6"1B &@% @! x?#HQ9pG idS6!uylɲ6)3|{g>of^Ie], "mHfҖ iX4V ӋC-N0,¿HB"Ҽ):/ܞ}Lgopάb'ӷ" y!Kg{lqB,ptz9RG'hcoK`m=e2Y74܂!!)?A{K]p|/ة8V~~`ް2ح`$QtԉPMкr'.ݰ{`{ ;a#Ga`={{ Ys~a/:!E4 {P  F^ =  MMMMMMMM̀ff^͆Q%΅͇̓ "``Ö [[[{FUհ7`oނ 3/ށ wػ`>}#Xl=cF&'ͰOa[` s/aa_ ?} -;N``?¢a?v~ ?Cð#a`avvv vv; a DX,vK]]T0:΀e²`jX6LtX.,OXYgvΖ" V]]Uª`հX-&57i@ c8}q"mm SH/[jMKХ?xv݁cR=ќh~Q.F%~GBA>( (O^_r7ٽd_\&O5A}NzQofEv&͹P|eJZTw >1 :_y": zBSB.OzP CAЃGp1'?-PS\_^QXqZFDEUUA9J p+!1[ofBe`ANYYAV^^Clus7,燯%7wK=6i計喕:3W2S;xEt% ?>5-\ť 48ٹy\ y(BVw1#+ ((nmrrZ ڜ Y(WzAQ+/oW\ ]aafN 5ʥGF=igKJƒ!Qy'1QQ~~yʼnX..&$"vs rR3mF*:JDa~(]TbRFX`o1*(?JCAI _\D7481Pq?C8@^QFmEj[]'*q+RdV,78bl(J2s@=q KJ|QčJLTbI??$wc"N.'QNu^,-=4b%,ҬVcHej0=%`}Rz$%fwi>i_qzou"@Qv~ֆV^B)Pk}Rǘ'{j7^ކ顨 (,-u>N*߿4IH0i& ͦV^j!'I#Q`0>NJ2YmƒS̏,*Jޤ|\F ~! ~p CʛBotoS2;1@VVRh,ڷf1HÚ~daz(((r">9̟rH'=(e]aJcC ./ APl5b~eFҊ $E%!lL菅,Go͹E9E\z2Y5yZ[ކݏ*((j[TaSML)N/opڵW Ksmazl)VUURVSPdCtSS[KQSS"PU]]RVrY/ۀä́gյP[Ww!bN~+/{7޴j!c;0oEڴ$M4V^^KGp6-+.= ,-(P^d8xP@,ϗV^G в! CApy~SK=XwK=lz@U=p#xpzכTM=z! CAЃABB&z! CAЃw|}St3e j"$Em; ; )gK+3 (V UڙQ]Yav>0kWR鳐FmOU]X==iZUcP5!| 'ƪv,MSړF`7LJ>Jb-kF+Y][ݞ4- Ni6$j5hcL3 i$ #T|cy'M SQ'aQVvx4#ic{Ҵ0\'ؙCpXnwiy=(d X{bO| WF2JYŞ4- 73쎵zhz! AA@AB<x^$,GW.+o{q;<UV_ ʃrߏwW.CF)/>)OA |?Xo\t8!DC " Ex!(7/ VߡFQoY`O`XQ)U=k7U\ƾ@n ;^9Zm4k|Bk RFDacumwb5>J<8[ B<x=z:H$#x=z! )z:P"ߓ sb6`(%%ٱH;ؖGq;M{`2[U=8~ٱ#N;<+,!b<Z@PQX ڮfW`Y|lCe.{/P^mx=-DV5JU7l(z0;V j%Sz+U¶2-}b /*N|H揲:ߗcFmH}38KP}Tu΂Sz1sq?JЃB<x=z! CAЃB<x=z! CAS=z MǓf-_t , .O5Å>g z0@AЃB<x(zhv'l{[hzpfZvyJN/=y@VOf(;SKXyA/Cّ*O>{o cT쭎 :]y'~$n҃k&pz@_jS kUK U$JZzzR$qH8z: =UneGeyV˩j홈R4=!,COI!5 @Oc# Y54(8]YaonzseNHo\Ju HP$5Mk,GFFbO솊tR_4UBqI=О"07_rJj˿^_zz^Yݚv@j+Hh l*NI:b`(^*ғ?AV꡾!T:zTE_ )DbA|ڭ1#%W|BFE $$1P-=}@zSUֿXb%20K܎zN i )i[QqzMڔS2%Q:@ٙ__FY֎,xU'-+ mU IhCh3 x1Pݫ4P]oZ'NVzPz`ͥSNRy1g~;ti4fכ7I&BµC5j/p8H>IT1@ lD G!\M8VX:ǚ5q$TM5>T˾XR{\NQU$I`8 m@v'u@PN%!pBREu ޴L8Jۇvϻu)ȆJ\\=svUS =в T=4x= ϳ ==@Azp㽔ICәss5G8]-iAq?JB<x=̮7bI3u`|wazB"AA>=q=0XgʜVgcs}X.9Ѓ]zخC͆d6ۘC9$Mb>=\?UVů٦L]f=6 kk4@:>%/!q}YkPlcfzh݇.l?Ϊ2OɴJGm*ul yJWc^Bޭ6f%ĕCE;.$dSj-z0[Lc=`_YŇA1 CAЃNInB2x=z! CC]D_H/ag 1K,]wO}C>d3VE )#Cj*d c r$#oJ#% qqau  /P~ Ezx>䎔J:dOȝH򦒂PR2iP6߈* sHlPbԸ/`TSɵI|2)H*&)PBʂ l`R8( RI8 P1Sʰ 5 dTD]'PZ@jJQ1ū䓹>SG-yًa28=z@s<~vKd-n@LNıdMܡnٽI\7d_G42`& |u1{Йn=><,݇uz!wIRRɷ L䛞M}:zPk UX[CbpboB[,Norߥ.?5!iLP|ƫ+$جOnPg?yp}?_ )<5mPf͙6նsfJAz C㼦- XE\3K޹|{üfX¶{T+TWI|{1%n̟ rüϵsP)M[31ǦKz1F5{TK~JYgdtu>Ӳ1A{8ݝA?еz |:]W?ׇ!;OjFk a #޵}H"3Ʈ/ޡ󃖪iȜJd^%h[dov.+g{]rV_9;@NQ$ϫz~Ҿz6C?'=^I-Bլ;$돮z^SuMAyz8QPHn0Ճ*GzKώƜS;6hf2 0ިP/,O}xDeɅ䟍yV!+\ie{=RsUxom˝=cmZehsϓ8V5PwHqƌTMvɮ(Q I{nb0|Z!}i<;K%MĭoX4VQb{D`HsbqT r0T.s7[i,I#> VaNQ 婬l{r2܂O,׬nHSZ޽y`-O{9>,Xȶgv8؎|J}+bY9PP"Bg1pzf<A ifsJ Σeb-OP=01>I:AB ,\WHs1X(lƥ+CUYdT{3nWЌ<<Wӆ}7LTVszӞFeyIwYZvןXf!qAJ,ű)DYJq>K`}Vw΅` 뱗_=ff"MpQhBqy]qڻ]5]Gdu~}~B|`~5ÉMK`YvCܖ'<ٝ+Օ&]#R} ^5{d=med=c`d@JoêUee=Č&5?I',RMpuk~nlyeM+@Q*`2^fŹ(2й+zk5!izp= ̾gT=C;ruà}MHsڧ}t(7՘r)wɶb /ӷ8{Mrtߕ=ksq|soc,UQygSy!\2`oډ|]FxUg* UwRfB̈́%IKkDdeOP?qC6v7T;2OeAqL| _R%ix6Vـi"Vh-NZ.#{tQ ,<Fe>#K1@ڇ7o3!u=CD 1 \|ED;ɨ1 AzmQ4͚vq #!^zH 1s?Ǭ#COsԡwJv\F.B3#0 գ~3=d`8(16B9=u<RӶLpe9rF p`ﳋ6CE&g[+W~3NznQxW`=8z8ݗzHK3_͂4 ҕ&3nwY<[Xt{;$spRA.U=`.r! azaJ33'd<9&{_pqQ=|וި "ig/p"M8pM{ܾ=&~TZ,w+罱!o{G\E E,@CggJ7Z{lHfaXr: 'qB͹^"HBBabaXK0r.Is%Аf8y=LԾ/ ޔXj%f:.74if1_J֋YQ<3^kT|E`>0= ^%NVʛ/N]}k]zŕ\|;e mRYMRU^E@霷u)lg1Tj}ޒsb[df ce SwRz񝞦7;@_/=iIx:͢ȝa3C7&pw8ayQ_nQeFr澭fN_L;~&("{|5>!Cz[ EXCZ=zȟG(` ;E$4禦W-}?7t.dcˀffw4L@=UI}fl\|JaںLz2,bF&zP4Pf(% yS]+1x/݆y7T͍셡Yz`2P gl3TyTd`yG @h7k]!H"u  ymT~UGEn7G=fF|@3k2&WYU*`#{_t"!i֛@$AOpE XHUM)6X/XÆ?PFİP~ LE:,h"!Y & saPIW:כtGyTJ8;xPnya7nv+6a v'.ݰ{`{ ;!XðG`=az={$)Xoi3ga{6 {  FFFaa/Â`1qxD$dT4t X(l&ll\<|ث0X8ll!,l1l l), :l%ll5 ؛`o 쯰5w`ka.=`[ l3Sg¶¶KvW`_þ} =.؏hOݰ=a{a`a`~;0(w1qabaqsxX,K...RaaW`i0,~.Qc{PBCWuKvyڟe I7҆0KglD͐7 pKkAEm׿A}'?vǎRn'}@FxȰ#Rdt29Lװ_9dL֐:0Հ@K1I,(3+k*]Vȇz>/%p1lp t sAq:TAw)P E`#"AdE9πhQfQj,mDe*lE]\ӇlXP,!ӌ@#?K@ЭˌS,`'H#dD*E\( #y4Mhy蘧qNc !`bxh5pѮFCԮƸLCqgwgoS [3 >[A:+M9!'-qA'ڄdJ ʫ|aw ȯ>k[ {j$cST/( b iLޣ](etLȹl[r{݇[M</eG7*M4\e)#ci`V[gh<Ь$}^vZ>qߗȫʀ d$sІH{5ҍ'OK.kORRJmN(@Nw_DbzmM*cW9cF50Gjhg7:Ꮎ{NI <ªN]i%2;Id,HFd6MV\'zb$cOst>Ҿ'ۺwϣ4qLyWh ٜgc3ǀ&c8IAJO)=žQ1E9-M+Zl]y9m_vX1kD(AfbrJzͥa]>\GKD2vc,Fӧ^Ky!1 =X[QyJ|SK %-S)F<&'bѐM6mU[TvT=sTO"A(zt. (.Kj-]΂{z֐g#Y#.`gA۰JZX"|6._~Ut"ɵ%Xq16e(JO(~B(푍7W1&l6·z[}Dq)5Ҳ=.$e9g\̄ۈ 7;Yvrc%bUJz_2o7¿­Eqĥ4^!}aG=f X]_` a~밓pK5*wlrk5&Hw`'V__ؙ$ Iz;@⒎H47`'<򅝵xY2ֿȻ3 MHm35 wo KOƀ_ߚ!fvw;wb1Bma [3_?k_ߚ!fk_ߚ!f/4cd.LP`KwFZPK XbFfYX?4o>M&@ M~辖*}5pW(ȇ2U-n]5׏xRRV̩uW;Pe|2<5}`֌Y?7{Z͔ǵzݏ9ZY(?X;}Vg?zw|ӻ>ۣ{ӓy;Wm r F7nD#i Oe鏣ㄆG#i'?ŸO?ה/?R#4?/?v>\>kJ#q?M=1 ǚ'未TJ屄^LN?廎fW8Sw1.1:]9{ԅ)䚣 5:p^n̚sWjdJ p?qPMK5pDR5|lW`.KIV~T 0rge fp^ÁS)84Ñj`j%d/;3e8J)P*;mg}ݐ?{NTЦ ??Tlo{xCD-a'ъ%jѧv(w?^M2K}fWLU?p~::t$ <{@eOVFwGϿ * vWRn2 ; zŁ˳ ?r#cqA7 z׼cϨ㟶=+tWG |˓%c/[<+W/~wG9Mc:P^ХsʳW6kMk_ߚ!o7/nG7"_= {bc)qoޚ7p'Y @=={4Yy% ,2#w>'M1{kL_Yqm῭^}Eړƍ[4l} ϿQ<6bw{Ҹ3dSֈ'MSjSbOm;=i4Kl}c 4XyNm_/ o1 [3 5C/o [3 5C5F .7"A?Mq'|RV _IJ;~* |ɸrBU^;3q6}c2 es[6+pWy:3!on?rҴ(MXes CgSZT=tʕs]嵓8Yjkk)TTWWU\i*?U4T\+/+)*A T*C_vڵWK sm:EE\m ]P^g{8)+/H#S6oLa G N>hyyqqQN6&7P^m9s}qM=w"G7W,ygPQ俁奅" ۔$qky(--,,m&lv&? mNC!$rwYI;)JJ 5Zu X^8"Hw!-%#_8 I'D{7. [lMT^+2IR2WQ_ee(Ǔݱt@]p{(7R?G#ܐ?N#4?.?O2)ɟ?OC?ŸFr ?ŸFI }d@+4`&[_n4Q|?.>!\ؘ/Q3 (C&2O_N̷]4YΟǑ9i:c3A)X9{~*z}*i<¢}ʄN\ |ʣFI'ba:QF"(SY9)$SMχC4OC'=OYnL14,Ias^"(ЉG|nZ'c: QUe Ob{ş&241|?Mdş&2O8iߛSGsC<ٟ|chB?η{_хcdI;`dyÿgXy]=CW"Ђhh!(> [ʒW_|2lr'_Yngӽ'˯{t:ȢxNOզ.J|{Ow'7vR'ҧ7h[:IO>DRs:H@DiA~>>k;OЛ۱m"l)^}SQe'iڮ#F  ]! > 쮔Q ǥ뷷5B:~!yrڶD8Qr{Ob;CꧪJ*#_ yzвl1vya.E(|̨OB=7[p̉Eْo>j[A6P4 oH?M',11 o!L톼hiNK'|-+/-q/i: nY q;Vėkl1+퇱~ Tko|҉iݱ+h8xv_oό[X4{ G=4c$}^+@\a?A=ݷZrmdy# Fud_i*Y_ޡĠa7,חCh7D! v@OWΜ7galck(7x} @TUB+KGf/!SKQ T1!bfص~=6Llz_`  ey2 0ϹΝ;0039=ܹgd@LW>yZBL&+Mܺۼ722 )ۮ V׺3Ǵ9Ys|~w? o~ &wޝ_~ i8;=o~ߏItq$ g]3_//?̧cN?!Vql} B ~5o0 hf!:@&h~f -[CCXFGo ~n={ᔧx(>Xq ''20 "TD§g3,x,|6ax|!||1| |)< (|*q%||51x*| < _N Mռ4| |+G+W_ < &|;||'-w߃ ? ?&lhs??+K!W#_o ?';?OOgYB9yx\ x)\W5p-\x9^ WÍx-^o7/x+.t~7i@s1"hsz ׎GsDv.hI>ٹy3粎>m<ӝOi"Uv*Gzy}]0P/:HgAu^V_WѳQ8Yza988fosû蝰wY^\{ѳ!\rr=pp=pXqtЃ/$"'=иɍ끛ܸɍ끛ӿ'Bxx>˲{Ғ"mc:{!I$d&׃g3zأ"dM5HF֞T8Kە/f?BwuevS^8%OYNrA qt,Qe'SֹM-zhwNR9Ұ2HFsl tu<yTW7q=p7q=p[GWzC98q=x}S}h\ zyQ$KgzB3/^I* Y:m eaYDf߼TEi`a;\n~VX- 0ds-졫H_a[Ň1g &pWh?{gq=\yLkmN]a7]4t|ҍ1=~+3.77=z}Mn\|{>͍|Wz08ϣ8b _Cػ ϼ̿Fs꿒^==ۙ{Ip=tq=p79\Oz777uk=pt.cA=px\rp=p!Lyqv"t(98uQNC"#Lbdf  tUuoCɛ7Xd}WRBA4a(cPƑXR'8̀w{=RcR8U@ͻSEy`z?+Zlë#t.̧0'He2YJ) u-hRlКBVQ$ų| ]D., !4ΧF]"7 3I,ޭEQ5P9,_@2R0&=RfR U"5otVKژ@*Vz(>2hJRlѶӆ"*⻥dk0] O`Woίw~|ݘB>>~c>׆zC}F uCdfd݅]=@ L좳QB[F;t x%dR|f%r~[+`zhPy7O>942kČ3O6#{:-iy?5+ȿ<1!O 9: z`Āykt;zX v+bzLEh]yx@{1hk uԬs9_b$eH2dyţKF$ǩn:Bw23="glXJ%A[^%P 2-W;R1EޠұR3t 8@R!@[̈me"0CjݘԾ"mm"Z΍Q-~`aiUR%/Q.ܵP;"I7x8uH]`|q4WC0:{ t-/,Jk% :t\J2ދ L]gL[\آ358Vl%vh2mࠋ+0;)o\e仯{78iÛVJLO:1JaLy`+L:vKh(Dk\շHHфhVh&,׆&F/_P6^r:pi0=©~ˢ(O$.^_;\" ˢ6b(ݸ ɁtbdtSr-bکfr]iUSb$˩iHdmXd8\ͷ&dƁ-䨋*"vY--b1)v^/fZ 얓QMoV4n~ 0sZdքN\%eR:#5AO viT1gL=L j6ro&$6%(wQD=ŵL5ڏOdTfJ*f=rB(-nw(ެ/~>\|h+  b5=BFD?؀]sۡ%ߙX~4jGJŊ:(a[RJ=;MV#5CR fP];઻ !GFz( zP'CAEn<n>^:-nUTXŒ}B"i؂œ]dQYA,)+=k E==Ó6w\dփT&+G nσ7@vQ$%TS ;.|T5{f:m:m|Ea)Zao:Wwsn`v`jCWO?fzaВ!dsV)_dLQzx;nw- pYƺ$Q_L UBSb'*̻WTVMZD ,r%zhLS=ٖY7*0cbn9dtMB tQ9I뉁6<$% й%1>^MXk42Q;tvl͠X͠Y z\e.y|za:UtnP/L t0/ n? ިz8ڷG#O!Ao)+966 Md$ָ%+ׁ"LYwmg慄lƁ/zQZe$b1o l_/P$:|Ow!&+z4~6in9T \$mq[cՃcCg ?~zddAz&3>(O.t ~i0ʩAJ0>J%!S{wLo̦]exˎg.{mު}҆%f-2HHټumZ äť 2t7o-؀!C3{E nW {X5dVm#.wx?=PŪsf5ukYʳ%,wTaU[$qq%w+G2/:~Or&R='Sk m**z@}z㎠d$ex7W`<:s`W-dx$!5YjKU.,;DJ{N=sE=pé>H?̙B׽.sP-c`J  rEuGpCԶ-׿b8q"j!+T$&,[X2&ٶz`m(]uz9@!*@_$-I@ƞ:RfW wWas;+ ĊgK~ uGUSUQ=+g฽8M=zKrՐ`Mx^zR@a49۟VUlVU0HyL ȜuYGUι>|D=z1d]R,IBQ7A Dg~T߫|uCKCҧtK-xR7o6.]3s]Dhr11 Pԁ*V 6,G](?v'^5$?O\2je*RL\T 7P2*V9xZ؄윂V2=M@qgq*01Ճ,Fe2a(_{NXSm o_yK򕕧b)s b`J03ԧt+_}--: 7}kNr __"$0d:gem}uql-clCLVYPy줌p6Cs*]Ʈd?|aBq5,]7{PŞU $QfYV4f5mO(8MwZ#D</mL(eM)lt|hI%1s&4)vQ=C xPG^;LEəB?h40(;_vjtbLGzIxx)naSY[̏ £O(M% @Kߊ$!6;|qksށ[2?Bm5 A"7ϛ<~<_  j5¯_~|<>~#&A[Ço>~'.{Cc'?OOOG#3Qhx |<>0<O}P7Z(~K ]AXGBy7|CeeS3 }U#+3TٶjM<#d}; 97+ 3NSDSb,ѲWeed<%tc @G@.H3뻡fMM!BvFbe0pc ?7 KM0h;3-@s09:HJHY@VU0-5ELƫ6Xbm|X 6wA?yt- -:}wu)F'AB%х"dM j,WU<ɕ"{ H</s l"Ħ@5bW_\FVjOT{sK= L݅SNO2xZaY%Q.x=LWӻ- D1Mt8vϋ?_dJx¥[ZYB~M_?9t@ RWdh%kutqӔ,diHNgB ;<}rB?ď߻jV Aῶjw[8]Ϩ˙&ih5Qަ>xƿbGˁG+ī`qy t5(*Z%G8zN`"f?v Jy]:yDnX`إyH,Toݧ]ܵe̜eG2{Vo}Yiz2Ę/dtXBsȄ2]%~e!պcUuEMrAUKٵI`TB#}o` IW(jI6m ZF΢RÅ#s34gEi˼7*{UbyDڴ;I88@O$5+bQ]h_ ޫH1FiyTPꎱj}gO52ϳ]Z)f |{ev%}*zq[i$]Eg<Ͷց%+OMjxr6 >pb sHX!?@5*Oi X')pO+AJq9DmG1Q.P jG"Mw "WY,0* Tg'0-ȦLbXϟ̲[BVԾqWeSn/MӁ|9&FMjLm*8zB3Hгz ĻvE!VZhHs`#3{+8*?)P,/_F |Z;(j[}ZZNƨ2F}ma}6ڂ|@-aL'*Vϓr W^ż&-.eCշ 3=%rѶLd1 SBEY0M?FK;e pD_]תX>n S,mۥguJQ|YgkS5bBWgAwwUu~V[ŧ왣ny*nWL7y†☛)6qG+&֑,w{Ft HNV ^\i_ ?{ H6R NlN d׎Ð,Q7Kk,+V7&$N}3i(S,liCBW""ز̀w{+9Y V B/;`{ ~C߱gV*ϕ 8<?7]\bp93>sKzqk>o(0Rqk7__52OriB$u7&Ehfk)nLSL1os__p0U೽YHbWڠ9!]ٳl66~QʿyCbzDp+3V;/"xI^bߓܑTߓ=o7οw]{|v%M{8 |{ק%(ޞ{ri߻c3c^M K}ܷ"K3ދvEp+s/ t4@Ԯ"oeޘ7Sy7 KG;_t>n&'YwhVǂ[_WlY.]36j[\矗._W\2! Pz/5οwg%M{8 ?77οG]{85_jΤȭs%x%[xߝI[JsK/͞{vO9"7gZ;*LvfF:s9ߎ9"7gZ;y-$QjYm"@atTOj:?goɈdRFgWNxN g9w yE:靟׿K| ֻϠ1ZaC-l`WH)%UؠZ>Lɱ'l6׎-HOZ B"!3).+?Zݛ`Dw]+@ג"Q~im `Ih^%64 H1%ד5ua vŔJ+RĆF 0DB $-Xf[VXGd"Q-'bH(S~$( 3NS` yYt6N8tvWSO4o)n@%!T^w6msq'O'k'jRc+TR=Z:(]4(wEeiV|b>BF0&Ŀ GM_XQf;*{e/~-uO-=Dy8Ꙫ)njQ572cr3.DB[I$ģ.ӷ{߫m n({quϦ $t2hQR=Q`|N 1ȡ$1(S1T}z /ۚfwKO,ЮY^^M[0yJw@ăx #] VLl)99۞*߾4=1}ht}|9\F{~,)W-> _TS5jU_'_uqʗ>^}./JL}uO}[u&ϼY/i[uUEFmC}EcCՅ ]憮D5Mj.4*{NEs{38 rc5kI QF.ǀ}t"Ň捎 乥ctͪ;~K~V0Hy;*Qg]JKzKi=?H3z<)Y&z'qYkqe|[/Irm匴yxvB;"-/KD`}Oa$gG$S "vgO| Bj2.pA=\{ O?$=wjen~>.y16䏒e#N=uXGJ#x|ﳿ/H,y]v%G7{DX,}X}in~x#!ete⦱p6ol?VYՏLaۖn`݉M@zEWmO˸L~;wӎJK;PU2F 'µs}^G"緬C,85%_=UgeGlے:2Y˴LQ_;GZ;_cLpl7D[lU湍){]97b=NoHx}`TE$1?uNGeV Ӊ"dKJS)X Rϴ~O1ґ<6?QrN;G]jױihK<=<񿗬7[)J=ȋd^p 4ҹ!)?A{Jlq|oXV~zrezηnHH؟`nHMA5i'=uO}#N]aaAKWX7ðG`=`={$ i3ga}`}aڶ}1O`ka`66>m} OVؿ`_¾} o[wa?v~  v+7ﰃa`aG`Ž 8$4 ,, ;`$yX2",vv Kсw,Sajray|&l)` U5X% V a;=iy[i{JCOؾ8C[A[/!=<|֤ ]oǞmi ?/1.͉]r=6- jQ;?u _KB]Cu$$:6yrrԉ:s;7[(1u-^[-7?z\Ӷ [+( ?zyn HBA@ЃB<ŜBuqi~yEaբkEWUU(%׮yyCBo~}̈́Hтn^^{CLw_Ay'1k'`9~=((K̶/TTV#P JbĨW~ǖ7e}Tj JJb ]Ad,b#Ʊ0*lU./ P{ꂈ=k)EfbXycP=l/Ɔ$c8Ci) ENؠĬM(YO/IݐˁGTSF9KmM*yX|?4)%RYOeec!XX߿4Q]ZDKGlذΟ[P_pE׼PJ<{;Z$c1&&hs[?=§&*1B)I&npx#PZCʋB-{JpoT݅{#X̧$4o`1 ,Fԧ&t9Cqy9XrEEIOh/$ou @.ҲVPƣPۘt ,"-bY Ұ&ߥ,孟J**J$ί籼l$||zDb(>cjY[Xαz (~h(8=s(q4?KVzI1+6c!%_qAAQNQq&׊R^6 B3Oc[QeeE-8s3ꡩ顴"孟^VRP~jAqivN=Oy맇ʖkUU%e9EV>W'/#Z꒲ +}!w+o=ڇ5ނBF\sݼ{zU^sȮKrФ&Dm|-QuB_ۣY٠O{4^=@Qꉔ4'HRJA9 v2?_ܭAeCAЃE{= zpű zE=p!xpzכTM#=z! CAЃABBFz! CAЃ믇}}1ӆe j"$Ye= ۾ ɧך6=]1<|Cdv);͓)&lyhT=lӂpF&FᳪKl,lFc%Yİm7Yzz1| *QVerMR)`AGVnxh{WbQu{Ȯ&f6a5N.Ȉ_4R# +Ɔ5g:q5 ?J7N+);IZ~ fq3Pu*ďWIJΙI(:֫!|W6Xt9XZo*̯5;_5*vBh%D8_mH=cT@D BvCUvK_o1h>U2(?(KkS,ԲNy:W.1a*ۏ|w:vCpN=@ | 5:T|:zVs1TTk+~~!^g]*Sf&0>mm>/*!阂?ޙ=ОB"0l=MWɽ`K~;fR<bޱE (jvI.|4˃ }8&{31`ꚪڢJ_o=(Sz;  بO@>Wt\FaE $$1P[z@c聵un5ŘY ʨdiJabb1&BlRlXG& <]Aʁ}8&DmIk9́ӿ6JaOXAZQ<>N'[ڤ}6Ur[OⷳLzՙ_xzh"p!hMzBm9D0T'$ߟl^s=4FД'g_LrY '*36Ǔ-@.hSIHm(0TQ|7-MZnw5Z t[@S)c;+St6w -[@KՃ@c@AЃN{7Ws вAz! CAЃNz/4S@'\| DЃ|pϴ9=,0_獱q>l6-j6d L !lC!Z$4lIe TtD"*֕aK`K!q$[E:VC@p5ۘx_DFӯzuѐHjFm*ulF'ŢYn, }VV .уy[m\J2+o-I\ԝRl׃ɂy-$~^턺k=`f|ưb# _HkhH3W: R?nJ`z3M"ԩ g)&Lm":N@z`}D47Q*K$lUa2*zo8?ZhY=IB]zlǐiH(M']Is =>V8M^]f=L(zP8ЃA7 BJzB"AA>خO,Cփ@=R z! CAf@cb]B<x=z!._H/ag 1K,zϝWOyM>moVE #CJCZ $A26I2GZޔGRK( `,Q$~ EzP>䎔J:dOȝH򦒂PR2b(o@a9rE(q2j rtܩ$R>N$ՉX( !e_GQ0)EQLad[T̔2C^ T18;TS)*x|6'5ysK^bj NAO)_5R[%#BSqtY'wKvoR(Msc rsG^?=k{G?[{F>i#ʫ{{C?7`GLBN遝t&Ji:$H|ӥ}eZ6VE]voz0Cm3{.1]tИvz!qwIBbI LIy8r߀PXk UX[Cbp`X-LbPIwOTHz!]fu(Uխ~փ<'ϑ7/D;#{:Kvvyr_n=[5Uta7P =0,7k:ݢUą0/:>'r7K֣1|**Yk3d\cew>1y±0osoT yfLA).'kQD~:c#zKnJYgdtUӲ:As8Aڿжx|*ɣN쫌ۋ!A:Tú~m?7ë}"3Ʈ/mE[T\ndF!%PjNNS啳K5]:eGFI/\o8uTqD%uk[t'XΎkB6r8ꖣ|.C[qx`^$q +O¬_#oN쁳R}hR̓UϞ|xӃƗc=@!Tt'6-=;^sJOp2(cjڠECeX/@xB|,]wۈPo ɷ yV!+͖\ie}{ 2mǗi}pkH5wfi;hR+C|l1|Uo!h*xכ쒓]Q: aF2=|BhB uQ 䩬Lr2' m-]9YY Y|5yIỶm<{a|c]G eLr`;~>;(oҰʁ8:3F/ZT 樟Qbeti7,oyꁉ! Tefᆒ@ӟ->,Ոv \2ToyYuEB)hkYqhO% T6SY$!wRzS%>Sd=hz0]w|Iĩz=(y|ʦgY 9jSմL+-hR+L:al |,^ky!y6rxQ|FAsrp{!PdsW#1eոWC^@ uơ[uٝ;<4St1$?C 7y=ءǎʛH 4hf? uo;.WS=k:@SJ́rc/rl-Y:} >kӦT YsC+,잳x+g/Ž^}qOjs ow5h'rv V^,3VYI h&-LX=K<6Am սU]Fgtz}d>Bvtz.,}ؑD\(z*o ;ltL~>|) B$ %=NH~k/8e+dbKoFѱ}^|MVv7T;d|3 zPO& kJW5ݩ&VlaV`9$nKk$yA \5.&!%u:MQ UZ܅`D1 23_ ce SgRzqퟢ7;@_/=Ix:΢ȝa3C;&puz`P㼵n^>΍xbșbR3}f2%ꠈUh"z=84Ƚ9*Pes=֡yD & CQPIBnnJzsC_ӆ,Vcl0W,fP <5>96{`}CR\\}=tWgF&zP4P&(% yS]@i֘jcv<P7 i=3C !X= d)x'CyW]VklCK3h<2M:8eȑ"}F+ ~TI2@hy2t LUG]J{ql2"ق)YgxB~̉`e3<*xs<ԣd} _j4n ENx $2 XټVUx >j^2HgWyPY5)@$ʪRUҥ I z+b`Hu(6|` +4BêC >0jWUd]c $0΅!MeסWޜ,v=ʣjgQ呍`RXSsG3P?Rz:dJtH$`"/b9=M"0\w/B xj"P?B"8?xP`7a`a>avϰakvnXg={au={+aXw#Ga={ i3ga}`}a ^aC`Ca`Q@h؋ X0l l,l,6666 6666 66 { 666662, [[-[ [[ -- [ [{ : ؛` 6aރ!#ǰ>} [ 9l3 ?a[`[a} 5lؿaoal'l, 3l7l^>~د`; ;/SӰ3X,,K%’`aɰ KeX*, p]?JG訣=(Nɡvefn"#l=a3Fڐb ͡AG#]/jK:]]jjk.?ǑLŨ,>zJ;2ǨX ;O1"YFPN&gj13Lגj2UK11(p*&iyF{yeԶ[o{c]t6Mu%p2p Ӵ sAq_.S]kh{e=d^>+kQj,Z2~H"[-ӇlXpQyLN5,- :@/3`N )epUԂK P"42 c:W`9A6bC ϲȿ9GZQ92 N?PBoiեW^YyRn[KE$Պdi2yMM&kT?ڂOs$",<${1ϑ1wQM*㿭6 g,9sEԔq_<wR\1X7&y߹ {bq :ISMlf7,M5[kr:]t9 TD{ "6 NcGۜmW͆i_~qK5 |%_5h(V ;nfR^˄s>;<*=7u.y^7.6,1؈V.czP=7./;k)^?ȫʀ dI i^{Sɪ oa [(4r$] w]s[4,;C+Tl+$Y)o9` %3uGCyn:9*T1ѓ&zT".,"o_'Pi۰<.:\?QI)-;|Ƴ\9mfZ}~i ChjWhxo;9%3:VWR*Z/3EKOʂ4*oDAfd`uʅ˺g.zM4$`yTdNy#GY |Wj|MgH/ |&cntDɟ)9yN-6Lbh QGCf6«[-jb"{樀E;@(ztN (Z-Kj^:֐g%Y#.`gAJZX"ux66pw~Ut"ɵ9Xq2n6e(JO(~B( 7W1&V S7Ixٲ)|"#-,R3pph+s ERxT]yp2>_8:N%L=V9&:RiM 4?R* 4p2+Jk|¿L8K~1Fsd!HB Ӵ3PLMZ_7jtቖw FG/9(V0FGx h¿y#>;#SDޠoZX#¿(\!gLr,xݯWZumO,k7oL kߵ9ߒoa ;CZ4g vK+&I#F]xt2|vTHM;n3uo_km|+_ ;;"}j)]0~/WtÂ<{G=^:̈́m I*#DV1۵ʾHÁ:_e|a'7V.%Ӯv%Sމ92QCTĒL*7ݤ?}?5]<9mH]_Ql En%I5V狯5Ԅ^UIO"d mt!e|agחEL~syޜBk ;ӖĴ!2Jo{L[gMID31Pee87m/ )ʒ__՗^FmNKΌvA/?/ۨzo<~k/c&ݷ#|w=o)hq?+-#]#- ?;C/wg F x]0 OB/wg ߝ!3w_ ˿3216sI01Cj. fPߑjiA%-`UIfQ`i|7ڊ71օ^w(ڭҵZPH*<&< ~e `F@$zߌOZ/R_&cu[ൄ$Kk_aUs*y)-'3JdwJ VS/bBrF 0.œ)/Q9M j21"D%bNx@2v p)Cjmg3ת}hiރϐ3SJ. /xP;w*=%åBՋCUsf֌A@@(L 2رO&}7bG0&m¿ GI>^^ڢ x'e9Fu͹ճ4+ghVN,^2>;"H5xVi!c>wdOUNCm '9Em*E֭pI; yc\Ҿ6Sb&rR1QY/O7O?id$DN'_ Ӿ>[tIETAk0̩?7ǎg;Q sq\3zԋ[~5zY2Ipj~`Y3|3˜+ulяϳq?am` +`F9}$ge g2?gy5-葄Qԟgɱ K^уNӇD˧A9ًƪG~Yg`3Hk∮;)(Bd?ƠtQ&Q/ , xBv*f҄TcPޫ /ct]v>ӁLi4 !p^ъ[H+ԋk^ 閽 ЄuH7.٣;gv9ih]OOP5/ {Ag濠3@3p~iԌ5]G=~ WCg S9(^3uȽ͚jpgz&gF%D=ڊQ+s60jܛtL< NmT~9ٳgՄN3!_66?aOϰBO*Ÿ9vCqR y^p,}\)eM5c`ϩɞ[=1̈́q@ƿM@蠟]|yT+cL y*mi!JDFH]SSNwk֠i}==IPFRT_vc%U~Omwz1]bu-fC<7Kܐ{ܝBޖ͉tǑ;g҂_o=C㻞mwncv?=??q˞}za";ܗ3w}?RI=bg%:;*fbK a~3b' \X\&h3G_l0BL34&Ю<&2X@=]Wb ,w[X/g?~164X!_.!t?-4V|%iv8mbwP ?Mڟ{?GtiB{ _ ?ŸFger/U.sgqyM ??t'&4XS jΥ՞L<5:p_O?Ud9WXYJv]5?IϹ~1zB:u \sR ǓcI5Gk~?[uDHgR\R3p&9ܕZ<9\s,X<O,5?;#2jsiVgyiH~Eeſ6&q1IluJK 4lk׷-O>H[2ſÐH}H4A~ Ce|FjzΣV]H"vKɈC:uF^ă V$ ?[bzB~n].!IX6'l%Q=<:[^Br)\,P\@$%~kUxN'#cI1=(PTδK EѯXP"};XH!b){JqArr3S_)=_D-ܜLU%+;v/2g&=+kyٹ* "ER/]N:/pUym?oDdFjRڕ+Xh)qΟ{ UZȿ*=f_X$kH=GԾk>V^ȿ6;o=]ѿrV6s0?X]QZEѵwk%׮_qUy_ TA1*V _Q@~"~%kB]Ciu%37m:䳭u\WVֈ?I\7r38(A#?OLp1wG#? OGH+zG#4?xU#4?Mj&:NQ'=4r'Mԟ&wDTqAuF|?=_qs@z7r?Md5rc?yO JSS}IS&tb NS%5|M?{3y69FڈGH'db~>i;|,rc4ɤ1&1#EoNGGN<­s8xOO­*S$k~(4@̏DPi"'(4OޜԮO?Ÿ 8dnŏ }C/ߎ'LEq!a&݈DaywLփnr" B u\Mlp3lKK^~%򉰥JsxiRI O,/^{~WjVri%ؒnmwu;b)Һf$%-'-Tvu_yrMZ}[۱m"lIK웥=:MCusa4πRom-ge;[q ʋC 堉5ړ2w@OtݽR=a4O -cy\vyP:͋3Qsk2n?bȗi=[ǘ4h ^Uc~<:>j[A6 esjߏYA}ױ?M,{/+>[S>/)@4{'̗ŬEXyi}q)Z}!+t΢o}Ƭb8V_L[YA3YB|Hcrq+6ꁆO$M}I׊틷VυQ0Z>Ұ=5o#n'X޷oDՑ~ZyvE z~߱CnXh7 [=E^^8sޜ!N*=G)oJx} `Ev% xAb"D p 罂V@A E\LNrB9 L;tWWWUW%)쯶ߒCL@҆4&mqW+R`M:F\t"x|h5 FK$ϒ0m lN$3wq'nB:Q{pG_q!8:=,wߏIﱷ9~ҲyћAog.8~H+~?zN6Fv@R i Zui@PͨB:ePMкr3ح`  v7;^}a=a={(1'`}aOž :!i4 {P {66{66 6{I9DhX$l,lll,ll19e尗al^ {*57`o;l-۰{}a l-ll=Sga6%+fװl } =l+؏m`a?vv~ ;l߰x~AC` ;; ;;;K%N’a)TX,v ; ;; ˄eat ˃Tia"X1䜭D|Va F?Lj(pbD~mm ڄRHO/PjMKХwՁc9R=ќh~I.F%@BM6H>( N)]^6밒+l26#XsY՜fEv&͹ݛQ|eZZT7ӽU:Fw:X|;0" "~-Y@BBJ=(! z8SXUR.,)x҅-?Jp%e>^^GZw_[5{x=~8梏vk IHL۵{꘰DUUxyñyPבƧg妞N; u}v\>^^Gp|.bUQ !G=z.--6OE.z 4e9ӹ(WN/oP\^%/,l ʶ)A}ٯ DMߋw fujꐐT,o//'$&qms 3 lJʫ,*-΋ AV2bĨP!][́Qz(J˝>imI Y(ps6P Ώٹ:u'+/2\ʛT–a{16*OvqnyJ5N`9uYZ:4rZR.'ȁSFU\r._mK*yXI(4)W-8CYUXr ֤U -L1;*+瓘5iBHuքV'Wily5/go"\kx22$=-s6OJgᓴOBC*x |=Beix8%KJlyE],U#|"UwٮI(IL#X È$-̈́.gyz(KNΪBzIz-xz:$[PK =4)(TzsC֧3Dle%% ׳ 2B[,iXBU<=TTH9!Z Oaygu5H4t굡$Q~SղBІ]^*P{j=|Jiqzy zpCeM Pl~{I12jօb!1{{^rAAQM =\Iy,qJZ[ݏ(/PkSV^ʚ yzxRʂz6OuuuނKuuUՅlwA>  ^+}!_+o3ڇUgotDi퉱+'gO/CcT[ǶHAcdOEoH Y'J`7O<ޭstڱ[{ΛԵIepJ! VFyH#i@98o:\{b,8oV28Eu}N9fb$ ׏1v'\Pߟ\3#=us1;'J}kɖ/`=1y+x({xD&GD=xzPB1ЃЃzPz }t%2q>ۊ7G3 D~rwo# -ğnA|?Do\it8!+DC EDhVp.~.[|yG!q'{_o;v=Mwu˯{_{_aCGe r@y<ś^gz$^=dH] \c*_\4=~I`RtbVV&3م4O@O$FnIxg8t;SRv=h;"k{:UJ9%$lN@doSOl끯29:U,2m@oy@yi9Xkʡ|ɤ}[IU"A1oۣo y ˤFe47'C͎r0i؂l=(;   4 Q CA> ªubLlXG& \\W"?»kxTVM|Gicլ8e5+m7 ą!2˝Ub= &B,x&Clu˂t ˊELjb=Ъxk xeGߏ4qa@~Y XBEcDp] ЃCG5CPv"\ ޫ]V{/͛?ʶ,$|pflKdS:/Ӳg/Ɛ`¾m o͘?ʶP6Ɠ|5zPҳ\Vnbugy M ĵ=A܏ADPAAezA^旙ve+>lKm%Xg[B7CX\||eZ=1&z@`E|#zeŒXh[2_t-zT<-ol|\\!6^f-_C,_PჍ zΆrDma`;$D0 B"(Ѓ`2| xJz2ݘbi|ٖ/Wwq2ל\-҃Np3 Kh*uqa^:]n,=z?0 b!U7}ٖnA=p c}ٖכ}Zϲ_`}rIƛ!lz"_zXѡ zPl׃AAen=Ќ`ZɽhXn}[_zp)lvWϽX>ϕ^SMiЃ]bo݉9Ug?xGHB&=ABT= 6f-$?د/W׎4I5+lI} ѫ^6'_+R\J1Pc7ǓxJV[S =Jn=4ުЃBJ(ʾh ==AA@ G{)IՃ'.OZ5B4ߠ%ЃBJ=(! Bz/R\F'[|AAezADPA6al1v"]zLg2wlc&z ylC!xN>Y..+O&˒bљ;˒"l_VS@y56ۘqx]M6,;Yqt8 nуy[m\<ĕCXl|3d7H>T8n hg}1m l(6@1柌:,8ss`2\.+aƶD6S63gcMKadfO<o6%Gi_N= xrrXs=I5=`@,`Ӑ8;ǟqZc)zٽ`pI}(&t )OQ4O&Qb)Նju@ gڙ~Qhp-\_q'KHDR9Ԍ#S`*T=.$e/Z9l)P:TLˣ5媯n0_F6hZ\ H`5*>bUP1 6CBQ~A,)߸bMr#‰84X48-{,ʣr\zm|ۡ׷l{xmz}/|=$1^$q U uȆ@}h$gjz؊!}CI|DӔIΰbzb@Dfd= DW{Xk^γO{9ˇ:}(Z$gR:{((6G5b~AĂ^U~bǠ4\qHOg\CdwOYATHefᲒ@c.:>Rv@\2oyZE6B!bS@ {VjZ/PQ|h>YJ]b,Z U $A׃KMZ<$UM"g 9$n_@Igw{W 6tn_:"P:; h)|:/'C#[Ȯ!SXt"e8YZܽW=kg#3 bC?@X?8W.;gLUc^R]|IU/{#F(^ux^!q:lpCazH缤m~maE+ RJP})D@.rMej}UHsw"9Pm1݁eSMR _ni\ઈe)Hؖ=k z mb,QwRKܫ3JR+\<<a`o8ډ$|C #* UwBq5h-R).K<8Nuh]Uw\z{t?z/﷐'ÎᲪ8}|A ʕ2g*KQI%}+;F[J#c[ˏ[!qr_}\e{)nɦYyx,02bʒdNj 0õaLɛ\3efbt#}#~>ywu>дR=@  zJ QgC g5A;h&/TӭؤNӬz$` HY>T`m_ףTRcg9Ru}-a,UJ͌W52E(_'x*Π(g_8O;&pw z`*_rK~TP8 -0mf ̈́1U}^vzȲ9k ¬pgPS䃢W[V=3=i'z}dzNJ(zg6tMtWLJ&zxmFnaekL16@vv} ˆgYz`2P)|?CuLkVlC Ey d_tp|ȑ)}F+ )!TI2@hy2t Lu 4Ŷk\B{ql2"ق)YgxK!B2 u~9XW1>/{5(n Eax $dxjN[hժ[ّP׍t0`]oHgP} ,j@rU%ߕҕ I zs1c}(U~(6l,ll1l , 2ll%ث`ހ U`o]{a>}cj'uOa`6> ؗ`a_--;`?¶~m   +7}aa`a`v'(8,; KRait)X4 ,,vvˆr:lh*Sr`9]BS3 W֑P{S^t#mHtf3yyӠ_@~B5R_\TzrCɝ@!(fȈ&s|2U~Z2QM&kd=.gSnqcǕ[Nqۺ>P{Oo ŰOKshAvMWA(P 6hh|DgfdN MLuub#l K,;N&fF~jօЭs U.`'Hdh&* x&Tbw@Z#tci a8/lE9 ҈Tm|R`(,ttY5/F_Vzg}%W3;vg_>Cg]~, w1nA O yGɼ$&,8fqr",$ AT$:1tsMcX%[hs\/֮!O'Y{OM97 8Mc|zWbw&f|Tq-Ok-GId: #]͌sG2nFvtqrq$u;@y8 d2(?}ewo6g\5fHg5]VqK7tS,uʥs7 W89P?Rߡ6#R ^7X xdU{Zx䘛0n9gg6D ;࿘ބ4D*PV6Ke">]z-_5zhm.2sZޗHFvZʳ1Igk9(ˢOfw&Of-,Ty3$ƿ\+[!\\ڝ6GC(ҸK1lX::߬8#eR#9vcch~Qdb5yN.Ft+WȰ_eGV};jQ">,el"-2P75i/=3 4,9zib~)=[3Ɂ03f}4@:N/$#4}Pg{%{:T7jГ&Qz"N/"o [ǀ(i07y]v^8LO)-[Dz\9Y}ne6}Ch¸o j  9|(Co*P>GuRHhKIUMO)hnh;SvNafjbVi̢61:=AEi;h|ie|ΟNCdQX U"Mz!C#e_Ky괿>2zѶv7:e<w_ <1Fsd!XB q&&J˵?:;ˍL ւ3ڜysV{;_?c ( h¿yFYq=bژu6v;Qh?~VS( e\tyN퉞aK-] ߉A wo7F /_ }Ս? vnP<ē s z(woh߿xG7 O[=z3oJ ~ҒN _lW*WH:]_lm|_鿭#VeNHӂҟ5?gY&_ɍEdn4oa w-ɰ`/k_Ql& .X]oaz밓yjEw/vͿgߨ]`'__ؙ$ Qz;?]TDTEllk<߸ǟ3PVZ"J7θ&XlJ(7gkL wo ȿ7񧇀xWhpf7Z+^Kתot>=,:~ߍ:zk׿ڟK%և_V?1ihhh]to O߉A{ Fh1bPCG>|>s W1jIBk =8mϪVeƼ_{nWiS݃sSοv1{G2g1SOz&n0&_r䣤-+z-J?裥mWghVLӬY:AxlALjsQOgGI|aT?w%l!׽'sr1.||祛+^Ņo/mYpIt)  G3o=z y>(MQ OMxxRG%(zQhk35/OU/^8`HaCi F=7_ǒD<,@{t&OvϦܝNT: Wh[ 捀'ꅣ bFܘ5ci"nUw3~WϠÙԟ>Ga=ojjNX " }F=kfFܬ)Hnj5ԟ` k'.LV{Y ϬgoDgTs.zNzf͌ >dpi מ~m?2hsȽ .9#Ʃ BR0+`fzƓ>= '܃{҆]t'~ϟ3d!mϬFB܈*;oSSOjj߂)}ԓԌs* hB?^?Pбt{ِ8?ꑬG=;{lF=?UaU!lGww+52r.J?ؓ 51[CM|OҐOiޚLAӂKǯ:`O;LA3{Ceiz/=_U9ZH5;[-*¦3M91 \ÉGN7Ψ4~ns`d5<7'f4$5$P'Q@ A51fm o'9\S^~==^\&0 6 1%hġNz>L\p̕Q*;jg}]?;ЦF̾})?xh9Hkjωۏ8\~MA>fٝBdöێ|i|?hҁd&3@6dz~v\|jڽ'iDzB,ʁ3?SB 9wiYV^T3j\$ U_ǝ tLG#?G#q?W4RyVV[z%}d+[՞pemެ?[\RxT]mjyA_eʔr~Q 3|O;5tk3GK|U |<خ5>wϿa[Ğ;2\92{FIIzh^c8Iэ針j#ߑ9{)X#p4ضxIVvr=Ö[*+q_SAkbU{Ck~5㝼G]rax/}i׿2f}; -¿)HO}Aシ׵SשvIoJx/56h 'B3)0<28K\kK~ W\?.lW p_ }V hҕ7;M {Ҹ:M.1|cVឞ=i<V^ fviyV#x/,$-4W`izeh[=1oiO7o~ƳJ|8vj dڔFIFM|k6͔y;`O5n-kOObc=QV֟(z d'6gOrk=Ͽͺo1P>F ϩK^^ߗ!2__ }/}e{&_f"4?C{h;C/Y[ZuZ~։sG3t2QPGQ.]嵓8Sr7ǭ"b_d]嵓Dy\)eiPWk'Od6yUh?q*)6Eb|zʙGdpL[ζ3K EbW,4,!YI$4tky,++h lv ms!f#,EC@4%j*,/Gl$ص쐒/*+K5kҌ"]ӭNCEEIiIFu&*B ܚ4)Csϝ1$x]"&uuhT[Q.lwelG*8g'"um0 Y*s65|Z/VfSwۇrUvIΗCǝI iIؾ{WX6WWv-Hk?ߪ‹5*)+ɪ,WT\)TsD]]MAqK.wWy_ }DTAQ*V / a-N?ۿ~RJ۬Z2lIWF2[밖lx7 -r)43?}8Z_KC8u~?-O?A! vc; ?? OGB.ZzG#?i;|?f1d'oc͑"7B'{Q(VK8y?`A_=tj*%Y؞!Cx|?! p]Ly1KE/׻1& \*1841iަaP uNCQ˩44a,1_>kS>/~ ]DB/]Yy/e54T}ՑtowE`Z&oߏ$8]޴Oobjwr!={"Q/]ERbgr1וꁆg)G=&޺~K:POWg;p- X=~t&ɟX޽{ͫi0#^i{d}F~~߱}_nX>vüݰ7SZ2!E!ok'x `Sǟc:o[9M:xN7׼BN8<QQ+Ck9n[)4EU I3I4Mӥ%$f@/a8gnı\<7 .3M3C!GOH< G[Wcx't63qƯp~sqbR\T"zJO-m)kw^_ъ[O4G?x=(ş۬?]oro=ST< O3L ~Y³x^.?%x)^x^Fx6qa6ƿCh:xވ7x oیߐa o;x'ޅw=x/|f0>qlO` l5$>Oc/Nj>El#e|_o`|·|b7{!b?a?OpA)p8~#p$~ /1Gp[aklmI| gЋ> "_N2bg| _7 o]v}={ao}?~'8 pa8?8?Qfq q8'`NI843p&q."\\p9~+0W* `\ \;\܈07܊XXŸ K܉p7,ǽ+)TCGc xģgx4qx<'Is<_<O <ųl<|/ċw{^KR /? *bc6x-C^7xތ?V 7މwxދ~|ć>> l-6ħi|,sG1~p Oq0P3#s_`~8XqfDq q*N8g,_< p!. . 㷸q%j =n p3nXEX۰Kq; wcr܋4!#1p<GQ3<c8<O$9_x xYx6yx>^E;=/?%x)^x^Fx^_1 `SסF o[x+ކxĻn}x?>C GQ|  [clOS4>^|9|_=vv—|;k:]M| w]ݰ;c {cЇ#?88Cp(9/0Lcp,8p"N88t3qƯp~sqbR\[\ٸWasp5bZ\z7F܄yV,",mXwN܅ `9}hbh <'x(S<Ÿx x'dST< O3L ³</x1/K2+J 6«jow=x=ހ7Mx3ނ[6' o;x'ޅw=x/|f0>c86'V`[|§_lvė_ o[6bW=|{`O?^`_> 8??Cqpq~%fhcq qN)ǩ8 p6~skp>.72\ ƕ 1:7&͸b>`!a1n,w.܍eq/CCƒax8?#(x'xO_/Wk<Ot<o,<s<</ "/OgĿ`# kM)^Ѓ x#ބ7-ovw]x7ރ>!l#(>cs|[`Kl ')|A/>v>/;`G| ; 5|.&o;.vnC셽~~S!8p GHG_b&18xY8'd~p:8 gW8ƹ8\p1~Kp).-l\09s1kp-p=~p#n<܌[p+cb6,R܎;p'X{>41t <'x(S<Ÿx x'dST< O3L ³</x1/K2+J 6«jow=x=ހ7Mx3ނ[6' o;x'ޅw=x/|f0>c86'V`[|§_lvė_ o[6bW=|{`O?^`_> 8??Cqpq~%fhcq qN)ǩ8 p6~skp>.72\ ƕ 1:7&͸b>`!a1n,w.܍eq/CC'!#1p<GQ3<c8<O$9_x xYx6yx>^E;=/?%x)^x^Fx^_1 `SסF o[x+ކxĻn}x?>C GQ|  [clOS4>^|9|_=vv—|;k:]M| w]ݰ;c {cЇ#?88Cp(9/0Lcp,8p"N88t3qƯp~sqbR\[\ٸWasp5bZ\z7F܄yV,",mXwN܅ `9}hb伃`<?ƟxGOH< G1x, x"?ǓKOS4<37[< s\< B?G/r+/«+6ƿal:xވ7x o/xލA|>[aklmI| gЋ> "_N2bg| _7 o]v}={ao}?~'8 pa8?8?Qfq q8'`NI843p&q."\\p9~+0W* `\ \;\܈07܊XXŸ K܉p7,ǽM {<)GΝ£<<OŸ % xg-g9x.x!^b#^ex9 WlWxM4l&ſuo›ފ?_x;ށ;.{?xޏ6Ç|DZ9>-%>Ϡb;|El#e|_o`|·|b7{!b?a?OpA)p8~#p$~ /1GppҞR#R'SSj墳jإO?w|äAsAn~aUG5aFMȹ*FFvk:u[SMz{0Ώ{ZzOƤ C ݾq-NZ}aqhM(B!"Pߦ\:nVq*B!\U݄B!u7!BAM!"}PwB!H݄BŪ%wYcWZdGYYa6صxnB!Dbن<;62o>wZm.--رﯺBQXOxS7|Ьߦ;3/hqxbKnB!Db~wo>iWoY _\"0yXkCqI_u7!~1/wal`t]X)oպVa7UwB!VRTp+׭g5UwB!VZ\ 4z@^aw}~5UwB!V߶ FDXfmX}Yq&M/rFqaYԣIro:~֜6n5_Ne @hۖmwݗ-_.Fp~۽$&B/.Sm':$xYG˰p1K`Iro}e-eZhVmFw_6#{"f-wq2v6tk+ްW6I !]٨m[cɲ˶uo4k6߶qem$ޢ^1VwKh#wگFSka>F]b/$Y&B/.SXZ VI -/yiӂ̒VFmb4mճ{M OufC~Abt7r:~|sI[-k۩nB!D2EPXR,_^~Ӧ%%tFnMR L9)ضmc~A0fwKl٩֌dle+[xmc-ydѴľ+/nB!D2۷h&Fۢo?mi|il*(\!/FwKlSM?vfК?hh\[1ֱޜ~UwB!VٶcǶ:D|GSZ .޾æ=VlѴ) @}+^arojdyEk6n_vNmv}&wKWM!_X]dؖl~mEqcI=r!m`O&F3nda[󤑔1;BQLum-Ebv7Jvd'}݄Bevڵ}΂ ctnB!D2eee ʶn\P5UwB!sW9|{e{l+~  !y^󬜅}({ ,_67UwB!t0M5K6G>xqƼnB!Dbap3yQ?xIty|MWM!_,ߘGz9k;rױ_P m݄B!u7!BAM!"}n!"Pwuˢ@n#Bnn lܴbæ7.nc#BnnYeK+6m^as#Bn$Dpߚ̅-K7 !&P)nB!DQwSj9nB!Dn$1nB!D uONUwSj)nB!DQwSj9nB!DQwSj9nB!DQwSj9nB!DQwSj9nB!DQwSj9nB!DQwSj9nB!DQwSj9nB!DQwSj9nB!DQwSj9nB!DQwSj9B\gBwT߅(J)(3n(($e_|Ĩ)(3Inݔڊ(8;In7[%e.Fc~Fv^FuHƆ8{~w+(u7ݩ60oaՒ%-ˆni~/K~8kI4 ϨX " /ר4QoźΠS'(RQwSܝn/r.if$#:`‡VE^y O.U4~1\6~dD!Tt2뤜F[}m(JEMqw"t&Z_ش-zip +:VzBVV({w6uV ~6OL#i:}y\̲-\95Sf$WV4(Ro;RČ֜ѢU ӈ%}-?pn+NFVs`-Xԛ(JFwfЪ{Zb8[ԘG?qRgb3q+zSEQwSܝ8-?RQcBy^y+hMQDMqwjy뾻G3q.xJ[<^##$Vo+!EQ%M;\EQEqFMqwEQu7QwSEQgwGMQEQIvw[yanJ((Լu7RB\gBw7!U)u7!")u7!")u7!")u7!")tn)-BLHPQEWQwSu7EQEqFMqwEQu7QwSEQgwG-v ߨ0L_(!nSݭ7[vhw%0[scZh={ ~5EQFMqw~C7Zje0Gq,/Z20oa2l*Yucf >4Okxg,Xװ}&T6{,B֌\JQEqmw yE:`UŠR֤K~31nik_$EQ&Pu7%qawFv^F<͎ߤy}AOw YUwS}(k6Tu760oQ3ל?|7kTYnu˝G`G.QwSEqw'mr"qSlUhdV_|/'5s Knh&t@8u5YqL>Ĺ(ڨ)N[¨?.JVdx}Genlb9EZٚ֋%"T9$EQ QwSܝ:neKJw_Tn-}(D[ljݜdA|U(J%~EQFMqwEQu7QwSEQgwGMQEQQwSu7EQEqFMqwAwB!LH&B u7&B$u7&B$u7&B$['nJmEM!H"nJ-GM!H"nJ-GM!H"nJ-GM!H"nJ-GM!H"nJ-GM!H"nJ-GM!H"nJ-GM!H"nJ-GM!H"nJ-'!+(Jj t>CG! SMqEtT!H"nJ-GM!H"nJ-GM!H"nJ-GM!H"tW)u7!")G(u7QwSEQ8 n(gDMQEQ⌺₨)(JQwS\u7EQE3n ((qFMqAEQ%Ψ).(u7QwSEQ8 n(gDMQEQ⌺₨)(JQwS\u7EQE3n 6/(\`|u7EQEqu7@w6u%(qEMqA߼[Z|i{(J:FMqA\|i{(J:FMqA\|i{(J:FMqA\x 4uyi)Ҡ nJve>uvi)Ҡ n 4̽V% nJZ>4̽V% nJZ>4̽V% nJ ox}B͓( *n 檤j^iW6/UGILQu7QwsU0{7쵢(J([ȅU>nK$)ͪV;ñUžita/9FBt4 M~P+aV6xk}KPfOpKqXBdE ϩg.>ex4̽V% nJZ>4̽V% nJZ>4̽V% nJZ>4̽V% nJZ>4̽V% t7iH.;PE+qvWNQwSj)r-xQiJZ&{EQ amkqE+Ť| )T(u7I ?k`i]z5(T#n *R8xsF;, =xSۯ(Rͨ).HK;eW7uש PEFDUawԛ(u7I okW8z*^OZp5\~LJT8޶&XW?eo:F]s͡f~GUс㘡;\XXg5 {t]sn\qX8p5Tm\XeTwS%] 5n-zvYqX*.gnwsvoـ+Tj y뷺aإ}(3yD-b\(BC YYPMQzu7IVwj]."|2/ѮGvJIUvZ%˹:֓:AVYwj9q-#u(&n eg$m7Q@>BgMI9]CքZS[rΫݢvJf-V" E7QwS\$v3Vv\.%M9O $涜sl䍳n4UYΪ@M$ͣvnD}.rnK6[عoTw|d3kn7sRO1KY}\ cִD<G/ Q[:]̈?zV~(>gOQtvMV9`u7EQ%n RKLΨ QO(Eyt7n:>[:s֌bhoZXCK7\75TDlڧU:M> (u7Ik-ct`U/E+/*ĸQd9jZݿG[MPwS%] }*_GYXsv7dԕ`{DH6 k4=Bި 7xc.*n(u7M09H`}py޼1hX'rֱ|ee7sHOyUwV (8[Tu7ri=uEQu7Qwsi=uEQu7Qwsi=uEQu7I6i]z5T(u7I ?=Iփ^GQ%).H푶O \KV!QwS\Ď'&{1!D<).HdS>!u7Qwsi=u  n"_N"DUk)Bă₨|M:cBxPwS\u7Wփ^| Bn N{e&i,dqeg":5ⲿ31.F#kC6jEed|d9'F.M#^Tu7!D ݬ'uƃSewF3YEy2jq^Qa}Iʘ|bTݸp~Fދ&H۩YdA@ݍ佒4)?n΅_1'0Ĉݒ um߄B$u7n6\n4㇉}X+;[1'0ĨnwKl/"]PwS\nh7?lg6y+Ѻ#wQSTEҊ}H7H*w|b$!=ײҼl*+XmCY݅kvHdS>!zԖgLᨻ !҅z݆__M̞9)0m\e`UYCs&Sϋw]/˗}^b}6V{ u&3% !D<ٛ/6#TfM L::0yT kXΤa{o Vy 5,b9AS;-Qw2 t7!BT[#JFu #gԜYɡ淺n[cԮ]!Q1SvX݄B$gFu}VWg]{v.)YT#_V16]^iY,)]ZbxUwu7!"3kcurΝ=5wfVѹSFN|G}ݍFfMٯ^X,k Z*qJum f !}-dtb-4VtwiAѦ5WpgEM!H"nqλmWa4 ϞVx*@wKEQ%5Igb_yW^fuVft±)$B!DCL'y7gws蘩.L0Dr@p_w3t7UkѥTvTIU݄p!H#6wS%nB=K6ݔzu7!\%zXnqλk߲>Њз}>/6 Jŵݍ @ד|Dk}-k_JSdcٶ ewٕzJ(\R}(J]Dݭ᠇u1)L58'kPY7q*qFMQ]g'9s,m;[i5$6̠M̘>> LjUL\V -"r~!Xs^wwnSMpu%)y,Pp͞E,gP6/c#wf5$6ws| |5=0{Z`qI#We ͙8dO>/F9٪i}μ`>YĂfO/u^OeYQwSfnj Oٳd_-,\tܞoƆXDE}+a5$6go`یP}5%0}B`Qa9پo**{Cݫlu7+n܄}m,ˢ&V6oT/Mu+54YSsf3'nWOm:ӰV7Mnj-Fjmmfr[;7n غ;76XjXm~wVk6jڤZ79Mnkִ_`: QVe]nmQ#o'm`"hi};[ckMf-s /hڪ[M*t<{uZgnH : 9IB䮥n u83['s'۷w={[|wI΢ڷ*Ƴuz&;f +DDVjݬ:~ԨqKf5kU+y+y;UYwܤnvgW,gt>'Lw׌ T؟SLjܝnՌ?ą5#GaX}0OܖaֵEnY;-gz]ݸqYZ5n2Fu/>Smڴiٲek{$[o9-25' GŸ&~u :u2oނ .s&uuw'r$~Gcr%wyaO#2lv!rzsF/fg Bق1%_1nv4:ϰW ĺɯ6F{9N=]Eg^m噛67O$ĸ ۝<7Ww+((.Du8ѽۊٷ[ݥE|):?3eJ:`:9/:f׻}#tX*܌7?ǚVݫ79jywZG]ӻRl;nϷst]׷bؒyjvS+jN؟ gqʺ[mȹ5Vew1y vߌz4[[쇵y饯?kgg~yiߛPr`r٧m:nݺu3׭#s͚Pk{0^3  k.ƕxMڵfNNe$uyo?5ú=uW[nz@w='m" {FUq԰5E Y]mvutTˁ?q35*[&|Ժ8oսR7Xi Fw\q5jEv`:bg g6f̘)cWs___z暍W~bfkZe-Zm}mj$Ԙ"O3 wwwOɻ:bu72>ޝ瞝˕Wnnu$>kĝ}ճGNO nqf|.e뜷}eVw۾neF׎)L ]l)lGO!mK?T]<_"^w=w:)Z|BQW>(Jbw7gq p-8ܲG6geM[D}:7U_=fy7{a/Fƍơ%LZ:6WSH _pC`=dsw-oqOgfO'w-cӜ7wt7k=ܫCvma3πi:=fmPߌWCpF*۹gw3g/0dHGſ;#Y>w~0{i?!{}-y7gwsԴ8]nݼuK샛aGQc(I΅ Bdi_‰5̟d&ݜ3e%ƉfqnNjԸo?LU IUw;wINvo.,Mxd:\k+Wj*k뮻~i.n[b.`37oSsF8DQ-4fi𣜜Wxߝ˿dwοo}DI޴afaaΒ%f~_E-Ypu8Cw=^/v]ACJ Sfk-Y;ax>mokϦE3ջTiٵ_z '};zY6B>/̞bKv7H󄻨:ufERn=IUw0`q[߷ fIu#̏?6@<ꫯ߿Ybn/ضtlk=|hi[/y1[dN66Л5ǒ#8p[ݙ4~ɥL9,({w*u%7۲y[|wS%y~>kRM\:|k,,Sx ͦl[RHniu"U7m vN4|eyӗ _S֭ 2'uX {1vk+((nz.7޼t҅3?k-4C[/MśFaaۼ#qΤ/Coh^N#b$:*;}MgMQRw7*R#tHm:c[F7gN_\M61+>|޿}>3{gtԓm5PYJƍd&4;}-y~[gZoQ?WA)Jr;{ ʿޛ+YK-n VA5)n#G1"j敯d^)D4O> .;7p_d 333{*kO=E{FBi2$sO?$p_w3=ײҼl*+XmCY݅kv$7{|oP}} M^l5=s a Kݾ&UkϞ=OʝO q{9p`}2*3m[Ŭ'֭;Ջk~Igaa褳͛{2wR[>r3rd *+^:N%Ψ)JrS^;{Υ3w-΅Kg7~qsΘ_e{C֐Hؿ#GgyTnIszYj[HB,"S쑸J*}- ؄YQ&_5~p΄e%"r>(oq:=)JjpHڿof0WR$֘s%۰7k3' L*kh!{J7y1nqv7?ĕ&D!_ݭ^֣GݻWQHs%g>{3f۬)SG& d ˙4l}V{Fv7uk,݄hȨK6ݬ__ɨa̚399Vwz"mkי:?\vw3 E'2J nB=K6̨ndo޽ݳkoَ%;wk*r+cƽ6f'9& ѓ|Dk}-ݬ\8?`^ٹʝ6:w)(oU<>Hy#wMÝ'=m Qw…I^g2wr~[1z+]hӚ;E`O5j\ !I}-yqp~{ʓ6[YhKЊз}>/6 JGM!H"nq_ZVMe%˶m(+^pͮU{3f۬)SG& d ˙4l}VY]÷>4r͹[&B$u7k-W2kh9fNu7݆HwuaGHMY c6:X݄B$gFud$}Wg]{v.)YT#_V[Y=o6JgXUK )*KXw+*ٖWTh%-տB!DnVw .\0/wSsgfN;edwڷj^fVZ>fMy fIF_+ЮxJd݄B$g2wr~[1z+]hӚ;E`int7>-8 'jB!I۸^o8=vyIȭ#~a/ Mq3옩J\ww3B!Uw3{w/[+/u+3vLg݄BV-y7gws檨 !%[];. R%QwB!KZu8ݔtBQ]Ҫ),nB!DuI[-wlX}۷b󨟫}݌ufo h#/z65mdnM ߲Irk}f@]4`_9YXB3ͺ[1dSYƲmʊ.\+UOPmYz66g*kF3gr5g/\E^BVдwR[>r3rd *+^:N%$|Կ̷l]9\b_! Tݮ2>qQw3*>6!0cb`FV`?30yԪW3apYɆ>/g_Y˭?yeXwYoc8KnУ#xnB!ҝnqλ {9=-0sR`ڸLtST?~s{^ɧɆjVq6Xq\1SۜԈ阩BwV-| fշYS'L3i؞F{B'ZYA?Z5<^}VMRf2?hVk4X]h~A YrlW'%Uwb%3kj,`Pw[mtQ_gV4j<ꥶU|쩇KAs },Uv7ݭjTŽZKW/R!AZu83['s'۷w={[|wI΢ڷܪf`W6ⒽĹકv7v{6 ]c1/6^b̿5\c^Ƽdy3VX̀bK>hvY.A{M+X?r~|4ȫϨ[7WP>OZNBDV](;_-Y1o_2q΢W&ݾxy;wh޸޼vyPfQ"g*kZsjsYGYy@YZ4uD.a/mOzh(Vm֢l.o-QTW(JK__m~تm}4Q# *E| " B%(᳢<$D@H@Hx$M6$f ?3wݙ%@M9u!wfvl9MY(,J n!^xFx%)%36h:^v3"C7h4EQt!v[6$D")tvs77,TזjvUyc AX!^k6 /xi l[vFDݤݠUm͕YfPFF@tݩݚ[[M-- `niA-I3 ‡ څmZ[G-'ĽMUEƂ$ Zt͔`L%Ŧm4*8BkaqFW}FT+Y~|u4=hkpg4# :v&HlYA`BaO0fX>r0foCfwt>5vp軫?\B?Ta.kbksRtM)?vXKUPaC cT WW[Ih^g? GoSTy+n{[}5s w [-y+kk\W[\[;LKMtFD;EjOTOI#I-A AIվ (  Q$.O͒PK8!VY:'>0ԬNi&c)#'i֨LQkyyp.ʼt^nɵvh|B4@c@JNwSO|!i'7d*SR# vU -3?1i X8zDf[w 8 4ԍԏn{s&;~ڭae~p_9͇!D28[M.Uxh2m VҾ$~%4*EWh7W<7oh, 0B<<ˮz6Nzv Z߰k4#rl+a>tŬ4ȃC;aFZ2^LKC> 8^LNm;N*NEPw BiPOpݔb# VK7*I ,,VLD"ՠTn_UgdJ *1iΧ$ 3 c/>тp4J3J5c24O*NRgyFr8}/ۀf/2b׼|H/"yT2zEkl\uҽ:&$>HHLb M͗:&}UۭH rFZ QWGʵrCL'1nni ]n.$:&fu4][ ud9C/64Kϰ|J3w V2:ôNy 766\(ϛaoh0f3 G L_4e0g:b2~nYqMM/ߍWUFA_4Xb, 1`aIՌKDi& t5vWS #J%4yR'ywbbNs~;J#z1 MҘ8ӴÇMC7Z)9wN{@y &:nj)r$e(9 SމV#VhұZY8-xh3ы0?T +]tq(=n VfxZЄͰy1a0f3]e8ݶ9W!Qe5e2O2n6ZYzC [ Es fGz Ъݬ8ԘѬיּe@[t}ݘ3]fb!4,.'mi)w3*t6lf cCauu}1833̙Fv3R$ [ML5(bH/T _qVvGlm)=Ph :OyVݬ>6h\:hGlm[gUy:8_k+az_v0)f3 3d8ݒEG9_{GokmԾ?oW2z`\3 Bߥk&O]Q.olzIl!}*g^/;ZzeTڪ\$5PziO~lZҊ6yDZNaQHBiSyc[5M#f3 c^yAX%h鑬ҬévVR8/^낮cO&qo<Ў. [{]>).c\_7i{pu>mQ]onu>۩j~Iҭ3͆ cCf G[&nښښeHjk7~ q^n|\c:>cj|TFJ$>yTO&uthf_pzNl( >_"e(#1a1Øa0ff8R,Oֶ鵙^MjrwZS:`@:4n#|fCB;; cS2.fs3La/8%,gڭZ|~c@ k7PuBk7@ EwZܱe%/".![CC o = ʐH$Dp>6lHwC0Bh`?cH$D"[޺'2 Nyqk_ j7$D"ݦz-ޟ,MNSmmegky.1+niGrH$D=zۆWfnhL6o7m6n4~u[ߛ3#,ny2 xjBjڔ#ml{X[,]DYѢcZ3倞`3jyLnUǺCT]$K,9KD*RK5]ǣ:G$9/ڀ-u׵JٿU1T|D}/ͥ-A(f-e4p͋[U@\4P![Z?Y8z2=Xu\cW@@ Dgnk62%w@c9}9m9u9#ޜid@ A[GkLLRM;MӶh޻\;7Nߋ<}WӳW^S P![}͋ GӗMYL}V9mS{cKwߊ`F ;c-LA`07]>n P $ ~h"Й `Q[ITa nmv\AnDn:ה˴?ɔټos{k]g4oK,eo8 !6(c *,n Z4<&GB:vI6z, c5$5S};:Qex@\Zj7Nkf7X[Z$XJo֛Q/6bRbd*S#q+8- IuF{x!fnFn5=BkP@D&­z[ʚ66QKs RA;.vl1*z3c腇fbzC D[Ş2K[(y0/q)#,ڍ=W`QMON%T1g7@[}7^­;pڍ]ͤ(C,E')>,׊!"Bnk kB/- xq* \v!z :Jn#˵A @  ڭgvH\j7@ :pk邏.jG^E^Ffm wP-P![]о[몥{;V 7 Z_O!?nEnH$DaniƜY9i')[R?X!o,;ˆr2eŸ~\7 ?Hߎ1թ'Z,{w_`e6Nd~>ݐH$nъ _~&錜!۠~N^ݵUP#<Fم;e~W I`5TuI Ҽ2%~j7$D"f߭trNi785%PXf7 3B\tKq=S\Kfl1QbDQy~[~j7$D"fLoPF_[oU퍽'ayWxE$5mYHh (8ƿ@/P]j7{]>?H$D9}V`eKKu"ؾۀeGnPgK̂!vauVa~Q fM5!tTf{*ϫ𚩀 D".ewk;:d|^L L8Շ.!Kmkrn_p6+>+LʯV l+C^n,V>@1$,cYzۭ<2E\_naD"Ȱj B0Y VF dorzrꗖIY'  jhQ@Kl4\\o¥ ϰhp @ pk~7Yudܑ; Z[*}> T B xv^ X}mP_*5*@@ Dgn +_z'|)Bj7@ :pk~%,Kmph7 .^ ndeyc/YB^Mfx@FAp_9wD"Bk7ßvv ׾;ۢEQQ2K⢨iQ[ITaΊ0O(A ! 1@9g8!S j:Wixfͣ/W1QMFH ߓyn" ڭ?o/n^ڗ&C[4v r6!ּV#jA(Xؗ굛]F+]@ n~&L6Vzk<¨SB*!h7c7f0Zp>]<vn^ǒf1ٜݜٜќm}on .y)25{n4Z@]!ޮ@ ~pk^̄PPqiRqږ={7z=k{ l.oZ^Ch$jŦ{VVB^no!OsM[J'GR.oE DA[wۼX|ϖ˃LRLM>+NԜɱuRژQwR$d?ؚ7޲Wn`?oyV!XKsސnk͹-3tp)ci)uyf׺@*[-6H7kv$]݈?].n[F D ڭhG@Wh0gMHۖ4n53e56A4"|s翛[7* @ x[Z$%,9s_k}4}/#z8ƎtK]w_^@ :pkpTYXr*(=Zz`Wig[}-uM4ҍb0&&#IsR@ A[E&nښښeHj -VzUQ'׀ @  ڭY̟*ڭmk3>Jq-ЛvC 3vVyvk%/c[vC 3vnv"4vC"H$2HvywZcmKf^*E\:D"Hdn#Yk^avC"H$ m @D"Hd2ޟ7uDƗ \7/nKWq@D"Hd2ޟ,MNSmmegky.1+vC"H$ yn^ǒf1ٜݜٜќm}o ݐH$BF޾GkLLRM;MӶh޻\;7N(Kw\їҋ7WX]wEvC"H$ yn/3H1?78Ssڦ&ڗBf0 u T|&Zǒh$})6h ڍD"w\AnDn:ה˴?ɔټos{k]gKbٻM3JsJ+5xPvC"H$"BI_93Üi4/j7#n[J@Մ~Δ.vIK5SzyTWg`-a"ѻڭ")a ܹs_k}޴`%QhT F鯙֣zqD"H$Rv[[wr,ǒ{HViVFJ?+MkK;n{zy. 1$6TE)D"]wK^?vĭ7_[S[S]^lQ;ݐH$BF޾[ʚ661`G DvqAF P!H$م}=-aez9jfkQa_D"]wn(ܺݐH$BFpת_n[2R)I͐H$D2vnNkpG@ DoA8Aqaڭ D"LƯx;)?d%7fh{}7_d7 D"M MMi?{lc_~Mn =˾邏.jG^E^Ffm wP-P!H$2)gT_^z{8RBqPpI ~:[f&d& 7_xnͭ&ʖwqyE}ҏ4{ CS6?-ftİIӑCMʒPͱAz^lg tO#V]vc3(4* ?46~f ZzWnH$ %+q;7_nJ{ަTo^wt>5vp軫?\B?T@/$D"Hdx(i7^<[]i*P2!}kՓSLʲgyvC"HdDSB[s>[aG1EGDw*W@yth> ݐH$єQv✫\oWG\{a6P|BAq}[wC6vC"HdDSZ[ւgcrR[i>lΦ̤Jgw#%Lf~|pa @ Dowt2E(Ыȋ,w^=z:ݐH$D2vij eµVGqSmO/E5v 9D"H$3R2͘===79$%cKGƞ[>"|[*(n.\&*1%| 2CM/kI~:+v O Fcռd6g/hf :N"'.NivC"H$ ڭ~UAgNO>B zm];Z 5CN*a]*Q&H5xdD : dClP0 8D1TRd23r D".dWkƚUTf9m O@aQJO$t q5c.Q=`?Lq-AQs1w4O|Z,P{lz}/(JQ@D"Hd#dڍ>ytVt{OMZ0Ix#LkFe6j&+#2W)%hWn}wKj\W6M 4vʐLuS,(0Q*@k9оĐ,&'X_ hB;4@ S](٭[ܯeR剃A9گbo]"kEIBhnC"H$y[ ۘ;rG\k^}KJA(KҴYca]n]ڍ Mu Ȋ,Wd:#[Z ;Џ33:ZΨ;㫝yF[|;=Q7W 3iGb G }b1c1|pOi>S=Ȳ\F֗Z(*!˯F<b+- J G۽_TT*4T#(Z787_HEg" 3 cf>^FAV7E)d9SDBhV\\l2`')Rr\P]ăImBhw6~1Gd4) Ll+C'036-[Zc()[Z3S0f3 }7DAhVb.1JD>EV-Q*%CN%fep,*[Wn7t@e R,$.lf}PhV3c1Øa0fge LvIBk7RT*rRF)-9lYrêȤMMXMf\MR&RTӰT?\k x[Q_R5چ̰ڧs`1Øa0fX wv{_N'pݼ/MK5jAhf-ZU:ά\vQY噒תoQe ΞҲ-˖ ngCl6(ؠ,;LݶmRKZ%[6tDv;4fݗ {E@s̀;JZ F[[fHv%~[Yv;BW) PEjVLKC _'xAQQ;kV< o%ONd(iu'`%̶y#@Cl߹A*XMh 46Y|4DBS_RWB^rʝ+Iw\I#’M rNI +V׬^ɀҮAuS:KHPjymP/{䨔 +cXX/ԠSi'WfU>Y2D exnzuyڵc1Øapf[88kh?my| MtFDOzf0_ x4uU&B鮿fڍ!vs7hNW4675ԦwU꓍xRmlN[ݨHc#6҂<ܶVi,0tsϥh<VEG7OH!CV ==:&:fzU111qY0jin*q.1n>702EdV2͆ a5{jJ3Fs+b1Øapg;X%h鑬ҬévVR8/^%ľPfC&gZS%@#4 GXh VGf;ZP4phf~n4Gna˻11--jm17p1uGc*0[l[4ˑ4]_Y|HB2;3-OfMm0tmz0k A kZO:k/BY̟*ڭmk35]L[}-Gno"AIng?Z%gk+mNAҥU7@n0֑~öfqG+j A;bk?lU[QZ[y(ֳҵ`H1ØaHa̰_%zV| Kn{[s>/n֢]JsqnAhze&BTμ^v*,UϹ&|IjҞش@m4 /77/ CizR7Ҧ6Q+6> jc&F0f3 wv-p}ڭ.dDOSگZ4Ws=|J _jZO6ר.7Hj5~$֎f c1! {GMwZܱe%K aPz[=CG)WXOqعA-}~)fOS}4vt^f!'?nH>mLa0f3vB3)P Pmv7wAzbQr3Jm!L!p`1 3ܹM0^-! n@ ΋KnH䥐n@ ߤݐ=K^tD"D +y`H$sDYvC"H$R D"H$D"Hd!j7$D"ȾCnH$D"}hy11rhL۳T!HddqN3_OHV@rn?@+I(cP%1:Vf}jjH$,`"QuT!J$DF&i0B,_M{ճLuNvrڭylmj1rd{2Fa eRU<Yx;\ z.np׆D"H$ɨrk;]wMoamw+nvō}woݐ?]]<E~n;~ݘvF>Шsȷ.P^ KXwwl͗09H$ #5ڭ⚻s[Ώoe:ۻ㿾+w?q}۩rj 'u~VA:3DFZ\uD,.qM*-6ʡ瞸ԡH$D"R׷o*I%?aˆ=Pv׍^}c?]qElŷ+.>oe }oTIϙf(j&8H3zȊ."R,<;kb_wW}2ʡՒbJ0DIR?- B?YG^;:9R'V,&@±@w,-iK#N6#?"`_4Q{"̰jD<&jZraQm=ae*nPqx?|}Nmn~aTB(Rå|o|StECWiiXv] {x}=C#̹-+^YUk̀%6Zx͋ۯ}fPH=Fz]hlq@8סù=0m SC@`yXrNJؠWB3SWQ= cYxX?Z3?2D? vă0H$K]0>RϜoF^?lxʾ@3x'UFMʿ=UuDu9 iv#*}%j? \8Q B{' :5/{` }A;M۩72HGb[ѷ-AYCΥĞ[`Oۈ!v}3tj_bֻE87prPfCKxBX{Z610u3m8rfp#&#i/@SIc06n|ZЌ/?  eBD"H$ٻG i/JaCVnw?Wt+噪<Hb*r'S" )h75^N7|p MhlyreDQQ`up㊻^? TnIuLo[x+yi |T`׊h7Q(7X\Oڭ!#X?5AڭyR[@|0͚[CqnQfr oTJh02}(AYˣJHhb56]G+a!ld8hf 4oND"{+$IU[]x$D"a'lq2AxuԔgV=|Ppc~yoOɘʟxUzqi_ě@Ik7yv9c<.1oX7_!һ(EeaYx吚F33\|Kٻ [iIip_qgc.6:KyϋnEm}:uWS?qAF;:l(#oo S%-r$b6Ǚ~ǃCCKݱݒ^}-x_0u+R1a([\( 73ȑD"I&(+$vöqUr<^9&.޷?XyE||bӼkɶRI_ןZNJo2u>qqOoz?{&65Sڍ7;ȱ Sz UU-@"HdX_HdxY&I86VnzfG?ix}]݋oUO_ +NnOqLxEN{rǗμF}uUp&jb >A"yhh4xR?oUS$Rf"bs"oUo?k.zKW}Oc[x}kƔ/,~L,A[s8ynBH$D"@?1Nj k_{^p˹e0wrx@y$Ep ݘ^kR&ʚǐȈD"IvIuݒWQcI( 9KdA-mf@lp=m eAM1'!H$DF4kY 4⎓rP)mUlSu㦹0JwƠs;^ ¬A@Z#s҂|YӖH$(6XTQ]D6i j8 cNx GƋo+: @oc 7ZTM]z $0 7) +~r0D"H$22 J?}2L#8S*{EnjˁW`Qͦh7*߀ č3&ld7|6k%mDF,C@"7 /"pb`!U|sM,lvEcX)ˤ+~ yC"#ȥ8ұjS(Qb6iNŪQuĂF2=Q8w"2z}?`62}`C -o}`=+] v؏`?)~ _ ``Z~?]nv#؟ 7 v ح`6lX?b.XF 6v/}`{A{QD'{I`ς=6l XTi``f{l `6`s悽6e`-{5`^{l17-[`V ljw[Zu`%? !> &O6m 3`I`;> l7`)`{f;vaL,/;v,,q<```'N;VVV f3Y`60;XX%X ks5yZZ΂y|``02 5`]6` Mo};`]}J~`? O~s_W` `5`ׂ]{?zv0g&f[n v`# v؝`wł 6lh1`l,8{l<`=0#`=8'&= `πM{9`SM6l&`^3/`6%y`/{lث`-[:`jXE}>""" ,QVDs/D զIWҕڦ;iҼgsMBs~MBy ^7-0 &w.xL`>O39| _o - l0߃y`>`X ~?_` X ~/ V5`-Xփ `#6-`+Hi ҁ AY \A(>E`A (PAUԀ ZP?%hZ6``p8CapG1Xp8N')Tp8g9\p78 Ebp \.WJ\:Π t5;ׁAOpzAAp AVp nCP0 w`F{(0c8p<ƃxLGcqx<πgsyx^Wkux&d}LGc |>_/Wk 3w` 怹{0?,Og ,Ko`OVjzlfl 8A:p7 d^ @>(lA1( @9 T!P @8?@kR`?p(8 ځ#(p48 ǃ$p28 N3,p68 p!\ . \ :@'tWtׂ:p= n@op#@?p3n@0 n` ;.0w{Hp/F1`,x (x <O,x<^/*x o$6 S=0>i`:| > % | 3`&0|#XE`1 ~%`) ,?r V*7X ր`X6` 'H. dl< rAm`;(%@(TjP jAD@ǁh ڀ}@ ڂ@Op8A;p8ǀcqxp8NSitp8sy|\.%Rp\:+AGp:.jt׀Z\=  n}@_pn-`[m`0 C0pnp h0}~Ca0<,x<^/*x o$6 S=0>i`:| > % | 3`&0|#XE`1 ~%`) ,?r V*7X ր`X6` 'H. dl< rAm`;(%@(TjP jAD@?q-A+/ /p08 vp$8  ǂp"8 N p&8 =\.K2p9tW* t]ՠ+\z@/& [0 `p;ap' #0 F`  Ɓ0<&`"x< ')4x< σ?%2x ^7-0 &w.xL`>O39| _o - l0߃y`>`X ~?_` X ~/ V5`-Xփ `#6-`+Hi ҁ AY \A(>E`A (PAUԀ ZPq%hZ6``p8CapG1Xp8N')Tp8g9\p78 Ebp \.WJ\:Π t5;ׁAOpzAAp AVp nCP0 w`F{(0c8p<ƃxLGcqx<πgsyx^Wkux&d}LGc |>_/Wk 3w` 怹{0?,Og ,Ko`OVjzlfl 8A:p7 d^ @>(lA1( @9 T!P @8?h Z֠ }~-!Pp8G#Qhp 8'Idp 8Ng3Ylp8 Bp\.tWN3]A7p =uzzF7~f`0 w;]`8^0 cX0A0<#Qx<O3Yx^/+UxoIm0w{`*x|>t?|>K|foLf9`.G,b~KRX~`Uok:l&l[A*HN\ 2@& x< @!?(vP J@)2P*@%ՠAԂ0:q-A+/ /p08 vp$8  ǂp"8 N p&8 =\.K2p9tW* t]ՠ+\z@/& [0 `p;ap' #0 F`  Ɓ0<&`"x< ')4x< σ?%2x ^7-0 &w.xL`>O39| _o - l0߃y`>`X ~?_` X ~/ V5`-Xփ `#6-`+Hi ҁ AY \A(>E`A (PAUԀ ZPq%hZ6``p8CapG1Xp8N')Tp8g9\p78 Ebp \.WJ\:Π t5;ׁAOpzAAp AVp nCP0 w`F{(0c8p<ƃxLGcqx<πgsyxd:j0D.PfG8跎&܂r0O .~M^MI?%_w&oOIOy kl"d|-l"9 %9ziqzqm*iL}r:m;!>ǭ>5HeosO>#<=9_FSWM]NS:(S-o-PWp+=In*SiDsr8Q9NۢոVp8huPOտǭY mGdtdzqoݤҙ@ Ll'>ÊoS PU5O jNz@_ї@x9 WN2Vsc_\*{PyJߒw\sIiŭp_/x٫'mi-=1׾Ru'?GLLwOxҜ׷u kт JhrIGs껦ȳ0 /@ޖ=rVm)rEN YHxEʩ ZNijzUG!WB^PAo#廉Wsi{Y+}|TS;m^ ̚Wc^hhV;m"F.'sgdMxZ.u@Ĝu,!4'V~2HisOX,=WT^Snig5/nF`zS1(9Ǭ9+pm6zuFs\kڙ=#u#\!;yR2}<ٺ|wcvR9˯k{hPdG&Y` jpG*mۻIp8ePډL^Jo-NѥcEsc_ogeameD{kiLM]C!.2*)ciy۞sk^SS3҉8Vg$m>3Z$ڀbVvK&GxlƐzld€b$*E9mZ5{k 'DDn)qaݤj;nǟ;Z tܪZVeF4anGC YyOQuyZIZkYp}y Ve"8dav߶͐S_"&,5M;Wa]72rǏw'!C˴P)+[޼"° {VPǂ:J3[K>mzv: ;ZvkJ}Ox#_ggGk,97YX"Wl!g-x KT=yΧj5ոh1unًtnv"t:)c('>ihjw*J9΂8F9P;Ex!2{D2`S۞Gkcpi.̈́W+;tN8LZ ]>E<>ե ~q'krh;%RUʵm&2՟#CmƄQk ֯FcKf?^l$wSrJI轠ͨVA >-O*ح@5&LG'h@zQ>cc_ȗ_a22D_Ȣ/~P֟SȮZt["TL}s/τ+ÙSoUoEB`mwz*cK^;dPqM_@>MPaQWK ըO\OuۋY}wL2\5`"]Xz3Ů}p7JߚYZ*sd-_35*wCtr%.{7I.w/YעeK\qX槌m?굖HTR]`>1{v Q^t-rKIAvI? {K`_g׋ӿ]XQ;vqc=(WV믿!''>5z3lݵwey/ȝ_X4VeF-Q{Ͽ[GnW )t)M[ehr]_,v F>~7pC>Pnƨӫ"DUX*(嗅r`{jc_$oOL3?^ތ}jا1=9m̓ zÑOR1 f{l֔b[=ٱ?/8~xx[\UmO7bWK'*zTY96=V?q9{<_U>ΏF(h',ϚCˑ{L˲)޹Gw_7Pꕁo7?#\ˆF f>ۢn=pm$„v8*Wj2xW+XS:9RqDbF4>cbˇB;&&0M6mc;a grUhc07j+5U@UUҢxUxeT~ NVz1ZT߷GGL M9sAӽ>RkA1W]G n o,FZH?oB9WD/z.,^n~KS:)cUD=Ƹƹ!=ImGf^/|9O:%G=g}3':~`~jMeY]_=6~g[|1I?x' ̖_0^p}OkYpЄ/b;e}p~;1}Ϸ7-do=hft8}7c~`XwxdN1n&7wj6^v|p?UvVpޱ_nb 4S(SL͇;=#~p`u56].O>8سA&6KTQY2\𧊚̒z&dwOqn5ڻpŸ*2Xc~j ."Y?#t ђ?Ud0;~96 m/o 7ߌv7uKT_zzwo ]SEn@gEq?5~͢߅?Ud .&dwO5%ߜ-lp7S뿙Po(7Лp)]Kg9v]ĝdw,l|z4?%H o9O,i`׾YR\[7M[em/^F]~soi@,]|?1]K快O{_O%>+ZY,]|~ן͟N˒o3{ߜ-l{=/j{s?j.h~ڃotO4M@~SBg=m{1|$x7/ :;Ӭ_o֯X_T Q_#;wp ,RQߍ*٨')٩VlՈr ަd+٩yJvfPRRRRRRRjj{̫FkM;k*hM `12KS>(5L^JomӇ,N0>ϷgY91]*1?jJ Rmvs0T1)2h5Ř0VUC?4a3iTibXeuZO%Fm;BU}9FrK-ǰ 3l n =hR?l#--qi/K9cYk>U}21I^\l9No#))j5.dl\Fl/]J6EJ6*wΕtWJKJܶ'Ro>J_TE{ۿQ,qn-b[bZ,%ֆ"vQ,q#aa;l06f 1+,_8jv~j屰hY< /p Ƀ-Tb .A!H3:(F$'؄ w|2{%n51V69aj6WNg]FVY%ВF*G{ݺ&VZfw׿Y9lzۻ[وek=d[ޭvXydb# [:R5%,Ac;ݺM\F.@Cg])\yN YZ#'a]F/)--)46Nu&z@KJ6gخ0vhz~3_qWŽ/%V2Cs$|NވJKK(e[?e ow!q'th\yځhS1x=n;ؾ΢=.UXOњtyk-=h5E܇kgvtyk_=OFvfk1 2fK(>b0_ϷΝ\nz]\~jvQ.oΦous̾qY:觫4?!}vQ,qe[FocjȞ3u=8p;Me-v3tnR5%z|ᑡk3^鵕d 8цs r3ӼXuYvQ,qsr<9~6}W:uze6F]C7w;#NR5%nLʤ-UWGa1}F8F|%˘25%;vgd 5d@sbZ͎n! 2.UX\.W:۳v&1F{^}J6b\b]ew?--͙bw;18-NS9.UXo5YKG`VsqOsGտi_ߡU?M\yPoӋ\qm=W=7\Aaok{J!FPR=hTIJvx%[5"d5|J|%;?uWIiϐ+))))))@~%;~R{"u[j1UTQ-+٩ꔔVE\R=jdQeUXUQ-op9SlR&e?ULvs(`:EL.bOXX9)|}o<̾#F+Ga ha6*YKwոkEłbѹ!pͱ&؍[h[т1b-.֣mZ]'mYo7Yi>1FLc=P K_֣g4[V.okh;FahI__\EZ=gSY٣b [O|.gZzJrH[LlE_s[,;P:Jr }|7;wysu#maZ'qӦjɟvGwv;P3پ!D @f"n>'>-3m I,/?y^!| $|/k[+Gǰ:$Uot[Xer(kAf ex=CVzs7wkϋ⣍:86X@:率:n5DdE:| H,CpsNUHIƮp:E7. [˥\̅i-mMsh'|X424KOBN|M*%ÂE8t%'*MS$r]z`0MO5$}߼PF/@*)))))))5HF7-LIIIIIIIIIIIIIIIIIIIIIIII!^$_PRRRRRJB@\vMv$$ݿ+SL2eIlYzHcZNU?d zLdT%&8E;m.87>Mځ'kaJ{- ׂ{4=Ъ)KD+?'_ݲp;|xsgx=1 &IG0W3Ke;ËÆXDdžfK s‚8e 7\amrh֣hD"/,ԎwBG7p-O'*\$|RƱ ¡`X0DKۄ/Ƞ棻W1 !Cd!|5iՐ aDJԌftM/tJ" qlO-ǩpf5ՐhӝݺU 1h! VO#&HuyioÔO\-Γ$/#el#UZk,NMMtjRjh WVI?`R&Z82rJYY0ʘJ%tܘF_R t]yE9o#a80vhrap|[.z^__* Jh&fr=8CcЊftT&s ٖW8PV  *r|vaZItf@>|r@r x)@? ~X@䩧[f#2zx08/ a6%%Pi֭JEkRm@4C"fzie 'Hi5D%b٭Mϵ02&\ZS,̕g2&D+}qrt4.V5.YYV8 Pݐ9?{TMW_Ta04QƩ~K{E4ϕiI!E~I>6j37`ҁ_PdH\/Ǘ݌|>ROn54>wKZ WBHbg-h OvDxHg3-$ RxD>ԓ㾬+Fs3S|eZnn7l^fCC;s \h"^eR$L+y{y<\qb/-VYp\*%-* &pfmz﵆Gh?|{OY1IÖ1-Cg1Z<1<āp$E ̂im2Y3f0f&< dZ<3M,!Y[[Ȍ{5Lis1V8C7wέvdCcȠn7Y4XgȎ-ܬY,YIúY8Q7[OwKME$RHRq*rtAKkȀtil%l,]rv -ESI r2,8_DJ穋XҘ~d9EixJ"GߥvɓS7[4gfl&;ӌN'9(-E5ϴFr:iNSGTbw;19]S93UC:}S]᭰ԭRM{N{RM.i0:DuTx9v41j Į){?Ov HI.y_TRRRRRRRjb0%~ZԐRfh/()))))%l I._&~TRRRRRRRRRRRJD߿)SL2eʔ)SL2eʔ)SL2eʔ)S&l@15P45ڰNIJvV1uJW%SSV2RKINW N鶲rЭJvjXPFr +_-G5#"JW_III0ۓꞭ꺮aBigdX4I.kCfVvzl1'ŎdDb&:o$~lm(nIf&$pXX3,q{yXt3 Gz}=6wzxsؐ7Hpl)=9ayNXeSfava1I;.G%}a)vZ_~D4br4ZKdj!Sv|r@r x_Zr?#"O=2 VƃyaتV촤BtbVVZJ7D%R^ڤHsfZCDP%"&[*e2,X/%2.btRKJ4&\ZS,̕gKLZ6aKVl:cp]ibs8,[KbS'X٘3K}%_. +Vz@.ij{.CwԇJ3r\I#8s~@sTODbJ~Se~yy|iȂ2W)iQɕWʢjīp5Ah?|{'ǣD`!-/cZTk=|yc@=s:xb=yH>oIz'™YY&tG3Z2-Lw`1[Ȍ{5Lis1Ik&;JTaw;#M:顛hM7Y4&z8Cvm1f}nL2Nh:ĉb|[jg,'BJEWtW˕Nl].@kl,]rv NKw)\\W v8._t]D eW2Qw]d~M\"E_agfNuV s:uG}S?0ϴFr:iNSGTbw;19]S93UC:}S2'SS᭰TlJRK.i:'蚺.jO#ǎ&SSq80cuN _@Jr elR)ed2%%%%%%%%%%%%%%%%%%%%%%%%2{@\@IIIII) e?Ir7;R \vL2eʔ)SL2eʔ)SL2eʔ)SLl4e\AJ6Q%u$%;bLj5"d}Jvj`ꗣd))%**/%%;WRJ^ ,VUJvJ%;5,dJvjDDFUdlLv,=[FNFl%%%%%%%&MPf}'-"m.º}.4[\"`7?6@d˺qY*pXl?,:z# tTǗ&pX"ay%4+,qɰ<',)M^ ƬpškVm8,Ma1Q spX 'rװ YY%R8VvR a&g* a!m,"-%{d# =ސҍvD=EP/DbM Cr~(&RXdnlB/ҩٞZ(/,f4T%dL#(KPͪM5s#2Ώ=ޤ}25ҞϋaqXLŦC1(6fc/USlh V-+\"z'[?wZïi| ~[?BgEc y5ءt#se7l^3q@_:.[bڎl螎i=L>gZ#n4'cmtgZW(O-xD>ԓ㾬+ <ϐw%p2[%Fv^li6ZFɑflP?~9t*'"y\2_iTrkz'_Z.UJZT@rէ^S&bb x<9i}QD3Iy9ŔE23Z2Lg#4,Xf4L13#1p.ƽ<)SwdGpqs3%p rf6i[gȎ-ܬH,C契faݬ/Žn)H@$[\ )ΛHb" )ӜXNOwұI׶dGwSo6 /qhPrq\ZpKx&.)Cٕ.$r]z`z#s;*;B~g:}]Tɓi'-r'%gr1xxzmzxI_N)Ţ74Hwѡ)|hP[y]N/X{3gv$QNJ^qّO@(x{Aݔ7ܻ tg̸0rD2?a%\ܻJxN%2/09|w.z|O/|dH 9l߼=F^OaȾ墍75#Hl$:o iۏn{ ]z?`lrw{A"҈383<L];cЎC: 7my":mGmaK$aB?: 2GpDpXkazH>&GDfa3̻a=|D 2 [a?jüWt/a,kXeMsd ! 9%HCԇyj=)(C= !PZ d^SS]ɖX5~q51G;\Y@b -OW*Zg̫*Dh̫ROZƁ6F5؏yrۖrԭ4inƆ襯[oe`N1 S50!?b/VKJKKa[ZKO6JJi_)@,#5R%%|+/<:o'Vb2*6bD-65‡$_/*Ê`~MV q?׻#)/;0Eb:eq}>_!lH Ŏ؈ď}>$3-Zd߼-A湹^o.5m#/j-g.ԏhN^eR$כkX&W˕ H%A999G3ӚhH >CBc1< 2ςefff=ʔ2-Lw`1[@G3!pV37t8v!;p>[DD -Ģل\tfR.ESqhPrq\ZpKx& Aδ4fN)z4u:ӜkNyI 2jT)1bFד#(kLyK/s wxv%Q?RUYrwC񼞙7_ސYcS5/kXwՂU+Y9{y;?ج2G99ᵮ*gdeZ-|kx٦kC*oVH;ސA4˷o"Bڿ'hV"^ #a[jOk#Bͫ{nK ;C !kТ5Q̏kHjӂEZs!,В[xC"HMЏkkEM&ܔhgx׶H j*dg239N{tI'ΙiY5d&ح$8H&EIN*#ǶL,/)-uIiX6MQ(QRQDqb*U" UBs޽o 𾯾zN\XeNUW:43Oџ34okE*>9?_Kp8Po\OS\~r{ůXr7>Z.?$Bq+vwkKO PGWT>?19yab|.;2rv yߏgx/OmMKs7 ח7'>UE9Fw]v laẵ]Rg9FNC?L3?}兟'>4/_я3P>?g5ˎ8Z6et =vJ \_ b<}G#Ox{sW~|w˙ߙ:[=;̢5l=c4@pbtZ?yOfOnL̯O? ?}iQP돾X'gģO_3O]?uo>Ư㍷[c+QVO[v3LnS׌V]jX,]ZZ^adiA׾Ye`yE;"TB-ۭ._\^[*M-_ym!en=tdï:3/=ЏCSK[-2u}dTb\,?_~ʥ咳/WfJ5_/ݼW2> Kgˡ 7T+^N>b璏>|dzb~y_sR#_wג/|GGϦrt }Ƹ*7"Gؖ«g_N>B䏞M>CScs˛ǒQ;`=ǼD]u|m|{g|:u~!'<'@,C y>b3/SO=LϤ2g8qzo u8$}Au>a1!`XMF/7>[)l/s֮>ƿ)#+9L>f]&}g_"W6dW`q[_*ծJ5$6cWc _:ckFjeq~|h;6 WVfphD+_3ZA WV w׌VпJ׌Vп>ƿfU?ƿf1>5|h;c|jF+g1O?US_3ZA*_3ZA WV w׌VпJ׌Vп>ƿfU?ƿfuxsHsmunr3?kqE+_%rS]X7 W:_lZb7a捿D+_%_moA+OyxtGI3Au}ϿVbm;?ergS?\*ѩC'|o5bj` \?ssD~jtz"ƨH-UCaxcПП;?-?-?-?-?-]][BP]%{PZ ׀5ݵ=7ɇ{~H[TWurkI#9.l5y:k#B=Xc*?]yր?c?2菿O O O O Ov?PZ"J@OdUY3Ya 7)N-UCv,c^plu{^H9c۴؅Ԙۤ!1η|q%K~x.+FwYIv\5\V~Ʊ<+WF WJ%lKUerw+cHkU6= hv3.: 7]8*7[1ztݚM.ZҲߕ䯻(Z7A.]/N%3N_$Ǫl%#$WH[.:@IMJ%( UT,SV^,E;+ lSKEѭd. /Q6r[b-.EK2ĒƓ)Ad8Q&Uc4=5Ʌ+1%{‹ ,~ k]etYCaD ́i1z.duffTJ j=O9Gs nX[0/^x܈\t,ͻn5|}|{Æo_t,[Iɸ=}A>f!"v:4fs.fg,qxzdž w>n6a)pn/s< ;N윪C:(^N8*;YB$Df=#Ϛ3z&S3=g f+ƙ)0팳-dű:M'wlXnվ|O޵!q$|X wdeֺ)d|F6 ^ua ׯ5顒 .teIɹ}fi+Ѵjjj3*)BwOs;"M[vL4G2oy©?EEy}lFf>ǭy3-lX< NQλ]:0B^H40U^yqQN@myC6yWɩcۻcD49xӤoK\WԤ a~qJFvvr(9>q wRk&W&<VSz:");I= n}̊1e >"6>kۑ\n|<7~XDžqaiɉVqu1N6|蛯Ȩ,WlFXvգ¤J:1jzAD_:`2W٭*ˁ1W OTGU'8"HwuĈ8b9㥌"mtCldd9QV6kH$x='Ѝ!]r&㙇d9omvXar]dM9k vPdW3yy C2Gu־4Bgtbөt:r lW ,&z}DA#Ҡ*BqR2E7cz"n:5vZr3KtJ՘T2uz 2$&) 6Ltn#:mFS=Dk4|eHBj$#A8Ae5:)ݓtܞt'~0 ̀>pn40p;Q=<ۀJٜ7]O 60GpO_o([]LFc8kAC~K 6 7 Ŝtw^oAAl2?()  `ӸI@A0n/  Ls 1$?Ĝw?AAAAAItI}JZW.vwSg!JL>wκ  FC[kT3c SH0Y#> ^< >``eG<@EůA85U&ROo ?#].@/ $$(~s@hI~  `L8r8ΙsL34:4ϥs0KnIqe43h:heYdAQ r@Ѭ04˫b?g|3~SOt,Xm˧/?8H*kemLsVbr|`<f9X)$ABMIOܑHA}KV.bh\1v]V~"W>j_q,JxQ.+ʊk-6P۪%m0{AѬ:PrXQK%7ιdV^%]-r,}J7DeRI]ߕtZZ/cU+PR-TZVㄌbxY pq`ii$mEUq$Dt(r[b-.EK2ĒƓ)Ad8Q&Uc4=5Ʌ+1% F9uY4j7B` n7펻пÓJiAr2121Xp,..S3,X _41Vv>5nCSù}D#v:4Hw)<7;7ņffUY4X6^euVSYm{w|ZD&^Y gh 6+;}lgub ff # ªl&jpgչ`8fT7Cȳ0c/Vyxt/9^ڌ &W( j^=BKӼ:/yaiG5L@"M:(Y $ atr ztˮ\V_Wr>Rk骲R ONM:0I6R61uS{`jƛ'vqkAr91r CT5'}57 9"rLϙNDdwf味cȪQəƭ\rf|=>fwE-gSزYe6y 7&CHzgD =JI:\'1z2'(t'Qe<䔯,]DY=u6##NsWGxcMRXN(c{V>ƈ4HrDUHۈ4"aF Q{DRS՝lZPHZ+`F)|#7gQ;y!7GmUdTѝt`ad2rx#ϠDQ (g2yJƪNRxxhondqH֡Ȫf0dH+2}}i m񧣇 fG*vJR)Kq CZExGҢ!VYZYE(= iQuCJR)Y&/]H4MIhJ9ci(p29 $/%cuٞ4*l4!f.-" LFWq*uhs'jt6S4')=Nޅ*|f ܝ1g+,Q=<ۀJylӹz`y0?2`x+|Bg/]LFc8kAC~K Sw߀sy8 AA$       Xs 1$?Ĝw?AAAAӈ-?3Fҋ __*uvO,[d|3yOݯ̥/?4xs΁`<.IXy2+K/(={e_o?3Rzkh.LSWN8d?џ=(п`'KLvO-3Yd?{`O ?O5.1>}xY#^/?g32S0BFd<¤|2O,k8xmC@@ƁZ|Iv z/:/ j; O`k_X\͗N9'gN?U ƓoŜ/+s   UqSLVKeL Mi =甇co9ɓ&athGO9QV>8yUGE>ʛ.֝9eȷ8yySZ8-3>h1eд#)oqhV=M-$ABMIOܑHA}K+Vk5&jW#*cyx}WcPIB33]"^qPNKM9ƶ*{Inc4jD7;wTR s.Yy+#WI׭iˡ!Kf-iYܔK/ Fd,{JLXd )TtE(Uz8!%sF~VkTd[^[f^^&Ɲ(^bX{IlhƨE7LA"ɎKKE3DѭԖN.d%={.Ţ;XNkRhSxqqaQb-JÂj-5]ws`Z z\a3';҂YpFQ9{(_DYZIq-9/_P_W wo 1s|Fr[/thLב>$fvVZͲ*Ƚk:4fg.hVn 6+;}lgubpz|g8 b[(8%XDA5 *z̊_P caHuS9 jhԏn+/6b>( qgCѤruL9 02C 36be$R3RUy ]UVOԡl#40e,c_6M2ktuJl}Qbdt!uJ|(,b'|}1*zHթqv"T;被#aF Q{DR~FlZPHZ+`]etF2/QV9qeosN:0J&xE=`F otcHWC&x+f;iwЌ=wF~=֡Ȫf0dH+2`C}i m񧣇 fޛ\!YR8N)˪.VYZYE(aR)7MGU )iKtd fv"Ѵ6% z)92uzrp#VJD Sxp09L:pɤQ{nmFS=D@m0iђL* Lqܮ Is褞*ݓtܞt'jM:zRF Wx ǀR\GӀ[GnCH*MMSf x,zQØ;ȀM|L!D 4=-v(i2}m m7#Gfvf?DOJ}~? )椻p@~$ `ID1gLAAAAAAA.$4$AcH9#        ֮G1[]~h(sYc6d7NlCk.߽qn}VK[.s,m_ksV3!f;|f9fvViΩr"ګnF;$Ә̺nY=Tb0feNnVtO؛E333)xW P33 "zsp,Xn3UVyxt/9^ڌ &/$| !Du3@jvQ /:'kwzZ6e4/qgW 0cf(/ad=jzZ=meW52tU)*żv*+?zfF&ybF(<05n%BʆiMYӔצSb:)=O@'7?=,UOlo Rnx0ԯ*J攋h[T/ٞSr٭!s9Iq*]UFWjx2#>w\&sN 0˪9}t"s+c ~3hzƐ~L@9CW2V͜w{"2ιIe>œŰCCU_mȰ <`zurG)|~h_!{~3rp4ofgOgR@?~5lp|3 q H1'ٍ  M&Ŝ3eAAAAAA ИA!$   VOw4y%q&۷vm7/|LrW__?ߵko3por&|<9YMȄJҟ+_sWe֘IL߱cceO9뮻.:'?I̶mD ;O}LffW̤g\ٔý{~{o}Ɲ;>ۻkqV޻ww]Ve'ۿe/!C{|p~LQHgdMcRl##gt9zֿ裏?^&{ww7gY+h'fKN[OFˇ{3~?v(sO}6Z ;S="w,|"kJR?ÿ?п*ޟ?mOߴn}޽ÞOn޼h;^]PyCԖsյ7Dwdy9N;b'm_M$!1I?>ޟ/_ʻ֕p|LiӦc~3]{ؕʄve/2S{e|&>[Lt CBG7w_yg{|!S}s΄Ϟ٩=Mk?:˞b"wŗo?__+qga!og|RaOQ1qCzCo,d2Ik/wx#+}}̋]6;_}uKǺ0ѣGŲOlI'￿*ՑBe;y2ȼifNf335`\/ 7y̛d| 棆\ߡe#%2Ge;~fǜ~ӴJQ&Gd F!>y'sgƥ{1,k gU8% M2?|pԜ9T_i9C9wWFjKVV.];g/fJp5?ND,ߕ GKl'-mӎ%c4΢ {K,)s_VT̗KmDIp.mVboa|kɌeKn̋%l`iiITJ%^>ғ[Ӓn8qih(Uc4ji)"ŅEl,8d?*K W "3 7Fd~¼Cm1/nny8o7w9r;ngEۜګnFvǘQq|fP`3 )TAVx Fñ`]? *R~GX)"|~󼜗?ӼIyan dAV[s )q~#2t05c2ktuJl}Q?ڈ|ttddTYmı7v"T;Hۈ4"ZÌ~1Sܹs!whϭd2Oưߌ#ㄒux123 ׆ ېsc!8(  Sa:r)e8DMGU )iKtd^с)9"2dH&%3&%iђL* Lqܮ IsʄFd>pc-jmc0m>"^EId9ߧ˜`tj!O892GLdy]n~YW4{a2˗4U2׈4H2p4[<"2_WWTdl|1s'YV(Taox߬cv'gߝ>ԔqCw. L7o1cǎ||h1 L(HOߟ}__5;^Orߏ W_;9|Hzg˳mW{/أ{jx>ظlmW~܆}law=-|yH|(փ>|gȂ\y問vEZ?Pw@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z0u[0)L/LO^`Aܵ9q(յ($q[w۽QaJzLiiii{H-UCвI-UCiiiQ=| jjП:?_O==945O.8o)RK@ZԠ4 jjП:Bmk>j?-?-?-?-uĺ[-WAh Sp[>8o+mOn3mYl>j?PmV9ߺ~G-Y񤖪!hC@+?HUy+/qZ2{x, wtE-UCXdb-b.okWVJMTq_ O=nsqeO O O O O O C{+ZԬ?{4:5 ППv7AUcm;P.5 W?Λ z<\ r~r`_JX~.O΁`&.{f#ރUCSUtu 9 ?֫#n˞Iͫ W,iI݃rKoGa^xO/nx\kTbrgws;8dFjvk M?£t>7=5:5Af_> jiiiiiQý?rYzU^폵Qﳅ"X=ws1kԿr4G>SUq66ǿ;a׽a5:kv:.pZge4ЩXU':^9t(֮:R~!пbmAJ?wQӬZ=`}zݧW}` qПППППXX7U>?@jQ?cvmQO 8nhoTxTqA Т#Sp:͸hEo"ƉϽP_- ';A}_G9sCnhh_7侬{&ƉƋA\?-O]871>8= O O O O O O O O O O O O O"T EoeOƇqF=E^$  I+  ` > ʗI{ Z9}PLJVc['Sh;` m|L)u¾u 6rk&*̔[ J?|P.iTp_|'|t›dhu^Uo\|ARV( y+`e=m:L}q3׿:-Up:5"K{`疫jl#aҋ[I*W`_,Rg4ʼn|}Wϐ՜5Wja'%w!F2Fj;llUVy܁׼g!+gU=:OW^6k}Os {*>;9u}O~{s.ПLg!x2 >wb)ӷ?K{^-Cz/=G=R|O/?ι"ǯ/䕙27#OZoji|&2F37AF?΄Oͦd$ ƐӍc>0{ei    s>ODʝП[?x'c";пnLAOп*s?΄?΄?΄U7pjiiiiiiiq(5*YXáFf0 пVHoS2h MpPɛp W8t1 п&^6~׀ݥhWTпo1^F_?-?-?-?-?-?- O O O O O O O _ z{ݽ4L-,==/(2R;%#+)KҮ5п􉝩 ߨW> ^)>s4 #}c7BSiiiiiiiE" B"8@Z@Z@Z@Z@Z@j0= Ɩ]][mu8K8ڬk۞Si8{6 .<&3кzbJިڼ۰w [N AAA: ICAAx         Xb"{Akc߃[BgBgBgBgRjdK$${   Ɛ@AAAAAAAAH}53  LtL[ '2Gȼi3{ZUjfNwdy32?"D#sd̑92G'̑92Gy̛d|T/ d^? 7ȼ@2o>y̛d| 7ȼ@2o>by:y]̛d| 7ȼ@G,2 ȼ@2o>y̛d^db{g?4oioӂOO O O O O O O O O O O O O O O OO O O O O O O O O O O O O O \sA2@ZT? V?8BgBgBgBLSZCL Yw*?3?3?3?3?3?3?3?3?3?3?3?3?3?3+/[ puc?GZ<&~0Ƽ&ljܩ ܹ6& $-|sԅsٓORKԠ?RKԠ?uhiiiiiiiiiiiiiiiiiiBյ(o ]6Jп?PaO,?+!mRΉuR5 6'6@.~u,pi!R5-X'yc$- {c$'vE%ԝTRR0-q|6o9[%n ou:ثwx BS}p[ ZӢgv$E8p|\.ʍ'O&;aą#ĐCG ^JBL y~Md@Ap{6AAAAAAAAAAAAř.<%ژ"ڒ"t|ekZG߹&o$96׸    q#LJaS_ ?-?-?-?-*?۝𯾓ӫ:C=}==}XPI[t.oo[!ï%v3&_z,Sjml?_{<='ONTW^SO5<>KŔZK&Yr%n=ZWRQhaB/ ,98Go$|6?c?M&g_U0}CV@>?P"L9 AUA|?Ӣw m~D qz>A{ܑ& )_G4=zҼ]j]&se}KU(; w bE YSGRRr(y?{=>{*2J/*^g35 'x_g[wmw{dJ57Jh ㅠR{8ߘ0_L.ןQ"L9 AAAAAAAAH1'GqAAAAAAAAAAAAř.<`,G`:qeٹ&qt':qHH'`cN;     $И+7@cN@A0$sRs@hI~       I1'GqAAAAAAAAAAAAř.`)R&9{vX+2-<}w} $$PI1'@AAAA`hI}1'  C9_9 4$AAAAAAAAp$            Lt@J^L)RL=P+w5[LHH'`cN;     $И+7@cN@A0$sRs@hI~       I1'GqA52{sgSo4/6z6Лl^lvuo}gɜ?ww?+X|tխg|?[',߸4+ї~Ŀ>ߺVBߑԥJߑ$dnLS++%Fr p[):X.rl^uo#_\\X\\X-LMG迖6B8g;3X&B̷13ooH(lIxfdž ;}2<|ύԿ6Fy wC0adosD|~:p6R&u#|ݧ ;7lzZ驱(k74Dyxe{mbOz&S䅱#q,Ė?8;;U7cÆ;NYF5?ev&kֺqffrjC4_>F3\qҰܾab;3yrGW=uQPxh:BZL,c0YG+~IYe'uprziR ϏOIE_|μ8=ύIF迖6B9d/>scF3\suo#??>6K6#IgOe?ߺ?2t|Qq|@M@,TC?Z j & 6~4&ə`T򁋥A 16}h()h7k)`g_dمۙٝ. _1<: ].AnEeֶ7o?}@ߗz>=k;6ֶxȭȟӷ3ӓ3wL/sٙDxZqV!C)/2&ZWn겙2fNYm]o2mhR:۔%[y;9 ʉp5Hn/E|OeȉȉȉȗB^(9y:ж[ }#ʂȉȉȉȉȉ<}MnRȉSՉȉ!{4̓]r|w[h^Q8号{K`bX˓g*ylXV S qݳ>LXfe]$/Ʋ.\ze\昇.+C+'Y c=d'ˍۋXHnsselŧcuA-lv,Sw6Xnyl\o:B;[A e5ϣmDVniesP'%dDCF\>} y_ϔޮ%sv+2*R XILؒP랗_`C)G½R2ğ<p)}+Jvқv?X\#m0+mmn'dWsv2Uw[aazwÄ99G }';@QWWs!|v?hHn4nиAqcH^m2$;/Sdx}`Mb   (EbD J( ="|~"HQ1@B@zvS!Haߝ;;&,ݝs}w9s{c[2ug~jDfn`,ɇ1 ^|c2< dngEwL5Ȧ/z(YWuZ+]>gd>gwy]yy[s[=t772֚=r2җ>>> >> >8u;OOOO3`+؍ c1Q/=^`o0|`E0 !Pp8| G1`8 yIN'p*8 3 WN48_烯oooo.??? ~ .Kerp \~W?׀k/\5 -ncMfGp nwqN7p; A&DxLc` x<SSi0 Ly;0ԁz0 B,πg, </U`5XւAw&`S0l^ ^^ lo[`fV6vN.n-x/l>>>> >> >>v;OOOO3`+ > 0| `/7P?"`8o[0p88 Gcp,8|N'+`$8 N p&8 gsk

    :&6wp!'./=}C#bp \.W+OUgp5_s p u__߀߂ F0n[mv'gp+w?=^p<`xLG}D4ߟOi`:fY`6:P`X,Xe`9XV kZY鼝'y9OhC#ߡ'WCOOtLZO]X9vTcK:k:OɗFR;&[u@ožcƉb4dm\]SEQ5uU=WՐ3 [.bJO+$^ HN hwA; @H%NѕUT#w'.g_NHt{|ҖB~YP^q﨟:^h].E8a_qiGO'v;ܒ20^\лh?anAaNA\O\>z*~eh_{_k_pl@_|&C<3~eո˿忰 ygd́_UN]5Yܸ&\7bB|+cOTZ8((cKJ_ڍBYurU:ūYN w}ńx+rvqS.Zzش12&^.񿮱{|^Ά[*E忬 K[Z"}th`ңˏqte),:K )W V>MY)hz[%N wr@%XT$8,INTV6E-IĂ._$)u! ܢ9:0makIRM,LϤ*",v|QE^ެLd``)vmߣE4Dʐʜ\wy45OKA[/_!#Fzrno|4:y'kL#7Hw2N#ɴcw;v~EN _G N hһ0CEZL+3M1ih"JjzfΥњ;zJ _Fs:C\r i&OGGGgj 24mVv{ƗQ #v\je#8C\L4FCϐܴw[n{q ̊$6Rqŋ'ScЛl\b .:ڱaxH~ջ|dCˉeNj\bZӻr+}[[8 Y-HFVgsMn% vsTl=F Qգ!hLB080*mNcđd%/ ӻ(YLS9'ssܿ&eom>@Ѳ|ɠ˳+/)d+qh5 %82svԜ<ȑK;e/!p@;PvW]yNb'J;Ws*ԡ'{ yt1=qj2ƳsG8Z~X4I{j~eT)Nz'#s_#}.컘{&+ړ8O]sD`;uNFƆb~S#x׉w227\h<:sv)ܿbVܞ+T{ÅT靌LK=q8Ωnlw0 N hwA; @zaH8Ϟy]W}^Z{B x\w @zqC:; @0%[#}a``J^ ,2V:.2(`,Pd"+ L9NFV/kL̓r@xeעf`SR6LXsz?١а{w"!ʟG deee;#G+ÑEH9<@ֻ ,!+p<wY,Kz'skLsi.0NAʎ SXbLv' r8w#qnNx>j/V}'s{kC](֝?/d\\C1H y"mÑuJ̾Ny 'XNzG@c[hz.qmYqdmƄwYs;tIdbēW{ޯHdnnw;v[NFFfkw22@ o;@hz]DݤwA @Hv@z';zwЗ $K<,[K01 TGoҖz?Ѝ++=H HcY,3̈Ai|K \˲*5͈M=)<,GJg)>O;3t aXHVJǰ ~ͨ"}P;]J,q;2*^beXPvn&Yӧ0vߖ8z/JG?K"ʱFi_l"P3Ո)~ TڀjBᒰ GrT/db};SSSxb\,{Ed~a/ uNo1ӈ303"z1lA뀂^,N 4ʿlĄ?^к_߼÷7u_踾Enu^ln`_X7{%&ޮ!vw*Y)b Hޕx`HzA"x l^[-:wN;z&3I-z$_-gz*]wv }z;Ďytw!j;zw,vox il\@hL؊fr[N=6iOMaHC2 l7(ΰɹ.(ilì7Vz_ڒ%ީϏay#|rG"/so?I+Mr'Lj BBS}8Lm!v<". (@0<1S.*+/+s,+ف=-^˯CKzzKm>> ^tӑ'_\ťhP-xH)'1Vz)9n0|z΅k|;\pa|:xJ8]#5]wu޿Q]aQ z7K`v|`ػr֡!5=➬M45j!Ft=fcއ^]oq':*}L4zFm>L3}`+-lufv/wf@f,XO"vUNcbVs;vP'U(iFK[rvGϴeB/Lʑ5srn$]/.8YcM, /l;o$ ٳ|V`t T#@\c:Xї' Ҥh+#x YOE,`NyȤħXs!B1ķy&[-^ R٭?? =yZ=w~zOX5mOx2Gs,.lݬ1o0;ԿfQ%zFҮc2u`MFj6K .r5l|6syOuرLg8b  |q/]!A9k(Qg}%g!3tЩK/\w@mso ͽ_m?!i;A CI0ȯp 8g bPK)4F%. Y\;_z Y-hywhV = TX!栺(DV,37nL[:@t "]d>> Nv)w(fM\1v ՛CCy'sjݧ`?@` KB)s 4>_naO3/c1ŎR]6(((璗팤w>0y '7zj|nf3 |x@Gn{;]XbA|9/ R߸O̻k)3ىMRf1,eYJ^H|G\Phvy+>~™L[3 oǽ7Qsã z9}[>; d |w % fy8 &XAͳqPwһ+ 'S9.ug}V4ޏ{I0|A)+A꿭v7ȿ X"dyl97tXE`1x< `XV9!ocp1\ .+O*3?` /9\ ~ :oowp_/^mrxhmDIg8ĘW+F/c;E>_ysk\77tls֦xg,yk}\b!L7c\>s ̴Aq=/`qI1", `/e:36c/<>1҄a;|&ʛάm1p?8.2Ç .趂㹕!2#\yQyԒCP&^L6τM*^#f4brMf\|DN30ƿARc o'1$XXTA'P(Jr"'؈9}as #$@r um7raI=REsmv'5%|;'w2`^OofމN)M`R:61\emǟmOϦfQ la30}M{ak+k#,tNzasCIǷ9=8S0x|K|7ǧ|飣,l<[~a.4(C:st`yeik6Ym.dSP3OGDh#P~YTuNt4gl)vM2M/^/ҕ^Wr]9_˓{oAQo[Q1؂fܗ81swv[]k`gLe1﹏9!g @qNY-Yb|շK,[aY_0.+Rd[Y_m*  gGkPbV7:^(ULOߠ!t:ftuإxuB_%P$8cwkE #TafG˂ELz:ɜ9_G^ŕ/Ƽ+.1}]rou/@|B2Y_Ryr"t~/&LoJ&r1) =9}BSS8LaF 0O [BP{(ǽ0fee_+b.rݻd, _c(ډ)]h2x|Bd1mL:nf)g|YH$.bLt/0EU?㮦H0)v,6N214 qh߁<iqx|8 SH)_9'xεSظX˙Åm* 2"*X-6a0ŽoE MfnHcqG*feI*pM7pߴC /9S>j"ϵoc+xms )Φȸݢ1u<2,!#"Ɔ@Seh+"H?בǺ r/90=*5U=p7&(no2FW(gAJP)Z_]P)U&n'W'WΨQkAk\ xPmoHW(_]kuhH Ql#:N^yjCbiO>ŬB|dŴ9r7_M "J1]Z!ntxC,)՜S1nRGʱ"PDGGLƚv3HB-:HQGߋ⯮Q5FW<S ?_[+U"AJP)ZşexP+Ak_S=!߅>2 }Wc>|.7Ŀsϼ#< }%o\3c_yQo>ǿ1Zyd ]pG݃φknV4n+-& Zԋn %Fİ\E p zenCA |APR1TV.x&".Tx-EԸ |#/jlB@PB PPyEJwk>n*&@ `8\J222222222222222222222222222͚7@5 @ h ZEPjiT @ ASPơ7@5 AP8_$@ @ddddddddddddddddddddddd76\V@l ?꤉iRJ,+|V{͞2n+ϭR]b>FE-LˬßYCdrV6߳TZ +c]gEwL'lV-&)'w~J|"*ؘR9Ɣb#FO`p :º_Mr! 1 K|BSY >Ɓ 8i?k-Wnyg >nT'=1qycFg3;&j9޳ݻ]4y)=+KV% >hZ'ߚ^;J=*r`5x "mnpL3/e|6}ȓ\t/ cWKJgC8L,\2pp܁]GBfgC{Ofh{gn>boA>81y͝/猂rsʙߪw=f++%iF!FvXnNi3Q!5:&6ky9 '';3ߝj}@:ts^{unᨮsZ_]}w-7~%m͹]ҹm^/>5wJx>(7j ŊaBdisV?tGwTo˥`59or&N;-uǙ缰Zen \ Գ.f#.F* {^`zޑ9qLzAv-wrOݤ@.qO~rs;֥YCM.qk,~ ;}>ݣMƀG~Nʝ;n\g}DǼ維 >Ǟx/o|뀿jr$ϧބ"1CֈgGw-{t;n߉Œn? !8qh7Nן T>D';139!-r47m5:֯ 򬺏t9 tnqwn^&n{݉=Hyk{Hv}3W'=u}v=Ⱦz->PAΚ89n7~ۡo;c;u?w3he%VV;eآQ9RC=-fKɮ uhVrO1!}~gGSP+Jw S,_q "-SfL+>Anv R v׬Ň K/i9 f]K[~;K4U{]i/>_M{Fj+%Uxׯ$e2 ׻h 뭐U}׎sIب݌L1S]wbb\)i1!!1iT$P.aAxLV>GDy"Eq(2om^(xN/+D:qA-FA֗m-څuuSf.]WmKCZL)V-A}GXU)V5 gzߋoYM8j%/A9- ={&/_^gK׬Y{Pg kD)'%xЊdEJշCYٙ3ܺ55KN(˿9E`_! Io,\#ʳVWQ}O_ׅjdP_/{_:e52>/oAҵp .0c?5ns?E' }\e2mJ=pv1V}w|]<ύZn1-$aō _L{iɂ ľV"=D5Ź0u7@^LT:C+ ‡F,gvꍺ 7ް75.W4aoSWkf.rx]`%E^by^(1b]&*x);p RvH۷}fw7o ՇFx]p٭sOCE -pxlԽ{[n >|&x\ReW_| Zu,CGn𞢍`(,/m7=M7<]{b^7~ڡ[Zp>:W4 ^ty6~.=s~s=Hsݫ][nҤo{1POn>|rg>|\y/_%K/_|jp{5kֻ | P>FMA\ |;wP#Ap'C?~IpgS.π-O,9p7>`?8~ l՜AWu7o~}?s/!Wap [wA? ?0pGGq8xIx x*xx:xx&xp <<<\^NJbR2r J*p lx_^ ^^oooooWMp xguzN.p 5hx_~n >|PaG>| Xq'O>| Tp[ig>|\y/_| ReW_| Zu7o "-`/Vmw|^};w?~QcOw?~ +Ysn/}~p'8~ 7Uko ~]{? Sg__7o߁ 3# < <<< ''')iY%Rl\pxx>x8 ^./W+KK++)j5u*F&fp5x+׀kip\7M=^Z/O[ /x?V >|(0#G >|,8'O >|*-43g >|.< /_ |)2v+W_ n|-:7o{fp|+6;w |/>;? ~(1'O;w? ~,9p7>`?8~   ~*57o ~.=? )3/_C_߃? a_  q  T4t L,?p)x6xx. <</+%eUx5_Z:zpxx#xx3x lk48׃ww&nplux_~n >|PaG>| Xq'O>| Tp[ig>|\y/_| ReW_| Zu7o "-`/Vmw|^};w?~QcOw?~ +Ysn/}~p'8~ 7Uko ~]{? Sg__7o߁ 3# < <<< ''')iY%Rl\pxx>x8 ^./W+KK++)j5u*F&fp5x+׀kip\7M=,xo>}>|5`!C>|h1cǁ>|d)6SmO>|l9s_|b%K/_|jp{5kׁ|67[o|n={?~ a#G?~ i3gρ_K^ e+W_~/m;wc'O?G߀\  #xx('_ ;x$(hXp'/p O  NgggKssey$x!\/////׀ׁׂ׃[`\opx n7w`kn pK^ |@A>|HQǀ>|DIۀO>|LY>|BE/_|JU׀;_|FM` .o|N]#Ap'C?~IpgS.π?~;~/{{{{_~M[>~~CG??Kpkpxx {p1xx0!?< <<+7?ccQ1p<<<7x"xx28  \.r"p   ^^ ^^oooooWMp xguzN.p ΂I--{xp+[>|p#G>|x 'On>|t3g>|| /_|rp;+W_|z 7=`|3| |v;w|~?~q'O? ~y `E _ ~u7o~}?s/!Wap [wA? ?0pGGq8xIx x*xx:xx&xp <<<\^NJbR2r J*p /x x-xx=  \ 65mZvpׁw; Fpx7x8 ln 7x[>|0 > |4ǃO> |2p > |6/_x?-߀x E[^ |7w?~0? ~ 4pWσ_w/%ppOp/p2po ~ o]\ZaMŨz0dQϟo{mq^u-5=fnlruY֙ssp9·{6m" Pޜ! ҠAD=@M' zNA5  j:AAt AQP AD=@M' zNA5  j:AAt Jӏ?h_: GAݦ Ut <30ٜ^r'{ҥǜyQga3=묉 .XnWR PH_|51/^vet "AMg`($@[o믿b*+.[֮ŕ^x,5 / _sruW8pnƫn*YǕ'{,5 / CWz ~uADPHК8mRa׽u\3KM'" WZi]kfA54UlAW#t bPHP~ 7|mU*e~圦sA30Ox!\:tND P J eZ: Ћ唦l,5 / ׮]='Jӥ+(M?gAxAMg`($(M|7ovW ZO[|NtB͵63Y׽u C\2KM' j:C!Ai:D|zzȺqx%Z/54}fz(8oMxһ],5 / hMڸ{j:C!z-\3uwL_?s]΍Æx= _OMǛcxhPќ^YUQP dJǩaPHAD_ *g\09Iu1dwhJX؊3z ['gz##:EX؜7N*Ǚn1:*BN#ׅ7k!AMg`($TEm3NA.G[ɀo> 3xpF@sʿ(^.vX5$2ׅiaPH5ntC*Dѱ>(+^*zF ЊqNgf $30z?V%f?­\sja7̧5PEMqiPMUmS{u8cr۩+-3PqÌwyNNk:*~IVs^XyY3|W/P8GtDѕ]Wuň^彲e{4]%ս>Df4Pp^X#gi֛ lz IS$r% އQ%U-WgTlJݜm3'TN N)kL7]^yϚ*vk5<*ntZ d/lVNjs]}0M P鹡(ԓ,?ATYh3!KkQ캬jPA<ߚ9jFŲF.zj:Cy5 ԑIkHܨ t RGe3T3'P He 5 5 QM tj:APH: jz2[qU^G}CT]\J?zPH'r"w *8j j:C!.?҈( rN%;Ʊg& [&&gz#c:EmO[:ŴYwj~iן*IW k՗䏌"|ӹ%1L8T8a'C_0<2PH(ۍr> :޴=tDA%@Uu*-}"mv*lެb/_UN2Y񶵓í*a/]aȤ>w^!L8t_#cGz!c3D82PHF7\| ;t1gyg83F:k ֮[wճEkzsNaߝpjg&g$ @ Bv_mc3Nu]e5}c*=e?ld[ioL'~^p\&fsT`dItB4ky.+\*قϦٰPAjiSD)j/4ݰv0ƞmXFw8&I9ET \dDy@Mg`($[o믿b*+.[֮ŕ^xlqr&trz\NP ͠ރiڏɹgS5fݟRSuج4^B_c8W:KX<'~cdػ]tv J,xL!beܴ^hd9$j:C!Ai:|rnnCq ;[h?])Zo58 -Pih~&5crt n`m h)f\gKZ,-DX*ڲ UFt1:iuAXÍdC°߰'Cvi%QBP JV*;dÕkR~z!)/gңbPG<30Coh65Oa׽u\3[e f?sO@M/ #$q*Oj:C!AiVAoZ津K_%t:(Y5Ehz(se(<j:C!AiV)AWP~ dK4 AMg`($(Mn6@[oj9MA54}!跬] h)ׂݟtBttÕuLNWi˖R PHКz eߪk(M?gAxAMg`($(M|7ovӖ/54fsu@uo5kx[uFn%R PHP^zr^ɺ f5/ATtB7kS7ި>~uAg87KM' j:C!aӦ6}B{zorm/j3u9޼USo[.=1a_6IpaaڻWy/6D30T(Jcn,Rn qʍ=`ؽZrcSg_W;٦} RD4 FLMq:7!^*6-FFT28h3>$&W5FՖFr-I݃t RDnkSvr]Cѿom6{t #39wm?]iSEw;P:.S {WQ֮vr265#26/N j:A`(Zпys}8g Mpon(^_\?96:zw|j6|BQ*/T/3ɢ(1]j:Aزi ̬ 5 dпeY{tDӶAM'*j:AD2DAD=@M' zNA5  j:AAt AQP eP, *Jk,C_Ӌ .EfVoD;8qnVQ epHZU7AM}(yk}qK?-UYrY~w\{i|ˉC ާU֜w[zs^(GWj-{eß}jչMtr*rw| ӉbAM}(Ϝx;Qco\6qٱskr7:Ӻag8( Aom޴]wiKPkʣw~e'l*l\~Ҧ'Z8~dUGbwjxg\O8oSl.DAM}(CǗ N09 MpQ3Ko9Quh/zkԈcRq=}Rg=j}l`1 Uɍ2і 640N䉌4}tlNemik} 5=f%O:5 GTˠT9ϧߢf'aCcD|9ᆑ$^02T iZj6fW´Ekl sWA_YV C2MG-EN-?Ǵ|w8z'45> nh|ˉj{4>#] "d=Cc#zfXpbfIP+J{OM  5T'*Hӗsӊ3% yce^UOбF'(V3d̩׷h  u#:8ۻҔX*ʣ߸rf,?U fYMs||ˉ.G>IZ&JM'EW[/s4['ıp ~9mdݗ R7-߸sOo9A u`,8 ַvŽ!P `qoKAo1}Nhzc\qA*S1'n5}zj-S]"睴e-\%ߗ,mIyZЁsOo9AkT5^#'54eMW^p}X_ͲꀚN|s&]M~&Ä{WcY+WBy4}36T]u+ldȺƆNA$#W@M'Pkʣw]r=.t%w_5yp-e_q Aߡ\#Gڇh:zߖ[+/Pʾ%@rOkӗuFm, )~ݎ_, Pkʣ雚譯_~ƝL; ];9n%Zљ3k-'*iz2HTڇhz^9/Q xvc_4>i,lbwf Kc̅q/#-Յ#Fv'>=vBX3D1Q,͈hX*4NmJr/69L-OI}lmk('Aհ0{5.gZí8LBH^?TW (z# O'o4gx@]/q{%rݴLp d:r9Ͱ6Ңt Rg۲fnkw@5CՍz! M726 +݆Ht RĖgA`9-8/K}T Zok(yMRި4/5. gZԜgd?(dg!"j:AU薄|c@7nԒdc#:@Fc? y>ݾFkF zvF?]ii{ w"-P H5r1԰1*-TGg5t B،5~˦)FEM9q5 PQ,?XDAQP AD=@M' zNA5  j:AA$6%TLJ#߱bb %ja&'54t`H+ӪQ-t-;20N.ܮ³CTJ¹e(]M?/W^M]6FN LO Ve;ߑޤ$uXVVIޅJE;m,vZRj: wGU jpYA*]YCWcPg w>6j4O,tmKG5]WscCHMGbtl@P'Ѱ=ds/j:3rix[FC1];{]ˀ[*i$b/3 nZJ]MŰ騿ntjP6Gt$pVv5=cu SӓPis|MWTs<M7 Y݃?{p܁z9gdO@t[EjT \C=a[x"j\(F%޵m2x5 1rTvht] F)x j4Fk@꯬ԓԍUe:t%QgDUrx(sIu8AkHtaU +O:%l٨w9צw`؆N{V mnqMݬw[{ "׶u'[{ַDȺIݣ鞱w?–j:Q-_-F kunszŝ&wrw@yu5r2_ʤPM|+1Wtmʂ4@SI;;ƍ95rDATiz1oUSDϺ njg*ֽ HWe6Y NMĝ zIMKۈqurJAt5(ԙNQP AD=@M' zNA5  j:AAt AQP AD=@M' zNA5  j:AAt AQP AD=@M' zNA5  T4}#Bsl@߷\9rqŠ}?u:،S*q}@sxx0n\1q@f)ط3NIsm0r!R=I42ȈQƝEGAk9T:bo* "H%Zmd.gZӝO) mi:/cӗTIk/At :tZt}t -8I_I+m))Foc@c#y,5 ѹ;TȹnKػ1:-㔢٩-E*OjE*]u=T\85]KNѵ\ӥHtORIgΎWyt졫c~Kkz~=BAi-r٩z~3'u.ڝO7 vJ'c1 K w9 "#2VqCNČ{OPpJ \(ȱtmgغw-0[.AGmaB]9ٱ͐u7W,' j,ֽ;"r 0Ŭ39NAi}sF=7A+xyoi+r^_@M'*;rAQP AD=@M' zNA5  j:AAt AQP AD=@M' zNA5  j:AAt AQP  JLNADGYfAC.陲!łJժxj9SܭIe,9y TzK KSөI*]Sө):yB^PөV< I!wt/tjzRJWtjzN⤐;jtj:5=U+pj:5=E'BqR5݋8^|@Mg`````G300000#P tz{xU сP@Mg`````G300000#P tzj:C=BM?3 (-kzx ېCgo@ԾkA&AD^tCBMϡ 6`a5 C nCm$* Co #VA#Xz`hl/h4ۍ-]?m!U\9d_ܩR*V< ЯRt y8e0$8Ul jxe%)ᴢb%ʳ0;,*Eq@M/t5=L|:<%AMWgxD7W4>vl.lo &W2,1r&* #OVxo)H39.ttO677Z_94 tqK"a%Bn躃Cy.l%S[rmO?>9ܰKըa~lq>2*Hp $z&^{<qn_1"nP.gyHSM݀&5=+QfPgس֏bZB8Em *E2E=9~[a:|푕,n'EET4]z ;M;Ŝ1*z k˙hdijZMlYnRC4]qz8('DD1fXq:*NƏѶ0 `aa3ng8/pV^_eq<,*rHn;O:]i[X?ݎN?osY&KÎ~Mx֠ی]$7fFtۯ=d!|cX63yorP|N(|fyvsç4#,r@=(GeOw6 bcToMy<0*2Cn|GV^ۯ]LQ9t]G5Ac2b\d+kȄt Yʹ@MhݻtvR[eZ]MoF{\,GKU†z0 *rg: $,n7s{|zmPl '\9HMϺ 6EM'x ېCKuB3$HPˀnh@9p6,LЀPs(m XDEAM/P…P0^tCBMϡ 6`aE[ (-O/GtAӳ/m XDEAM/P…P0^tCBMϡ 6`aE4]n SI5*~CI7 $VߋdD%>E(sޞQTD7r-YũbFMR•TT6=+sgQ*șGjz%\iKiEUK ˽;#vtjrz&hMhtnf*ʡ~k ^ NnFe/uRμUɠ|raU]Sݘ4s#1衛.o'qn_1bF %-r&j45-ek̲3Gμ;j-öt(%O*^={}”WIyd=շm_Jvy2YTDLӵ΋ݷ4p6FeQoa l컜F푦:sϲrrӪPNS끳:)̰.aXșk+AQ9${CaR&64gxir]4ۉtrh˨ˉB,7]o)μ/<:nKأEm9}2:)Lʱ0/pSĩ͐ôn'EET)kIk9m.%m45土FsmbE;,^'Q?]+i~zNƏϧ+O0f8Cw9JI+Pt8.IG)Χ‰YyZi4]~;NYqb:vI:)Lc>ݳB.,smFZ˓ɢ"*׽QF#h UV;ۣy~LHWu J?Mmj׽{ `O+吲ݔ^1׽:)[,\v<׽Χf>DYM+j fI5 ֘C nCm@M'*,4Ss(m DE׹QuE7Jpj&QQB6Gjz%\  (e@74 Jpj&QQPˀnh@9p6,LЀPs(m XDEіb  J ])8Kpj&QQPˀnh@9p6,LЀPs(m XDEQM[$TF| P<eEj[=:/ν%W ]"ʀ2hzU*6tjz*%r:!SMϢ3=^Pө驔p֠f.ϧ( !~wkcKedӵĵ%?LQ45ӝkZv7p4R]rX]6MIǁKuE:d5Q ݷS,ÍfHskyy^cXVsCIM|ME39؆JHqkľ˙a2,vgR1T[U-ol~"hqP*Mw* (j”[ qQV^Ӻ]LQ9$t6zSYаUj}3;TguNI+Pt8.9Pʏ:]HYb2FKJcVlRizt(NE:7^ΫtYJ̧ Y.O&;V7Ac2b\J{ B }sQu{Ԝ׽7TݒqW&:t_8N +٪mYur 6jCd- gqqkkb3ŕ{ "/Y)T5 SS)voX)5H,4tjz*%-Ήre̅bQӉHDOpr#5=.܆ڀIT2jz%\  (>}[[WtCBMϡ 6`aajNM)nCyg]…P0^tCBMϡ 6`aE[ (-O/GtA@{ZQpEyk6DPˀnh@ :t鮅@ @M/)\R 7 ^nA$@!nH wTHa濋An H*\R N( ىJ3EY+Ke2 N{1Lol %ί4H^ Nj)]<SV.7q^Y=-Pjz>틧eSumgad K$陠1"vn.7#w6sWk !G)q{%``p=auNq#t7?ثĠqŽ+ ڋTN7uph 8spVIʜFr.k[Ds#rdL QYyFYhieM1o*11ƒEҞ6鈳q=Qۜ8-FWdl6W8f38LZɪz_OxJ[ɧ)@ GTFJӒqe/; 8'^Hƒ$20hF{kwJoatNZ v 'fęk+ mY(YvuhO9-/\ԁEž.7T E)IYs.VN#Н}gao$[Gid(tK_bzcd4m5RCʳNZjkz0ǝ~tH G9tΓD#5=2vkgG|dQyA[zp"9M7+%],iIdTGu**#sͅVg#)U=o<\QYyǁsvFFmMYrnIO> ǠdaQv.Ixde'a?=O5]hOkn*R;`л;upMW|3J)@/kMhtg_^Jip&9?%aU2;t9!j_qR=0d91y s줍 )f { <鹕|ꈯdZӒ~[[WtCRn@֡(Ow-HC\AQZ@#SpD :t鮅@ @M/)\R 7 ^nA$5 pI-܀C7xQZ h{e>h;GUO9wq{S,OwHZ~tcI5K&l3e3QyW_J!5}o=\a$ CZ9w-5=f'ù.bq&ڜntcZ'>`dA]?]% ^I6żIp,AlMG=sqb[i:wxױp^)o@cj3i9h'E[̯."xgXJg夦ZR]ۛlj7.{!Se]ȽnWuo綥"(Z[2ZpHZյr.̶J%t _,DX[YhB@ۓ84<0h(5tsdQtRII-m[.k=GC4^r<[]iaN[/q00r\^ܹCq6On+~綥^bT5Jۺ07qq=[gW)~w| #Fn_00B@t4m5RCʳNZjkz0ǝ~tH G9tΓD#5=2t;rHؓ5czE9=%ّ%yBŒ^|綥^b;QZߖld0MKqǷPtFtqGКF;A.cV[҆[Noqǣ:듑E ۹p&-㑕џtd?]WpFSe]GjGO1\g59.M LkMX#mg?=sj~Xhz_#~ߙ޽;IoOI@Xգ-5]Ndaj_lZ|̑f6&鿰ϯ."bX̧Gj:`ZqRR~Mϴք5Z9}99E?_ab- H_Ж87>dN5IR\4i`*R3} )2G{o4ƀ_ABM޵LZ i?{q/qډʻJ=RӧpR3OQ׽kS.*a^R k#w\ġA0FuAظQaQي]i D;aad/0RxEXuͰF5yo{̂PKniDZ" fc2'ubm**gZ͒mn{. f/Жx {RˍctwX_xq܎mjvBn>5+щ6^v dµݼ`5! ctKىLk(sb81e;g͹F'dL QYyFY 5qthS̛JLd bk:As[nȚ]fy3wBΤ5]+2hzZ54~]kOWg;e];tj~?wq4=Y#_#+xcX 8rߤ7$ Qt.'2z/~KPzR,٦yN}Li&;icBʞ { vʒqN%*|zAokŽAZ+tuȱT4}*|z5!#5_*i9Vv # 0qpe;#N'h$۲YCGLo ֙Aiomҵk53Mhi.zUg.Se:ZhY2׽k3|~( k@u}Qiɻʹ=RȠ\rIyZ!w"a{_i_i'I~~iK=xjJ4oOg\›*tկ:OŒ_nvӡy^ Gzآ) \Ӄ3^|p(M4pXFGb.(|zit^VKXgvOUWǗ,Lc>= }e䜲^uv<, uq΄fg7]MWIcV6$eUa>Xh{ ҷXͰ:t;Qr>H;׽8ϊ"wOU5*ol哸0Ց-^J8wxOX OJ<)N ֽggg7~z-ȕTXM+L*9sWLV^9޵uT呚u ')f2LMO 4p.P)$j+K>Y9q) i%5<&5=.܆ڀIT2jz%\  (e@74 Jpj&QQPˀnh@9p6,LЀPs(m XDEіb  J>ːMSvz<n3X!0]M/%0 (酃%0 ( 5;n=3{Զ{3W#Ho>WDv<8G@MJA& 3]̞jfZnPV]cd^J_Y]PӻĀfWn"fZچC߾2 ͧOkm^8]b@ 3 +],wa t~d蚃[2pDEяy6zp+'n05w'=e92օpW>ihSņu=6x~xWaͭ\b+Ξu^m<[dW¶'LWU~gJR18妣cuR?A܀;蔨DɘƉy҆wS/;]F;N.&c,Y$t]uK|MGFMtdMl8q7 ~SӝIA3Y|bをh:STHȜ5\chj~gPm0rS[?}ݮFjFJ$k$۲PƯ/8u8CO饑GfPGojҕ KS'Y'-]78=GC4^r<[]iaN5=, O[.yC_~1y8# Eif[dL2*a'D딫~թ|f&.NgJ }gao$[dNSU3\B@t4~2v[MTa򬓖ۡ. q'5ݾ2Ҁ:rIOttஃ]QNQNU/ʩa=' 2Ȫ:EMwf&.d0MO0J$k$[֛KԆw8Gog0limI7bV[)ӥ1({<~>i@XT`k g2Y=IKM_3?Ԍ}C:2f3α|_ӍSJ~̭L2*a'ĩ)NMM$+8M\̺V?]>AϜGӓ55"GgJ^D`d٤ժ!(sKCMmvP~ \|. 3@uxN}Lι'MlCjƬ:bv6#r>xN^c.IV&ٕ YRϔ04q1s:R1DG4mY(3g΢ߐtgzvt-ZL֮ۖkuc䙙Cj[v{G)~͆,Ԕw]aˤ堐CitU~WZcl? c-/Pg5堧Ҳ3Euj8U>SŒ,7YnaQي]iddL GeȂhVq"2ާmYD6 搴t]u}~z-sg;}-?Ǘ?Z#癎܀™<>S,ܜq3 ɬ;)V^4}*lSsoaﺩPKPӳ.bˍ^ dgT S8['ȓAQK!lHR5MMOrEfֵϢ$.mمSY'`h6x%3<n3X!0^8]b3X!0^8]b3X!0^8]b3X!0]Mg"tCRx 7XDEіf`  J /bDS} `+&QQPˀnh@ c0 (e@74 p IT2X`$**jq0q![ShlX7 8yS5+,Q+|Ul5 w`l߉0KL[!W+ oܰ8y/5 `(WeaLy[PtP+i|8n嗢&ňvÑ7߸~;;`; FڹO%l3S̯asEi$["msډ"C5?EwYšdtxoj';iTI㹇i\QxpY=߲a%둵Q_NŠa gj2#ضsN}ShWP%CeY>QX#v 68s؀v{G'jUAf^),O?a*v~Uแ|:BF*ʴY( t՘˗+7뾒n{D68ht3ShWbEH;xؐmn:tmIYxQ,(܎|kjL 3swu\QGqΦᚘ9A8Owkz>EH0sؐ:m'1FSL᯿o R*gaYBF*ܝie,Wj-9P~8bMT! <;"~znEl$a߀vtJꛧNF|CV Ⱥ2RQt>~zrEQZM׳'zzN>ߘט=z6_E^ Ի>VW9]ShM]4="r6JcviGӓ.|Ru5]wC2bS'oTL+f(N"GT \~8 jEu+$LFn ,t]&Gkwqڜ9Io˥qr%>&0sQu~oCujPRoT?=ϴY(JF$Y;wF%G;Oϳ<Bh+/ HBZe^SSiֻsGM1E a{_B8AAq4.ؔ ϋCVmHoP؅A >V"gPө2/l>V"gPө2-J@bDMS6+ڗ %Xꟁ@MܴN30dg߾k떌*,9vcn?;tMc- W5=930tfN]o< 睨7.۸X`9ܵKYwXKUPpGnZv¦ Nx'mZ>qrGA[wXKUPtZX!p &G9jfɱnk{&U8mMf{M?qƽ=7m<^E6mA( . p-eW:q:nY,R%/];;;98'A/ ωN^#}Ġq\/2ȴU2ibج98+PːpQNxEyԕ{1x:`[wȸ%bT??-l /VV#krr9!koHSm ֚"ɂ[sV<[:}8PVc=w}v-kiD~/ˮdv:#lK6hܵ=uTKvѢ=Uu+s؎O,PNN@)Dtb0PWZg z8.rF+ID{qfjJT|BPpi35^q?Nhzk}9fݒ9M[HMGSybki:u^ O{lmmk˶ZjKڪGծ _[PT<_\(.xS]]TI&x7;yW ;{&,: V Fe6ma=$]($fܭP5j-+|dE>D{/O~h_/\{AO[Ov~j6OkՇq\G}|yz9̻={!{{Z 1 6=f .ڰqKlw4,,&mz‹.ٹv)$\!6;O޻=RslRL:Ӻ obލ{1=6福16KNM0oΛ3;TuN) 09Yɠ.u:m:֙տ[\t5}#Κԩhq_W1ǎ~wvo['s;<_xEg(jto?~ooF/8f{Xq`t.as@g=s}6p{Fm0o|^#kcrmS$"6]`(vmzӧw}~0޺ⓟߊGJzj6o<+ǿzmgLgZvME}6!{ _Nhw,ܜ(Mo*i;eGxJRsrm:}Wq~k[-|Uk?-E;&M޴Inݩ5Љ'8O:>zٲ{WldI'])yy][gԞ}n֋)<ݫצWO Y/^TxWꦆ/u[;VѦ'Tomz2u7%)vmzK.DԵuk~֬Ch?UA^OTåzKKKHs^{7p;;;'L0z#<8OJвrRӈm:CB2X 6mzJM_ٳ]?S~stծ2?mZ~ʔ6]j_7⧟}رxOJЬj= OIm:CKw=pᱵ;ׯ ]-[ M݉mzc4Ul٦n]mz{{}13_YCi3'ˌﭭWhO;'b/_p]vb>Ҕ=T9}\hJ lpkzn\-ŐrwKJ~>]MS6m!p.AbaFŝڑ #z54bK:~ Z7ߦS+MO~gP0$q\zB/Kٶzimu'ilӳڦ QR D'$;\Am^jhIK;jf앴eȓ*)  (bm+TRy d.skئ׮MK."'TlsA^^JMm:tP]r%X!$$p"JQ諝+[l٦Mg6m:tlӕr驭UئMgc6mz kg6mz>l٦6H!tpK0_I5(ellئMߙtP1Ha$ծM/`IcmBI+%jľg^.`6mz\0I[p U8emz} bK)LmzC*lK٦MOT bK)LmzC*lK٦MOT bK)LmzC*)k_Cs?1]A#2_. eA]ks?υ|w|? E$b///'Ý)Tx||%< <__ _φooooomp ρx>_^ /ww%Rx|/^W>x ~~~^ FQx8$4 ,<o_ƒ ~~ ~kpn\_ ~5no ~3 ~7?0xOß?  4_ 2x߀G߄]x$  >!#O‡‡?GG? ''¿OOO7ç-p+||:<?w?ggg> Woy//'Kv  wSitxo*j?Lx| |-|< ÷·]p7< σo{^x||'^ /Kerx||?^5Z!ax7GMcS3fs~~ C6E%ex; Nx_~j5k~f-[o~n={?a#G{?i3ge+>W_  6H < ><>>>>|CG?> >>  OO   nO[V4tx<<n >-τςφρ 3|. __O/'×p|)||9<O++ U,Z:x6|=||#||3| oonx<½Nx! ^ /{ >~x% ^ ?kC#:^o7›''ggx <mKvx< .Xs~%*k»_~#;&[o~'.{ !xG=?$7)gŸ?"%W}_ m;wp=x}x4|| ||0?    ||4| <>> >> ixx |[  g\/_χ_O//R2rx2 OWW3Y5ulzF&f8 wx.<{Bx||7|^/}Jx~kGup?o7OOOOyx+<x.;]ހ~JUw_~FxwMo~N]AC{?IxoS?EK_<&?-w#&{(h@ `!?>> <>>>9 (hx,|,<>>>>%||2| +>n[ 5 >> >>#'_σ'||!<_ _ed< O3WWg³kk M-p 9\x|;χ ;;".nx1^ /+*x5Ï~x=? o7- Vx///0\w»` ν? Wï_ ~=7o ~;w ~?=?  8 Oß? </_  :/ xMx[߅GMQAC? )|(|3x |8||$sQ1XXx||<||"K$dWp3|*§ pk7o|&||6|GOs>OBx"|< n;Kp'/x <__ Ogτg[<|+|wsOBx"|< n;Kp'/x <__ Ogτg[<|+|ws18ΆV!>b f_nT0(%̹q@Fj01w^U3-+Z=,N=iuk o$ZHծ;t1Xڊo]짯2>Ժh YTmڕT_Y#ϴ"1C|{G:-VYA^$EY ;GXu_r髮ǫ?Q~[5]WFbs1gܛX<jd+PO+}Gȟɟ"28埡aтkvsCXJVOYea[6jCg_TMDuIi٩6x  QxMC 6a]KE1~0 ;g<.,g 9g 7K\O6oRLgzӖdi/A[Ҙi J%sd+۴Q>ig(ǧm2""NqP(Q%ř *Lr\H7A;XٷN+(%#ErcB<ܒ+2h+, ,ѕ^<1?YMm. O@P/ݴвTupOo"럊Py",1B{ 5_Ru ;9#͹]ki(KbfSsUp'`٢tf’Mu5;OԶ% x`wXַ)&H34il;mb%(|K3-A R>bue6g1mLo#յ؊;mga"( ߒD&9_.vEeMW[ Hlߒ "x}i5( @DJ/y,&6ȿ_' (UenZhYPZRNz7OE?bv O@<U\^h_`7@jhsԺOK!RF#[,)/٨"ϲȟS$ubo{2?9^~1D(??x6튪ewhCE_Ÿ6]89zbX'4I=Y +1!ai/OOOOOgOK)균1000000000000000000000000004NPq P2( %C;v&T-??ٳ&S +a8 ;R)Q(x?^ȟɟS)R}Uݠ< xpUo~@?M洍ȍ^F3f[eֹrc'z>V23?'TkNnq\nԪ0I1瞳sԞdo2_VŶⴞA#si<`-x>d ȾNyHtyNL@iH4Ocw4r_ًU$ ̾'iH6eBi4=u:*Tzn48z]1b}\iw9'qN8zBHq#Ŋ4Çeߨ:ܫDA P}u\Osȿ@?9d\﹡h5O@Ƴ<Ͼd<4m٨ g?>m95 =zRiAԞ/.g,Դ 'ycaaI~8׏g QcvЋ2b+;r/`fZy ?3Lp1 ;khfLcBm1q-/`ݫ>s&wJ8eFXOFQ?cigm٨ w =}gHqূN}dNAL07k_gi*^+O3",>:֙TۧjB1_55-FnR,*GmU!׎5 ڋVP),/H IxyurIB\ lHg_y2} x' Wg?2XR2VM0YO!2ԔkVK߀ŧ'GvtWv4Z͟Z_״֗ Ib]-̦IkFvs[x {'xj}ǚvwJKޜńH:SRa%]^S YU{?fX?n1}/ Z!>5BpQA^*? '-B=3oX&EgVO)Jyvה(GD ,'#"Ko2ڼ;+ea0zʆ7TLCʿޞgȿbki! .Vs)dX u(}s)i,8~73궶`wX:s{0ѣEzLLo[yHJ/I%ھGo[ $T/Ě9{J<P?F[uv/d cۤ DJOqnrM*}O =q ;S~c}%t+ˀX?AJSMBSǿX ]/v] igb*$x)UmCOOO=k2NȟɟɿfϞ:"[UOw.]}zyYbmm_߳ƻ=/r+@BEJ)*nxT\k\]YcAO?J>}rN`7/Y[pj]u8(?qv̒Z7 淯i {e$Q:Նd|O+~_3l -/@se t5y];u'`g{1rCgHLqo>CmpSsGYʦ-ƘZ v1# 7k{*:A(&11SMFa6xuibowj ]_rd'V{:9?֙g:H*:SS1E("O#B Ե u-',?˒Ԕk.; Wϒ/BZcLWhSKFv9x;Gs[eLVl僭4MZcuhE-fX Әik-oת꼮Ay6rMFaW/^-`wVmA#񷋺Y,_6JyoO:c6;}?ɿ¬sˍZĐy+%Ps01YL 3'ӧq s&͙hǝ6b&jf\.TOߑ^\ Z?gYO2P!=ZiȲȟ,',Rm٨ lgZUO7N!hsr=ms2&Y ΊJ׬u7ز 0NF=eЂMɈп=7dߕtHyf=Nv 잙"IM[ٵōPܧ8ʿE5( R\i۴ǧm22%qCI.`3KY*:Nyx'w/-Ğ?tOVeƩc95 (_R7*g3(_i4ި6?^3:N#׏WR*(WTT''dFc]I<Dž? usZ zjNn 2#87C g\O2PCQғ5?gYOYV&5嚻U^F<}3o@lQ9sO\uhY}dG@W9}R8?ԾOKrnVvr53Y{*-n.oaG9s9iI\#NdܮIfY]rhWxŬx3)a]oeG^]&z~cPͿZߎz|B<ʙ{#:W̅yz+q W/`]rݕBk׃]v3wuBpz'gY|@ƥdJOY+Rո-`zt ߝBnn%E>ǺMͭM])kW2?IzGږ3@" ;bq7/" 5V ]ր tzĵ%)p8NF:=Sy *^,8n 94I> L"{ƥ)/Y%#74/X|kOR`$LSU9Y/GTMR;1:͜6E1UL###"7?^FPgn-w|]-VP$!FFB64",Ud;EyU1gCp~CRͿePYJL;Ӧ DOOWJd?WϬMȟɟɿf/K.䢋. ?ٳ&vW>RM[>>u(_h 1#ڦMچ iVWT*ՍGGA^=B?zh/ bmg]y[[[;hĉP]ve㎋g?*{.7/ξ+O2%UVa:_~MƄ _8lԠ[YڜCi=mܨkwkn:ujgg'=#^(Y&тg_ [h7|*m韴[n:߬|֭N=pz'x" #7=?裏w2b >Bb?}uϿ.Xqr0?U,_qEzG  9]3ok`ֵzҙ=iߟI2ҥw~]ک<7ﳏvm5#Q> CqE ז?7i|!p޿L_M^=Df}ڙc^[`Y#?=uj3?y2~8qǎm{{[כs;Sϼ-gk ۻ[?;t7-]?v)?4֖3;=tLU fϾ{kv^?|o;IڔO>$e(o^&} EQEQ*uؖM°څZ9McX(27EwAC߼@1 ї7=MC :<2³;?Ntd0!o!Z}G>tgX4?m2N$ZBI,iҢELŌ6*~/!o]IsmDP^<;"j[ /dӖv}V)ǙY<:ɎZ˹b8c ջQk7YA,󡛎u F ƕrEO'D(-R(j\sw٫Mn("'+fѧY>Ҟ6mj_ /*]]欦I|{ucCߜJ*-3o纘\%oNH2%珨r]%qJ[RA:S"iҚ̕M@sE5kf^D >~bgV )V/wU3 ]O;N*3Œ+Qz>v㗗*3Œԫδ^zE#T4FG^Og%;rEmU\.exFDqO+\ƐQ(Jȸ(M` WnPg_|4WxwD[rBPz_`gwz݃"ǿZ%`-oƐ>~(nTXIrO(ibvF͠+b]Bu1%ʳ#6;s_Ⱦ6~Pmٝnג*/_Cj0BF  YpGt O.pY{*rӾh#˿ptGy1G` Px A+~鐘_%N"e#jӁ0h|5~fH 8$/oVdI +8 >bӾ#g@V P T?Lqa犩=untᛎu F ƕ{!'$-O-',N 5+@03kMM'Fc.IP \rE]tgMO>?8=sڌ'6m6lN;4D8{v~VmI ! ugϜUWO_ye~ڴ)"҆ؐgՓS"|1mF駵636gv?}YArjzW\G:7oח+GHLbx;AWZܷy}#4hҥ}ӎ"vv{s`ǒ"w {i1fvs=>75/)SdsI{С?}b_v'Ǐ[O'Mx``MW{^/2zuizꄫNO1c\s5'tR˭M T@ua%m+QPq*;.80#LR旼*-v ~b2BF!#Ly laV:P}dǗr2Aqe9zU" @rXa#L63¤!#d2#d+RUGr>PKaOx#,'1?,% JEX(ko U+SEX(zC).Oٔm!J+rҨYQEe?HgÿFyɿ~^d?5WO wW?I^ /AX@uo96w z$~CJ6_ F ߒW?I{uL%T ٫cߧ·d૟d *Lr\D` K/ H$W,%#`8Eo.bl:~7Jÿȿb]_ꫜ/}Q٩5@_$&F,uIw ū*:zS5r䉰^RW' A)zs䡪q hsԺODu_ <*',?ER7!'Sϟ8(??x6튪wdCe_Ÿ6]x_P5e;Is←-lT9mEjHy:U_O# MG)1 `RŨ c-O=?R° !k4Bb50ydlCҎHZi5;z}  [q% P_c]˿lԄ2o^ٰE~(&ᯋJݑm۶n+',a@HuD%z?& UT^4d??Eu% G4XS^QEe9Ej+>f>#Ҝ".RX"q'S|5_Ursҵꈿ>sDk/>mlb"Nvϩ֪6ɴ8-}xER} 5 p6V`ρʿkVǫG/} Htóy<{Ă.\~%v1m^ ^zqu:_Pn7R? (GD W> R^D3^#"׿yA?5kԕſpCI֛R~7jJ^'i?}FNIB-+9(/o^+Lmi_h`&.7*^F7/gN*pm-җ+$ /[_uW=uxyt/}uyԻ]11X{ )$ܵdW |σ=4_u"jG Q,y#-J/4|RjUPdw}$@n?O߸JL?2B)//-'?"W3pkZТII_sqJh7IaDEIɀ'WgI@׼df"^A[gD*,/ h?e?Q>&ks?WO!x )R^D3^!fUivMMLo>u_R)rߺС)epyԡ.s9P`QDD?rCiJ)]!#:,)#j_l: :IW=?+@d )gPJ 꼃C5J _yPƥVyWͯ@j 64 SFz?GO٠imic:=߳wTFoᷱqZE Ņ!-">F]W̠{,Z}%3x3]O)wၻ, зX>Q+3K~,&-=v з]xaO~tV_'C_bc!x/^\kZ_-VnHֹw ;::ę)ga!'qMZ%KyUYWiEU꒿pv_!Hz_|^#?)* 6;2.Ұ˿j~W_m WCĨWi{Np8 󅮂[ܝW焾OĞGȝЁ^Lc? (ACB_.A J (8ދR{}]#:H_,A?jBKzM{[S@Q*:G-{f#Y9G^׭//`G CZv"C|urX/JL4z|8!?[uBN_ =(nhְ7WbBNDd/M:Ґ+IRZCwT4А(@jCW> R^*/?Ӑe?gYOYV9n.FUϒ3)EYβk`3!vINp| Yu^2;ҤEG|Ҟ߀C< Li: or-!L8[);ꋿkGHoă?q D'w&iR'߅QOjJ5xgB'3[9L!ҲNE/C*M7:OTȸzEe?gY?dCq4ina+_ ۵p;S>7bPeq/׭;z\p5zWJ2tg>G_eIr;Œ{.!ȧ9h/g`]o8z\pʿ,wT>W?֝'|c=Z܉5bx*=Im9xY6q{UO“aByL`OFߪoVW~)_j%UO*T=᫼у ?"})R^2^S%',?˪v?J_˫?e}33aW?j'!?xSR_FJwŽVT\ es"ժARͿ^ހ9A5ɿYJyxOȟ,',R޴Qz DOBv$%'~׵{Fyš>/.*"TiQtR~@j8SUdw3_6A>*Ezo3eQIo(Ze]j.>b$+L `gT_ 7$8:B ge+ސ;*KOC+ȸT?"ϲ*_W͐cL??JsR??(sj~qC]9B72_KyxOȟ,',R% ɿ ?!߿B`#H/5ѐ,l(u͟ S 2.AEeV;2.(!-NH=iSu"廠*53އAg[rfb=J?c/.$D"{D7ʟ hs/yT@؝SXLHG/fT _eM,Q#S(şb^B4/JJEFԦaѢIL=Qb߱ ­hgCȇХS%9 biߑ>0w< x9%J?GK8qZ7WF\OEcȵdq}+'"SZNX_%?EQT|@ƥPEQuqC}\Ii)(n8A8A8*TJKy(((fʜ2jX}T˿Z?eNJvDg9V6¤"!v5`ڔ {P_DoZ_YF{ʳ,6(˕eFzx)t%&<*:⺒_"ljw4UVvXV&Fe+´6RGV[=F(#d2DV2BFav"d!#d0;&1000& nIZ(60'''fϚLUO^rT5xOUUOYEe?gYOYEe?gY[ y!FroyioK䟵2WsMTuo+uMW*)/|c_/Bh٤)]?\ǑO5_w8][tԓbw)Be)M_!ZcݜsqJQ:;tL!#V&X\BFNgJ޷RͬI4`HٯI'XFb(] N@ml! 0HW:ZSP)D/3*S q4bbRsY{-Y ܻEL$a+EAkK#nfHW֜_"ϲȟ,',?"ϲȟ,',?"ϲȟ,oIkl9ǽ@k^&㧜tQ 5i>n}xuNwAߜ6t&4ⴅah|fXXú(@Ζ{oqڨ[B',-.Qʿ@S\%ߘjo)?Kk~Pcs?K8ςijMIP/?ȟ(((((((Ry_L[JhyG'u>Xϧ` P-bʿXY՚e 6d|E5{+Fߧ` >>!+~@P.\o Y׊;'1@~~HY5Y{>+c ]<_oź_O}CU#y?J+n:.R%(("Swɟ]R̟Sjs3,vN))I)((((SV[)IFR^*R'(ܸsV{/ͻwhβnn[Rm75SN1?yOzQ}G@VZhp ߨ y k6Z֋?̉R|ؿœnc@ύ-gOp KjSwV s](mD4vC ˮE6P-c<[ _=<umw*q\[ h[u⧼1W!\Ei\Wʯ,ܸ|e;nY ǵvk^SAk0_3_W!\wPsW w,ͽO?j~aK7ݵ5~?fx䱗~aΒs ŸhmMA{1~ɿJ6SҋZݤRNQEQEQEՉmH44Ҙ;''o gMJu/Gփ_((((((((((((((((((((((((ʀ&55MZ<QWs-y {|Ճִ嚻?[*xTg.4=R,ȭ]Vmnm;kS)fJAM9_Ag/"y_^+?x,I_ՈS["Te&)l ӆo4U* oK%]p,'{{ZY+ȟ((4W5VRfTJ׌*O)Ovè^3*)eQɨ^3*kF% J5S,)((((((((("mIHLJY''ogMJcP=(((((((((((((((((((((((((J&55MZ闺4|OT6UkdGSYv4w[(:Z?Z̘f$Vlql=s|Y>ҕz_3:31難%o2 u53ʼn'/1zwX)+_!KH*NnvJJ+꒼pM¡TE׽`{3dMh?F5q,`p?xŭݑo"2o @i_hUZ]%JLq~[W 8KHdNiJdKQEQEQU^MUd?0ɘ[<ȿZynx1]'n&KKM9cb3"A z ڄ0ߛxW.˸:$Etw;}-㎢pc^#(y[0a]oAc$^ֳN--[ߎ9p-e#$FQt%w~1vTuMmhl%"QSc}@Izx 4ՠCPk{Ŭ&k 1ɮ)ތi]FC&  H]t.w붴3g9sfݻsܹmwvܙ3ߜ9sw~{δR2M#mdKgfOD*ZKIԿ- ƽt^/dB*m)Akd:hH//c[66666666666666666666666ƏL¨M6 <<9ҙU oL[5"h玿ɑ`V99JM9bTÿg߬{#Sm#9oq>5 $@\qWRTԧ^̸(13խ^ȿ?19SoԌ9 O<{Q^tJn=1S19m?8D4ǢiJEw/+R[ґkf/\OgϟV^v?j#h n¿yyiqqn~=wn'~_yk-7p__^n9($œ>s 'N?.QK/ܿ0,/--JSF=T&ֿhvš/+|!EC$|啃/ܿh6GpA=B7t ]\ /G]HBW(?_5jhC Nu/ N$<9=> JjE+g~~]{ dU`u#"/.Ǐ'bK_GMUnK.)S ϫM3B&[jb~|?YXp. oǹ/~hCތ|/>%_~7?q>-asqtDv 4Hd}PEp_a?[Uie H8Ky!ZhXj>#O?}v꥗ub bO. ZgNr٥sϟ?{9tyj\WOڟّWп?ϟa' b#)H۴z#݂??oɫRockߒ*w|92ߚ*okrW/O*5?-K$iIԭ*:?^?T(.?*cAS itu"is*>:|<? Я8qűZkI:z ]3#=jֽ)}gjKn4a(%[hG?,V%'etF&^htdI=YMTN%SPW ۍjaݜ6y8 ֑.Q fuN/o Cy\GF5q!Dbx+e~Ӭ' &,tc(;ĵ^]}LE+\\"Xղ9lB+Zgm:ck͵9CjsJ֚m&JQ%D(\,ՠOK%Oަ߬ge]n+^CO["o$cv-ә(–RZmkE2`葔j|[0"}KVҥ©]a+ԉ93(-;FWGcV95t2'bƮt}[Ia/eWÚ`V4'V= J] B͔VU G[ڟlmNBٱs5^6z"|}4SZϧlWt}m</:J-i]S5_j-Lj61ykpHWRm?TW_NZ_WxsfEG$Zi֝W#qf Z`nn˙.Uߕ_tNa2nhXW{*-_m`'35W:ɛ\a`52;?85GtX.6 F`/rړt'O[F67~r8z ͑C9CuaĪ7-ͩƘ] G*bIFȏkc0vq\*?3gxs GtsjE=bƪM⿓M$+b8z[QJ7 S|~qqH>$;.4]n1Ժ,fėGԩ mx{}1WUHF~iSdO;m>2:8@0I<Jx} `I@4*EEEAbDB0En `A1BEgn6J[/(F)VU0Im7gsB3gvvv,ɲdw7ϳ9s{;9ΞcW~]!,/c=Tie*~fL^j,ɺZ;A`nbY2aOW/Ԯ_gizwmϟyjnQ[߷Šp7A|^ߏIl{̏=̒ptgr|D>.u;q|ަZ߲d=,L#c++_0 pqS9O}/so7A^XCa]/Apxx/8ǀcq`(}` 2^'`$84a0θgq,p68 > "0\ .$.+Dp%+'| \ r57ςρσ/n7/| *`*n7[4p';.O| ~ ~?_}~7?/? %xo+?_GL=x O?yi ]:Pe`9XVU`5XZF,x<6flA0{Ae`0s J?ц 77A`px+x8  #{{}(p48 C p0N'C0 Fp:8gq,p68 > "0\ . 2p9| LWI*0\ >>S:Wzp,<-m~L[z QُF[[4^$oOE_t,m§~^ῸIRkRDS^_:ҡٿp$Nu {7@H|җs#ǻ7]»˻~w++;Ի7Ct.MVeKuz$Mzkɐ ^U}O=ܳ]"@ e74/+[ZA <0@P~ @\~ _ũjlM㹚nDcS8wtܙj/׻URzv!)w~5ת=IއB;/-Ĕc9Wfɑ^I,o!!z+)Fee)>S ?ďCJLu>_үw3E耕W%Tx2Bc"]䫨%z7Dy.) e'tWaUת_dPe?鑯; Q+kkQ]Y{eJ 0ea:db,9skk"++.qKɯ:Sɼ*`{p.5+Kɣ_L_EPϦ3&/׻!sUm-Pi2((JTm ǐ)=(PQSt~$LI{S)Yb)"LYld2&6qm~B.uuh\0ѬmJJjVmjD/Ya۲x $+*O T~fJ+ED<$**ﻤ_((.UuJuuI,yspm^BHTV׹͔.~- |mVVSgx!,Kn\S_Tչ [DDTe+)*pjclw_Lu:ZaվϓIEʖv.El)J(~DdgۅU%z7Dy654T{ꚜJʖz^Psr'$^BH JJ׹LElovђ3"lvXLuDޤ>UK<66JEڅ(64fDֈ$b6xõ,)09ЯE2u@&>L_ < QZW#\*Eʶmt˼wAQjLr qaqm~I Q"@Z^c*r_ߺ\W_B|ܹFoAٳUJB_үB禦ނsMM eU5;%z79]|+tBm}#(|-_ڣ}EwשJ/׻;yôvs3g#Gl&P@B|;VX"eo/׻EW+ p8'}P젝EڶG_/8J%<_sA%<_sq:Z?"##묵[&W.@$TA%< _sA%<uK x.HK x.NB>V n:y +r>:=XZ1.,uӞTYl+4.zD~mJdZdٜ*5RZ$HuFLaKisq\Bj'OB̵?CР t-V,Zs%,L;gDdZ>aΏd)٢,@Rh;d;;]w2POܪ_ׯnWbVͅdjd+J)iheXS:jUZ"hWg24w\o,zAREYĪEWtEʒD\ئvV)z?jUp-~wVw$Z}$҆e2vMh.Ak$, 1Sz8JZͷR!gWاrŁN޿w2vSc2vzG ]tV)):jpWHdNعzo_gWdWh3Y #sHZ22 #sHZ22 #s:\/e /  4~a e~ @\(_yj 湞k߷hY]"../@nW4@X~ υUtK xHǂK x.|A|M \"._/~72O/Y5үgy~/̣́~O*e)ꗌLCs~TVYb:p0e^a|m[P{&wPw;01"OY'/f@>bPo1v[:ЯZ^ϴ[= J=Dnﶶqdd[gݿ #s: 闌{@h~ oS^F%< _sA%<*z_[qj,`@H~ @\(ͼ2EH!"uX_ H` ? ;PTQn&'PÊYQX|Q8Ey,oP[f')UgUv3%ԯ HCK;ԏ#8}_{̗0ausXlvv&Xt˧f:?ҺՓVUsX<4.z>@s +ڢ5hm*#kkXw+erNoJ ~@(jmYݓc'z(0 ,C@ +ˎT wwݽB>f{#>*+_~gAw1,=`hm{- ;3̴uh/++;嶦A&h^rmRޣ\?Ƞ!3oyˤ _?1ٽ'\}٘=vxฏ;֯h|!^Vs ߎūy+Gqӿq枸{g*{V᰸!1k{G]~=~aϋ~_+( lOl^T6_pkb .(8&PY5q~}UPtt_!NJc17pKk$(,r-f[~ߊ4/HQbS| *4u@c6[{!YlexMrKYAn6柏;!~Gk@hV4<"?BO'7}h^i '( [n0reJ:+"JǞqG:f!U}f "gBVN n6{vݒ0:!>PS հѢ_к?lSݓ/,{|d! a d@D<.,\TD+  -1*)Bj=Yw+ěw7?Lo^(ׯ>N$z!"Hy$q{}Vd)k15̙\[E5YVv{&v ~3G J,N59Px0Qݴ%3VbW'[%`A3GO}/B>CzB_Ŀ;hv b  v 6%ae}1dJ9L w)b5,2fne潑R{flPl\?1HLiAGi""[ 3|0 CF8:Į50ha%~ 䗽+m[fiϾ`Ղ`S>QWqJ sN(~k \}`oC˥oc z m4ɢٿbB44m^i/2IBp秳6Ƭ;@$ lH8w >iaFrItbdյo4hC9}Gngo:v>eg\V:5n߂ U*0=% >fs4RQ:/֞pَ 1{q)EWCC:먝U Gbe2 Q;~-(b\θ`qtKWmu4!}(_~>{UyScq +=3!@pbA@>\o z%-22EK>"Hle{*Nn<OtkYQIK69/83٠-E7G .=Y׏DE~gBl~ -]\FNcL}hJl޶ 6yJl/4`gڼV_&n,Kxt:źX%|۴a1EwN/À1#E4j~;[mxD֯5:P īt`I̔fs씋6ԯKN1R%IރGnKV$B?yn"U5wFp~[~?Ͽu>=&/å 9 bBc!_ + /9Bwv~BՆ7WlZAgW 𤥺0I£Vԅ Ϳs~E ~9ƉT,G[ (.HX$,jЗwi4~_Yڻo|Bj>[WƹOf6L_UB?e>Q:\;`ۍm[k~M~:]"'Eb{/y!hP`SKw|PnT~sŚWWX+K6.~t:%SF-:x{G-CY/>oر~vN!҅ ԋ?Uo{ŷz<%l 6}8k!&z4# O:66l^W+ϔ=aN,\p8/U -]0pb޽ǎV翴Lw0~N>7bBWlcVi* T'H7 Sr- ,ݺB6.j[vtB .uq ,]跪/+dP)_!9#`)${P8m7.@K$?P@S"}5^ڝ']YeqEBeEP4 u/x6sVl N$Ћz20-dY!=B{ߓÿpW0 T8֫T7ϱ=cBp_h!#@nv_߻9 佐rէp!,t 'Y⹒B՗,횿˧8aWKur$%%_Y(EjmZش:Xv^Wcexϵ(d?7Fp"?Ko߁ -Vp|  Lw {_'S0  <_5_[x߃,0OI#π`XŠԃ%4`XV`X ր&< σMl[A.||? =`xx9 xx5 ^uFp x8Omx?8-k9^{&x'z%/Ȝ^~HgЃ}WbR7ؼZu=K/=}x**z4:7&+#GtlA|-.c K#6O̷`N9ͩ$X^sMK~1EmC^5l3߿#t;;:X >vP¢O2LiES0e;RP'¾a1E,_B9W \$7naO1bJ=h|Ě@QH䗔s EKW[`"tlėlJ)SZ$.Wɘ_AF. y: :B 0Y^{׵%檰&qz_΢Gf:f{Q4 4h<VŦ <8KղP0'X#|^o X 9DhfЬ.݁yR7 }$-#ۭl mbk|9#2YxRWǟ[6?oޡ?[SVk`leR-Ѧ'6P~m4H/cEJ#+/HjLjjݓk#0%,$0^;H2[XHKf}y0h76Gm/X eōlS͘8_\Z&;hQkZBjy?R|yTyЯE{`o[ךᠡXlq"%=2/*U}Tyϔ֠~o-11'0za{䥷[(Z-f+,v`OI#svv]QEy eSEQH>JKBLy/N&5#kZ)q8t (NFVDG׼Dy(&.z,$5 vj CC?P-=X.Z֫ᰢ/؛ܦkީ͝??)Xx_1ʗ"i,%t gK@9 Bڐ "TĪ/-.S}mrOw(Zϐ\F(ښ?),lSg0o,%CZtlŒty%D.ir0D<2%%R?ŎG1u^?Ϭlr)T'i:Q`C^F?%ʂߦL#|<7.fjͥDn+1 +ȇkBNL_qdڏ0*ldbSۣX\VZYYG:J%"%q5U&mەvuŴz6al$:^CGF:G.흩*hjs?jFn-],6v2Wƿ5/uv.5k}9ge6hۆH.lkߒG'!:W(Tؔ\m/3O/MS׶Xni\D\v\I|WU5ƿE_şQkkËS}=GP) G[\x]0OmA/ߗATS}B)5F('0u&o=ecWE.n|Sou2;߃_/|~9&^{{sw̶mNڼuy`jE%9/*''mgmvgG~/ͻ{(VXA܄"TPت^m8A׉{ly~:8 .7~*E hؿR8QiU~Ω*^U)͉, u:Gwꖿ ;ߌ1Q5{(__[S}/Co&k}!FO747A2(_şˠS}/?R}mx(__[PKeP`ssv=wD/_R Dl~)AK)!h^B汢{4j'\cE h2wzǼZ/Ĝ:# -!z!X|?Z<NJ@ ,4}Zw;EtbR <9 @ '08o222222222222222222222222222184@ B?_7H @)hǡ@}@ @ d@߾n @ PjWx9>(GAv||!wʯgJ ٸ@8)('p&]2Okvegж;_%!㻼V~D*N*n?jB…Z䫺2Uu_?M{ 5T!_5Uʯ[sg6ԙ*J߉5 rc;_7_ֵ}#Y,,-"b[X@2?64L5eBr~=w!N"gNAÉ",<@}}MMuia__u@÷RrDDlQ>햺uuUGw"nːmy2[#۲]w,[VUU|w"n5PWW2do؜m'C:-/ujk+*K35Cz2 ۖJJHYXrK(dt߉5,`2UY[Xxj<·3eˉǶK).=(PSSQQ/)v'%ǵb{D9bqR2]{Кr]Iqw9nX_;__:Dw2cBW5sU-g3 M J)Ql|'?E}]f76@m>;Bȫ"GI fwdgl$g @-S%kdO` H07Es^-f*+'R䂇`f1 '£/(#6#N/ r~yl &-gKgY˶+.tٲN8BpG|9.Iu`ce Myl?u7_)A)( kkZ޶_,~e^d|z񩹆5Jc+?P7ؤ7v{g9/Eϋ KO`iU;_ؼ5e/* s B3S斬O{4pS~xOlk/FƔ9*?_'6&>'V,Y5]"Jb /QϿ`ֽǧ}_? ?kES gTl~b8afaU~En$ݢy|\;iw~| vs[8"T/u&Y*E3ʟqmww;_0 *ϹۊbLa 1k俒 6Q3e!y0J[n.Rs{?s=denrЁ;`^ɬ]_:Vr]k~So*!Su8h-eX5ݸfKgVldfߩUs>F}irgd_'S~Eꜻq&+TccQge|<QIR] qf *6$z@9|zO/aE  u{iܰ:$yP1`2d_7~ B}a P5xa~ydIҴU1VW[[݇vsrG]cS{ f[R0+pEqtCt1SGև_߳`dfu< _*?n,+[>4G_1(sɷfNOt|~o΄١W挹,{Ͼwxh@{{9oَcW~G!>q{? *}}޻҇H6Ona ,\dORm*yި5wRMZ˿},QynDÁ TO1mj)""vPTfq ?%N@`t>Z t R{ ~UsOOwܜy7~J##^#5_[fǣwyٍ{ּk~~'4O_rTE׺]K%=!=W(N^X׺rd俶Fkk俶Fkk俶Fkk俶Fkk^iͯphn??kѹoS׼$8[~<~Ew=t3`΍uEQ\gWů:97ޓփ"99^ 97ސ{ݑqx=w$-cH_]3lzXwo% r`u +b!3~ΰ)9-CZ*}z2 *bIAIت}ط%.ƒYR8&ǷEXRL3܉k+Q>:kO M՚\Tpx.R~3T,>lU97(?LVlLx.~Ow UguS^zg[ޜc_y:;;_E&&~ddٷ>2{߃r^s}}*WM,;U]_g246Tm>Xs>T{\3ʯO ^>UT]F7 ]֖si~kȹEZq~7%_|C=W~kvp_%ƞd]l4F1 c>߯}L7ȼبu*OT.|tcܝ4tRݏ>$_:ڮ[?"OʯߨK Ƴ^Fܼr/#[X^Y/i*{UFc{h65ץ_޿fEl8cv`ޢu?yC9N-ȾJOSS~x|Wnny k>xgأAkXrTY>*1KiUGy*uCpktmM ]K̑|}"6o~҇\,1kpǘ;~:u}cGsu|6R [33q|+\-ʶboe_x{/}XDeI䷦/^ב! }eqE|M |:~>K_=wTټ>lu|R/Yk#K~~yޙUYJh¬ARt |"0?6,7!}*ǭӯXwoagӟgL߿yC6ˑZ_Oe L4J7ToPq^  __«ow^ O8 o7[6x;΄w»,8V:޹pp\ p\+=^~|>Gcq( 71Ip)3Yp39|6||.||>||!||1 n /[Wmkkp;z= w;]p7;|+{½p|  x0< x8< Gcp"<N$n8 O)4x:< {GGYI?S3s\x<^/WWS%Rx_-m]x9>^  __«ow^ O8 o7[6x;΄w»,8΁s<8. ".K2 W{p%\ 7|> 㰵\ ?hOOOO7τςss %epK|9||% n_ __ _7MpGw)}P;|+{½p|vx < 08G£x,;.x"< N'Sp < πg&^>~A!aQ1qxox6<~4 ,<<~χ/ Eb%eU5Tx :&^~ ~~~^????WŸig*+kx5-lk¿p:΀7›x+ 3.8 Άs\8· B.KR .wx/\ Wjx?|>^C^hRvJ$(dNiVR>^XUhc:2ߜ?Zecjd$eyWQz Qk)ۣPl׫gB{+f ^h֞ۼ ڶ@]o+ t=Jܩ¡_gsĶ1{5m?jή"21]k.Po- dj_>vW\o'N`+ l6(VQVϨHn3>Ƶ2NB fZf ح%BNXBf,!3BK!%Xڽr8{ȁÇC]KPweb, K>:;秔VWW8eb,9o>u}>?ma雾re%U2c 1u Yweoڕ۟~ˎo*eXB],,+/(+R^ʠ 9%s7Fr+*#XBEfN޽BqŞmhWNo/3cS^Y qFY#K}8Reb,2s*:Y]q=N7,!3#7`LS+{"Ш))ldrlʍhR\Cu29KݶK2g> {wuʪ17V͏U'6vw6XkTA׮|"_P{%]ʑ.m8F>8ˌ%Xd쩮2y-طIo`=DE ubpwŮbX{[ ] 6mR'hǸL/(x\Cƶǩ%ސٷxqӾccۤAN)/"ccc{6-i*]3ck/5[ oLb_Zx{Hc^6ErZ Y7mr)W]Wخʏ0c 19F:v?h^!ƂYeL_c gmB[𦢒o/3c#+CN!b'~ͧ'fo/3cAΜ_3끵3C] *ޯ2c !D?XBږ%AfRf,!耏5gEQ!/Bw&PK!%`B~g,B dήM~,!3BK!%`B~F0EQTPKQj~ ͢( (WX(Č(OX(Č(OX(Č(OX(Tcfvo2c)3(J?1c)3(J?1c)3(J?1c)3(J?՘;0c)3(J?1c)3(J?1c)3(J?1c)3(J?0c)3(J?1c)3(J?1c)3(J?1c)3(J?՘]R EQT@bRE'f,EQ~bRE'f,EQ~bRE'f,EQ~}0c)3(J?1c)3(J?1c)Nޚ !$5cO$mSQhbR. G+0Xz36eVPa,q&!,vp[RuچUxSx EfJťfMBU#£T(3}WSTxSx DƪaeTy!oNðlFaXق` >  5PN.&z {bɲM.L}QHE&*y4RSMqq( l3 N ^p)26jZZ9x)KJCl26 S^6ɬ=ӃVaD,k|ČjXc70nm͐& tn mvW %KՃj7] GYӁ^ǹ_y&i"1cl ~Vf]֗oS_èPShezhBdH%e_TvanO,qpyf5`/`Gᗱf{*% Ʀ:U{#8RSipu?Sɬ=||Pe]6Cۖ`0We} ijYZSY޻>ČVHd>MᗱYq%[ET*K՛£ * Č\eVPa f,({x 1c)GãTK(<Ւ 1S$2Ql2Vzgl{aѡ 9GٙTK(<ΌDXEQvf,$bR. 3c 3rQxK£[-: JgDz֣qXXr\;3fYm)+bH~03UJ-YsB&m:AkTsIbf,B7cSa ZvV.#}T;@-Y&l:Qf%@eǥ{z3sg}vGXѣv˂J*~uuYS?j-c;f`R*T26~@y;%=,5|򖱩YfyVnI?ɌRdl8 sdܶ:sX0SSMVJ?DR*BG'VJ6XJ71c)qƢ[rloߝ3rQ]LRA"f,(;3 1c)GٙTK(<ΌDXEQvf,$bR. ScR?m!D2-@~\~`NdveV0K² 0cIX=))Dg,UsO9Mܷ 3sHϛ%I} :(Y$6XyhHlꈶ9.mqo릎tc<OdX!v x6zXy]+c*2VNrV`H\*CƌEڣָ.;KԼD!cUs<6P[ ou1Ì ;v!adzsjO˶iⲅ8Lm,xlaڮ`P^vy&.Y;EpUu<@RYflҙV-uB5!w<N=gv_32eۂ4q9%vvg?V^i^(iXVVj\R7s  ԕ+'hQ飼2z;}dz"c7"ckmArgzBھUuh;0>kcg=QSW]i0cA{O\mAH B䅉ek0>K² 0cIX=۠n:[k9ufM=n7L[e#Ӹeu5ٽ0Fxz,lPt".UۗS!!3X2V I 1^='SRzݪUsLIx DKk=0&+dqK<jN}{\m\2/r343ǢjXܷNvh̦86n5BEUrՏku+W&{ƺ26G5%1˒zL$e~ޏu F:wk\۽*x2~fEX5(;_Zy@8 36dH?ےt}<\y`S:R%ötP1 t,rrJUl~,N+yb=CyMN|S{S.F RA \#71 yxc<> U.k/}gEvX9:wŏ~nPs*UorkN5j ya4q 5Fd#Cf)=/z4oXq5jm˹D&f!￸}ڭr8Fڂ`|\ٟ"k.SKSojqdnIԜ ~D#=^2c .*dd>ͦsRSFIH0GkfN{:eKƅ~7*Hgy؃ESF)~I;k%T+Nn]ˌ(J?1cE'f,3(ČeR3B f,!3BSƆ BHIׂK!u3BK!%`B~0c !D?{dH!kgڦrzu~oDAo^Ff^#o'^<5cuQ&PZkn#$$E^;FǰB^WTfy.6w?ņuTzEޤds~lY_k[ eE(Q(Ɗ %ՓQ. RH'GOB}捲.v{7\H+`:^T+$S맰+3bi2!80INqdrCw'7eR1^vxr]UG˼-嚱ݟh=48lMW$if8>efC)6dBH_k+b??wNnm?8{g\^v+rʓ4^Q&.+7"feֽf,Vfq^bz𳕄(.{lwozӺk޲wzJgy=75uS[6eI7oGMQ)ZŵiJ BH7@Nz{츢k>>놄me_3,u|n! ?_AӸSz4lq1z{Vf\AE{cU3͛>d~M[fn|ybʦW|hlC|+mcTfNV4,LJĸ/A}n26a+?M#d KqOaOq_B+1ék9-OlD|B;|!_nB[v]3(㨼[?~?P}Ba7%K,n=tSJN ÖCݕS"x)kʢQs.>8)J!K_!c_5-'FcV}%F|d²ч{$QYe Gg)[Cb0|8PbWoM !$`oU+{aϬsM,P;='vXi|Qǔѕ=%I-Z)3YtmXBlrcː<4$#d+fiU}4 Og\.K8e\2{]Mdfo ! +W@eL^ĂS N-TIE'uH*Vǜ3Y⦽O䫕EʀͼF|ڑ]-y"ZflQlK~hM^&5<ʖEJZ~#m ]>U#F -t OU㡧\Y\>hjgvM\VAqAH=*/ӵnω3ӊL+.@-7EgovTfl-U3R2vӟwe~͛T9lI[7oRsK%c_z-co~_u-!WS]1\haq.%,ڏ):vgU Y?@T p]!xCVP6rܾw ^4lFQb$m).ݼVE-?;3WZ`k{,2V~vK=41ꉍLT*^o}ʭgH%OI+Rr rv>Mʬ+t/&>K1rLEZVΉyzeER#l} ¤x̢! Lv/=~yky{N>ιQX0HTd,ꔱ}WbV=Pزq Ah_ \F+w#͵|ٲOA|4g1ob.۰%BH0H^}/BNPPq#wxhJG×ϽonW̾nHX/+XWves+ѽ dtkƾ4pIy'rRި/+XK[ܼ :r.m^!(7(3v%ɳK' 6[?+;."9CaG綋Uٲ#X8 cZ[w$-KÌ"KX窰^3W хAF  S*lbVM zϿel~Ǒy7 U_=8YmuAG%c6Jƾs-c?8[nwq+_=Ԗ%cJEIdb@ XeQųKR#<ӊ\Pϖ]E+;1k|~wk4B~; j3CƪXf,!$M,twϰf?Z2 V4hjaI}&ޙ-1(tk[8 };Wfۇ;D>29`e[1+31K }⃜!#Y=L/yD>|seS,DɄNJ)pGO+\G\'F֫z6@jcV$ۿe-fHOX`DqNf[AN7|,zgU;,)l] `>X<Y40IʶϾ׆~qs[%cđ@]l咱R5]2f$c@  r7R&-2h]9y,E *u\~]*t {Ezf0dC=YO݅HTm{fy[n !$Q[hr?:Que?ek~g26XWȀjV%o+|!M !D^˼Uo&Q }d-ꡐM*AʾX$0:XڀZ9dJCoY/?N!!A OOtwaMblߩN2z.7d{.9,K_r!0ǧD-r2d|I'+?%;/z#m?)a5xwɫ*0b6#c 讞٨" Wr_jʘY#\8]QaqyEN@H}$a@=3#MCd2?Fݔ~잱R Id3]OώQN_%J"ÿJ:q=_'[fC}_Wmg} >>n 7g-KKp+r J5|n op'3 wo÷=X' }p??<Cp<< N#;(x4< '$Nx<< Ox*O3= ~~~~~~~ ~? ρ?? ?? ??υ_Bx~ ~~~~ ?8^ /߂߆߁߅+Op9% ^  5ZG'g/o:x=o3&x3 o;Lx' ΂8΃..p WU>Ç(| >[`p!8n7c&?SSgM3fpsl\<|B"b| |)|n___ Wmv p{|#||3w]n-pwV {86A`x< px|<cDx 'wIp2<OSitx<6Ϗó'ó9gg ~^///ï¯K772[;r=}x!1 N??W__o`3^   ^ po[mvx wYp6yp>\Ep1\ep9{J WAo|>a ,q ?hOOOO7τςss %epK|9||% n_ __ _7MpGw[p,>p_!P8'Hx<qp|'<O'wdx <NL ???? ?? ??ς φO/Ex!^    /_߀߄ooG'JS8 ^ {x-#3?W7wxN7_Fxop&gp p\p \ n+*x_t`ӛ8jIYMg yw\$6yU l 7S?%9bsͭVۗͲg+?тGm-a8pޯ<4aW+w}T @ޢgbH#_)F+cJEbT202? ֲ7Xx汦Y¥OZ.ki"K ]+t{+r'j.ALll:3 Ww!ю$dN\1d{Ԅ2 &`_4Lpaqϱ3-@_u#8GNIVYI%r_`/H}I&T?}2nC Խ`*ȉi+l*'S<^Rse &!Bw /$r;j5e/H*_@wYנk :{a\cCH-_cJd% يn#pcbmcT_K7U\NߥJej6[ck(K-zB2DLJYآ7J>Sf7p܁Uǭ%f{%?yVVEΘ\NK,]҅ZB ԿSJsgK2F}5Pщ[?u"񀗹qkvꉵϱտ}FZBqfkKŠ2[1ZlY^e 'i4(r̚+øe_y^ɏJ֢{?>눽k]0K S)p[K(!߷H k, &~WQO;3`hGRKd%?ƾ{Ij( ?d5=eYZ%W>6 LcMQΫ-+)щ?4i|+kl:3sKf|Ō;.\Ꮳ7H>.|l{5%;ͅ~Kp=.pkVN+mQ޷PQNp.B]" ˃}S{y9@ܶJ;qk([V"o:cy մ޶*XT Z~_u9/6 f?([Y9m{[TMWcD 벇'*XS:qgc5 u*9-m^Uc=xxz\Tk>((e B!Ŋ1/e H!B!B!B!B!B!B!#`cE ? !dƴ@t\ؒa庮VG+Bwãъh-AGjdHX;!^@qtyڑKHG=eI>;G9#=G; ^A b W'Fp&1 @Ĩb$ ͋X#0gjBRB"߀tFVE?v~b$DDǟ k|<?B|`H0Ft ?/"mlXH 0ÿB!B_1Y(JK2z+B^(v|S&G&9X/$߹JUM&)a2 e [g2U\jП]pLMEN=S l]}?|(R屼J-}?ȫj8F_oBݴNcwHwizro?o?EQEQT7@#?@!B"_%b_B!B!B!B!B!B!BG t~B!Ȍi㉁tm0B!Ԓs: 8eD#m2u KpaIp$!xcܪa:6xyr;KN_#\Ye|BZ7ͩLc_C5>UQ玦wf,d2^'C&¯_WV~! ڪ 0'0R;IO;}Sl`ÙrnUJ>`¡NJ/V;Cۘ ʕ1&vlc 'z%d~uXNpg¸q FqG^_`[.00D}V{кgQ%wAmM7DE8ֵ^7m%}5sgߵHmߎ멬N֦YiZ/EJFTBd=wOÉE3 ?;cvy:a+ .=/0=[3Fu|%.{G T\{r}Q>=E=Y6ҧRJT]%$?81(90e`eǷ/^WPzضb|mҒ-* ,y|^\ZŒgnLi`Lqm'b6} ^=t`or mWpwߢCf +P-eŷ*ܢpw^rJ;NJ/ݬA4pd_ K?܋̹*NMR2Ѯ ]C[<}rkOKi`bqKk2re8fb#ӥ`b\S:Z7֢ )Z2~{7Wlk ~TxFiP_yaILMmKᤞETԾtՎ690-{;3ҋQHb1Q[=6rg3q m71]vө`cn,ݮhd№%C/W$K|*Ji`}{3[o6z2j{C@]5kz *E{o DDHhK Eo`m/LAl b @60x!b Wh\w uPG@ÿ;FJT | 각ND4Nq!각ND} K .?ܹs}Y7OL&ӌ3^~ T|aھ}{-w[JK-˖Xrs-YYӧx߶:YN \hm+VUUYmӦM{!:5ja||yڻ尿v[o-]iBk (cPrEEl[^%;۲sB6nݿ8_ eV\lqUxXRb:uiXHaO5,D.X'l6 [( @cLc!˖-+_[nE2V‚7ҰvQBk %) MاbXppxFL ٰa Y}ڡeU6qهamfLꌠ|82ωxBG ˣvv;2/9/ZdIkj+M<8o<H/9#OsSvy+6o8-,[FMZ8pda!4[8==]81U a^u _ywfϯ/u m8'MT &X74P@ԃo{150R>eư'@ѸF}@)A9l Ԣ]3d f6 @qNzLۭ͒+bw yչ/*:o"p)]~,2Ï߫u)NUgͳlwX oA G27’Z5a,XƊ7VboXcUJTcU\jm$TSb\fX4%XJe-CASj݆ -Q{ѬGuZ{U]tKS~o ~?fê{^gTC_SC5 Ŀw3NmlwJP  F7VboXcQCR7VboXcUݶn-z(fk#ODmd>?.o-A >NyVG/#̃k;FX]G"0Vbot?JD|X*t[[U"t\mEnVۊr[C-x^UWw/ٜОPmsR'o4~;V;ǿrnH]h}5!/twa#|Ej}}"r>\u _Mȑ4#kCX.pRWg9X?-*t[[U"t\mEnVۊrtm.p۳EQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQT0d+!B!X*1D ? !B!B!%[29EE<% B$,/MBʼem$!(Ϯ^8FZ's&5TVONtc+ O~S~O\JHzׯ_#JzTt=W8>MOEB/ +ٹd8W@gf$N#76\B1=-=MGS\I[; >t8ƆtWlrbgneZ:ݍ9meNMBqA]>{<|ea8[x!!0hr dW]LV`Ɵh M@!@49 M@-(PS2M@!HB`EOU w6n &Bhr@ hZ@ &GBW@yhr@ _ 'Bhr$ /Bhr@%_U~,%f;!0 N@ ፁ@(|>tL0a.*1x ssrX@ᳩcV@_YCgSOin:V 71S-2VY#1פV99q&(&=ToLzTs9;͎-1:kj́'bY_+?(?2?2?2?2?2?2?2e+GSo40eJE wnڞdϧ^rM,Kla> $LmyHǺk/ƒ( AAAAAA g$?6 A&h(Ra]`q =- V]WW?c>5``l|4 7t ?r>{dd[yowD屑890 j|2~j#?:6ү8:&&]pԻi-szDb>?at7ezI;zhr =(1^?^+=XS&e*r؃B ߥы+hs{qdq _j77H7ޱK$+ ߨ7B^qn>7$b'K?w{(cHd8UB:uu+<9֣/6={U+Q7ܾ/=C |u73U{> _fBsi+3@O"sᠿ?qBAAS37 džR>di[2̼ =L fGa]v5!}*1hVF$hr*]io ]W >ڳ-:ڷ0;R1lWsxlC͉#0&P` aq5?br:<XO51˕R;ˡh0thfNbr Ik&eUmfm>}59j̑|mfV14P`ґSl6u$y [5,AU@tD- 3<,(Xp͏_[ebYop}R=%v^oT_JTf_󁻵4_SP=RXDe<7:/ϊ j%mJɚ\ -'iOEK?M31߬-)aec%oێ1b ypx7NIG}Okal({c}vWޣ]61գ=chͺZmRYzckjc_nN:hoFy/RzQL]Eۼ8xev1w}װvps]^Yc.yz2?]Ϥ}ۢwm uyuҹ R-ip}+ZV$eV=v5Ujn =ïI}bgQ?BA?KgiQ2Z?F˲AJWY{DX^͓mpyhH=j_}=F%}(ru#>pu׍_7ٴg=S2v2?a%^x]`U~ D9=O =A ҤE)gV zA;uCS1lz!۝-d?/̾}o7춌?gZwASDO֘vF0V|Oj zf-x< :( zWBf]z4?Uy(-vyys:|F]uyZ>lZ3FX+v^+^mVdݕNt}gFq|LcO?5v.DZ4lq&FFB~S'O)3mdG,lO9`5w}{^7//ۀmKve ,U5`GZ:/ שo xx#  v=0v}x$7 &wp 8  aC )p$8  ǂ{T>p0 m`6'޹``h,  X G18x< Ox L<l[`"-x1x  lv;ׁׂ;.M-`Woc L`/  .p08 )p$8  ǂ{T>pN'S4p:Lp8|sGOOOOsgρσ//// Ebp \.W[*p56O]=p >!\~7__&;p3p =_GO/VW0nwNpY~h0,`1Xe`9XVUqb.}}')蜬5'sca&Q^68.y̹ _cmG_s$C=/'Fu]#b ^nN 4-[m9Vu-UjC WWR9Uy BDje! Qv7T=v.BٞN {e~Ξ;ߓ"Gx詂=Tzꫫn(zrj yCa$O =bJ) %w5Eu2#[}{-I]\F a+S Oڂ~~9O8y  =˶u׾o*>uy-y*z@.&eNhBxonhWnEu4\mKS:YҪ܀2Z{ޭy{Szyѣ 9RQ}tVAUHxJ r(Ko 3L݊=Փ FaV tT#0u+SZAAf) 3L Van`jnyJTCrPSF)bJW`ST,\Ce5"T[ adOY9NY<"IJ'Yֺ?)jHa5"`),>5Ocgy7}D#~ZSIs(_S& b7aU{&]cu,Is`%OESءEvZetb5DO[3<QHJGN )bA[@eٸJq( PzxT),/Lo8%&6𝖄222OnHu Zy0 ЊPF(D+ ju{ } w ?xN(ɏo݂Sr#s?qʷu[rA 4'T)#iz!;Nqgh!V#/~^uκ>f_\Q_IU멶"(3DT?|ZT=A,„Ό#(|T(4䃑@%;~(TyvjH5Q,]C)_,BUUX O@)|#0[Z'Ow 0L\Ncjr+S*i JF,=ݱa;JJؓ,i69~}߾} p-nѮ˖V-:neܱgW_uD!>`F" .t  Gv6ws=3,9qVBڼ'9d%;rrYY_{ͱ{y *(X[({4o78R8Y?nֿc^a)Sԩn)hѢWj`el^b,seo{W8-[{֯\ [a$Tu[%ŋ1X;"Gu5GU[G+[YYY ٶm[˶oxߺ5Ww:Ĩ`siӦթn.O]D" SOn.QX[L XH lիW7;7noltTToIc>!d I{QVUu5&/O~Qleן}09P͆*p! ÖKIPS~n"a"[,0ߟB|A">Xv0 Ĺ⭷ A=~! Öe˖Iw3| QW%%W柱;gn3f̈t! Ö˗{G|s+;̜93҅{ &쀳EV6҅Bܓ-y@)A[mA"y@)A[mA": !,(zUtmS OڂM S:Oa O( yB O( Tb+s1H9ғihQWO >z.%CJgS֡s~e}u~/&ϣX]$Jˢ)K M_oXV Ήl"z"-=ѥ׭ݟLUOOɭ}a܌ O7! )ϨdI}VbHOl薌%S$a1ɷSlɊ̊JlM$HK +/F^ˤe)[(y|uR.4Fʹ:l"U rI/ 1bLpՁ/ /-v0b?nV fQs+X]ڢYsVE)M*D{J []j#V::Ko A&ja -bx%Q~{JYf qo)&0>)IR!~ e$\Wc`3et~UOYM^]m Ƿ4)iA%USQ*ܛ>ҡ^:ׯJA8&G"4$U6%OQWOzkd+izUv`3F)%]C+M?G %O(MO{*raO=S)y<^~kwNu3, M^uqWl`|q;J`+1r))S08 +t?jнW„S sk[~/27>֮om{owf;2߾gܺ]2]b )1HP=%)]4|7n2 )GdwJtwuw\~XŃP<Ă=ݒ+^ O-i_,m%y?Z5L Mf'k %ުJyW%|)'ØxwU nNZ oa|K^3L`NϪGyixέczqo~q+y\A{ ;)j?~_q${|F7t>C'(Pux#[~Rvl [3MRb'Mpq8>iȱ Gp=HqlB@'YcgÞ.[Xe3|K(}42<ʄ~#f @I٧3@ַnHNױywCHIXkba /jzlJj㑳ϸ ][ԏ=JpO*;~> } $? O6x1 ;c+>tls{*5xS'Ryb-E '| X>iKM>l4CZ)0փC]צpOmid. ui=פn_;DJPuVRan\Nx 0ߓ~T>FS6x޻q$_qO:x呻]Z4pǦƋ=$O!:b-E L.s8 ^)ti&wL.>v)ӿs3垂c_^TVWb:LTQRS۔׻7ʹumԏ+x]>q|k+ՎM8;ϽO:/݅FS/5TIVz>8p>^;ILheo+szrX#cMG#6ZC;5+u^$adU۳VGjOQB8 I>Oòc 5n# ~D* JNO<*oU44p¾s# : +tpAہ,h7(ݝ;[va'.v[ہ{ Ł~Qx,8u Y綒O9~yGQ =һ[8zfq%XˣXN8S߷[¡9_hXo+qM:Dfņ(BQו?e3~#Q1+4c(W ɿK]:0]9e3&0N=ySYJᶒ{*+Y%O(_5S'e~)(P(9N$%yqkO BX"?X3 1';bV$Yu>%W3F'Z1x}p8Qzf#Zj)ɾ-: o(myfZrO.@'#-nOM~xʼO/4c+^=8֏ %7ݸrMvzIbVlS'0z<SX6zuX`N:sعVs.G>CbSs3_,?prA ߛuLލwJͽn/=C?vzr[ *=wyxG}qMX 3čW ?+<5tF_=l֋gUӋ`>{9mu(>Z}Rrf8HSb"Ob=5baełUO//&^2h /3rtpw.p+f_;a۶﮴= D)OOb$y>@8c#xDKޠC-^S0їWZ~lk& )G5zWE*(QL0- |f%%M12{"I%'xʺ})xJXIn(i5+R2(Cbb1bX`[O Oa 驇xXb|r!S @iE8>?/BRN7q=iq$uMtUVVEx LZ; |k8k 8^hDZ Ǣk{ X]]/$<\<[H~1Rɗ؊4Ķ^vgqW=8^/Dm7;t6)KKP@8'5W$O JK( d;?{'}t7EQ ܳ۩JHC !\~7__&;p3p =_GO/VW0nwNpY~h0,`1Xe`9XVU`5XkCax<O'Si2LuF`c`<l &gg?gg 6[-V`k|B xl^ ^^;WWWW׀k׃ `&fV+ {;D0 `??8C0p8 Gp,x8Lǃ$OESit0 g@ 08|+8$48|8> <"2;\.Kerp *:0\  Wo׀kOOugzp9% ok[ n7߃? n3movwp w=^p60s<0, "8ЏZyyE\Z"XL;(˩3\y9+nIkl]6Owj9?\ֺbUM?ZsЋbsKn7`ۅlXqqlt[ƺ1BCH ٛLm:TgW,ptzib9n{/Dm$S Mnj9 ]ky! O$'68 7`/j<8{T@,㯔(DbYa \FjÿHk9_/ H[26пYbVh|OI$ -Z #J溔Tli5/!ɕZ^*Ap.?I|'ٍǟQE7V N]a}Ezy߭vJ sIC &zȕ{Cf%?[v>_?߆s~TM&O:p2ayH&~D&d+!^do%%/e Zk}L+aħ Vn(nٽ5lqYW?{;%כ !:SϐZg?ďu+5E~*!yr+Kv4kWlP5~_Dog=)nשּK= BRQǛL9į>Żck|䍧paƏ9R÷cj7,R6W Uw|b&@nNK\ oBSCbWG%(6>[Ma&e;RY˫/O;rfb]r\w糕t_†Vg 6zɴ@SΣGK2_Bw+q|sJ2o|n7+Kk~2{­&ي _>Nq`i4X~sH3N%( _ODzPx7ބV`-8Mz˱;%WKݛ;+ǭMqޛ0ǟ\Sc ||vҦ w%қz=lZiUX$~FSNa޽jH, S)WψnȻ|s]!/u~r}+ =_ey{Lbp1N; 9f?.hI.^r?uQSlIqj57B4BG'_w0SZBXa+L&JsO"ZBwA621#.i[şq4Ms]Y:Ab߹ C/[aChzޖS*R&D? IXO2H?'c+2,bDKXAA^g議ZX^)g$t3~P^;B;m.*{5n_~JlW@e+͓Σ;! .^En{Z _\9Mq{ug"ČݙrS{ MMRAK.K1eʸSB#duUt?J:Ky$Kg)=⥴sl"D]XF8:MJҦ+tPS\W{zm"OEO7ʱ>ߓU^DWTy\xhGm ]RW?h>ڹ>#udŵ/=W9\RV^L_H:pk Rl"4HT/i W1{11AA1a ? IXO2BLԘbD5㏾ u?'c? IXO2e,'c? uןIO2H?AП?@ H?A ҟe_:&_[$B_;fG_,'c?k/gjQ ( I]ۭ16DOhXkSF"? ,z?b. Q55rwR'VZ-Keu)La KeF¹w<]-_BYnIaWsa{?v_˰"s;ECUl\w{{`0F2FP!n{aXk+ x7th {Wjn-&DYH繐R!4_p6\(ϑ汣Ks9]"B0Ky*v`|Կa7%BrA"g׻>!^;BJB15ȃi/>D^H=F q,d'廣єx*V)kkP+k6{'ڈNF,Twn?T$&fq M|9@ @  O#E t[8b;XY,FkhH+ jaoy^:Z-~4 TYK`Oj`l㥍AïdoW {Q~s9m<GE!t4ơ@ 5t@ @ @ @ +V,]tѢE ,xUϵX,f e"@:{ۏ>Z𠣪Q^()q^3g e",_<|(aٲetk׮qTV?cƌ ѽQ&tk֬wYjZק^2 9z>G/+㝿َA{L%K@y|!ƑǎD,.vL>=p!P}2/^;BB?[b0L6-@!W..ؾ\|v<Glqm۶m[:/}vSe" vDg/Gy=ؓ,p9wmok*e",\Lv0! {<'٣A?[867D `69ƞ{:o;&ut1e"jb'ٜIl6wǾ}wbKvAtoc t7P{'~rޙΝ?E ] GM}!$!1k<; aVn Qy¼5o0oF+[ ּa~HHd;*JߕԅU*T5cW^~= ֵkT>-Mj}ybaF}V#T ej-zwsG4i !pX+3|E6_٣S)n^ٿUy f冼b3j.9=EQkH}_rd\UuiU|o*5WS^bW*1ڽ!2k/ UUUj݅,$C8Hzr<wKidOo_uVR'(F0D_\(p.3ρ)am [=;e%.{c&NXW? +8ڽ$_^7/43NlAm?,Co4Xɵ'VǥbְοcjҕZ2))%.ѐ cY/-j|YJ+itO1F). @, gçVVYŽ{] @;-687~h N3ws^_kedPER ,x 9;Oʿ'7{ îxeV rv e^]v([,[Hۋ]V .y.O?Px_uQE.L\0۲S:os/(9g=ee?=W׾^ŏ4L?5?~}=v˨C ȿ?1g] -./@(/n*W-(_t鋳JM)~rqE*1p &jޖ7k7npڛZ2o!ʄ2f -[ײO#l)GMV0y`>5o-H?rS:ن]u(@/ϥ85vގsQJzmuT+S}oSsIߗO7y tE૳t}چyn^UDRkS6\*y xynKs|ՎW}|녮2*s`_ح|>r,1` ErE] $o9w)n22G\4}};viCyϟף툎: ``ۂjvtiźqUlQ;<ؿhYwgNgQJ )&o@}|zùn[6/󲝼*u ^A(hư´!& Uۇh`~wNesxe2[,a)H>o\IɅN)pE{{Zms]{LYt[ﶹ#oG; '.ԫhB7.%υIgl5Mx}+$Ǻ%lQuΐmP>NL,ثpBS;dH?qUqOh*@2C9;卹5\{{V0ւq7ӹhLG/FQI{R;ohI8^怃LPfI}mпRnqcvJ;}]n` 4F}ps)E' Om_niK 3emѷCF˷>n;ZyfwzFf?v}ه/e*})ع+߽欵N?wmunqs]gםڄuW7Ywe W}|9[,V)sqGXqQ((;S9LjT|X0 Ż HeHb;Í{]/owC/ !l.!Tfb6twO`լ^}e*4b0EoEL~Q^fG6*ʤ2LٖԾLǣ7.3 }T2͢eq~IeY[*Բ=7p{2]sHY.~ \fLL]C%Eó<0ppc-Woɟtc߾  RX;^VCIJV[.=w \׿W_]?u震M(p^ݎ]SLw}-'75ff:|zb-7CC4YaoZ=bN5^_JSTãswv.ͦjȎ?9s 2 jaHj_vP jNX _5CloPT9tc _ _ _ -^Yݟ{>(;'leYi^%᭿Z"T}r[TUŭ2ZjH8X՗.ӭj_W ("jHvQDpU. UooR a$H}7H}7=/ UoUCGc>W5HVw\ )'=A-_aRŷb7Ou9G[TPKaQT/P~LP-?>#%/?E_hOG5B8^ޠzt!U#CuYe(''H}7'a@uTAAAAAAAAAAAAAAAAAAA}7H}7H}#t O2_I?6A ҟeQ]ہYfLp8]-]JK]^e w/wk!*Kky2cuEɗ"8ʺwjN*'EC/Z\׮1oڻL_^B>w!y\|Y߽Bm2jUmkwۻϵWP皫5_w_A?ռ¼5o0oF+[su#G1 ¼5y[aޚü0oaV0o+[syxۣ~ `?U&ZSss?H'b No]?TX,L?c-B WG9o~8[!diMNjM{Ӆկu`6Qs\-M.Z:5<歹< \myk.¼5y[aޚȭcANtADü0oaV0o+[sy歹< \V>}3Wh%\`hͅѿg$o#ryevᛆ=I2'Kܮ/;+0Kg=_UqlfGK\Go2z_%}#&HE ]1_=(^h|f# :ᷡo0oaV0o+[sy歹< \Fn8th'FPjn@+oyt$hH]:oF*+6SsF 4_ }ߣyW|{H\ j*3Wz{=Bŕ֨x[jsO,s/穒GN*qb/^v?˓1@>"wsO̻Wm!0~WkC߹}*zzE`GK zV!_>CH?A ?:(.̷AG0gc״1ux@G~)Oޔ_1oڙ_N{ȏͩS'g 19Hh董GAGSÇk8(B t9t@GSymm:B+%տ8xBM55Hh_S+%՟2 4WUJ S9Hh_VZXZZqtw\;rdb {߬oa%Aq}_]P^v#+:z? IXܡb4~B{n;=f:_ =cB/Vmu ٢WqUJ !~Q}u*S}CTPAT$y:A(D> !O+d9H[Sme*~C&==;߰"fOyr74Z6w=d-̈'+m oh4(n3(וUdvѠD8roh43*-~C{YRҲ^5c$9I+vD׆6!}F 6$ǡCU%Fg]1sm-݊0kE"KZr .8kiHK\+ܭ(; (r rXd"<@;e);$%-)Uҿm}yJw.Otgf|) "K (W݊ J\Ʀ!"{-l#*&tޙ}N:l_N "WEX\8+!iLf)(/~6ʝgʳeŊۨ"%* NߋW?Xڋ%.zĥ۪w,Jt%n[L {C TU~:4M~!mOMA*!{Y^-_Ņᬭ+68]Nd[JJ ꯼߰~=!ML߻XK!{܋g.TV XbR`Yb?GU7P܅g:sfyE .tgZ&^wCwoQڣ]ˏƵpoof?'ϧfo ֹ'Zai-rUr3%ynD[dcݙuw}sHp89]3>6YD)LNMl/~gs\VĹ)OVMZ*XҒ׿Mi3;gmAV%44oyK_k,]/cKW]\q]Z0F=}Ol6F>Gޫ܆2`1|/[:>wj>:k^G4yƊҺ75wWwY~4Ͽ>⛗oi0ռp?_`$0)(x 9q ~ 'OSis K+0 L~~ ~~ς fY`6 E'g^/W<0  ^ &(oBo,o K #1| >/|bj`(le@ûTJPA u4m4fZAht` .v=(0`{` Pup8||| oC0p8|G1Xp8N')T]p8g9\}p8\.%`8.~2@&\Y*p5:0׃` np' >p?x< `"dG1# O'IS3x L߀߂߁߃g90䁙` 怹y#x 䃗/0_`x [,`1x,R>pe!| > %(_+*%`-XJzlfx@ AUԀZPAAh-v:Av=`7?^`o50C~`0|!P0 G#Qhp 8'Idp 8|Ng3Ylp8| Ebp FKe`$p .W+A \ Fkhp-cp#n7[6p; w{`<`$0)(x `*1 x <?tk7w,xy`&f9`.x^%2 x_??5:Xo( "6X K=`|>O39| W`9(+J k@ X ցRl&lPrP*A5ԁzFA hmtN`'@ /'M^`o50C~`0|!P0 G#Qhp 8'Idp 8|Ng3Ylp8| Ebp FKe`$p .W+A \ Fkhp-cp#n7[6p; w{`<`$0)(x `*1 x <?tk7w,xy`&f9`.x^%2 x_??5:Xo( "6X K=`|>O39| W`9(+J k@ X ցRl&lPrP*A5ԁzFA hmtN`'@ //{` Pup8||| oC0p8|G1Xp8N')T]p8g9\}p8\.%`8.~2@&\Y*p5:0׃` np' >p?x< `"dG1# O'IS3x L߀߂߁߃g90䁙` 怹y#x 䃗/0_`x [,`1x,R>pe!| > %(_+*%`-XJzlfx@ AUԀZPAAh-v:Av=`7@Q7_>`_0C@ M-p8 app8ǀcqxp8NSwi{tp8sy|p\.`\F!rpd`ׂ0\n7q&p3 n;.p7 ƃ x< & LA@.x<'OSis K+0 L~~ ~~ς fY`6 E'g^/W<0  ^ &(oBo,o K #1| >/|bj`(le`+(TjPjA `hMVA]`;vn `& | } _77A`p68 wHp~ǁ Dp8NLp8?Bp\}==qƂ F0n[mvp{xp<0dI`2S#Q'Tc$)x < ~~{,O 8dYxul/r㧾ރO{ 5vїqg2Bϑc+ تwu j#|tfp0EQE dw^9Z׼} 1Ҽ(V8*fY5o+O>(F//Qo덁<$M5b+Ÿ]slύ\9K54" tiyD:}j`r!vIWQ4I0pŮb uS&yܐu,(S/g~'̮nEQE ˣQEQ[;(*D(A;(*D(*67zkZ;thCuuwN(mЎwlilf{ӪXӒ>O?0xU ۛ]S]ԴO ==пaR}GGSv7K0t|tK]}}GPycZjHd{S]a[<8ѫOVMu}dfbCG'ۛVE]kHhۛn-RԽSfKYɖXH]6yZqhWuk;ۛVE]7>|Ba׍Q{R;\nV`h[u* MZ[r2M0~R?PTԼ~}y%ڵMT{gnQ߲:E]i5Fan[k+QqacyUbg{ w -^]pYMyo͚7ZּZ,{-,bpCS["EX8{mH_m4v>*_R(2{K6ǔgYMZ4 شWmm(57-AJޚּmk\ڪi9ų3{P 6UT^Q9h9jvNZfll/4-Cv$[{U/TdsS&fխp~wQWTb X<wlȃ)-J?фsd[ݒruFy w 1Y^16AQ|C_cF!FH$@JlDжmÎQꤜEyk&^h]6.{ސ2%kbkCL/.|G;L0߶jM`JI:l# W6ü_*/|2kN&J mKA1$ַnm3"~DJnIgj9l/.JSng{Ja0ihi-;'[{Aw9l/.J0 ww(ܾ1·~uxE;ަ0?ۛ ^]ԕV!;`d/6oŸѳ{]Bݻvut]_@aKˁeBh[{Oڴܽg={6.w]޴j/.t@~5[{1:O\;PS6%5uloZ~ a_~ǫJ4lrO劭rpm`чۇVUBloZݗ~GQ1$~ynQk.lnwjQEQY;(*D(A;(*D(Aa.`0 #j^|uEQE =)(*ZQEQ EQQEQ EQQEQ QEQN;(*D(A;(*D(A;(*D(A;(*D(A;(*~~NQE w +='~`0i<`0R'w HHMwJEMs@50|t&RkҢ<`0Iw5- )gϟϣի{%\u |x^-+ߓ%亽bwh`0XGb5e0yHHZ8H]%M˵nZ<6`0b;EN#/{:;7++_LМ򳲌-Z:}S`0Eπi¹ĕت^ϴ<ǩw߿sí0SS,L fi$< ;1wsj2i'jq`0$0/-[ݴy>*pI暓5VyNXf1 F"INz'.2~ 3 %k _k^Mw)`-wnט<3-p`0qzyN^$g}?';Yyg3`0Iwo`0i;`CD}@ H6_r`0);`CQEQit;(r"EQQEQ EQQEQT? DQE%Diw~`0;`C ~M,T%~`0^#J~_mD~`0^#b >Xu ײK`swӋ2 \Lc0 7Nsdl~]p= tCD6Q=,דJ'sqB Hr>XSb p=1~7Xp~%O>R^o+ 1"N8L^̔)ɋNb wjx 1P"n)lΕ'ىiO^3#8NgjY1?K`0V$ߕ4pi SNOowYO>uA;ჹf`0H$ƻ\]ٶ3^o.w<(~xJS>]rs➝V 1`".>7XrŕRw`0`0;`C Ac0 F:Dd~R`0R'(4TEQE9(J(t(J(tP](4D `0`0!w H1 #~קr  Z$~7*+ aUX(j|D2L/*٦m.hKd"e*-ʋ7G0 #.m+_ʆgIwCj҂/,2KӼ|1})YYY)< Adf0 F Enm3lNP~:Isf|kXnq?@J8}G #7T' wî>۸!P@wa0{خw7mބ،7~}!26dCT_`wy޾ ClI&"/GPћ}gIMmmR&_ݸ_&0{=f[|m1lQ-J%Ff{Bʷ(/[,7V@V_R gZ-(<\ݶ5hT(k[_{P]v֭ըVZ1p`=,e+a2SwJ˞L>#3U>sel|Vi\UT~=X}ː)&?{2s t؊*2+>ñ8ic zJqJʢ֯Cz^{zHCͷ<=^g>L$V|MF+ڊ }ъʋKȨ>1J^:7*Ґ<׍W"{CQ _~_ _T̷\[F-3΍uQi6u#T!w'^bџٟTQQXeWWUi} WVJMmo.j*.kt[EPapUg'.&,xώY]EiLZnžώľ_ q;_X3cȑP^mkՂ pX&,b/g;iu,kʛų&P8n1]f0Ds4B#`Za-zN_S\#kk\Q팑#F@YFj늞+Sj|ՊQ/(=78 oL1rbQ]ф3&Lkk]𦑡V0͂ڂq ZMb뇞rQP0Q3VQI~thO|Ԇ i.ms3|$zoz|=6NʠcM\F^acG߱dΫ3E.Δ %%[m/w@uuJ~BJnYS>Pfe)P[o̮6_kX-KMUfÉ] _5`ohXcrrX^i.y/[ A&p!eE݄8z,!f,_n*] Ȟ ՠ23*&/ܨsVnFVd+#.vurcdcwԷ^6UPҲg0##(]**S2˞ 7$CVP?WzzZqa=oRFPf(].%:Ai38\p2-eNsiAk|i󙙝]w;/tZcBdE:͹+Ųe-ö[æ֕4l?c}غX?RvKarG햣rەv;Kܾݼ=Rm߮*}tQjMaKInva_Fn_l +Y%#?oS-[, ;}%Zt+Ejr\Y ݾrvb?}5UiRR@@ZT![-TG0{=fpn׮]|?|ѣǟH ==B7+{sekO9MhXOбѓz|́uahal>{8L%ҩw?NnS#sg'}?{V&3k+Uݡ_NOrݻMG0UvU^e'SCeQ=u I=:a0{8rq=mdd6]ݦdeenf_V7¶۶ѻýlf(=HHKy H\ Hl((*%D(A;(*D(A;(*D(A;(*D(A;(*%c Q_]@QEQIEQEwEQT:~RmQ;(j ~GQEwEQT:(K ` `0!w H1 #~`0t`0!w H1 #~`0t`0!w-HJk`0anӥ)7\հu.RjVCW5hBĚV*~%Ң' ^UQ|w?JŸ;RjV^ ?H7(6?C~H a[y~'EQI.X.rV~GQT*~H A(*OrZpxݹ=\-u)x=ID|fV~qDym0 D\al^mC!TQ;ݹ(Jf3m9m|5Za'L'Zgu/ nV^CPilimojҵe{ ;ɣA;vn߱9INH`$Q<|]QLl{rÏwh 牶[s\/̛DwkvIõG?LhڞV go$yeC>rd؅jjTy qR 1 _THVg?z7ɊW|T\¼LlLG7~= FhQZ $Q.FrϕrV?ϫm__|^)_dV,PU<_۸tb=Mި|wOi2p~ƓDz^%#p2GUXݗ[sk ۪ mNe [k6W\v7Iã @oO)Wa5w --EM[kחW][Zҧ7^h5m*x&^x~H  ~acyU@7ި.x^h5\oN2pxƓDDUX]c[$~m5/#c[SJޚ52]^*P2lyj ]2.H)l]i9<,²HySO1jU6lTQd6<-,2Dce~SkDs53 gP* ʘ-BU̶6Sj8OwhNd/$ 0G u ѴebXx(>~HyL5ml]cJ#H)~]ZNٍ_Zָ(G=Nr [ɢ$ . SIm--U 6; zKCdQȤ3CȜ*FQ⠨؊zHɘ-Yo.SpN=R6zfC0Ҕ2]4eWNd',[(TWٶ/4O<Sa!Ҽ¦!Wִef61.O"RW]s1W56W UPŸU7W8, zK)mY&g)l{;/3l1IC۶r!{~U \Q'tWdB뗼D2k{|X_H3(N<_^$.Q:HjfI̦S̒*E%W՜iBFȜ19*JnlRUd6F'3CY,/2?'1`j8E22_,/9S^MOlY^,vS4.-vW=tɜ̶{yD!kϴ^3Wukm(TֵI#ko{7Z?}#cg9F-.ertɗۏh:1:IM0G*>Mh.GXEb2,{^&kbR 2l<Ա^o2t#øEb=v.j 3~aGWW4%Pohi-w6G ii{B(vg/zs 2HTc#8I^9z#L؇05u GU@0D/2}m'eW/Eݪʭ5gn]E۷7W7:R_-j_v/כn/gO0veN"%ۇC]%zVh9 OވVzy줡zR0W>rO劭_õGoZUY UlÆ'\q~t{ctZB tό #"m[juN-yOENœEQT}s7m>هr*wS%Go^!lNI(j`(!~SH \MQr7}zMQr%2^T~GQTʉ~(HxSyEQ)'],#uOwEw!$EQ)'b£#p2GUXnيnXJgV%U\Ո:xժuGQԀǫWcDKH\-[CEQ'W/)Wa5w!֢(ljnGH̑rV~EQTd;)Wa5wE%wZ[ ;ei^O~F`eyn,纽@n]hZ'?K^,B|8\.hԧOj8+ԉ`SV~mQJJ`1&X5?H>lNq|׃,-WP]z ÔeQ,TDx?BBMB]8+Nu˸1Av6'[ݲ}w;yҝ9KNEQ$;o­;L%0sCrn~Zayi01Td^/gJ(*ɕ<~Uny$"h;VD K s=SWZV:!'Bx=f>ߍ/&ҥ2}zѶ.Wi]1غt E",kZȆdQTpztSgZ!l. ⩤;1àQQ>3]-p^%¨fCt^rO!+F~7(0ZX.U 5, Dlk =RST(RMG~  U+!g L>Elpx}Xܿϗ%\`|xE!Tyme{"܎;?F31cTG8xL գEY@amٺ(~O%"51*03N˸~'28OުS/Zr۝PoXV^F?.zQT0N'C u YZ(*qJyC;7G1&û|~z=3Z'r)lTʕZ?EQiOV^FKH W+5-|Lˣ(*xPPwA8X~`ZQ~`rB >qGg('֏6y[+/gtX(qnfS#JV۱O!F`wW 7nܑ~^B5hk8O4+ζjb ϝoEQTbblL&"ٖ{?/RVZy'-(o{sW~GQT+~U32di-/d;y7ۖk4|wE%w\ڱ^w;ku $D&e 3JyRr\j(Jr>:I1S߹{~lQ xyij|OSs Sy5wE%5ϓx r=X3Ï1 Yas 8OT魷>WNʫA(*ɕwbUf^bwIjCj8O!>-ʶ2wE%w(UD _WLi31D5Їb^&m\.eLL 9;*/~GQT+:twHUݿ8Za*D5QUuxb1ţQEN^?K*TeqPcV)QaR[x0R/:OTeh鴊 XFʸO(*%~1r~n9;pQٚ/k.GZ+T@yZm,tQ~G(`>ljz-~GQT(~W1ֻ:P]F̧:2ey:*ڍ*ENUd2HGIdLUyES80]xiEsWL%bw"*XS$;y\i/dS[w`01T;E6p,y=Sw\˪3JT4LbWYkg:/~Gc0w\:{ϫ 1A^/UWz\ijN'-ztyU4)˧F َr0O\Ro_ ʿhz0oēFX:O %ڤ.';/bm]Һ{HT|>*#K㩪'JPOswZ[3"W;z FFjWջKcƘl;Xu)jy%c.#*lͫ%6~9sS01u:*JeiY=ҹDJ#=1L9)&#ԬMj.\ 0`D%2^Tw]ZZW8ܕ'gʋ=q5R\4yv)'"i5LYjzZnd^/6bj$JײU7¬k1#w)g)WaSm^-ў߉阜n0ri.3'$k<0X5ILrfg ʔGpx:mu>ͼ:Fۣw }@pۼZbs=3ͰG Sḍ;wx=GI $ټZ竘ޏ`;nhӿ3\|.ϫ0pUy]{vNH #KQ%#0nR>Rjt]GUX HTR>Rj4~s*jbJ{ #*~`$*w)g)Wa5w;#QB~'ߣd}r,㕟 א#pBt]Qr,(-wga'^rk}_XHg(*J S?"N[*P8&&jejp^ ~GQT+~2a~~*>^~桵($ʏOZnz<^nOI=+ʧE%)w֡^;s e@{>UX wN^4}FoX'r(Jr%Y?=;ߩ92 UaYC/v/emM,(Jrz~X1W~^nN9l91#aP{O6-<EQI}kNrv{l#3ϱO 6/牡Bvo<ƧYsw&|ՠQ"<6J ή~7^+/~GQT(~^-4]clė S׃28O{%Z\(+WZ~HZ6`?EQɬb*>DWTyEQ)'],#uOwEwס?Qr߅nk!GWTyEQ)(]UTy;;) hGKe$V rAermI29)^Vwİ@Lζ2m3?0D]"z=`xHGP(0ߩ"a9$ƅyM2E-AuY{mD yu/kZG+(8ChЊLCR<,**DE[:Y6}p6;hw֑v&.!{Ԙ^Ɍ+bE৽]%jMhABecZXVJ~]AEUQ6ehFӆK#})b]?S=g$gdn;iNwOObTte<1T'{zGW?L](cQEW-ڶ;{x8nh v?{4*ꡢӁ;^Cqy~u]Xu ~՚jҬ8@ɝ~ a,OVX̤Aϓ8Oړ!j"߫5ݢzP׽>k9qI>۪=Ro;tu>#OV՚`uu"~g{HUz3`Fݰ`sqkO׍2q^~(+WA ힲ|>R)'zElWm:5osuȹtks9opvg{9pS H;c/(^S:A1݋9"~p֫<3'I[k uSaNVnOE!,>QCYnwcթW}uEG\Zt\fIW|eWpXy嫎~siCQIwj\&CeZNU(3-OG 6l4l+}wۖ3xw}_1dڰ! W Y?Q"QD"zw1Mhp'7hh 6PTx%VV Co>iT97nwU*/ꂻνkNSfQ:@wN.J *o}=A^fL;Lzk@xS_6t}CAު|7_v]l>?*GDΆ%i1e۳$}qK;o"+s{o{bkgݨخlGQaD*;n՟a#9vwTp|t"%j#p|͹ԞvG݉#}ޒf7j:-w.>;~gk>R¦ʇ;0V;ayzjg;_zysP={ʐaϻY<S/w7.ޝrm|H:{W=Ѝx_ʐw8opEUwy- s-0#WמqWLꡗ{X+$뙛GhߥQMZV]Z8=wh`߬ͫ"%B;^Ht 1h0U _|rYMCD~w";恄-D=uX< o<@mEtP8ҨwUd=Tu1Çk?PsZrC=o^V tiXFПfq˫po׼O~HxSycnlǪ>wv|pM@QT%mj~Ͻ|ԄњqFO6 D'9#>rtTyڃ߿ٕ=A~H w]u&>ƅ.6l'i]msoh.J0.ڻ;zk'XZw 5'9k%ɚ` W2C ntN릦8jO5=JwwVܚ[{;T_0;n8Q854L6X^1dʗPҿ4+?sko̩wTG?Skqћ^`vwQxG~WqmuOy ְl]갫"̮νT U9WߺaCQT? %ei<]wӘV[wʵ姍)?}liWyH;]B"*F(m%mAܦ_x*pppL~B}5*5}5箅vyUSM b"[=:7 'GW]yȻ+/73/?zWu>;]Hw\հ?ge_zU !tX]zEQDcmYSj~2sfo{ mG~or ,+]]x>{+?ךGUXP~7RpM;3Diyhy7PєjvBY-{y?1˻~\{jnR3vr~*LNfa/_^]VG,jgr> \r& %K}=r|Ƒ&T"Wr\ֿXiYK.!a"K*jZ24 Vfj.ᾄ 웨̙3g<~qΜYyf}Ar v/ʔa6&4-؄PO FQnSZ\|w32屼t)4׿7eQ%'[)ɹ/E"s|yٺ+zO•A0R}JWEwG<=TyMtJx8tWw ͳíTE2/AaiӲL71g\fMyۉf ߡS#ό2MTʖb=߉RBFe{\ghTxTSjǬA12rQBKAۧ8L]|wq #>M{A8 #.N,Cm6HפKH=͞}WݿAXQdc3;z2)Ww,&{z|g{z7X;~i0ܟUۧ8o';NqoP徂?39Qo(5e`^eI;2r~Y~OCj6*]N(Eߙ^EYae?I}م&>+KTitxS&;鮌qs-"s% &8CRetY[{ʴ|dz܉RRUU!5VmJf; N``E !m1>~cyO1H 90oFd0R752ިb|Cp?2mnwMqQ !4,TA `SZ\QS@c49c )-hXԞEmfhOo=L#̛ %мYrz1 :_!7S- oi[?IQ tm*Q&)>.|9aV*oX@x <79)OEZs6+aTyGaA^y-tf Lr;_e~ [N9`k~pAؑw;r=>;'7NzLYgc:{ [Nx-ݭɕ$#YVނS;; W.J0qFQNjJ=;ϔSiݍoAvV򁑲U5Ķt:Op;tHl1~fݕ&ώ*!ZnNpN9? SXcrMl0,NLeI={|2uSk+Z;֨yi&V|-70c|1Ȱ#aWe{r&JD12#O|"UhrX+ZsDcw2T|(] λMH: Ԟ0q|@b)*Tj~]•/M"WOv`6a-zjބV +Σ0cN ?ld&L7n\HHѣk͛;w樓& ;0VHJJo,s?ng̙=s[rǺu9500} ,=&7o 2XwMhJ/A:Vn1?p&UBTaԖ+ZeXwY4o9QSJ8e{ǷҘ-WoYSfewI O"ȉm'PyYd|wNٳ^dUnT}C+RϺ|״ٯN}ZhKw__Z*F.Y">-:%ǿ۵]/RLNDΉ99bv+*LPgZYH'#UkċD7lMZ.G}:ų:1|ofلƯ/ߚ`Pi| MHHK|3Md;(wGuHG>9R1[Q|zLm(n+s6)Ӂ2SXwg, \!]+%}7AfgLg}?<ܨgGMȮ;JtsMwaaabj*'oŔ>9y=a;zV2kVrs}tW bRc&/. Ԛoq пZ1|!ؖI=yL;~'sCJvc߉sWFU| 1)2Hy$=N +En2l+QtlϔN7ǯ0w#f׮fOL&WR9;e4v.;Uճb%mٲ巭jHEcbŽVm#-Ϝ9"88Ս X4c_߾ժ$2Ky_޵o˛#XKX۾9fkc]#>roM|{$!_`N+5rЖw+uIʹz_?]XȜU|}kU|b*ӷ_J21oxS՛!]GӺ|}%mI,V.D-NySuTݴ]wVX٭_5 #W]*,#W`jOtܸq,uk֬Y~=w˖-4izQ00+ KpУ_W%")vjo5iM˗Mԝ(1RBw7ȇEn$UMjeB ߝi+X]w Ta$/_=|KYM˵]IԤ,DIwP%ݪ-B - Vm|GujoIhj ;PxKBU[(A; |GA8 GAP# wA#@ pA!ۙtDWgtMAWq"cj`CjKz^R^u;֞M()%x N!B0AX!A(ҼYH$^Ǚt1؆OX\ѿžBfF^!P pF(N**N d B$Q,k~  E?˽K=OKo1 t?kt$|S*A)φBAVP_ ^fdury~ƕGs_n7uKU' gP*e:d uTNh #Nt1NzPaVcnnNA*x4gVuwX{O˟~F-5j]-۟ |ӓ'?n]쟹Hygڿw\*CM\WQLY<%7AuUѼ{L׎ñǺ6}#Ot}u;p׸w=uunk?ZrzGڭEGϖ|;wHve!.YILAjA &r֝&S1%+Oϗ]7y!ٕTLT,/l%(# *M\ᥦ,\S}/?3^h9$AYMOοrܻdOw~/fxlw=Wfd|}s=g;X~?r6K.ʧۓKF8K't(O)z[A1[,{sS,e^Y'o^6U6O.OD\:/jicΎ5W7w3LeJGx*lYRYguvE/u JM&;6^L߲c:ezeZ`Vˀ<1 Wl~gm2\_9Fe3=X;QC0*Q,L(^*CN=]Ggzj;"U`sxttg6||~&]::}|W.%;`C 'u6̅a>7uropL,f#y[qM֡:VH+{y.SxQZ)|,'Xʘ}S^{^/rW-/G5}CTK3.䚿 [}8" *AW|h?zOkLL9>:]P+|r:&wt<%=/l{ڐڳ|oԭ2acL3mlr[ S-s|dDvXXxʵA|[3A@Lc^]mΧcCS {]wC.be+G}X3K`3KAm!ia tWK&7/t+$Y}ggHy탲f'Y{k+w:~=~ w Ć݉c8_ pqA4C7v/}|s-߬wWzݚStnwS/LExgcR}IuHSºf|A!6S}o`wUf1 ^K.gڸ)<|'cFW7TQ9oT3FsnFLj|^>rQVfW}UlLy@jv -'# [G m7$m@hCdg|fC鏿h&=Ӛyש^ehd7;fi]$;֝v4w9YcNߙeHQ\уM3U |ۆⶦ^HPU1^:UO zLof4)[PFsPhvqYrk38M~gjԦ=SIyǟn^wHve;|֗;ΝjxC_oHyOJ}')O/<Ν*}Uk݅>l x.C oD&=njRaPcn3QMf0w=3}<<9ƈNC J{_33%LLm0IzOH) 6wSpE2e]Ї9ld '~7vNr>|?g{9Cf~k|f_pWܽ/pU~&w':#񔗎/s r67$;el".yK5R4w"|7e^/-\uyβ}d;$Ӳeobϸ3kx/zo-@;؂M wG<=TyMtJx8&aXNyJMÃ#.N,Cm6HפKH$;wh-介9zfmA !1Kyo"yX[W޿Cv4{~ݽ|%x <ٙwr+|ۀ*aDAe;[<ÙӉ%p~ߙב= >w 9!4Lv<])b |[4EJAAԄጼa.g`Lu{ܐHHykgNw{1Iq3СIAɅ8q9H#ykz 췇4';RɎ )-hXԞE!ch!Haz\#r %7* #{eEq|ljxrRI=p7 `8|69| > "l[—˰| _aavuv]a7ݡ=`O }`oB_ppCap8p ߆0c88'p 8 =>?™#1g9) ΅/<% .7p1\e0For\WG Wßp7_a$ pwp ` wxFÃxGQx 0'aS/x&DxI<a SaL0flsȧa/+^E^߰2X+`%:C  ox'?x6{}1>#QlO|6O3Y|_-`K|Wk5lv=;N;.+߀;ް {7 ߂}`_ A? 8p( ` G 801p,w8Np2w48߇3C8~?l8~?sap>\_Åp.KR -\+J=Wj3\un&+n{>hx< x$Ox O0 a2L`*L0f, s`.̃",ex«k:RXa"n t `CoCwOx {>Ç(| 6'`S > ç,|>_/%| [W5ma;va'_avo@OzAoo>/p @8a0#` Gm C8;p'P8NSp߃! ?Yp6 ?\9΃_08._B~%p)\a.p%Op5k: \7pFp p wp Fp`4<ax` <c xx'<aLgY0 0t3ă90|xK2 UX5x K`),VB !tۡ;' =^xl C?a|>)lSi |>/a _+Ul l;ΰ 7'7{^M{÷`~@8C? 00h6 !p  8N`( ]8 N ΄,8΁Ogp.~/ap!\.0~ ~?U' pF #fnvn^0C0<c0< `<0&3,Ly S `:̀0 f `> %x^*,%rX+w@W6n6x;tw;ݰ  7|> `8|69| > "l[—˰| _aavuv]a7ݡ=`O }`oB_ppCap8p ߆0c88'p 8 =>?™#1g9) ΅/<% .7p1\e0For\WG Wßp7_a$ pwp ` wxFÃxGQx 0'aS/x&DxI<a SaL0flsȧa/+^E^߰2X+`%O@W6n6x;tw;ݰ  7|> `8|69| > "l[—˰| _aavuv]a7ݡ=`O }`oB_ppCap8p ߆0c88'p 8 =>?™3@G.4q9Olbf"F6"yHQ q]X*l &BC&a+O2tc{tEey V_sWuYy0,0Ry+iD5ǟ{?LM;6%~3>ۻg &%e #̴9Q ĿAc=rT9);!=21uO ccg]V^~7RcON#̎3'#Ǹĭ N&nMX?^(7ăW mUh #*1Tu&/KQ3L§Lr-T T;%NG U1ALv}DvOYgɸ$>zmIx+߮BOk>)lPĿGg]zǸ gY}U1|t}a;ۖ(,15ګ6l0S1}Tvǿ)`Dpi}T3o,et)ߡoc;ظMCſ"Sϥ8jٍJ,0bUŤۢ ^KK.¨uBwoӔ[>MǫturSy-|߭WAx?WehlG 7ɥemڔ}J¢wm3?S&o<֘E٥|blΚYf8i%xn]'k9¦Y}?>η=cp9pET_ LXƋd7^W๹\:i`[0(ofݘ-JFLq[/i}ukK.Ŧ}6NUL^3Y%|YφɽX]ۚlGI,I1g?î9 %/ml cc,>sK.۲u5f6UZc.V-clç tۡfg|HTd2u ukv uJ(sXğRvJGFz*/qw-t>ua#?teNtO\[ukQO˔*fPnYc#hј.u )k0tOu3_>(s+r~ɳ6]?rğ14wq+Խ{͟QC)ς%0QwFX ~$]g?E?.ESAd _ ?w1Ŀ8Lu C /K(0]ʯyGӭ\n*x.HaO!;:u9ܕ!3`7s0DPƿs, `>C^1#a; _>s_p9ջMOwd(GOwd(GOwd(·;:w\nF׮_ԆY⏊v`qThG m1zetOrmmcvnx|v7VCi+VWI-^[~by:#c1E^}_l#b1-ذva{@6  ~Qnҝ/߉ I|:6EuU9ql2n8SVś.NaWb`SA]cBٔc#/,s╍9 2nX:]gy `FT ?/M,ț7[24ʖD?FT `7yigmg.28ԣw)h&Ht46:fxElX Z!CⶥPjo)>fZ{eݹq.O]%ȿ/%߭Eb9ZԵkOkwB׶ԩ; u' şP~׭^J_k[P-߰EşP~'AĿP^}+lcOE|sjuu?şO*ڼ|pYT6ȎgS5$sGJT_b/]UmC(}rhIY>{1TlLlY5(g}W6Dc|Umv. mY۽_O}?P[(E^SUnr:%w4IUP^E0şOk*֣͹m)eenEo}ols|/_ YUTK m_YKYO]?#[my@#j+Waտ窧y?(_$t\\wyf>%. M Bh08ȩ$7֧oAG̓CAH.%ߜ}4k ¡THhS@-0PBhBK+ aq'hd2Gh}vS(L#4ĩˉ[sl;AAAAĭ; 1B>A/jC?"8     Z.tZBEˢPG MXz)!Z_9z$ d7qQ_qQOwd(GdşP5 (3[f8%ſal?\ ͡S?ߑS*比\(mWQ=([)oDŏ}}`5ҨLqqofx%I\ YӰ\?G% aϫ(_PQHi8mao0ĊF?f<>G|r BFE-'?**Z GSV+y̕ |b!lQ}J/x|R>g0"e\RaRDaG>J>|:P>&@# oGR1sbU)hۧ*B}W3:@ :.4 uMPcp~Ljx}J[.S 6GǿVoqPؐ]]sZG«Gq*V7EɆJ&KȻASP唞eR5§ފ%N⏃u-ς9ڽ,^j\.j)6pdaO~?*ȭǭ/+W{rtexcnw/`HvdL6,.v;b}RYCkWxu||=E?cK5WҀ|]Z,Zc~uUh|Ck Btef= (|\?k7U:Or5J/R.p{i)0^yl~N7S|fHbc 7SGt哱 ˲ ٍoOfG6?yAƳ>/ͮhh|: C ]E˓Gyl]4נklmt ^X^~W"{n ^1_4] -~2ilFh2iKi Ccy׺ꆓ4ȳ'Vg u(mS(qb.uS˼֗Ie퀌y`=COR+Uv%sdt|UǰFynnHE׹Aذb B]Iz邏MQ]9%LX-fѾ=n]?Lɩ;+.uX-r Q\a6eT~~2}1{~.>]qft04J3Y]ԭ{gGS TOx o۶p&52\))n}N%0"m~yng&ܮy.zR%GQbnͬJA~G^J22w) y,+I5;7528q bV ڠ2NtnJnpe-ONĀ{DJ>R?eO!P0_y:?PPsŗ1| **2DɑN7BXI1*l,e?0%)̭o]9] cG!xGPl d1'rkVm]6_v9:ߨ!Rlpb=Yli,R`-'HȆ]^i-M5v@=o)Rj ׇԦb9fJt裢-i.?NXC_cd6-voWPe/A P) O͚W&M?E  qQAAAAAAAAAD k*TPB ]y[Bŷ 'e")AW rnAgZQoFvFͣJAhC.%UcU+C30V$8W" &4DJ_ppT /`88@ ?%MhAh/`hs_qp~)'$_!aѼttsl9=AAAXz(WaS7|_ϟ?޼ysŔN0A󭨿Xw@~%R*>D?X;pȌ 15ULNyͷb%-2y1jF߷o_ͷ`% .n]$.W[_E@@QXXօlX5ak##gM`ŊヒqYYV%K#RƤI_:tyr^AazuGK))snz͚5ׯXl9p@^vf^:VW_!(.6~|,C腃7>IIرcbȑX VPP;zOlI@hCQbŊm{wz߼#W##ă|y$ųg1cT38wnbqk|g˖|ӮSg.ű<u-G}'?|SVg>\3Z~bM{Řl12UѣG/~wE0|ٹV?lG`a|&6Xi͞gth9񙈈e".E> q],YvL |>lGjmFٱwĆ@AЍ$M)X7P-[[Tđu(fx$L\N 挘 >-۾f,u6"; +CZG?6G=+i*zt#cb+8yO~QU׽`%6k*N|ϗ=1Wcq_n.J\xlvHi$]:m|M'm7\=/ GJ#tP) şP) şWf_:"n"M' AA8          TPB *7 d@q!9:'e8tp\" !&%}ӴGOwd|3ǥã. -%EĠB-XLhI@ !N#D(wp+5Dpp? y ? 9w Giw-1+tSGvfOKBs Ɣc{<ʏÏ}fF*?>LN]=b͟G ¤ ৌSpsP"+NBv5]nL@'ưtc &t'ac5hnayNra`!|G'8L@i_ 5ۢoɶ7GQ2|ijc:-1N']VYe}q'ɮmlqmۄfjI|Xb?bKK/$}>)罀 =3Fz{=}x@ K>/l}^e[7U3@QT~bϛrW-,X6'oO~4:Ñ9fO=?{򀬉2d1ŷno~1#Tg= `dU.|Ts.OAENOpkZA:!WҠ^^90+`C;4UhD(4;CgN*tTjHRIB=PTWu^{ΩS'U.dE}%4^}v4n]:wˡ_ZwKR;}~],I̿d]LW PdC&i?tضoz[_9/Ywx5 |>sLJ^OA ,y͖}G]>_GJ2M{j#k?7x?ji }uA'w.(dGL d#k?U!r U/{3W9Z?yFvsɞ=.=2! MW󡛮$'5+l{ȕo?rYC~Њ7 \O?&р>[[鞥U :( 3"C?M?>ߞsH${~^ZdxfHK_G+G_ _W>2}#_|w誳x39n ս6x[η/^;$K9uu);k};z.W]yn{W3y7 .?ezHKe9wplOcMug5]|voo\֗?q7|e\-yo& #S=ALY?i=D;]'x?ܓ9uy<~I ;w==75 8%ڱĜ"Z)_I^_b>KML_OD})$)\9AFK3oU/RTkܚje H\!$<+ar/? J&`r}_FذǬvXg=br`,&blTTywߖ-[6nx=?N_oN|,v%|8<}@`wnJg8Im|ؓ%Jv֭j;v.C[.q>Y2!4ͮ_կvzh׃w=4nɂɒ0I2GG)G̓!滻4NB9'yf ?&D:<Iak)GiJϞqڏû~ί}w#/4)٭ '? }`a],y': G/ߡ]=۬y;o7{ɇ>_dOwdիxpF -oϭr↻<z?o9'arpI)٧$5/Vǭo-lϞ37?Ed1|[Uxp/WX3~y{#dk!9X%Z߶aY7K;O_>{gSCͽ%g2r"! θ/k :IKN]A393Дon鮳a:DN/i:xwN}g N3%NɦM# uyA'njj;Zk4nxםҋ/>wmxNa oLɯ~뮻xGI$} LRV*0J&[d+0YO3I6V0d+"30JL% L`ld+,&[d1 &V0YLbt^eP|e.fd1 L],hrKvq-gn|]b\ dK??p\q߫d[ dKAa8O/cE-\y- 0c[ d/(NndZ\,XlIV(̢`E-ɊY wy- `PzPErM+\\ V@gQsE-ɊXX dK"@0W1ْPE9&[ ("@ɖbE|LVԥ4+`QsEܒ-͊Y}C>mU+O|K/Cٟ_+N,hyDN^Ύń-yo{f2 KIeOa- yv{GC.se6C10~ Ξ $!Il,DvUR03Wf|Ѳ\sώv_e$; !3eǿL\bV~/@tcS\r=39O_JsΗ~,燽~,/z: Gv_D@2HȄ'ۅF(0`?A_A߻^Q˭{sAC؅:Mܵ5xxތY2 iwٍ1?{'ORw2%߫ׯ/D\лwo|?nN^UU!_%Ijɔ^c989PÂuyQ4m'̕L4ǿZ_3`ȰsĴʜwJƿՑہUAgo4EǿUo\칾)`xq#ƩF۹ tQv$se:.^?ƯwN2Wz)T+ȿ+ȿRb}I vy*XW5_i%?lυ)9˟/hUDп,osn2k?g{E [?E̗Lg?$CΉgyiΣ0p݃6N&ȑ8~f?`'?Gux/ăo`RpR98/ D?ӗKF O Q8W4揝9"qY&0E~,<ϺewxA v{SRdppeRovL5wYQ&‚?TEߡ?T*G3R*?ȿ@L"& 0`?A_A/V1. | -tXv_% ~]b7GKjKY*dlw pEY J( Ríu?s׎Ŀ+ծ@Pg|D ,td_?  f5|/ˇvwE.0o-Шp]6b;h0,Y;z.2!}^ dl_i7(}y^/j8 6Ku_ +l-^۹$Ex\|CVy,ܕ"7p,aZ"_?WWWJ̿7 T02M'?A)E6>Ǚ~t}VmӒ|a%+8n, ~] WC=?k(l n@AEsGv2"̕>БRai78խ8 ݑ/ |P&#?_ZढAT*/xqi"q^'4܊eެ}ͅj}Gh0 t^XR1:&o<0iI!rY%φ L:8|04Xp7ٮ.<_L}~מB6镚jƩseg@3VB)"oBI?oGLUw Q97N*J_I6 qL"hP bb]:ۈhVz&+x=]M/Q,dgmnO : N igOCPZ`Y%TT,ֿ2'J:ɿszW=탹C1 uuf M7eM>\41 1OnӾFӡ ^ 1w? ӆk L/οm{9t]?2*7׿pSO>|_s?V9d/iBq9Z` \n(*΋ɦ|po@]BG ge[%8?/7{s{EK&?_>X ~(7{g rGG 9YUB RsegʿǪ zaӑ_`VmI斅HKw }]+Z-U-vFa'Ͼk IsU Ǯq9S&eHȿ4u;,F7ʻ;uAӲ#W*ED=&e'g~򚝛K09ؑo>%< Tf*yJ7'/3?= 8f.m1ߖNnٗ?55(0ozn"=W@!=A4n#{Af֬\ycq$ymK]ݖ4uue3c?|b"uu[mxU{R6 ŻV ~V9|@ @ QT>B@ @ @ ,Κ;|j#BҍlBֵ jGP; +Prm/6BmG4mXnZQ[u-@ @ 7@V9|?@ D=/{i2#MĀX@ Wb6O[q ?|0>җ$BFۖ-mP l`uO!+6uuV}mDb|<hDF溺ͭN {޶N랔M0 '$Ok4:nkU7[ KQym.10dƯ4g&L=##LFTAjl6?kw4[~7ٽdڒU4:Ֆ;vi8%zGA_Yx]/JdƃO$L@$ {2 hl@vѯ xnܽқ쮯1ttWr@Vl<8tbѱ#LFTAj4o@fA'^֭y"Pϛ\<駁'LY=@F#'A,6ѼvcSLRL5[j,ˉRnjq5[CK:D}[kc`KZBVllm mE)H`$<:Hph+3A!wh^W7F//'N?Эf-EL%6ljyM[X#@g&# +YqΡ{wH(وGd]ظ A#ja]7פ|LcŀD_G,zx]b!@ @ *O@Q@ @ ~~O7R9Uo@ @ @OP@ @ *@ @ @ @ @ Eor~ @ o AB`#-^ђ&b@,3 ; qk2i+n 'Ͼ./H㟼@W޶ng/y@pG]TRGyp?MXO RL;OΔ<$7KsY*\LOO''2z:{Tm=Ơp7oτ Pd!,&u5OM!9Xz`r2G3p{-%7= 9'>9ٸn]#+hRWͩG2N$xcWkY{duϺ=ysQU6:ԸqɚZV.;îzkn^ng>qpkU{\vTzx䡧zz4.$Z=Hek-%''gM{ ݓtMrrYh6xS%a?d8AcGUM45pVl5O<o<Ѽnc3Jp>&Kb dp&sɷfkt&Kʄ݅R~bkk76LKR밴4ƠMvFG52ៜryKn_H7Yliv؋%G QJ-=XHo}QȦ#2_d*KeN9$r;9 ey# %O?YJ1`]7qM`plOcMug5]|voo\֗?q7|e\-yoy~~޺4a]wgUy&J=ztvj"~ 2ANONģpy&LN&b &'H(PbHFLJG!Db|<dHdHhwq$GXdl(4S bcGՐl4:::284P%ɎOLJGΪH6 kі LzC綟*r^NυyCV 0Uf#"zJbVf̆ô]*HGę۞,f̂]+9rUNnJ'0`앹araYʕ0XrLu2Gig,Q S+2hT /3W?K~*OGl{q{]ze.hwC׷hU.x\fV@͆dz/z: {ON2^q7̕ !\gӾ*?WWWJ?Q$_͂+ȿ+ȿ+ȿ+ȿ+(俚#ՌL"?< f 5G?_ȖP74%~^Qhm s)o45gd1;5섊m];-9m΁9!}L:JJD{JTd+ +ŜJl2CjLm7s|VcIS)I*aYN- )}hv1baR֔fbSrD06 :%R:oΰ? R%VU &fdmF#-Ì!ƚ-څꁁl˜2?=hfV|hJ#ȸ=0֒LNHr:LiI&E$JjJEՈiѪFK#hbF'ǵ)RԱ0,Qa29d(IIӵOӖ8rc ;6&#.IG* 6'$3^/h=Z#49;JZmku`*=*A&8 =3a%GHn*2U>N$$+zDBo$ȁX<#G uUHDo'xLbCHaKx<&u+dg3ƕ1i+0MZmL%ґ.ǛU"ND ^`EW9ĴaG1~psm惬e t۵TkXFy5 %yD[*kx!asP JF2 aj5]ȷx΢m\KjdU[<LVDD8֮m΁1(6ZkD%ž"DYc)mk.^|ycMjiPYDsѠtxh/Gxt(j)Kjj6U%%$ZR6>XXB%V]Fvr`iU!sꝤ&ϫwa#;Wm s2"-k屍,#5:G"m(8I;"2"۝+e 0ӄmXVte6 \"*fK-Ij#5~Ń6Q֑s12#;_EG Wܹja{kV> BvqkXP"*k9F;Y R*AN\=po4vρ!S^ge!;VATyA)`3 [i_^%nw(n/ܳr2u%JZJ25[^u Š@p ]sEw03L(k7,Wݞ Gn<;'ēŠw R z 4nx4k]t A2uhvx@+`&uʊo R0  f:R;́m1TEe (袋~_lsWK}Rϲ)`[2øtÛ=p-@*}u p? # nVf.&Ҁ60#dnكs%{(vt.HRdDXNE StL"nEե"H6;tvvv( +E'j՝)}RU6TvjǝPvr3w(KQcvp: ,؊jn?*v.* N,migf8  S9hiK P{O'[ʼ~8[m6mZJjofll{n&C0uph 6a!Q )Y(,俚#Y?}%a1_A_d2n,bzW 5.Duߝ55w6p9-%_kW,ݸ^pa,;v^koڰTv ՓDw>Q.B#\|Wι.N E)ܾںvʀ!|7p>m ?r 6{q/:aVtە埝sVoPiB\Y o UA (=G;#H?"288V-_ZG)4NĹgյ*VRF>B_KyTe(ȿ+ȿ$,:+ ?_@jƢ+*.^#_A_׎o =K)?)>Vݑe~ȿez}%E_ven[d7Rl6,T*Qo۳Mna}?9[»M'?q]~7:xHqw]P [pɆ !ߴH{XHpcvziw8/oؒyzo+?/lPyx#u_oG (ȿ$,:+ ?_@jƢ+*.^#gq*3<=/ZK׏ R -^=N[q_4_S3n(uNtkVwm&w^F7]?u_@8OAj&ϷWANDwN3 cؑɱTt:YDN|'z#%ucʃ+Gާ7{@=oa@\޾mٝJi"\z7N gϿDs2nv3.tS_/ ^834*i[g<,䌇"ϧN A(=JQPPPPPPPPPPPPPP|?E  >j_@ Q%P|v{&sմvF̹T7k32hӝvBŶܵHRsTR|#HoeJSy;pS@ zTCɁC`z URp0R`RO֖HJJNR)N›LRkFS0IBJ`m7`!K+hMOlR*->6 :%R:ozgggfgff-ΰ? %VYћiEtCs2^PBfǧv6aSEF4ff4%d܊|z1 bԔ%i+C;HR.I :NH%"jOhU%4)XuI(Ѐ0uȮ SSSSB&UI݊f]&]=IpӴ%\ƘtzN \uv-L:RqKpbH=+I&Lzr%ajMr`BGP%AOgw"!30QJ#z|##f#wVDyb1UmPin,AטުbeWȤFIVYՑK[Hf!0cȑBU{C eVV͵7%յƣ:iJFVL÷r#*”xTy9:QC4QA=IF=FʊEI:Ӂp'ETG>Ҏ0waɁ5_>@]Kj5uRhXC"eS-m܂4l<@ 17H#E0w\}[#"N]ģ ;ŽȨ|j 55^  dDɪ#i,chG#)UP C#.?43{ &"F*060R@i 6Ph8O6,wph }.[Fi{ DSC5,D:.۰/9 Q/>$ۆbtVڄ5q/ҙ,O8{^Yа[w!!͆U $rW=˖,EݱNK(+B.R_ﺈ<Go-`p :72kёh+O A=5PύA'MX40-zrWF9=z΋lec UPz# d`@,FԞT趟K@?JIYOݧe.r N`g4xF":m1TEUij e#zzDETҒjϲ)`[2øtÛ㚡45;lVDRMpwwAB-Jбh.n" eV2}̻C>] TI e#IAsa:a7Ou1UH2bKP\t+"An wvttpNQjj xG5L;kS>ZAS;MCy^:US lil@I݌'Ja!?ɺa[{;,2ݦQvhx; AlJ Dm {:=RpSڼ4m Um,e/n}dư!1L2daGV|@ xRqUo@  @_߿r~@ U/~_T fkX$6y R UH^YǂyuO=uڊ!zϿmii! I*+68y O^^q]''FFo~-x_*-ˊsV|mZ|@^GdWTkf|}KlL't|:q,1>֛KNOOEYR`vv# D @ ~)NO3J|ѽpC鐾(d)w#|߿T,@ Uߏ~_UD @ *w+̽EnyeΥ^YӜAǸְ*u@ܫnv)2tj.6"g!=%*͕RubN %}R!Tu5қ9mj>1BkmT꩔$$025G(蟮K-+.u(RF pӕg'7S#a) x]sw YYbY]`XiFfD 0":̈b" ]8f` `:#PȈffu׌2Aƭk"͏drEL ̌mIх7&m~{nao5br'iђrqmcu:$Kh@o &o))FI›&=,&ͮNמ>M[eI7d[[g¤#g`8}a,'$CbBIB=oL$yB. SlPr`B=q++zQ'\P $ P13Lję1mP۸0}kLoNb,{Ƹ2&mFIVYՑK[(Ӄz': UQU1`n2t GǩD؆)(DyFCZ>Ԍ i*atwTzaQa@{F/ ^2•DQJ;!uicSŠ0 Sg"b; _.Qޝ@N^aGdT^ G(U#%[2V`F@]xݕhfa!Q͈t [YFUsd=y3<&aO4|t\O7 eR^؊v=G#HgFDs#`-$\JO0 t )z*D EOP|@ˀ|*`Fa5jP؉0m@2 1(}hӠt@wރ-Q$GuAd)ZE" ѹI BHYY 7u\ʁ&`8LAjǰ9]0 8 x*Mcԕޞ^OëlVcWm{F=rxs\ܣ4ҴG91`?xS7o㍭r9r.{ݿ'"^5=`:]S(>3Nz w&bG&ǒSS J"@ QXc?qCgb ܍~R@T!v<|?G}U @ @ .H{e!s)h`ζu5qNj ;b[N doν}TjNKͥDE֙QJY^)U.x0H`p2Sr)z*r z2DR*TpJptzDJ L7-GF>lThv1)J+hMOn&>%GcàS)PBJz7L1<;33;3KVfXefFfD 0":̈܎XWBx` `:í(2Y5:Gq`ڟaF#3ݴY]bx:LNO3$rZeImey(/Yy5,iѪFK#hb iOɤ}dDa$Y@ze0ys[\frIu'HLLGns 6 RϼP$LWWOgw"!30QJ#z|##f#w#W@ O1Gob18/Aa1:ًbʘV&Ye6U(Ӄz': UQU1`n2S)zex<'VJeʄ{`|E0e:;*=IF=FʊEI:Ӂp'ETG>Ҏ0wH&Jt m$ꑈ"b; _.Qޝ@N^aGdT[i~xd$!#YKXSXjVA% =+-\fC8,Q*060R@i 6'm0< oD)$K0,!6 ezX4,GΆ F4L ғ0 C]CCH  I8 R6 3< ?M&(K (Da<(LǠMbUxʮHTǁWhGP "xՁgA&څ@?!?A`@*laȆc`s Ad`p pxUڅ#(#C1<6h?&F dKOO/h+4nm]{sHQsk5MTn)=¥G*{UԎ w"]LXy-v uwz+uK(v]K1W 5pԩxI$ԭB踺T$]VU":X[#`K'+uMlTtEtvH}v ; e'7SN=p)t>:5f ؀ܡ;hAPA0EdQQ$}y1|XJ;x>.*,r;liԦ](g;j7LFͧ)`{:=RvP5]ne&.m XEa6Á[~>m2cXwƐnm xp9p݋av@@ru J_V9|@ *UQPPPPPPPPPPPPPPPPPPPPPPPPPP*G| @T!|r}R2:cGa]euD<,Y^^];^S==&'w/߸#@$9Yr}_NLS)jt2>3Nz|O?&y~'(d1YL“=d:YZ^, 鼒%W_6]:<п7ܓ]-YgE*LE*,&[b l5'eS1d+lB|T,O<}d1YLd+ 0Yk1K}+P\JnWIksunm1;%9$;bss)DsL%Z4H`p2So*%}.@Py!٣G QLEREZl=A5e>z?dggfgfff0ȢfTܐڱ]1s;0f ȈH)dTĆmeYijdT-2Ij$0&ʟ$}씋L?*̒Ö8tO:M^#@SS9$;0$05 w} L d;p{%@tFzSCq-1\ǫ@0 6η<(LYY>){]m]I P.@  {πiḾ"d{]G6:=zLszi9ܹC]]j]- 7.W 5puwu9pؕCD:tpOTtEtvH={A1?r)L90ҩpԘj`Nn?ť~ݦQvgviFg;j7L٦Ӕv0Dɶri6^Q%T[Y%Xv6~>m2cXwC%4Вm/j`MzE>F{?D-gd1YLLd?;d1YLLvd/~d1Y?S*gP2l.:` LRQgc9L5^d1YLLd?;d1YLܓ;0ٲ<3|UMcLRQgc9LuMzCq>mU+}?dV֚ȿRHYSsgS߻^wj>l .a5:kߖ|&Ⱦ#ʱsn/![鲓Wl"?(Fvw;'g) W*X55mt> ?8^PE pN/M_Q_t Y}݆xˈ4LxjٛTt@qF8_ťHS^iknc}r<},1F6/tD`xqIWWtqA0\Н r ǭ3dxHAqb8h9OWBRx}*7 @ @ (8|_o.@ J,+ Z>&[+7؎yZ/yYr̨MŜl㠥R>E˘<;I(U冲ʀ#UX 9Ȑí/x}z[߿B|&G@  `U9^*eZ`L+R \xelnͬvCYXKer?‹ `U9|@ @ @ DXUv@ 1|%ػ6ڂ|{g_ut}ym۟i. ʗO^)C[7/9\ѢwY*3%trzz@]`H?52RPi YRk&_a|r V@Wkmiul4klF9mJdߊouDp nkuuK5OU6YNQ"1^0P[ zkmd-M;EppqD"R0lb( kJt_cRA^K?(+ꭚ@ӼncHEhO7i XlhRcnlU;-J5l|E|h,6ZX] jy# ht@]gKߕёAQASmmy;г}@ok_OsO )**Yok|y/ol=bax=N@ D͊`١h|/;sKU4qݮ!\>%XUo@ @ @ QpVߪ]|"Qj}xP\wy1ػH-Un`3V~ )z[oir[zCW޶;q%^o4yYW${|,ጧmJ2ͷ[q=:;5'/^[<%^o-*Wӓh$LƍFǃU-,qLN&bPxJV[%&H(&)ozU{-˺iOŢPxXo-' 6NmRU{_[!WR8ELJGƓz[tQ-~YyAR|[*Tٶ:UHGBCuC\nV+_mP{R-4{绛KUKRLؑ`oxr\ooݝ`Z~3wK ]:Kq u,U|wlo]cW*Ph'm<9岨u7@3^uT\|*T5V}CAWS v'jug'st(͉MS|ckŢT A4:::284.b+:i5:#|i] T!-EW ⋂5vѫhtdt$84Е6ۂj04 յfʤU֥``3M<%[o-Wb,YpAKѥjc߃d1YL6d+~Q*ԏ&\_xI5aN:Y8&4Ş+&E&Ş&[3 9堙lA/&[Ic<'Ӄ;Qm9Uu>]'vŝ&t- ,6),pXΏ{~ƹMg&p lSƄx砃;ߚf^zԊ0L6ldbиqbY6&='Lb)&3wA$SdK:ա v-3N0%-U0ي! &[1d}sd}PAyM4Y}Ti?-=0J&[0z| ilYL ,MXp iGgD>rבJ:=GH\ֶ5n!s5r[=4pDG+nlx'TRc'^~ iHX[6~E[ϽRW/[=icmK^/1ZrےϓJ89^Ot}c瞽:I\e~-OַY?p-[#z?Py6F8G>&R9=٪#/{^O՟IǛbO)u\%;WIt?;_On_ʧXgoI?Y#)Fz7= 2ɪjx&8430gO)=%jq-Vz2T2^^8|ᦨ/xy`˜gIl5/Kq;q-c&UsMv{-[GY+ٝdwO?7y JV7i#9rr; ?'DCqQy&wap+ŷeOZcfY'Ix2ix:gYx6x.x!^%x)^qWx^x^7`-u,w˺2ٲUo[6۱6FYϐe5V{^la[h?;C.aw=셽ɉqO§|/"/+*| oo8 w=p|?qďc?sįkQq G xp_8'Nq Ni8g`"Y8\q&B\1RLTNq%f`&fa6\kp-7&܌[p+nw.܍{] +cV@XC0<#(<c8<O$<OS4<3,<x.x!^%x)^cMījzkamuF cfoX`Cl ށMމͱĻƻ}vvNvƇ vn{`O|{ao|1|$ŧi|y|?/ 888[6w]|8C##?O3/+oq~{cq3o8NI7_SqN3q98|\IbL%S0a.+131 qj\kq 7f܂[qnwn܃_2V`U<jx<<£<<O“<O <³yx>^Ex1^ex9+J kZ:Xoě0ozXo[6۱6F[`K [ak{ އm~l`{|;`Gag|`WݱGG1DZ>Ob_| gY| p0Cp(o0|}?8?? ¯Gw818'?/+wL D?8)8t8glsq q.d\K1Sqr\300Wa5z܀qn-v܁;q=C{T +cV@XC0<#(<c8<O$<OS4<3,<x.x!^%x)^cMījzkamuF cfoX`Cl ށMމͱĻƻ}vvNvƇ vn{`O|{ao|1|$ŧi|y|?/ 888[6w]|8C##?O3/+oq~{cq3o8NI7_SqN3q98|\IbL%S0a.+131 qj\kq 7f܂[qnwn܃>/WXU<Ax0VCP< #H< cX<D< OST< O3L< sx^x ^X+*k:oZX`]Ѿ1x3x ފa,ގ !6#b3c lwa+lw=x/-ޏlb숝!cݰ;(c8'IO >a|_—|_qq7qŷmq88GG1~g9~_W5~(G8#gp< 8?/smzO~sp.p!.ŘKp)`*.4\+0Wbfbf*ո:\p#n͸6܎;p'>'ksyv~y=kqhdV G*}S=G_1PfWz{[3k0o^=zh!“qևٌ8-FI0(fZ26툕bZJaS4%kEZrr (9JXZa?ɦO֬CSZb>KZa\ P7\)%Eۆw(ԮЮ᱇M(?>Q߀"#Vr?>3~n3WyԚ.-iY-g}%B2Tט\=fJ,)+G!(*S !&1!^F=&˨DŽBx({u7޼e햭l[ٲcGel۾~붥VU !;sWfwתF\m|l>~[MklBwR!I3{38ǟF;.6mBw-]oSI6wi꼥˸]),?Gk|cBԥiqrW˰ 2$J[zLQ1Ue2׬]0mlͺ =vzLQ^1끳{9 k٫_X_c7lsv/vbucL4wzr-Gzŵ:N+V$/_gݻ3]VӮ=_uSnXV= ?TrߥxW=&( `g}ӫ]WY33gw&dJ!L)5[*gIxٝn3|ڭAsǚ}qv֔bt=̽qp>uf3w)U !;R6pž;ԙ2hAgWo3t.C])CKVd걈7xwXĀw34)ŵ1!Dyǜn^ qpk6sٸcY :j}5K3CXd;t˪o.Gsf3wqO 0_c6m7/ofk7scݭocSek -ٰ!c=;?4C7a鯩?0Sެo8Ϫ?LqY9DoΛpkcB9߼ٽiS=o9Sޜ>mϟo>Re 3׬M]"9N7[ȪeUVϷu?4²z:S wYi~zLQ1 [lڋzo/RX7s.v! 6_ܠ/xȩ=kԌ=;=,vgGq9 ž1!Dyǜ7nJo'9QbLeh}n$qǸ-L0Zue cfM~x*mv_c뛶l?hZ>-d5=qKRop]qzLQ0۶m)/l޺u+W豊vյFBWy}ǎ vذisu!zzLQޙd]wڵ\c _)AzLQa|үU {QvٳxF({u_y| ̔yo=5/#zLQޙb沕m>U>xqPW=&(<)KZ 9?p0b'mcB!zL!Q !2=BB!L=,(({BLPQ!(B/BecB!LQzl̙ B!D4;h֬11qB 9s(؄YT !6̙,ǒjO! ؈Bz,x'BDJR !1!^F=&˨DŽBxB/BecB!zL!)}_"NX!DؒևW%턅B| JvB!"# D{LO !0.d?*B!kcB!1!^F=&˨DŽBxX?N!DY{,*=SEQRJy_*(RRQEQzLQQEQXĽN;Ź ˊa3[VR1RۊI6H=(RS~{ldVeuMՕ)&bǽB{,>gY| qaN Hl|fpJRcÜGQ"Xi)-1O88=s*Ί? cJK|)܎eQEl_ ǜ81') b'.֊ 3yEQ*leŹK)) ̣(Ra3#>cDz+)ɷR<(6%cuK{eXtepQElP=\3,$)yc":w_ gEQ c(JYzL=(c(^zL=(c(^z=&BQQ !2/UBBecB!z,&G!D0걢X(Oc1EQ/G=SEr*XY]FzLQ`=~T.zLQ)=#rj[] OcJLV 3EQ~JNzY1FuM}Q#M-7.:XLɛ-豸Ӈ8h~CEQ*Xoh2~`i33H3=Z{V({{,>ŗύ/֊3IgƫEQJ-LSQEEgǜ#C1̄W(R)=6d30 ͹\Wlw9-WcԗeŚ>,WEQO$c.7H ~URXSgXE;WEQM1}LL혮R;31LxLQtR{lUk;h.Xyb|EQJ'NJ|>`v1EQҌz,SEQHc1EQ/G=SErJǒX#1EQzLQQDŽB5cB!#1!^F=&˨DŽBxB/ "BLXc(>QEQzLQQEQzLQ~IJ4ۏSO.kn%OK4|òbLm$MSE))G=62FJ9Szl$guMuckRs'%qq>_ S|q<|7>2((]YїSD 1wㅃcNM%؝K)NGq;..3G;(R>S^z,W C3}ҲF|!Ƨ2͜Ncf X+u(JetҨNM9_m?*gd˹Tȧ)+ mdVb{.wz]]G ,*a _,R3ؗ-˹ި(DrcG%RV.=0ti-b2eV nŜ3)1:eo9Ssjl(R,~QPc "Ƨ_~GBИEQ%D-k8z1v%tCQ%Z~&'*1EQ(F=Q)(e$1(S)x91(S)x9"BzL!DyD=&DTu߃B!@MP !Yš${l֬?gώB9&͙3!=f木*BQ&ΙSqZ=俺 BJDŽBC=&˨DŽBxB/BecB!zL!Q !21!^F=&˨DŽBxB/BecB!zL!))(J zϿB!R1!4Q !21!^F=&˨DŽBx^QEBc(SEQ(EQ/G=(x91EQQ)(^zLQErc(SEQ(EQ/G=(x91EQ)bDQƉcQQ%TX)=]xEQ*rcZE(JEzS(xzEQyj%Oo(91OW"G=U\%x3YkOt'bs$c-,BxEQ{,gĜ\ =s921Nsޟ8ig->)?>6c"8X_Mw!l(i%W{bB陳o0c?yڬVI'O`af_BCo(JO);]Y)yiJ@B efVQ\WDJ |OdJCo(JO{XJ~'y}.>UKXw]62{Ā-;8RS.1y|EQ~c =?~Ӧܯ,a C%߿/^ ;c҄}it ;[QEJc^~=O;/7OIcQ'o;-t;bEQ2cp/G"CwŸXcw!E(J1SR-i/c +`'&q 늦bïݯm(RzG-\ ;)ܜ{ClA(DJ?z_+R*J.xEQ*r"W+U\Ŧ?ѽ~\LEQr(XspA=+!q !2edpŸX{ޯW4$S)D("\壵bdOi\: 'iNeǜk 3E엻ScD8ݚvX\>9rpK¾ay?+/ÜX ~uOEhc)w q]N¾6g|CKV> bp4{9e1^(JyM4z,>%yAC8ЯWtяaKNq"~YtI N+!o܇1̍WEVcS^>m'0~1ab~y;O7 WEhJbI1s]ಟ_&+K\O'c3?щ0{_>k za~+x(c  y:L]ڽ gDwWi2Jq;?(MX Oo(9_1*(xzE ǖǢ7^QVQr+R*J.xEQ*rJ8M2N("R:D)UG[(Ic1(^NXTfB7>zBEQȣ+*zGQ(ycZQ= EQ"zX u?G(J䉸"zŵ-iTS`Σ+(쑩6_>M>n1ܷ=cdC3q]KlkӘp?{,U?1v|/O}(ŸS=(J9H=\<=bMG(qN}wpNjE1؞i,{i=HWB{;]?zLQr9nYY?Yu-,j'U ?zLQrhfhcf⬆;Sҟp.-9dJǜ+aac6g S=(J9H{<-PG39scTx,;.u?;Y-{Owk?zLQr2cϕ1~X}O,Y0]Ai-g^O٭^E1ZßS=(J9H{}}ِa{fQSBXݽ֚ ?1gl>_u5psE)7v?O^o_h^cϖ=эn+‚?zLQr!>{rZԽ%Γrc,9x!O [6)kN?zLQRﱂtXl[;h: b0ϩS$KJBK(R)Z ]Q= EQ"zX u?G(J)bc1EQeJR:)NɨEQJ?cze su(ކRXEn|ԷA!"@=UG}"cZEn|ԷA!"@=UG}""wYFX#Jbe £cKX#N =j~[񮢬BxXačj3$S !D .=f 5vCܶ%`GJf k'03YT9BjV1P !P !FzLQcg0VdT2fqFڋJ8R^B ~ΔyU/UzL!'Kk( v?LJ%+Uu1!(X/t㣾 B1OD7> *Jt㣾 B1OD7> *Jt㣾 Bcэ)Bx1NBD@iBQcE{_*!4ɧXFB!DiBecB!LqX_V(ϔVB!DR=&(iBn*<kTx}[#F=& \okĨDŽ:Kmoß \okxJ*FzLQJ1ۖ/^Oߟt1M ۲|O=Vз5bc|Ƌf9wQx}cl$z}E1SGo<&=?wY)7~?O g#MB h 󥀻ny2cݿ&ۮY{oHt 0W_ ~D1zIJ[~Ի埃O:K~8_^zѣk׮;w.Җ|';vFNVZ}⦄{v;\$Q]SeYc5:w$-38H7ˮc9/N9tQ͍]Iy(3F!gqݝ4\#?UkO;i/s]y9ǍJqFk7B{=.w|0 zcY;k1:0:$zvl3=ZhQ푞nᇾ}kZ[߳q@nYD-=⬄K:N}Ma!v-]:|*ҥKQ䣻k|v.۷~;]+֬qKOyq0rq y~,gdnY^arN*k8OD<0K|! ez]b63~t?nIgÒmb9w Sϯ+B 93F+~IQ]͜dv4uvPߴh<ÞާC8hР1#G2bdY-z͢ʬ~z;/n|wʍK.xwY'&V>*cT6wv P̛2ed>ޖqNa{鱼Z H1XN-YhI=p1bB w-n]YIڵ6W ~#≩0NԎy zMF4>Xwz5ߊ 龴15a 37N q c>ؗ[f:k=*^Rrrr̜9ﵗg]}u]xqoFT¥K}ɾ uV- FeɳgVNoإʼ Еd9CQt812'p!$g|]1=QpǶLصd%3v/2GO37"1y$gcj |{k$3ӷr%b )+hȑ|ӟlof_u'Yc_!sѷxq=ddYꕳzW Еd~9#k;ODɱxl]Ned&;UcoXP!SNoYfy nwmNWW̙}_;q_^6k׎3_NNn_f?ŧYYݻ*C{!6k'B3],'%!Y wKdjC..S cF_lhjɒ=zdfa:_Q}IS\kyv/apf&cN"x4! 4૳g1cyzڵkWnpO{Wc1|2[|ZB+,č{,cG^fWTf̖4m3i2o1O{Y=تG_ kekU6֚vֆ6uR)*ٴDgD(O#nk=֖V6,ǺfFGՍlH~=܏U-V.vueg*Rv~BkX[Vv'_+'}Nj:-րKsv+Z{h;=pK\L~W[uk"K!'v98Oj~u_uG_W|sDo|~_풱\8+7:k87*3#c1+u@ * W|}s{"Wm#(#>릝\wڙkܖxmܚxm3ϼui>y<VgA*]>˺k,31Jlg*;z=f*+9KϗBi<&kta&Ro\v+[\*fԚw^zײ [h+Nl~tlueeW}v崫ѮJ6Y~Uۤ?tʇmVƿRa6iF5jN93bz̹܅LWw$g/>UJ3ݬ= L X{Vu^0C[>;9KvljA;SUB4QZF)c^Rajˮwy+ܿV׷Mmތ2OoubӬ#dUYΊWίt(cc4=6lu (|q:?+Abb)5 *S̋3c|U焺YGv|{t]͋Br2n;^{rVgUyveloyUvtwŽ1yW樘LZU ^] H>۰^잟rkYŤwqo@!7w93 ް?Hl6WWw3=#l֞^!Df/} [RiFP)t^PFWϼm3!١WVF豴Z h-3fzlB<>آ+7US̸ Qo8 c^Lg aw}uuzy' 6ܮ{;ksý݆eyuakjYpFz rߪܷ;sS՜aS?N5w1ް{wEs% ַWajcJome+ʺsF״t4FG߶1̔XO:=\Ze3^ӛU6 f6vӹen Z;s3ٹW9U~631'{NÚ,xEuf-6poUn{7%mH{kYpFzd ~nu_bX3 ߆{c}q)74f^OM+p%9o a0 o9;]tDzhu=3hcoan߼'740IUsF5:FêbfQN]>۰Z^,dX꜅y}׬nnO&>6kMXo[ b!B4N}fpEZÇ[;طbY"!(f?~|NvLo7ә|7.E nhܹ}N㴳hvA =o&aǂzly {ǂcΔDRFvҬi0`8upR VLbض!ǖc;޾cǢx B=&y#}O^u~!KfՉXQ״[e5IiR/l<1=fckٵ[^/'x,Xؘ?aKYcR,S>\צ-fBcҪG^]E9ƝoWpJs_rgڥw\xΩ7=Fc_`iVrʌ^4E㜟lS>&%pOIcrkz,?=B!+˦zu՟Ӷ2~{Uvk1*n{TͯkLyM鱼XpMjjan]eVzX-cO+}M]-#_e7NC=&"{u\+ V:<̻h3Y ;7^7[qCg6}5_c\aMc-ZJǚ!$=jewese.\qo0+z\XuEc3oL*[A5>㪎{'[b"D$*ZcM{|@Πt݋yl/Qbٝˢ2퓙w?yW=V9!-SϾu ܑN]rzcSb*}43TY]].Q?0U1SSY-{e42Sj+ .ov~oIIkS^D1> zlCic\cBQ1q~qnkWٝU9PbjU51j >WJYDtq>\TXNg?G'];1rÞG^?ʾ~G@mYV+4ir{_R/ UU*YVh?RUXU<Ax0VCP< #H< cX<D< OST< O3L< sx^x ^X+*k:oZX`]oa}o0oaclw`Slwbsl-.ln6x>A>a]v^8| >>})|g9|_b?/K2k:7p &|a<GH?OS ?/K o[hXğp1''qdTq&Lqy8`.Eq .LeqJLl\9Z\qnMV܆q]XU<Ax0VCP< #H< cX<D< OST< O3L< sx^x ^X+*k:oZX`]oa}o0oaclw`Slwbsl-.ln6x>A>a]v^8| >>})|g9|_b?/K2k:7p &|a<GH?OS ?/K o[hXğp1''qdTq&Lqy8`.Eq .LeqJLl\9Z\qnMV܆q]XU<Ax0VCP< #H< cX<D< OST< O3L< sx^x ^X+*k:oZX`]oa}o0oaclw`Slwbsl-.ln6x>A>a]v^8| >>})|g9|_b?/K2k:7p &|a<GH?OS ?/K o[hXğp1''qdTq&Lqy8`.Eq .LeqJLl\9Z\qnMV܆q]jcex <!x(x$G1x, x"')x*x&g9X|/ċb/rWx^x^7`-u.ވ7a ތ>ނmcl16;)6;9xx7ރb v 0v c쉏`/썏b>c|ľ>>/%|_W5|8`|P| a0~#p$~')~%~_7-p4~cp,?O8_W ‰8 p2Sp*N8q&8< 0 "\ɸb 2Lq%f`&fa6\kp-7&܌[p+nw.܍{ЇAcex <!x(x$G1x, x"')x*x&g9X|/ċb/rWx^x^7`-u.ވ7a ތ>ނmcl16;)6;9xx7ރb v 0v c쉏`/썏b>c|ľ>>/%|_W5|8 ];.yxGx y<6+[@ X5ws;_||{/6O6ow뎲NX3u ~U߿ã>p}O8ʻ;V6 rij5_fݳja>Vz jeݓaɲoɣ*>Α76{}}'} |Ws6u޲qXD8}Y| |ņE·(">LYU V^T鱹J|GGwWsDsL<~|̜"r=){$>|/.E_i/׋0jlrq} B.o؋3<&G?L);s{ 3_̯@:Wp9|s]=i>Geio <6.ZrǑ)M̅F|BM'2%w(Gp;{n}2+,uw|;C?;JU˱[| 注Q}m.?ij.?ٹa2}i;lsV;f>k60}۾[.)ڻ\6{ f1ٺ.ɺuwE#ggͫt͹ǿ}> |E;Ѭ|GVqUsaŋCA 炀Qи>. r]*\$!!3_}M\{jfSS]U_UWtwzhb6`qP6d/P򑌧Cm@EL'6S|m؅4^Ӏ^id|Pkܘ1Qα ReteEFZ];'ĥ:FfI7#A:Gþ,man?HvTasXzq1S31C5f ZYS,П{] ,//I6<+UWZh jK$/Wnf/B+yvXB"(gg.فOF%yUog%(jZ]fuy'X>Fef[DV*:.nC2mS +ȅyu)_%e$)\W^@+K:#nt?txxWD0M1FXIcVS1ϵco6S\,Om[|>s♕l,mJ-yXJ*"̢щ.o/pՆD]Jj:["2Ϊeհg| u/׼K^{kz磒s%Y15kWuk̍[i3l?pf;9JUPkVۧ|m󡭺e6LQ}J .Z"^,6rq)5}Ǝ5%.Pw>?./v .20ɽ/OnUX V+῕{?}l{ܛfm6+῕oeBW26YPD?_˞?{H%q%+_#!m_j3+/oN흾n&Šܕ6[ŗr2vdVW Nqya;7T5nCck|U6BM-Kb j/ЂjtIY".ݍ2擂fq}NNc[}uL% kh!+YNyd)I,'{ēgZ̙mq_݀w1iug5R`@j3jGY,Lzrw6S;86oij uN6Ic^uV/;CC}vϦ Aʹ6;NwiI4 wrŹ=G)aᅨ^y[le/v/D}t8o G?Rz3l e@o?2?_>d(a Vs?3OFlBdNW!?7޳3) =n bz){Q ڊ9^!)1AHL `S7+six/kD/?-Ij6\mwlBP$ K{3,kʔb2qg+Gbu~>T{vjZ_UR_ Sj%J̬_m/K~9rc~-(:9Eqۿ*_?(^gN;*P4gon-{Fο*aΜ4C)X{ÜzvrrݚՑ,d{_;9ݚ w:š1 01Lu (i4۾Yafpe i{o0'jf pw=#P??M3IוxK ڷmy^M%UHW&?8}{#iy<RG)jʏ mj':òer!"[l5AAu{K9c>PdBOt5fZc\b_$o]+@c&}iƆ.sdeZȃ,4i7js 'rC _1VjX;3ʡp\/vicTYZ0NOt(ԩFJP.Wm:QٲJ{Y[XA_3uGGʴ W6R%*P]O5~Uu$lv oϼ %->b 9_ lrm9GPm=tYna 5%x9E;-Y܌ ~W\q1`" JSXg-"oixpK:IǧW&66F(ujQU ڇ@nKSfik"_}` cA;Y'J9KŔQd]O+gyNRݤf=J4 y@^脦6[cư\{*2sďmIe_,"=)ۣDYƶvf;1tN˄j! _G#p^kO=˔byYí. svB[ "<"fRiS B1u\T0->UH<5 2'&FX֠N9w<; &oT|vު)ʿnqk(DE'|^N7bF)=:nӵ),=2):"Ƃ30\x4ƒ!#Q"!.7,pw9Ip@x%c_@k1pzힼ`pʯCOqjq k3>o9}`1 V+῕?\Q\ؘ[H; L9KS EV+>˶g$ȉiIDo$ma_93+$e]U=w_/o8=[8Xm܁oe?2'pG.pmyߌۊ"R?_|uTyeto~귨f|f;(IO1'ˏ |\vxК3iMNG9?r@yw5{ Rg]:'KK]OwvƳvG>Udz9_cF;9_jw0^?_|%n0fgWܒxi` QS{Clj̀#£u'OFVSQTpNxRu~m0Wsaї\o DŞOsϪd8(f=:1),s_g*;?4뒦 7%)uI:*~ZhPݶv@PTK?i$hd:E_7?jӌoI㟾[Q|ϾJдO,AYY??veg6OEh'?'[,8?l M;4'?wYW~-~7dHf0f#:!Q7@ᅥ       0pb-'QSt 8"\nٸ7òoeddɒ ϟ?޼yT33gnE>[=j;|V_o[&V^n+)͘1ȑ#}-oə4FҥK-ZOx_>W_6v O݊Pi~~>-ggg/[D3PכiaO~{Wf^jUog\݊P{>㌌+V< ϙ˧hgIӜC'i76_Sc#+*lbwɤI([oTY^A'L7;vЧ *=ؚ8qi] rFd~mfZJuuiӦIcc$t'hd{ -ĭX/ >jVkyV_`4HWW3@ 2uT1GFJOrnY]`[-I'%hΧi'h҄ 裢") *6msιwml1iʺ[%71 Ϥ}׺b-m!)ǟ'Sfy^yqMM;Ұ^{D#)2LBssYw.IPt9gVJ)/-92ؕ2%hv44mײ= <>%%eIv}zJI%Pvh^Wٰ'YAd)CJPvhz%aVq?ivAC4ιShgNAx[R;햛+ {a@;߷~[ʟyPP+῕oe+ܛ!4 !O/q /?       2F˜ZݠIA.Q^Ո USU+ְ}QYl.-A).н\* Q B(nI7ϗѾCAڷtP%.~Fzɝ5yt|/hFnqCհ몆trukv]Y}{A}uˋj†UO 1fõ3FєU=uC_Ԍk^Y=ʊW'Eѫ\Uʢ~/ ű a(ϷоzPj)퍟GZ8v䵵~[3ʁWv?,Z2X샃&jInT=_=uha&fb$U77/|.ɺ"9 zD"Dՠ28䁮LSՓWO~ؚ jz֏w^nE[ Smf"Ӧ jijɡ(T)|BW=1zBk{=zsQUu/;QlGQL<$m5 +S9O>zUj]Տ{kmBWpשO?vXwCb1;( :9j~u07zKF4QK^G\9[尫*sUŕ}/,>^((:|7ξwmr!~wkZo t;{~YozaYÏzCD޼[.^{}{/]ۣG=:/-& nQNX=6;G->qE;5i1jlܢ.(̞i͙%yM8)>ŠQǙҫ20{>U7(ȠR\⊄E(Y~{BtDAt$ Ҿ["*.T@9CFoz,\ A"D@"/g9VK_lp= 1wo (qQ8 *D()|bɒ% .LOO?y\Thjj̙3=TjH!FclG֬ɮJJl3fEŋo!ŢE]b;rEORC $ Aavff{e_ロzuUorevJJJ )$(hd N662kjlԀ [inR[k[bIQ[T5ӯhX]m#PTd6mJ*zA A[][rrJhHІ@HtϫN]k&|鱍c@QtuOs|׭[muk.SRVBamԉd7:aYg[H Qdӷm= b{mwImmBAA; x7i*4#-XVSSE}94-$(@ܺ__?ml?]=~=m'OPA'I/P! B"4AE(BD:x.зK? Ȳ#{( W(?D: Q"t\}Q D(@AB{(xw!D:B#+FAW'y7مEQEQ|Q*D:# 78pyrS̨bhmۖ/TPSۀQ*$^UHyU! I_2^ IUYAҙ#7C{b#}V=?>Y*)LYkf 5mZ?)MOtPysW]`˩gs1i{V.ۀ_ׯ};4jp^`8UzXf=k>:gi9LFx(^/evr>m }sʞj6SZ0ϸ/8aY9Wᮙ'jxU! BU$ϫ IW?*$`BU$ϫ IΫ IW ˻Jg4LW?8 o]QJ#7+sWwۥN0 ;ȥN5wbTq?j; ꚣ[; louZ#wy50GWKϡ}sއaS'p叟;^ckQGj6*OAa7-Ưʯ?cSS?`OH@秈;9T! BU$ϫ IW=D8H+W?_| +W?_|@?2[?_? _?2[ V+῕^ p)g~6)L ݻoE4p! ῁)|ombğ4RۆLVUtBvu%Oò?_| &wk]&C4e? qI.N3ޞ7o㚿 ElTǻ38s>H78SewZ|'p!ﯜ}ɮw .bOY ]K{x3eiinp fϋo +W?_"O?_|}zRif9O,/^O }3.xŻ^/>e.dJ.%_ s_Y`7NWD8py1"y߆2;$|׹QxSvS•o?_Iw+W?_|     S O\8HrG J&@AAAAAA9~p ,_                           'q8\8HrG J&@AAAAAA9~p ,_                           'q8\8HrG J&@AAAAAA9~p ,_    rwiB|ЧXJ&!Б(B QEQEQEQEQ,E_b50O"t(BG"t(BG"t(BG"t(BG"t(BG"t(BG"t(BG"td(ܭ QXǖݻs Ql߽{KGAx9B< /(X|yQ,@Q D-> (@Q C}"@"_ DaPUA}f@QX6 7v?pyrS̨KܴނFi% ss ;Ҳu((Z2ue*+'|Xa:)BY&5j673RB|W[q:¾I)&;PG$u- YXO}u}?0 V&~ +WLd^DaV+^=[r"| )g~6)/fޒW9~῕oe?2lj N'x߈kA9`6[:\ZQBg ߢoe?2[ ?+῕oe?2[ V+῕UI]pGo"?_2~{ҧ?}O/֪?Y,j_0 WCmr  Y' >       (r~ hpT8.\8S̀'}P}ܶ-0Lj]5]WB,*ojx_o1o?  '?gq,        8}S~p6s9O. @#7)jbsh^0 }Ƨ6\Hߊ5 [#  Y' >       (r~ hpT8.\8S),UVciAhVPkp(:C5jLuY 3%zFyɿ' ca՝8|̣klrٷ$Npvt N[OJ!n>#k<~#u5-^W[n4dx⽚o^S#8vȑںjO-7Bs.1;E9K#]#--MMkjJ߼:hUYV ߛ=)VmֆSғ__s__W^_ZA]ƻǏן:ɿxpGk9yGN`lh]Wj1qjoow<փAp&NU02Q Qo7 @(ED D(@«(ٹPD(@Q[a[~f((v( ޽%((/xGlr,x_E! D("# }8F|ШD6G .Qp= 1%"t(\?r"hg W(A8 Qhv4QۑߤFa1'젍/ (x2~V6 \/?'k@tU.kg<]`yCBpu!evtr@g7({,!{)}#~*>|t9i ϧ )b6!s%=<Q?%E}<.!n̓Q{\nlҲÊL}ԶikpijԮSDBR z*6 ݣ땷S?Yy&Ey0{szšlg},dQzeKgBldZ>6YVpX'$k0a3Sy{Zg[9  Oɱ(?gjͺb"|˓?!E蠛i~>yP}-Gas|yOm+O+?Y<}.XO =,\s } ԯS3t6np-u?6["VK3 `a5Nl /3O<Ԍ?$?#I}~?<3ӻfx#.p1{&\&!d5L#?k:RZLq.K|T)Ż)n:i u>IKofGgy?` 8KϽѪ_G{|[5]r}ySq 8_"e+q(Ai0^d1 ^F2!%+EY J|#(z<;ڙKѲ:?a."xFcLߑQ뜟u+Jꏶ>#guaϙڨ.~hk#{-wtX{ZG]H^Fӿ/gc'_bߓm6Az&)47xg`!rξ%1GMߔ;<R|J-=B/.L[n:KDe_nHx:A?tna#g-jӍMG?|8&^8>OTG]1IOY_CLl);<4k_1Es)-+kFwiyÆ/nƑҿ1vʼB_+Q2>hûyó0o`x:ddSl[Tx]`$OA "(4 `(4GA@*CQHBBHB^77{{{˥]K2?߱;;;;|Sv6av~"3wk y $MS/̜J f|[µs´+h8w#W{WYm֬2?c?ˣל{9iܠW?hK a^: fk̹1=-1Cnۅ{WXw gu*o-q}wxz"->>>>>> >>>> |:ęYw9y@|B"8QR2r{pU5?7? 9 &W-; {n W~oCGG''??<7%eU5x:<߄G#Q[hx <~ dO'p\ Wp < O3p-< ρ8:3u K1pI@sg+~? !z>n.ޤkV&1J!j-tWzW qx mQ2ځfO~Zذƨ Sa1,5SF\S1,n6j/[Ϟ=r)L4ǮM$M*OI!UQ"$Աwd(WbiΠLM]*=#AILF3yyiΠT@ Pgd$iRn'Q.Y9Z?eZEwqz,p+ssԣ yyj#}X^ֽ(wrJj\‚kR^in .6{uJݻ}IeZ9\?o]gߝfjDm]Ta9VhuW<+_PXXXTT\RRZZsޏqTY*=ܜ8Γi> - 'J*;Éaͥ+*..Dބ2  DB:ot}9GLe,U1=| ڵ+GO&y?t{!<+߾__?v_&W eBQ{7)ΪUFoaw6) d۱ZƄHG6)39*4rAiѢ8,As戧W2o!~j1ɛIFWcr9zjjfӼ]l*33~ܙoܘlOƗv !-Z/ȷl@226m;v;t :U8ӓoԈ_Hɺh8Ņ_F6|8?r!': 2w?}njFڤ"]7}ܶӲө1iD1>'_zJە8R ppݽgSSiJ$oNқ$7;h<S>>D5&!{wB7l(hBI64qvMЌl-[nN霍Ml'&رf?6mܡ՞gɶK茵3┽:)Ҭ8qݿO*WʓLqL MeͦZbiUr3 3A>7l?AA-c)B瓤BCnVdN ۋN/-6%yZ4TI-{LxF69Tֻ[lf#,.ߵ :yG kˆ94_ [#('ܜ,iL樖/ |*?ghYɯ+bɓ09"kV$a:J-$H5& ieXl,O F W<;Ջ>l8\&R-W|$roDzLi|Z:ֈ>>ӓC46!&7sz#\b '~Xd"/23H&T)e/'NchT$y/Uӂ+bz beA nr?6Z7ܯJ zܱf%1{l'd͊ZG;ǎ۶#"*M#6l k!~]g7Lh>{7fy$*s}lpxry'k2΢8Ƕ1-3>YEYY~{F]/ZCnWjh; ivfZИlk}U{]6^fef1eہiٞƴ`;0-zvôlGcZfi]00-g_Z}ffA5_/k7Z1v53ƴ nk>udS"{EΥ߳>|(/FZ*~Q"9jDZO~M"¯WO_?UtS!NjC~.[3o-KULaO-'%7;v?CU"%o"?} ?F3'ȉԨ s>- ) ҥGd}&%j)8I$Xa8[6$tIIQ|l7B!g|Zl-b;kyv\ww^"?ROx[\ee _|Aw*l#ZN$͗_&/hNqNN&3qs#Vm׎8kJhӲ!ߛ "%8 98-]=6o%-b{jU"a PKZiiSN^>n />4۵#ݲ1r}{2oHނ;cAM?䑓{CTH Ӧ86F?S -;qd-a`ݰLU'jX 1Eu4jz-KLpRI-}[/;MIB.ƑQjnՊx7 nu_H7+ӲDtP1g.OLkF يmD5<G~؝G}/ձ.~.cd$tKl;*LJɛ ?%o7ٵ{X>},{*袘wSC@3Aʻ 3(% 3݁Rhw ~B"b¿iTqspG"xz#ip42Oi"c)f, e@Zq*hv'&gjr)ɯOw":YqX3ՏnrJK8W\/݅iNՆR%Mm?go6{9Qh>D8ċNNwIb`U4W͗NwV_8}p?|K:4y~]7*CS̎hިdqE1=jfӔfh i˦P]\_|CLJ(o^b|׫`<"wӈޜ|B.Bf(iYI|#Ӳj]he1?/o[|}F; ~Mb2[;N <Ơ"wl' )w7z֐fRL/![#ILdcs&Heኖ>ÒZj Y/C8eL>&ղƯ ZϜQnk>"؉!].1k] DtseJ̺CjF)aE: Svw| >|q隅r$rJ~|^7$iҧr#inb7Qsr)֍%|:9|HK>>iBr7 CIK=9iTa> djϏHnVraI$}+ǻ-ChW253-D- !T\k lQIjAQ==6 \_g;&v!s!L4hjw.r(ye:.'0 ZVN(0?^a4ě4h#|NBȪyr0=S'%vqٸl7/t%o5]ݘÅr7qn,tȅ|N_hǻS@)vCFqX)Krɏ0sQ㖨6J|w[FkSS_=_9bblrwO 1[be;r{}o Uŭ~Ʊ+}#zAbNiT5uO2|\6f|޶/Z(zEHUV^\5~j|Ű;';)LS2-@5|œ -ds F24\z F3mɵL!-QeeoGߤ/<%pBB5ejR՘EJ@r ]dmuzP#Ѯi r,Nk*j2m'H=*g妙q E?M_[ P )d̨N%5) xeL"yTb{3^a&d=] BrTf,7]LtQNr.,BSI'WDc՛g~9B}23;VmX2ӑi>vZ 2TTڹnGo_PAnd5|d .to`57m9 Zƴ #Dh۽% Ks]@t& !P6!Ë@xs#D[wɚJ~OvG"/ko9aZsf5~!I~e?A5A/i CBQئ/]BDf }c8$녭 @d`L+3l7$ڇ`FpXȪCpB,Zgy@0V6) $u9 [klX8SQ $}VE?gRtP?Wt8& 0!ʔ=O St?KE‡~T5ZHCC dvf^/̍3o=.P={2f5s5m-^yM̅4>;!~?x#(1 1xSx3xsx 'O[Ÿ?  , 9x[x;/;_w  *5xwx^>77^pox@ `P0|8-/||$||4>>>>>>> >>>> |:||&||6]x||.|<> ||%||5| }?O?%< |3| |+k6v7wwG{? 0wQ1q I)igg// ~ ~~~~ o7Hx<߆2x<O x <Og3Zx<R|AsIHp2"*2K'G q%3 6$OUG HfcEzV^\N[1 H:ɬ2, "-WƍJ&$sSm 7EMPrdcR ΅*)D) f4\Td%Ŀ |?93&>[ V.h灅:&ws bHZx1T4 }72#fQ.sFťnxnS 4{`.sI!?4o:ijZ Rc -C%u # e8+O0)ɠvj ÿI"Љa:S0T5YE%+u3R~r'$RkE6 _qcV=:x/[`y,8[fF;Nr'-49W970n E }J>&Bt.7*L_7"z|ܩS7cOǒO'n %<yj8u 'Q {,z'д]G";fM)D[p+y1k\8hJ_mƞxUnwD yK*h?HS)2v~.Xbr4Dkt\> }=%̄ ҳ$m|ѡ#5ɘ<,h#L"? ޡ>?n(Bx ߱4KKےhw< =LZ}q!IF]etշBRSN{=w])rČ?Gsz圾P.`0"7ZC"+O<%rQ^3Qgs)]kZᬟݫ?oG%7-M"X/-l@7>6}]!^P眣l{qu/u\8$\exȠCH9g:spc4Mkȳ eRapy^eSτs}~"> S` Yr쒐n<@"y47ǀ# oLxuȍ:(}/B7k:C|]^qG&B.=FW4u+'b 16OE7NEns/j8B"}(ZՆH G;nO?O,Zpi;ّ(HPDy[?:EWne"tBjbn z R8L[gȿ%O'#aG  %NQIS0P0]|(ȷQMF%)p2Ȍ +̂F KNt*B9\f~wR _q?_w,<0]9vv,el/c;֜[{(׿O'\$%85$uGsXxTĿk+LC6mJh"X.:btZLAzx~yz]O_~Rw65X-)/D?6:ʣߴ!drsiF9TFO*3FG=W !cv*b͵k0σC#&p=HO$'KkghVZ楨^/XQ藽9ReZU6BPdڛJ;gu*MHZWu)fCL_]hVȿMai_Wof__wz~Iw5ʞ:Cg`;20gg0 33Q1:1v͎6cOl#!oց3 ?z:8>!' Gȼbb={*o(;S.OP*4Ej:##ȟ>܃V`bo7{n'&ޕU*9J*ߖіʒfdgkh*J|V+$o參Ŀ-%?Quw_^sCV qʐ9mg.m~_7%N|p,Ӗ"Gx ?v_XXprHO 7PB#4"~+ZՇ/|dԥHi$3Jį!ה}3 A7zzwv_EEٹy#9.)IGC !Typ#ɕMLP吱=5AlNvO&_=6_RR|jQ7 Mȸ:XN5Vi/..:s5ڨ jMr9i.K}SMZ:v헷gJX~%[y2 ຘjG~iiI,7T!Dlڱ9eі\1c`#L.HZ BP+7L5͒_6oe*$kh1,KG{MeԷm C y>eɯ(oz/Gdiwp5&`EiWviV[[ۗ1> y?Eؒ_ogg0}IGZC8}_X w.qQm*(Nݫ(JWay?2H[cq 4y߫Á XN5{·֝Hd %Zu__-{uJ]rib+,cGO :+(..B2+,?SD 7'+3]re*,3_P_PW7MO(,/-3🗗Cv@nn63%Ehiy,"kog_G-[i_pj35)#$Vĭ8ͷݣuU{k7 -k^"''33CQ,o(c9@(IHW_E&G쌌tZaiy1VC$9(H 78 ["w-cde)Ux KgVC&oMFq-s9ӣVCVVZzB%kCy/h~Ĝ[9- oœ =ُ99 ?MUeeEEyBYYڌ}ܱ`33 PTArZ H 2pOn6OY&|4F& .dg x#1.Etn|U6 B&q Av$|{#|9VmF@HMFghA|%A RlhJw:.8\8gt.Jvj)@,Ũ_ _Zs5j1I37U-OdB>]/4Yń(-Yڰ}ўgnR%ĥ|X_O#9(7NH H 2q jFt | Np;5T؟Gg~,㇠̽[ҿ( g?^=MbjEcكߐu rMrq4'wD3GܷM]S7Ltygޟ*Pz[|jxax%>/4%/1+"? dPMdyR>YY^3]FgBz$7&y5|X B[]rvIC|$=#S7Hݼ_HBW%<}@TϤ=@x~K?)kw8(cM|1:&OǼ*'|)~d>egr/I )bJ'ikbH};Ft[jAw,b-7__>LT^Ny.q賉>me/D {Oru%kQCb- oI{czC&9&W%3$#O~MҰVI>&6rHۃ)TX0+?D[y#Tƪ0Y8V8f 3/Q>Yrg`f\=c 7aVdI- o\0ZpjC>&WSlR2iX˨-Ҙ&?Y`LyKxEsyQb3Ѝ{Z*'>-f߻_Nq_9$0M6mҔ>Ys+yV~S9ja}\5Y&oS$O%|JwʉUc۪G?_({+۹Hwۙw p-÷Zȗ^}UE6K˜N~GM}F>q&r6p2KròIN~yU O+ Z&>:t`ЁB<6͍?7Ekvߍ.;p~7߉gޔ|=3eGnŇw~.u}l_6k]9;=p%nvyq{?Y[[w|os&Ef~USKfi2NοtŜN>aC LDGtCh2'=N 2GL2+C= !C#Z |bx:@?8?@zrqM>s4)ba0?맾g33S`3-N^Uӌ"䆬Jt_7υg矾sjމ+KG= l˿F/]ʯ_oq׷tO1K ?As/Vq/"Tv+1਒7K\/:u9Fb7.T%|Trn)h_. , I#C-2OQt;."gYe~/m<twt~Tp~:8RL7*oy3e-3_?viy#A>hrBW@M i<_.nǯ! *NÿT,}wIw杌i K󥴋 @t Z-:|g_^#S} D,>{SXHѱ_ewZp?yXaa+H(=XEG.VĿo>JoaQνi?qȍ!~ V:oo+S uB8YRo|o ]oW 6|BΉ; z %u@\?Lkoekf;N*8SE`-|U5>qkdtkwcy9`3-)1S`oߦp0d hX7)r^E)o/Ubo72Gń~{5;ڌ7>^-0kN\߳7EqW wJAo;'NL+'TTB&~GLC%h֌ܙlZ.d˒f+ G''ڴ?yt;f~q UF+/G? Pf}~y睺8fWC>EF~ٛ3ElΗYY;"f;p# +'qOH&Z0۰=AKح*+_ 'aas|hՠk ж1)3WڿdP"IHw+UvYZzoTehULzua0ͳL7E_{Ol-8K\b\vjׂIk;,%KD9Z?<+$RNQ6pu\;סpu߇Ku(_wxQS q:"/l;E]ī$ܹxjru2 ڎf>{Ur8P[g}߫ VzcץibM쿿+))(..BG_/**(L׀tY㿠 V#??7[QR-[unnn63%EXi,//j8hcU>,snnVIQ%R^xR{raF{j(eҸkkixV/tGj|!h >@8eNBN HW";n!y\]4.>-#b:HYHTk-E&oMfɉ//J ++-=M߭#@sKq`DmUNhIHզʕw_ڴ#b'QG#"ģ^m1D+lmb*DDffjj\T{OtU9z2/ncC<.grJH#Mp4̘1cƌ3f̘1cƌ3f̘1cƌ3f̘1cƌ3fbc*G,68wspU˖W_[ZHﭖ:zoӆ;y s\/'Oeٴ,(p`glr9IZ|<Ⴐ=nN[/^_zҹ3./Z]]>}xB8ѐ#H}~rLY&Fye),;v6Ǐ!01Q/k)e c|N|֭ƍ3f2ܴ)-e({!|4g&א dI A=1_\l,&\IvI Pk>C~ZC&M{kZѐ1<`BZٲTB8:6wj(' e{/E_y5?i11fŲ4n\nYv4#!$% صFe=41Ԏ!׺|eA QR ge.Р fdԨ W j!-E A+ ![7wo!#ɟգNL mNXBRIbĸIzeA4y4-Kr2߶-=FT\QQMC޼|z.vyn+b0aر((…iihH!,L' \qRA=+fV}Yq:ʌ3f̘9a(YaX;w|XS^%մ=%s7#Sݻ'FE5uk}Lz܄ZJ YLaAQmke *14 Çm %KM3j?@yew3&.'yV؄ 5dd֠dQ3s&C+VT,cǒe3!`,6a${Ӧ ](PΜΝ XK5VR߾ܹ(??FçxǣM^Y5ܮA?hGò24&Ҭp l(,*w۶*孷HW, i[7~*Oz VRԉ-ˠAF၁݇6zP\IZfٛj͔eT,yO <nj1SVz >t,#GjUOCssLҲ`loDG瓤BCM˂ŋ N_9Kڊ}Ktn| PwcÆBY =IYP(:7 x횰ֈį\IY23Iސ'7&ě;v-HӲ%whY0AЎɽn(͏'i #Y4D(Ț5B4zN;8D۠Ii2JrL͂f};l!>uGvtDH'2 ֩S];̌3f̘1cƌ3f̘1cƌ3f̘1cƌ3f̘1cƌ3f̘[G8scw|%u^V189lp1~}&9$̘1_]&/Y%v;;=Lzxra=e[1{ŝl#(R})Քp؊~n]4uZ5Z8"~9߿tmѐ3#86>h\dNFtVIʆpK+cSe? e_dxGFR T rkZKYtCg8}>g%e 4]HYv?lS&]]6kt |otrC|"ꓸK[?:$>M_iKo\NHOHGfr^ƻ}p"F1'4Sh^Zjiy3=rGW~_dЧT3yprnָ='h-xvꯛҶI:3p2p宿:ztC=kSNmkk9oOfnktYZJ[!| ۟\~҅[n6}?bĉM#WߖrpEtF{(띃sq.D\:R\NWJ\хooV@O܆qD/܅胻[܃Հ N[=ax 细\)8a]v&.jOu?+k?0]uTfKOQƛw~۴A]7yhgT^מ>:l4=A6gp `P A !b$>)F3q_b<50S=~TLtLl`~\|,B,b,R,rbVbVc ?!!؀Pl&l![mD1Ev؅x$ IHnA RtEa?2a(;9EQB%8RQJT0QZQCрC?FY8+sqp.%Kq:r\+q5z܀_3nM肛tE7t-=v܁; w7nw^܇~ x1~x`!a1`)a9+ AXuXl@(6b6c 6D" ؎";`NB<$$c7 HC:"0"(@!PD)p@%pըA-(hqXI OpF{ \q.D\q :R\NWJ\q u7qf] q nEmwN]>=c@` x1c('$)h|1c1_K70a&c iYyXEX%XeX@JjA'c#؄؂0c+" B4#$" ؍=HA*Ґ>G&8,d#C> P"Q2B9*P*F5jP#8cC=p(Ɉv8 g=~sp..Ÿq).C'\+p%ո:\ktƍ ]p3~z6܎;p'z.F܍}{܋1c Axb0a|/% _| 0 1L4L ,FG<,",,2,G V`%Va5 k FlflA±؆HD!XaL؉]Gd iH^d`#f@\!(DQ(ED51ԡ 8 FY8+sqp.%Kq:r\+q5z܀_3nM肛tE7t-=v܁; w7nw^܇~ x1~x`!a1`)a9+ AXuXl@(6b6c 6D" ؎";`NB<$$c7 HC:"0"(@!PD)p@%pըA-(hqXQgD;98|\ b\.Wj\kq 5:F܄.AWtCw܂[=qnpzoq~=}1 <1C0x ? 'O1a >X?| Lwɘbcfbf#s#bcbc b#+k Xb#6a3 ؊lC$A,&.#HB2vcR4c/2 3 A.(A P T QPʛFY8+sqp.%Kq:r\+q5z܀_3nM肛tE7t-=v܁; w7nw^܇~ x1~x`!a1`)a9+ AXuXl@(6b6c 6D" ؎";`NB<$$c7 HC:"0"(@!PD)p@%pըA-(hqX|@Ljv8 g=~sp..Ÿq).C'\+p%ո:\ktƍ ]p3~z6܎;p'z.F܍}{܋1c Axb0a|/% _| 0 1L4L ,FG<,",,2,G V`%Va5 k FlflA±؆HD!XaL؉]Gd iH^d`#f@\!(DQ(ED51ԡ 8 glǯpy8BtE#.eqUZ\q~θ7 noV@O܆qD/܅胻[܃ߡ/~{q?~ 0A !H| FSg1x_k|o1&a2{阁XXXX *a-~B0a=B؈M،-C8"(Dc;b8 ; H@"؃" ؋ ~dŒB6r<(B1Jp(!aT88:ԣa\#,8\tĥ p9 W\p=n7&t ܊p;腻}p7~{;q/C?܏<?<c#P OI Sxx/W /Ex+W^xom ]>>1>(| c9b+|o-&`"$L|0030010 K˰XXX O:G6  aVD`"hlG b0a'v! HD{T!{}؏LqYFr|E(F e8rTU8jԠGpPz48,P>oD;98|\ b\.Wj\kq 5:F܄.AWtCw܂[=qnpzoq~=}1 <1C0x ? 'O1a >X?| Lwɘbcfbf#s#bcbc b#+k Xb#6a3 ؊lC$A,&.#HB2vcR4c/2 3 A.(A P T QP/glǯpy8BtE#.eqUZ\q~ p?{s/C?3?`!CxQSjL_t=u^az9H`.yk޽ʃu CQ'*LͶͰ ؗk[Eyp,k߫[DZߌ 2jۏ ۞Qh[V;LS=ǀ )/Y^8Na9r nyMy 3;ޙ䘫>dʺ \֒uJOGr2*WƆTnP꘵ᘠ5krY2%|9yko{ J]>1ֶOY8VWoܱ]쳍O(Ǻ%6v|kӯB}!6O[ζO>3,gXΰa[ӗ6kSXu68gmhތǏIԼUu6۵>kc]vݱhژQE-[f{e~dZ33u3e!mIe:33&ȴ/rpL337y'u[7\9+gXΰ9g%&K[;C%mOB%oO^_.>δU%Xβ f[GcَIYIʶ/y,&3f;mXD d7a鸲u[vY3۱G?ݲazru[ΰng'VsoI歚m+[ Dc_|~w(>qmݮUVVŴ$oPgLNaW/0rcbW11+˘2uWF jc1**|ڷU,,21[S!Iki/,dJ!SoM&)*2Sᄁ)s}k*RG Vf)***M(t +,g[HVcEEV**-m_]m8Fh]۝m O+xc5x>'b{J.w9dq"gXΰa9ÿ3yUYYvӠg._~t?0ȑ#eS7,B~WT[qRbhGJvڱ˗(U\\^[U̬U&*!KbބůNع>D;a.딝lEYF ڗnuc_źG@c ٧;scbx}m%ƜI؀vL}iv>vgXTtӊKv_3t{VAÔ3,g n3y33o56o1|FPٻX맂+\$]OG8j 'ީ%pe$o]R[JZ瘲sR2k0YGז oy>1tA ea&'epYY7Xt [Pʊʶxp2׹eO&[*s~L]mqev7=fzt$-9 gXw8r ? ;n<x p[D0S-KB"l_yZm5T )ceVe;$5d8fqtpq%fi*ffDt ~a&i]3vݩ|L>-nصEa2mbC*_{Л7I֩}g-}i<ĔpSƘV#kR1(^s;l.8q0%xY=׼f-Y{Z-}~bK#L}i– w5ǩo,D$-"vyk%䭊JPTVTQS ~J*UZ'h+T:&UFֵ+۫TmRѶl:>jkp: m3ut:=1#p,;jk[ӎtGj; Mkۗ3,gXΰqr*6~ծ[sn| T;ZaSc@]v3ؔa9.>6 EᶜkkõʵYy]ߺuqexn} /GIZjm&Hׯ-a]"`S~^ŋ)0sjԉK[YJRrOPSW]Z\X[ثV{pZZunuT}PʾJj6mmӴh?juj=ZZ':k[UW[@k蟺^ Tΰa->p[[uu 4OcU5孮 SQ\ǚfzfkeo,fvScvlWG+x?K8?m굥'kkҾHm[կPoN}n .{p9؆cu:8խDڦ7R_t"tOþzc3,gXΰ6}ljAejS{~dy>w_69nS_[-[a$=.iɺuNclm(u{.>x 'y9rfF+gi{jlgix}"o5;wm1#pДV:#]wSA_a.Aςn`TcO+<)uƸ^死9*̔rK![E×nko5t[-BJXe/B7m0YgobuYow?^3s,U;.Ws5VYѮ3ȴ h3_R[FOiQfDu4imֵD~~kֆgz-CiFvښv[ s?cVzVn|ھ4KtbJ)icL|cy[@ӑnZzopa9͝~L6~Q0%xY=׼fO)d5J6@r 3fi7I٩vkm #rEЩ yI{;/څJ/Bk[]Q[icԺbaQFڅM)+YEn>P.8O̷Ģ| m ڱnMSiީ8;ڞ&GStm-Pe Q ړ_͵.u=62꘸. wl{r ahyy<2\@'3E{Gqm֩$@:p҉FK}\NQ1`&ws{O]bjkKh<'*Y.2b䁒)%l}cX?`#kU֏j.xbbDmљVJ]]gG)<8wKm[F h2qm46Ȕk.vnD2ĽfbDOnoˬun@'\+Mi?өnp:E8enBVSЄ.,]nݧFu;d@Ҏ%ꒉvo 軠Yv//}zbHKKK7U][K%))؛[0YGh7{y{Foۏtj0KmD5KO$ZKejOPOo[?ci?ii3UW__˭ m,ou]ld:43[+n.{xc5vk8e>Zᾮ(˛K]<@fq|^o4uMo,J-s>s[͚~*_aN"Ο{u/sS@r [Gz[M>%jqIޒ>U|*PLi?ii3zhE÷{32tKu ҌcC<;Opa5ygtw'~)ժyŤݻ)xgvjAejS{~dy>w_69nSS[-[IJ򖴴tkt[ͽ)o}vtiF64eo[ZV\-[ a>_D[Rm$oIy72)_giiՑ;𳋵[RgDIޒr5+o'&FHؒJN\m'oIɒ%j^jwNj-sV9?b⒒8*,[R^f学 --  Xi3L/J?oa_t/K򖔗K򖴴t ~;2{+{TuŁdti`G-X!ג+[R^.[-6Va[D,J/Z,t[c/󴨡joR'(ʬ.w H4~j8nq:~{{Q7v a}~,q?Y=| Sΐ%咼%--݂ny+=+7>m_lr$:1%ܔ1&- GT -7N?&TuƬk^SV>jOQ7YbSjoM-)/-iit[e JK[9ErL)s^kQ!%w2)Ʃqbz[z|e?,,ߟPe sIoMf;ZIޒruJ$--}VsϬUQ]mp X?޶p[碎VBt s/qޫsoo}͝Mت8Cޒ:-%yK%yKJJV߿mBo?fedž?_yvBžk:/0=ONMOIIޒrIޒ򅒼ꕝMy 3;ޙ䘫>dʺ NaJJ򖔗K򖔔/䭖Wsswnچ3 MٛqV:<-)/-))_([RRN%yK%yKJPi]l욨U.:2rmt4+O'[RgDIޒrIޒ"5; ܻWT/[R^.[RRPEieeF^޾|hi99%,5)"yK\2gex˨#&+.)i:ɒ%咼%% Xfgg甔ZoM̀-o'X2dHjnUVV4hrp7d0/ :r>:)%咼%% XdKKsN]D\y߿y3u^?t]q%f2~d,8:Q n:AIޒrIޒLkFsRTryhfJZ%zIH␭B57Of~!%}zlǀD6Ǭ37n?{i~ն;LS|'S\|}dC"bcyT#y5rE*=+7>m_lr&:1%ܔ1&- GT -7N?&TuƬkk RZ-wk7cf LbJuNC[.[R^.[RRP|5lF)D.[J*+rR2[&0,CJ^ce֕SS?'EK]Vt3{r2ETK򖔗K򖔔/bYPP\^Nk+TVUo[yyrUEu2jRcQxo[:C6]sUU&\)`ˎo&o2IBIޒrIޒR_,̅ ZYZRLfEԔWk֭SF,ãv 4wH\=|=JR#h7G~D䯦%-K ,.j0'Y\|b5l\R?2>ykΝ[uu64>V__USX0a5uigV \ƒkn758mqv%o}}],Yj2Rxi1Kzɗ-)/-))_(-o8ť[|#]wSA_a.Aςn`p/? -)/-iit0S-KB"l_yZm5T )ceVe;$5d8fqtpquWݩ6nhc>wit-)/-iit[Yib.щ)ᦤ1nqOG>bPhVt4w1]rGůÔ5f]\VŢyZ-7jw֦0UZ%yK%yKZZVYeRVNQqSJFcy܄ET?|`Hkr{̺r~qjX(5rˊ1o,YO )%tL:qIޒrIޒnAUQ]mp X?޶p[碎dʺ Nɾ$o|Iޒr5+o7'o郑~SdtD#x獤كTj5NV<%Xho,o9xHn^{X~]崩F 2+1 ŴdpE% u {ƮI }]90]k,o<ͦ,֤TԜ咢e*t8]"v}Ûp-6Y\[i7"=E.C{WK}c+%iM FF'vVsoI%yKܼf}W1LD}t>]"J`irqe#ڵDM[=ja>v}@TjHr|zL}[mEm|6lӯ韻[>=] s [sWZޒj%yKՂOyy[e=#lvScC݈ A*5i"Gn-F?15uua[>ծm\9؉WIyXOg׷RQkoi'幻<jhO>%ݴn;y׷Yc2jKJZ㨤N$oIyZ5o.ӴZUuaʳ"jXLl%njqJh.^)״H\)WܷsD*[R^.[ҭm'o5nZxX 7̉`R3{w6w Hn7a~HyKƮK([R^/ϧ)׷m@hL Ry݂4;N\sM^ǝ_JIޒrUKKKHXy_«_1Y<MC [͒%jV OL%-sWNjwNy;`O0bF){3?J'ղ%j^jwNޒjuJVqܲCfWVSD Nj-3$oIy$oIKK7T,[R^.[-h[-e3'QGLW\RG%u%yK%yKZZCyUYYvӠg._~t?0ȑ#褜J򖔗K򖴴t wo{\~gu뎕ٽ~*K2:e4YqtЍ,g!u%咼\IKZh"ZVn^8d+h}mLӢn_HI+,1 Eq& 1댣[쾮><0mԟQK˗oM{NUIޒrm՜u璒jtJʍOFNL 7%mo,ou {:-BK .:{ӏ";*~1ڿ皷ozif +u%yK%yKTcy`yyAi)y+8@)%}nKq "\>05=Vf]9?85CqRڿeEWQ~kzھT\$oII5V>* ΕaV~+\ԑ'"oM7)M䚸M_\vܼ3J򖔗K-)ʧVum-}dsboV^c׷n]2d}[C@bKQ&G o?%Mx?Na?sKudIޒrIޒ%%Xtު嶡&mw.>-EO[PJK=mi ЂKK I rĉ#'>[C|+C%YmwV#F,J~_gǧvMxê?*gDZv*)=;&7\y9qէyV^&q*$@"+PEQn{Eť&I$j]S 0# c$(&NrI(KKѩd^\2vvpV$0J+lXiQ\Z8?@ ѼSO6N}k 3WeyFs w]($@C͢x%wPLr SC뒨p^^]$1lJaźc2-+ryo=zҋS0OtHMoʢ2oSsOz߯d7lvWWo@"KL8FH`(&B12^0⮲K$DTy>o $"Pgw8pEl"zwӋX(-Y֬y$o(5-oEP}S q*-VXՠzmo{Jؙlwʾ9֙ 5䟀@"+0K~@&-ЂHd}.LJ@%-V~oi::7Kź*Y!|)Mza kGKAJƚ&&&[_~,x<NsK[[+NiO;:{˩?>z{itz}ڍ` (-)ry \Qw:XVѬ#'rܽ_%O/ݟ5pOZm;n:q[{k-9 lzc>Gy]烸Hh\2%EQar] R\[ SDVs^V;_t[?[t<✡:uk'쎊Yژq;|x_;H*G1ѸYLɤTf*-)ykXBեoܥP[DWL?Uh|1B$xg󉈜\(}G`d--P0 }-bFi[(5_By+Kru2#cP7dHdo`?AU ޾v;ji R@ x $w?)o-HdyA+_Ƿ@B[ h x $@ wbs㾔_;,!` Q[ o {^X=[=] zU7֤l=611ցY[[ ;E.o܋Kwݴӝwkj4zC:>ug| ,qx+Y;MŪ2S I$Z%E#r%82N"%82NBJKdPNejsf%A[䊺yDz f ?S7,yh|I{Һo;qӉK[Koɡ^7g3o>*m$MIQ;LG«J"-XlƳ$ q 8E3]h$؊1,{ yKX;&[?qEn+W?^|E2;ފMO ݗwי[S4?)fwTP΂ƌyjtwޚ@"KZ#CD#QNqXl4J-,],56!V-IN!.7ihGG{oui/w)Tx5Od m;wPE^AVN'`zq^F(* qHd[x21W+C0&DZ$\̩ 2t(#> yW.x r-H9Uy bH7={aoV|HWw)U)XpD[rHdyI/p[+NiO;:{˩?>z{itz}ڍ.@Y[`0/pBh%Wԝ+=Ux4Hf"wygɓEKtg ܓ}鎛N\ZzK9ޘAOQa^r|U*`ȥܩf'n9uG [-tふ6]:äQ[`0/|jT׫ǔ֪u˔x{+.6=[3t_z]gnM\QC9 ^3~[~3ՌR6g0[9x aox~O-oFYu[7ddclϯR;xk5B"v'x[ä( x+ ¼5^eQO+REdKM*\=VR֥c@s'`e4L&D9cnw[>HQ^(F.xY0lUvXbV![T% YXg hx ~@-bFFSa䎷n9sqvkݓÏarU;+YZ}JWn&r<%M3V§Q(:Hf "-5[ӪR֍EBֵ9 sU2q[:]hHp0D[[ ;E4oӣM+5d¯}̕%Ew\v>]E7 @" x x r-_߿sK/NR~-7~g{>Ȏ<%@" x x r'-VXՠzmo{Jؙlwʾ9֙ 5䟀@"+EQ|sE 82NሏPjI$\ Nħ81w+:uFHET,%XwU/$\7-X[ @%eXuj,pJ6o%k\$Q-Wb" \$͍aS yKX;&X:`/$Ky[\.,956!V-IN!fy8$-Ђ|>$[h Ac)Jy[\O#S+cPɲ}X,<@H-MG})XwpYBr@ @"+#b,`X-AxJ*yȩ@PEx&:'XaOHE(og/,ޞ݊i.*kRNm(^m:GoDVP%x=^ 2q֩AV +F"x$+4[ ּ-__{rTqsc~QMFoHקݸ}B݊y,|"Hd0;kx1}2 AHӼ-VrEcYG d)rwx @}XKs6@ ѴxRV^XTZWԝ/S㭟xDnq}}w5Eszbvc,xm̸>oɉMH!JJ\xUhxNsq +& ns-2#ȝxO> BSeZ x  o CC=]] U;޺@MtSsG%Y)rTџWПӉ%^qQ^xw 0n .^.I>[[ /B-H9Uy XQ8OP[[ ;-2[,i-)0nr[VT8;SL0靕,o>% q`衤Ix !a$r;y,w7#)\X/A5_By+Kru2Po`? P%V\ ^ċA\-HI]f\rbi9I`d<+O0M-:ev/-f0pzyjk \C%)d9r]i0 rUܨf&@aqr49\0tI}}ȼeX6[,Sa䎷/探ŗrZ7u$N$M1;&lA.^!N[/qGr+#,,4%.e.dkţPf$Ղ^.(KGl^ES31bh\lT3ZͺQTC9[m hIbW%yÓ}u&KHZ񄤅Oo<Y`)QaL擽 =5(azՕ#?op7*jy˿r Wq[S>g@s.\$޸)Y)P%+-9f_Ϧq^v51DGrrq:a_yp)>4ޙ@V@D%R\Y+ nWp*o\o aȘq8n0&&Mf33[9*`%X/جl䇃Q& - DEm}-BHdU |q>?He>>@<#a7E%*T\&!zDPx $[st0p t| Bd uhP}Ɔk߷U6\:äQ[`0x!9LǷ@ ,O E&.> `p0[+io>H槉V]ioVf2Uig&ONK׎ԧo C-꽳!ם̭g[k5}icyW-Rpz&*~>)KMRlϵgk34"!+`p0HBh%Wԝ+=Ux4Hf"6|Zfqstwv2qٜ)ܯ!qc}E'}SS侁W-3ŠQwqUs3rD;^{hp{iN\QQQ^ umS,Exjsc!!:uⴡ x o`8qEn+Wi*_QwL鉷6f2ܛc_h%MkF,~|۹&\f!$6`FL,JݽS[NE ]f&Z{;Dv&{bᝒ\onluQnM*oБݬQWCYbqRf,;o欹#ǡqհ^?8:;4xK|Kj[.2UFfyCĎ0/ 13weqV";n@K@]*[DGj-u& fU2XG:\af`#M pQ[ꊙKzvbR_¾'&o˜]Ro -0C[>(-oh|@ I,(ץL]fuE";U~>RA[`0{[m~6[XTڜMeRҩ7OEl5܃kR]a+6䛪sU+tųc%=m(eGA!R!a՘VHX5&Pw~ݵ?d5- O-w΅Uc[][ P[[pG\HX5xtPx ?[ a`-0xx 佀x^A=x B[{ Zϋ?[`'u#F[(JRT,EQ<|ߒWC֋╔]8p?rvvܦ![ (ޢbd91dz{5b8DUpt @єdrPmÓE@A-{X8!7<>a~HS h!@˟\IZ@F ˉ-gyKSw_ܵ&Gb dLΗ]5hpq+QP 5KnMgPX:W= [d"sUqh1r[[_$@-KRx[d8Ԭr`:nlV;)Df#U3/dfOw@N4(9fs1(90oo@ 4611xJ\(ᘲm贋^NQ(#E=c=H*sJ w9¶+WvS+NI{)Յ\]\.Ǚ-^=]Ya_T~3y_S jZ7{x ䷀x^AzG/)R>H!]==8GQ(⣗zQG(!qREԓWG=dty!-J2HɣKY\3o?x^AZmr_ڧ}zO1{ecxcC+QK(*^C)P}}brNKZNJTO C iO[Z+a{vťbpz\&m+ݷR8%g'm 9&zX%5~͵wֹ @~KrUcSCCyYl`?_5/ T'vWȪ~nx :PMQRX|j%kRRqkz~h ﷷC6k`)5i?qoe攔p^'~*mvn;~]IqN PpW 󽇁@~+$UyYl"P32xhH֘a62A"ᒽ,L%Ԣe 5(N2l? ӗWQ H$ 5(Nie@aasaW% \V9,(ajXXSs\W-!Jr@ta-Cb7/AёѺŋGQԨ5F/[X\uzq$@#QkZkz~9}=[(]|j6b;GGx%5}ĖV4>Gsڿ.+7b.xL{܈Lqdp=l/L uJgE"S-ȩso A-c׳_*yNӿ ?Xk`SZ#\# Kב!YsNmtuDZ=hĥsN+FsGImuܐq\^6W@r=L͕/@~ x ֘Uh{-c[wiا?:FڜO4m.x~z6@k-ܪq\jՔK]`S'Xj;^| x [xD3 a ^`.icGhi[ @eq؇}Vk[ma.[=-ܣmk1-=xlυ.Bq7F^g7np@]=_z0{iOMZm +5Fix [>ƷoX/^y ^/|o  [ a-7{o`gB7C ^^`OBE[ a-PX{hؠ?,ۡ>~ [[o52 cmtfI?3[9!`08l|#jױҗ\8ޑ~$ijj*HQzM\|x 4G[r7Uq^(y1_ܲ%љCÏd{Fc DW4S_e(FacY䱲4CL_|fTf@sO_[[GKgZ8Vα]/|w=ݾ'sHy>R7 yːb2\=U}yYm0WMV,?e*;/9R֧g@so?j`p$xYŅ[^*c/}8w\|.XJ_x=-{>w{{y4 EEQV%EQ AQI#F%EEHJ*G1(2eR(rqXh)./ 0Rc3XjLsmYfV"2Pʺ} h򉷼DY,f|$Lӛ&zp3=z>ĕ$::~^F=ɥR(Fc0\ bR2/4ME3TR:f~ x)["Kc!ciAe=kN8m(@[`0GoyOWG?WH@EOYC-}yy@ 0o./c4v:&RluQ`ˢ*FnY=U)3e@s [x|1FcӦOhvp /eg`)gŽ+<ؼV9Kc 6[6@J73[9 x -ozs{x[RuZCW->xEQQx&i4^|"JH .(.l*2ͪ2df8!WU29 x -ooo除k?c<2y~E׻tӛtuK"]O:% /#;.]EQha4TT^.G e[/OIm 81VeE]N GLUXe[G89{`»9xn9t#s&/L¸-_^K_^E-oc]7c/#IWr|+(w1¼eεVYZer󈱐1l!PC h ot:ah7&&'f W~PCoԔق:`!»e1[ތou=&Lr|;S` Vӟuu5m^FPӚ<˥Kxb!*[ 1[9(582Y{PQ<ȽԊ8`D*%.%AiQ ]J.bQzNE(K]BV c$Jq!q %CHBwg;MFyX/G,׸O<q1XTf3z}#3sߝIO$7~~ڳ~(಍o5[:/ײ\-sc&!T[[!@~+=c$9(^CK$=y^. zT !Ӑrt=JezxF!dQx1͍g#sQJIYx8߲ޡp4%cw??\+R 5Tq⌼w?;x˛-=>6˞d"mBw_c~Śʋ"40oM+fzZ,]VvK} c vVKe.[}}U&bг$Sx^?QgFjlzKSeg+PL/ՈQz\`ZTn/[ML\xR .}#W}!;U~>RAn**}p9oet"rG=QQ=#S|qg@sPye*ރ{ *&\>n;/\TzhaQ!XBPEܩUn.Fh,8=+oe^z~<-nômEKf=*/^m}[RczywK.feGo:Ur!_zG 4G!~ucÆ1q`2ML&''Igf@sTy&c\&s)d @wgHp)-gмߚ\z˔^o=[>IvL/zst#ٞ} O,z #%|HdTG\qtděB|-oQWoDV`y"oƄ@x+lo{mլ+ԁ1=] x~tz g {Z}r t 3RR9JW%i4xإGe;0Hd<<9 -Ï f|$Lӛ&zp3=zvj<ĕ$::~^FUs{N{4{ ^Q^;:12ڌBr»wGs7JtezzZ!=O}t tX:4?ҧ>{RG0{,%GFIIb(\.J)"[oDVx G#cڇ/l>M^_"WR:,u{MX>9][U[ p7ۉDzj=9f"ŻLŻ_^/_Mn{n_Iwv~|1Q¼ܶR  5f,Y«d ޢQX.Y^ίƑnyk{˳<'6\8: 2u $K0llo5w\QJkUeJw-]kX— _t?iVZOwG/rt!椨$ v{%)a%g4\b, 3 @"ribE z7%8-/Vpvְ^?8:;430إoܥP2M f?;}v*sf&ngߔ=Jxf^F0*!A//|_SK"phUת_E[S3Mwk7SQ]oNeё]ǫW#XX (@}OÅ&?YNS\:o7w|pӺ; 6qwu Kq3 B*g7DȭĆGX^Ja|pY[`08)I}]=ѕo#_8@[Hdo`8,xoazӃ-a]iOK=ev LSVY[`08z_IUWmNO/e>;:ad2yYS x $`p0v?kL˙͌53ٯ} j#A x $`p0vf='WތN]mi x $`p0v(Ys G',_yKfj0!s8ϮYs7`08<_@B+t^鱬£YG2OyxMc?޺7nxwc+__q%--uM[s_ޑ2oTLimmo^%cp T^EM{` x $`;(muM|E2;2__w_~f`(..^u|b,{-η{{]uq{K3yCtNoGyKhP"R* oI4Q( LGN[ ؼ5 vi/w)TXI/F1^Mٽkox)?}?(G UI [$<.Y<ȭ5(,-0-H9Uy X<";{uQ@'}O_#?V7Ȕ?/HJrѕ4I#[!e,$i@" x ayh2!aZ:=:tPBBd)-O'%1iii[n[Q^܄#7`~1F#OVzaVCR+Yyf5lx&tDag<5t&8l-6o-3za[,Sa䁷vܹo>hkO?<^q^Eur(D\RwK"q,ۺx9B$n<>ZoDVy?Ox*UUyθ\y!Q GWCG:3%Ʋl^ '[>#ٳi( _C|Y}}}jaao q~hAHd$_ZW1n2MLNNNMNOO7+.KbZ>S R/NB)qZS12t):FX|K >?f$u Qhe\<&YX[x΂øs% >YT[3gYe;/U"sߙk~֭x}%X [\@YEgu$rW¢S1*셞8M>i4% $KO&^tkȸ3 Ft:ԟBu0KAC'| g$ ZTUo_]yW__˱/^3/mf4,i x $[gBᾝ7v; R?y!,ť&$Ǡ'41^8"!P$p)uԑ˴?LaG )N!S.b,;]2C['=Yi^ 'O۹7-釮?=Nz;O^:׿y+- oZLYi{/oH7yN<\y\,=,nz|ثg-ӑȨJsNvC.sg[jU}`_[HKSSS; 7Y\^o`uy'- omx&M!cַA[ '3akyRV^FRZWԝ/S㭶[qժUW^n7l`26oތk۶m(o2ܯQoJTxjF.rP1c=AFn @"+#bְ^?8:;4xK|Kju[?@a*RhD599iXp를B9]aȅYG|3 @" x ayKg4RΪk`ŸX$it+^ť7niӦ-[8-9VX x $`&ɄHkl||`Tn|K1:._|ʕ.U\SSS3339[y뷒(9 |"*˅QX*u@" x ayloza OY,q;I@Ƿ~{Ŋr {ڰab۶$q4âU.S$|.sa0Hdo`?,6oKD˗/wuuuwwjirzn0~5/KrwsbP x $`o w[oo;x BZfڵk'''Ket>Ĺ!/-~8/?Y:/_Σ.[V#BHdo`?'Vds}VzS#hA x $`-񓥟 wrw}qK'o>19`+Y[`04@" x p<+ 56Ju. 3ȳ`wKoUd3Y&soC);?[[UNl훧V~Wr[CƐ x Vpn-)amǢ"VimmfZ._DI]|Rr Rw TOZ555eXfffxiZ//~KxnpR62ݵ O߄(bBl3qZ yXϏ-__VyåZ r^Кz\>­Yxk m`v0w]/%ฮ= o5]8O%*7+/~:Ajȟ\gĿXmӫLv&؝B+t^޷Qy 5wݕJ{k=5!5 BHy;@]HB !B y $1N <;Xr"mdc[~YF,ɒv;;3;;xߖ{ׇ*+{{ɺZR"_WCrԀ+*zDװ$'gNA깱!Eg?,g;f%dmPo'>\I~@o ucþ}@+&W658 O<Aa[tmyvӑC_J1s||UK(K3aW] zX*nضzCHɢ4E!+q6 :>GƜ>*SХ fLgըIfh~ZLJ UnYDv&-U5 喺J T}a9hܟ2dVT֣G+?ߚgɱfgC߫yGz3‡kr^e]oE@v}Pŵ?+Bl``~.T;^ [d0oɆY  a*1pv Z5^r\ ko@{&BjLi[R@! zVfi}}Pj-)lR ղ4CldEJ5XOo Lm4Z55fA1&j!VOWoo[w7&{GM}l,qlGF@u_WIJr:e-&n647zxЫƔ͏2HMH!'ٹ&GV$!/ꭰa+8. c^룊?32WZo n+X[>{5w> ZkOƷo=C%W?CwƷai @JcV zk&HS%T֗uTEe2B+Wo_[^ELc`^ U58o9'LV[4+~MCMl&^...iE{=OjbEWX9Ae A-(|ZEPTZfQ[vJv׊-..oc'[jV-!n(I[Nڪcz__[/}M)⸛*4͉UiK{/`LJ]p 2-z5Wd3-0ppx':{jZVp\dW}=-l }?u ?CZ:y6=dC!`S+?>#!A".[a}:i]\ýQ\gΜ]"ЦODwPV{7xuX[/=[ZyW9>cq1qMk%36?^Ѣ!RbXP1JںƖ_*1W&`.-璁:a}b`+[1cz!`K[yGnj Vs|nu:-7,2,@Vr:wWCbƎ(SuEz'AY!6hd3+ih &d4/O(x:Po@tVF$sh:N5^2Hڲ)J[ 8^ W K0~kk'_uh>Ʒhf.UfST񣼅t¶.eLѪcc1*ѩF_*(LִukbuEk#A_僭LJ U Sܰe  Pr{.Q_? [aG߁ h7^"c@uI=|bc׿w>X}oCK HS czߑ ?JڧT~XL8[PQtޗJ؞Ql 2v>U,֫(r9a[Q [+ļ".$..=8dȀz+X wO}[ FFF _{> |τOXءOU3٫x g[^+ӰgWp˞īJ1;(rhz26[Aqs$?^EoE(ꭰcpO$WQc mU9ޚ {ܬ\voyvW"h̠zjZ%zۂV&-Ԅ+脒ޚq WS[5a*T!z}`+:5WC _`Gun}yV&VF-:qz++:Rqpc߁ ݹZvڰV-+Vla[8K]YƩ 0@<®Hd"0>[- ꭠ}WML^KKyQ#;'?G[rYB"!0N[wZZC[WNXUeݵK4q|Vq"ssOmوQyE +Po!ު+1-)yBY\l"Po>Po@;ӻ/~D5-Vz D@H譠`4~Vx?Nk׻AϦDƧsM [aljW[C]>yAu'y^SsO[H$2FMo;bMCs syQ?e2ɬ 3'֣G99??.ͧRLJĠ ܬB'e ńz+(r}Pŵ?+B *#u[TQo!bzz{ۺAo5;jꛌf?eccd=2JJV2)knXUGo)$xh0MfP/e>0D@v4|$& TG!ou4_zKJ3-$[VádQEtj55VxF2Q\~(Yz7X$#$z+(oe׫$jw)V>0Uo)Rs%*@D"C`ax u6oY+- c::(z[Ko z H-X7n֟BXB]h$$CPoOYvq Gq9s&w@'qR>T z D"cƿ5tA9>z G΁az *+ пa!#C ' ^Pht !(#ꭠ}םN~4̡Xt:~V(QOCgIi*8zk7J|Zl&l7HVHdR.k-uŕxVϋ4&̊ 2sh=zT<1/Ϛr1ON|79AB-v5.)ⷮ lm.]J+| q [H$2U Emd﨩o2ZE#hr_}k+r57WXô/-+UP  Z; @l=WAo%ٻWD}r0Jo]O [H$2Ԅ+/; ڊtot]BA\\8zk5Po@D"#AM4!͝px}@- BH4.@z DoPji& HLwA1|Hd0|bϿ3&So "pWD"W-D 1QDPz+ -$2y2"/WL[("8H$28abb &搘z+9BJo҉D"> ̿9|E^:D>Sd0OUU]Dq#ˆ[!|ƌz D-mHU\fa!wARclJ Gop3-$ѿ h^鱖=@55d ueE6 ˦`}b6)UɈ[ F?}r|HLAm:DacHdD"kX.~:k76MOpLGg%EI@? udnpEջV?W᪓miU\n+)0M[&h=*Ogɱfg{[ljf&Po!-OlN[16J̾bffTh2ћB5!@?y+Ŵmd﨩o2"1&:uʚ+VU[LfyHdk-"$.MoYbֿE_34N~~ B[h T2HzKɨ.^H^!/}0.Q{0gCM5abNl>Cjz˫1[%0VTWqFqJ{OlhW*'p-BjW^[,Att/Df&nas]CļY  @L4Oԃ,ZbJ;-ccBCc@\g龱Ҝ\iz1< Kmh ՘'[Ѧ-h&$dX,dLYل.'(xdP\z6^mcEט-xy6Z2AP 뭢lg1si>BX ǿN --m9$ h5?0SuК 3__eiyF_"EQ"AĐBc"4X!` 4f)B,ћ}]Ti D$ޚGR.2FZ[h{R!**g\-*l(U EMv^of"-Rҩf®h[Zo3Т(6'OCg  ʺkh46܉^ofRM/n7IVx?BexyzKg"qEMiۊ,,$_.(~ۚM7[A>Mފ4-żyi-n<, |^!AAzKL%kIN ģPSC?? D=;Mi:"65Gi8 j[3qsz hy?_ܺ/[!&XyB?(6.d b6FޚzQDIhQoiֿuSo]o[u dM'ecpMi^]ߦ㳿; c)a?qVMCsrtœo4}^TOoL@i˳X-OMv+@?1UCґ#[И5"|-PoūB F9 _o? ]ͿC!4T"Ɩz}Zq״*wzz{ۺ[;5MF՟޲Xı1):ez ȩ[A^?.VRU3>C[Z[o_3d~~ @Mvzs5gzpFWJj|:K*Id Ѐz @F!m+- f::ȈzhD٫ޢê@i]境ySBJSC?kF,-0prhşKF-6k;E'ė4Vז {i/hQoivBĎK=N zSNeqGmܨ|_Yj)zkt:CV-(ʭT9){[]~DVgPo! -6#dJA~s'UIxrP[!44[H$2\:yí4w\IV{1BV6{a[@o!)`Fqs$?^]o![A#$BEz D@o)"mRgBi9D9B"![c1W5B"![F#r6z+r@D"C [XD魨υD5ĘC-4A[z+ڕ@ 4IF--demmV|('G%8^^;9Z- Z[oU\ jlź_"כ7vՁ_fgɅf-gu5z @FzLnm(һgƭ!X!TTEct::"'3OU#AH+Ѵ@~u_C~>?A5'\aTnAd#Po!_ТҮdv䕋w_T=t}wZvѣ֜kvWK%~BK ܄^3Ah͟RW\i9j:QXa7>/*&ܤvbm tz}M"@@ |AzKeccݝ? p//_ؽ{zbUU z+YHM=-2q@DB] jg*!d﨩o2o% OOڢ \M7 1yKo,ry( )Ya4E!+,4k :zhN3ŘomBKТފ ~G7p-tׄzKW@{! 1!z`o9'LV[^M+dALtJo`zKa?pd|=3 H%"̴rfqg T6q \TwF)Po!F!-Wg788X_Z*׃@E{aT[! -0prh%-jB!H[?Qa?,$$ 6Ѣ‹-& ›[~mBKТ- ]]]_=g]eZZKGXoAGɂ2AqYX["1sl|\9t GbU$`C=^^a?ԁ I$dk!~'[,!j,[CzKp身CKbG"WH#zD+'Uao@ofD[%Po!_Т(6'lC7 =ʺkh4FhP3M+{jF$:3g(XFɥ}B EM[n_fgɅzK3Ђ ĴLH~zġ.qlYW^y} @L5Po!_Т(@odc-)ۉxjjd>ϻBW||>Y11-@pÕG[5$ˣI'!VvZ*hOxHT|ΉN$AuĥB"v[&TwּȜY zf-gv@(_z 8_5Po!-OHz ~AofsUf'BiD}:X?D]\p/?j̙3'C!B-W`hWlT2Y>5Po!p"2xsGZI彏zi/hAobZݹnx&I4Q\o믿q^{q:#VUYwFЂޚ |^ڜtϾDI"z &x!K(TD\@z+(@5!GIb7 AxY @r[BЂ ٿuѵWwͫѳf|9e2DKoY|zEjz H+Ѵ@~u_C=譲2{z%%b{;u54/WM —2bf:~:/9|tuYVް~֜LՋx]i_˯*⨿&Ekd(}rjtŌRdtR|h{!zqifזx-BŞeQ?hQo]U\n+5(0M[&̊ P]Vz(r[99l_z6BtB6[0mAYEO%}MWΟ'wZ-@rWV,::K Zo [޾o^Kvq%?tٿ*[lR/${OgL7p0٨2l6[ɒ3О"z DU3it.X8z 2hQoU=]mݭ]M&OoY,Y":uʚ+VUGoȀz",rFˠ%zgzGo &to] [M-UhwR^m~>0Qr|NVZoGV>Cjzfů2jjf3rd,uqI-ԙhsma1 ˠ]Ӄ8# T!Z[j T7-ooͿoq͍|q̙`d~lrzPi- Z[Atcx8H94WϿe¯XD AofW'^*27 mvH1$ӞDĆp=bhAowny7z+ {ʟΥ$*$6,:T:\B,i2B#Eu|5hQos:e:NаBrߢ(Rk {ylDr~]C z+c۟^s~o5vuv?]v;#EBjijg@FޫMhr?eJ1^^=,^1vVz /]v& dU>B^Q49G +sGK ߺ_<~?uw7,kb @k-"Eo; t|cW!!-#<߃pd|eU/y[E)ˇ -qs$?^Eo!bTo9mt4iu6TW'[k-b譺BQ'R||a37w~ge_K"[":"[:1Yo6>OX(8Tqt̑:&Fÿ ${C 15@@ |Az+Fǃ/jɿ9ĥB"Vd[见m5Y-U=kzw6O~q+z m2ĐB"S8oENdtk)nPDb@D"C[u FNdhzT?}d+_8EE 6T1;I-6yΤǓNJz0IܷHdԶks\VK>t|:` vFb$k$1a[FJ化})|wJ+HV[XW_NO߽fͱ>8]XGo@o%g՟B&d خrXȉU "R-rh*y}xn1)_A"Z(Kqe n'_d ٿUuP5^_A\kyH.Ѳ/ު>H 1^{>_\㥗>]kھݜk޻WxydW!#(уzK#NoUT4>zkJ%zK:j6eI,*1*D#S4Z͝pxRo"԰Rb˱3&q+rU}Yy|'/dVmI89 &[GPz"u"&IW[,텤 'B"5Õ 匾ޚ!5 VK g:^ǩ9DrV1y?rqz+xD[W*9*%02ϕ_}`d=W~5ǼjH$2*$D-1!d krltxxpYc8<9Z1mb$kxBz+MTQU/Ke!ǁLiyy5D QZ*8"!O<2'vY>* չc {za!&i=~Řxxe5lv_*0- AE/AGȺm֨s5rS&Xܱj%.s\i9x9= Qa Oo2}U*Řxx1VB¬jkkV6tp|@pū,Z.VA+՝=;**ɝ=re.U| oW3k0o2ј5ƃƃ55r Yo;Y8 '啼)Fp%`PזNN7Oֹ2w @OQ'Sǂpcxd}R.+;U ^+Wyu-rXʮkx5xUƬa44ak8z)甴}xa[,+omJ0).yNRN) w9x:;{/Tʣ^ŕg&YêySTU=ms>OGd/m5{NqoOpVcEcc(H{9ȍFWdG_ꪆ# Y働C|Ǚi]YH< ШHNy&w)Q1\5%BbpM&V;(G\^+,+4=t Yo5a!ܼyUW57`苑kѦ5EMdYހp>Ahn&T$ܷM*2"md У\Rњ"ѕR /E\1XBW:CTMtĥhrɑ\Ms5y5kT|9b] {uuE㣹W5xY);\2:q,jZgܹu7ڍ)̝'`Uǟ1f<Й%*ziiEe\+(+mP6`Ap>CR7>ivNtI.ǣ|d%eIbCVtMLi-إg,I&=l3_~Ғ*JIhOfo4So/M0m +7)Y H.M*gT&i7CtS^!w0K/2Wu>iO>Y \\rpvg4G<%r<*M,45H4i W }74ӧϘC3`<`Q;ϸӧwΖw`2)3Di<(ɼw7%E%Y3*,<0{xҞx“x}d~7V6gvU?ٓ]hKp XշCH5zʕϝc\~dX}lϣ}},>wW<s**lj5̲d OaK5xWuU_ߜ96.s)bU'1f<;gc9HQU4{57k8zkdttT^$HQ+m){oI\qGiJ>oAK9RrY˥s;/++ŨvԵK$iiem]Ԯ_ vմ#2b ]Á7Xh̊FAìƜccJ r.w#{TdyNtpzI.ө<}aNs/I|d]Q'w'pN)]X$WIr|+;s|\qEa=Q8zD !,+g&NGEpɩ,p5xUƬ8'0p5fuƅq/[^[qE03>Ng?a<;u{qqL/9aU'1_J4XNm#&3%Ehh<"dYo!GM&a[HdWDNH4$B?DL4$B?DL4$B?DL4$B"H$,Qo!H$DFH$D"#K[H$D"Oo"@ пD"H$YWPo!H$Dj/>9D"Hddz D"H$2L,صRˣ^$D"C[H$D"ezKThJc9 ]A V@4 0S,]twi )Y f-3.@{Isg䯅ᯝnoCΩ4˃D"H$21E4SI1"%m[*B490ŽF`9Z^ d%EP-(U^qtH$D"^{<ʆO6uiqX8T4f)J8OD"H$f39[*i2zPi!H$ A-*'#pasN"f :Z٥?ICh/$un.MBՅD"H$?^{^%b=?4.=~t. ϳwRl0~/ H$LXBiG=!D"H$r ObzK=h x(H$Di4 $D"<D"HD"Hddz D"H$2DD"H$Yz/8_(Mt|ī9rL $2YfgB%†[+aҜH2O[DYPhZ 4.p{"H$2>X?w{?T7[% Wvgɤ!ki})ـ5_:Kw׍B-] =K;{Φ\(0%I{Hd|ӉD&~!풩.|y0p0t0| !l .tEkɚzno}K%Ks(e晔T!qMD"A wLt$]-}iT{u[r,I5rYQIi+<9#g|P&U]ķN[RfF˃D"H$2T/{{~4g?h.].K{Ɏx?]՟s.:GYI?;3Wu/-[ToѿJ^E+x:3֚f\6#BFQ: H$2T]Szq9+s+}?oϝe+7siuE…3S -5zCDoQQEo[QpQ|ZEg"H$'_Y5kO~/^\M?ō߼+u?AZ6-~;\Dru-9m"}N}tOr9{QkygWfZl3EXX7-s: .*n)8o:դxӜ}gtLchZvN-2h7C|iirȓ(u \5D"Z`G SI"f`~76润+hh-?䶶 nn΍o.<9Ӯh>dRo^,-xD+˾F3|Yſ\-d'^Q+o[G3Fw b{F(; +6Mp 1 tuw'CcwOEgb/tIg'ΧҎ C9FNm8  C \4w6Yox5OC|dbC |b{tz2 W.HD"!m~!UZ}ҷL7Su?vCmtK+i}3 ۿ]To5̒VȭFo:g-9ޙ=?IҶ[;|}7fy;%r7˲ctcdt8X@3wOuqތˁoݛAB*;x`Dٿ$&ީm k4#oy݅Wrq "H$22\$ZKnlˍnnյ`y,n;o]ߺ[s_9(͔hEުT³(vHJo;c[|~ b{~f#>5Ng}9@R3T,Z/!(!7O@zP'3 GOf.x DX׻n·AQfy N3ء>k:o)ǨC[ytZ>ʽ`-'-$F( dҹ.k:-2&7 D"LfQHzW6-zGo}ۮuAJ︱\?7|wa˷|gA5뗒뮐'R/Ec.[3ј68 Gv'C l()iڷޭl:_Y42Ӓy{}XgEzj _x"f lMWsr*RE"H$9elY$m'=Ouٯ>ڿL<">qQir`CoB&/$2peBYoOz]|`UDz<׾]ODj6eukÏ mɯ`-e"[ǯ> \ :J/ם$ax[lz+$DQo )`$nB_ە[{WWy;;l[k鑶^%͗,;bbr[zN8~mBobJ' ثL,F!D"Qo)#y*[0%O?ܶ 5ޖ=uC_Bq=d/\@\A=٫ZWqOHd|-D ~!S@S־HAҞ:׹Ud{ϼ1{-^^4N\җ p;Ψ' o [8|/"lma'M湄M.94_KF͟}yזt?,:u8*"$gE 3EXVUjX˰X^e-,`I%l5X6:,`y7a [/, ; {X>CXVX>cX>e,²%`ɂe,aɆe,{a~Xr`ɅsX%`ɇ0,G`)(,Er XRK9,aK%,UTb,Xj` K,'a9 zX`i fXZ`i vXt K,ݰr^X`eAX 2 ˗2 ,NXa9g<>>A]*Wt *t+bG:." E@$I)@ B„|nyM #=޻s=ech {A3h{C @8Cp(p8p?1g88N/p t8΄l8΅|.bZCh B;h7Wp\ w p#7-nv w] {_p/tC ݠ; x7<c8<OS4<s<^>"/+*C_xAa !00ނxFHxއC>O)|`|Kc+_x0&dSaL̄Y0~9 ̅y a,ER` ,e ia!2! V*Ȇȅ"/+*C_xAa !00ނxFHxއC>O)|`|Kc+_x0&dSaL̄Y0~9 ̅y a,ER` ,e ia!2! V*Ȇȅs/`4| c`,|k&$ S;~a*L0~0 f0~0a>,C , R! C: d@&dJXِa |(B(uJ ʡ6@%l*P! phMa/haoh7ppàG;=?'8 qp<'Ip2NSpgp pp\ @khmRh2 nf:­pw?N :p o]tz}p?<C0GQx 'Ix gYx ^ex^u o@?` 00x[6 | >s/`4| c`,|k&$ S;~a*L0~0 f0~0a>,C , R! C: d@&dJXِa |(B(uJ ʡ6@%l*P! p hMa/haoh7ppàG;=?'8 qp<'Ip2NSpgp pp\ @khmRh2 nf:­pw?N :p o]tz}p?<C0GQx 'Ix gYx ^ex^u o@?` 00x[6 | >s/`4| c`,|k&$ S;~a*L0~0 f0~0a>,C , R! C: d@&dJXِa |(B(uJ ʡ6@%l*P! phMa/haoh7ppàG;=?'8 qp<'Ip2NSpgp pp\ @khmRh2 nf:­pw?N :p o]tz}p?<C0GQx 'Ix gYx ^ex^u o@?` 00x[6 | >s/`4| c`,|k&$ S;~a*L0~0 f0~0a>,C , R! C: d@&dJXِa |(B(uJ ʡ6@%l*P! p0hMa/haoh7ppàG;=?'8 qp<'Ip2NSpgp pp\ @khmRh2 nf:­pw?N :p o]tz}p?<C0GQx 'Ix gYx ^ex^u o@?` 00x[6 | >s/`4| c`,|k&$ S;~a*L0~0 f0~0a>,C , R! C: d@&dJXِa |(B(uJ ʡ6@%l*P! phMa/haoh7ppàG;=?'8 qp<'Ip2NSpgp pp\ @khmRh2 nf:­pw?N :p o]tz}p?<C0GQx 'Ix gYx ^ex^u o@?` 00x[6 | >s/`4| c`,|k&$ S;~a*L0~0 f0~0a>,C , R! C: d@&dJXِa |(B(uJ ʡ6@%l*P! [^ }%o8- A+8#w{?Op x8Nd _48΀3,8΁s<8. ".¥ep9 :p%\W5p-p7p t[6pt B7='~xa <O< </ ހ~@a a& mxޅ0ރ>/| ?_hX 0&7-LI0w=?Ta3ăasa$|X a,XKaB,tXAȀLȂ !r!VX PP`=C BClJU 6Cja AP^ }%o8- A+8#w{?Op x8Nd _48΀3,8΁s<8. ".¥ep9 :p%\W5p-p7p t[6pt B7='~xa <O< </ ހ~@a a& mxޅ0ރ#>§|Q/a `| a|Da |#Li0fO0fl/0A2̇bH%A*rH Ȅ,X r `5PEC1@)A9TPj`3@M)͠9 -`Z~? 8¡p8~?QG8X8D8 N)p*N 8΂8΃.h m-\ =\x.VGZyv88DZnn" !܎*_5?pJO)XĐueVq*pNoX!e<QVI7vYt*cկGm:yb_+,N ⅐x !qU5:F׺H2jxuN/NnrYx Z-.H놵Z$Y딍n%nѪOV_M#R+[xc~PM!xbqGZiީ6+Km*s-\^d.kz]2E&T)͞7n)+쟋_'iZ00)<7-n_qa0#Kz o NpŨGuWYuo֘]K.+NewFfSzڢj'Q)[W-.xNcbh柁w?^9M;n/wԱU-h_q+pn>B7?lvT oy]fn|:RίU9{SEX4-[ 'ɲwZ#˛Kj풗uY@kޣbc1-.-F(,r{(Rg8f?fr?woLT͕@lpoAfQnGօ?cao=}캕c\~IY#WoqIf79}DcojemvF~ [rab\YXd^V>ʵqգ4:pBrW&:ɍ ɿP`F7H[<;iqDWW n娻ZʭL{^F?_#&ט4^T)H[-nm֩ZeiZ3dw _]&Sxe++EVfwWW~)1pLE$__XDe tFI:"r=nqhQ?8]χV:D{*CdغGF@58Y,lIbeÝ'kń\FvބG7&wE6_ֹUcwXA_/2Z9&StߒԽ:"@^줨 3^cTҟ;oԌʍQCĨ{u?O2ߴj)r*Ƀ[9aSasmǷ{UF|{\TEit?9#ntZ״ڦG-hޥy"G]V7QF}[Ws 0>-./@'rl3QaNnPCnN]3[ݾDfsg63X=]GL\.bdM\;whTs9+!zcȅ:$87]kmTW|%ڽ2Ts.i%JJvIl/']k GF`Q%gQzK. 0^8駀x4^(<$ŽȻ5ůU:?9O Q)PQ*HW{-n\Wj'1m۾pGgEUU_Ɇ￙gd)^ƿ6‹q\ɞHxg==Tc2"w'b/Scv7GO{~ݥ),#7]( 23$wHSQbUj㺫sG>:ۖ%ewSr)6x6< w\4Hu|o7'F/P_ŝČ\'! #w;07Ol64=߿*{ʼ)n2r~z+{v6ڲo"v׹F(,,Ƭx,'{ř-Ն#:vFXmNJvƚ LycS>?䞣řZis'Ώl6UC VN&2d i"u]yyZs5l#!P$2mBƙfICf/ !f 𐓅)8_ooEԏH!ozMMDZrWusKժV-{ 'j9BU-zdAK&6WW{ɌeTj,jE56X^J"fP17ū3<Ū6U*T6SU"dIFE5G6ǩ٪ '%lԼas-zkQnh1F[Wu3UnV+&*cxTnL{}71c}+"ҽ22zÆ ZpCܣ^kƍ[i6kTG+*X**dgܿMNsAAr,:m Hnnm?W53,f)eJHa[teo! P2n/4!tmܸhurG|O Tl/P_y#Q eeY؝ye0Eo?=T/&'oaMX_A96WFvAk_>[~5Hkr=?αOiiݼy5k~)U7eJpzJ4ϋXc$$棐eg,_|/i)?.}ghO2syΕNTg_DhFyH>p' CȿxSv\w%8mw탃]u[9C+T%|p܅2/,Q@So'u_{r((K>86H<<ֺ'/ wDb,]œ.^?N@ة*:׶o}r;8w ۍw w/&[' y7zVgm`׷߿o?7k;va:_k.AcעA1\Ʃ|nDcŻuO^]m}4{#Ixgts; 9'Ʊ?enUw'6Qomd<]r (O@"auV Y%TˬkV[%R7Z%R խ-4NϞu%~1P6Uf7vnĿ *78j+eggOk֩2jٹ*3uX\bi$&ݷf>-n"VVDM﫳J~4r5Zc@%Xc5V TREV T9ڦ` jOREņu%K2F(Ƭ8pOÆ${şsj63jt=Vl61WfD3j&uPϿ+T[rUԨǐ IGuTޢ?$+n4kI7eʐ9&Quc!؜\kFBz롐/?f7+ Nr|.!]6sL7^(.,d`NzCC홻 mEԏH!oFqNVJnƫ:rZ"39ZsEVSMlU˨6\YԊkmD̠֭ToVɰ*_M *ו枪*jw Eg׫g2L=S)[FQ]*+72Zn+<[FK(sTFF3[YuذQ [/"q7H*#hDgEpC*-Oͪ&6C裚J0FV]eztEځoƪTy߰!2XѨOe\k,wg5ZE%瓃2X|NKU^\@jweR2冫 ]ϿJR,pR6,z@c":n;u>C.UeY.[*g0"biEuл )1"]z+/?fׯ__98}(6^b# -7G*l+Q6G3T>\+,t Iw; e3Gp_̪Q)4#uZ  ]X(,.ҧ"oBk͘Y7Ɵ3dA|Yrn8m] 3׃TDW` W.f*P3`('7֖/CHz@TchN[?fXk ?樼 ]^=3jڢT}7rҼV~3jϕcgmXSʜ:3]eŚ-KCW. -M|Ќ%Lυiu6 g"\$ynhqV/Cf-qk$oy+lDg.W`̣96 q\f,o8q&瞓sR7k~O<3G$wKlD˕?Iɟ>HIKlDyC.E:B.yolDyo;Bӗl6oy s5 s6jG'e5߸?&LyK}'Ւ)KC_/tՌSYg&OyC'hš 6[3nDGϨ&?.!n>$ś&oqlDGM8zο|zBw75䏙Sլ:M?iIOB27| fW|5<=w#c7y5򹾬bԴ_lyO?䞣Σ^W XA(MdEՅУBnS )C昐F-Rw\G=lZ6[|AB!c9&͕fa!GΏWWn!$۴f" ;!' 3SCgCjFcns!*"Rۀ^oԽGYB WTW#%\U&RU39Z~n*U4US \]6'3QmV YԊkmԺuz{ԓMQj\UU唝j&yr7vU窰8QDQazƪMq|z*t ۃ:5o؜rZeT5Zbg?]ܨW0Uã?22t̘~_E22zÆ ZJ"E7m~Xjņ :D琺S+cXE0Q 0xlTCQ#3rztEځoƪTymƷf}{5)+[0tiy?QVOy<9*%}mj[(S2X|NKU^[M%*PY7^A7sOBWtx2ñ7PfKpIIɒ N))-))Ⱥ!S%%N{ £ׄJKS(̉붋ri>䶕(YS*{JJ|]ʷT`ER%%2(BJHrK]yJͽ{z;4_x\@qym.R5 lg,ض'&F8;b"J9 nőŚXőm1faƞb-X*"jqX(*,**#clm9-ж}oT8]c{Xz-tENfըȒv,FanL5 YTh5f̬ } uzb {<'s#rxA~A~~mߦX26NU~r6ƌ'1cwp䒯50|e9_yy.nX'T/CHz@Tch﹉@z&jcExrݍKh<_6ME~ڸnsֶr\%uTS˝ӷusho?*JQrsEѩmYIWX;\ P=i1lf7{#T\\d,[79I.Λ&s,[ZNvNse KɺttȉR|Ȃ9~7oA9b^`;'G1cDLMWo (z&+WfettK֖`ey^3,5^[kEFֳh[ kȒ!}qTc gd:&ȱL :22F=SpE2a3qPs 2|!LX"=ęM0ӜO$7+C$ˁ i:PTc+Q +'Z֠l3]{< 1()MBG(A=[3'/';#D@Ky+{"RŨ$r/ff_zGxxSbL7}j~_gX̰-SЕ𑑑¶,Fc)ͩXZj>4薖jq $z"Ǥ%?"oh\Ӷ!ڔOEUBV TΚ]&ϚvV[Wg};y+Kڎ0yTTU_9C+1k#{wy>}Q/嫯~կߤѣSLI(m٭LIKڶp>osG5dȴٳׯZU ֥F{ޞŪ sI~߾c zo?l/OfĈ_V\oMt|ɭ{OC{Oo1|Do$ƛN3Ѧvq_ӯ߸!C&0e޼IǍHN_,n͚ےgZ$#D 8MFE4/ScwI#\y 8zɓsǎԙ3$% JJ3^-[6Ϗk^uumEۘ-S%ۯw/4֌vΜӳ箤ג뮙}ة2܊|뛔S4/̡ʯԻG2dJ~r/q'MWq{R$%=}T"+Gn&Pg V~POԻCv}NEo9cϕO_^wWYot2#ժbQ?;?~ltΙ}\!%'{ޟ]!|pp'JHge#b{oG,{ >C)v ׵:{H߽ O)֧ꃝh xv|&].uwo{}sr>Ft n L٤IygTNns,ȏ# w{/l7{UUUǎ_eL9'9Nt~1?%A'B4@̆p==6ta{Nן>vWLawsO]cJ%eF5?۾S?wOk?䴶Nk7k^Kv?Zkf|1CgTl-xկ~uT˟Ѳ'{?k--ИkY>;ȸ9Nʨ缺kRV,.~_v:Wsslu)N u6JgߪǸsLz&'줧Vq[Ç6lСC6סߪ.GϕOu "|BГ} +#?p<1v `W;*-[<ʔ|?js3/v^jrLz"+LGe$=eРA0`@~>b_.y[_:[%PY%P'J>dPu.JwX%RX%R7ZYYY%F7*jJ][%RUZ%R{&ݷXYYYY5B:Z%RBV5VTV TpVVVVVVVVVVVVVVVVVVVVVVVVVVV{O~XYYYYYiUTl(+[WZ(#ioj<2OƆDOZ 'z l[\ݲ5RFWm js bwŜ zrjC!=BϤr!!,sw?zhH G5H]sr޼a! +B(.GH4)P?$|%TwxSS]ȵjǭTWZ1<ܡ]KS^5f/gUCz^uWؚS1&s*U6(NUUnY>&GGUUhYU)f>o zw!l C퇥BM[3ZYyY9&NeeE4;65-jdh,SYJ'r!R~RC,&)oХbkh[SUWU8'zZѨ]]\G*mKUo/fCK b,cvo4Pp t/qzgsK;7eOE/b,񂏗f(w,Էʊ}03ZzqqG=5vh`.m shS jCEXݚXMx-VU2 PEbNj-jv(¢¢"qP4]?!,tc ܚ1WKHMMMSniF/' =7.GåEt&|ki>.cq3sw욲oj<n]D;#)m.~So ?'vP~|ԁ)2=-"> ͱ;HtmC-hT\SR/iw8Ij?k^xZJʌwm?!ZvKUk;WUy kfǔ0M<_jw-m_weUߣĕ)щfXO'lk65Ěb?fX秮N=2N0Ěb? nJ ۅb۶/n[pE?h`==-">n]o?@̔:Q=+]ہ[u81$vm|l**6a-ܑOhmȿy')X>tG^{*?fXOߍ?xi6F@|ìvNhH5}h+Jjǩi2*pGU"qU"ucVtCͿcMbz?VVTUV?ڡ|+Xau[U"թ*Jw+ t Y85龥~:Z8m5VVVV;H 6vmwt_ɺ&w+|T+jG*meeeeeeeeeeeeeeeeeeeeeeeeee(_|-NSZB-kű-Iì6O6稃GuGF뷕y|᾵c]1SseKļ_5yŐѦBoU!`[ V3zAԴ@ yCu+caƨ-2d iB:-ޒCa^12 m,;CIDis(dWV2B,!\tPhZ^dDs1œ^U8MW1"jqX1CD P_M|;XSx}mXPTTmw[4, +,t[SnЫO=J^W3BN:L.bQn!FЌP[B3-C;ܬ-$o۶rA~A68_L ԣQsJJ7TV dVPK:^T M-Xz uzS.f*P3`(=_0&m5NMkFw Ѽր7seڥusrmo?N˨.F-7yQ{vڜ\E딗+r)7777MgxR,^ZϮW󤫱hʪQ2ڲ"<dH_(eEz"2̷fZĎL'3S(-fV!jD; # 3MGU-#CGTezb^ ٠&uoxQ4w7)'7B2TW8tt=o3W'TF@ot0h !hN1Vh)Kzn{ 4 7} zу2Ԩ^ܱt' ŬG֘c)ћ>冕,==E²al?ݛ$ _xz3Z(QewMJhSFNޟfFM3bd lIQEIg4";C}kq[jiѢV T/+++++++++++++++++++FNJ֬Yf͚5k֬Yf͚5k֬Yf͚5k֬Y,6r%[%PJNhH%b@5\f@(J:JnȶJnZmexuUB **jXlPUX%RUZ%RU"չ*j}UB`cW_5n]*Jj*J`[YYYYYYYYYYYYYYYYYYYYYYYYYY1J5vK`eeeeeeeeeePKmQVkũV6-Q,j;¥6z^5A̕. #áZı6jsD"|n5XAԴ@ ykuڐ9YmjQ!]7Cʩ cBNPW5Jfm!W 92]䏫!=Pw+%mR׾ޯM8\ (W8^9SscH $ 'J‘89ùO'+)_-ےeY-g;䕴~ywvoշ0ST+(g u*`( #%b12REcFP(Cx) I FhCx!m᜴RZ^S#:R0bR6kir fU&@H6=$ CCab[!*Cf)V"(<Aʖ.oE1L 9Z.gܤlW ZĚaZG/ jTvW߳ 2 $, )!$W@)uA5)uR1 Dm8V]x? .~?@7q.e1dMJkSD]-i[YʿRWUJۢifO eTӆ}QVDU'҇RG4pO \J1}liZT/md4Oi>N2ESv_MRKwҼJ˩"yzŅ[迯$zHr2Kk/R.$yI}R!룦l^RTEr1 4땛HVUr>}rIZ5Z%^vKĤ")܃à7B퍘%jf/^j9hMhۧH^]h wwwu9Ѝ7ĥ)iK R$K.ХD+[L]]l&ZM7-ҤѥA6.nUٶtԥeͺ j].ESr]""k&8˥u5l"RP.D-Tq!n!r4kl;yIXڭXrܪY2ԞAW6Oaq GJqRV*nI $ 'oHp(ڦ2kcr͔F\)i+m$+hUV(]VUZU%-"4,q(tҐ9|ʆӉ8xƨyuJ$> tjn8U[~kwZ1TGΖQN bpƨF&QQHT#G 뚡0l9ԌA1վlF%k#UmB(PzAPI"eŐ،r&ԓzZA+-kP"qCjIll+`@@wg-[eXH$iLd;q!RRA lq&/Iq8dXBi5[`Zf&HqzhxR-,?FWqZePj8µe:vNJctu̦:B_A:6U\MUzݯS1 c XpMJm>Vemqc5fhzM :66\S&ӗ2k\^@ IcYY1#w @ @ #xw3#M2of9?[\"ofث]..RmJ1WƷDqSeբUo-󢿩b~?_s^"O&|0h;gg? w4_@&.§"d7k>s;DNl'D`^"fDU?!.o۾ɽvզ!YW\\-%U%ֹ;E~`N8?w];=ñ^rΗ O4SRqq}AZ>~G'vL mwq!b#:o'^~zӷ;}yep]Cd~v@k`lB4qw|+Ӻ>5A ]Az+kre_/i7}!"s?@ჅF U"%s%5{Σ]/Nq?w;:}${E_V\h"9tL|:=o>lKv1퓯j{|9}-E-iʫ56@Jl1GuyxrKyUF4bF0~xtD z;Kn_+4_ʫ~w~[+qVLjTsMӅ!ZhH):y;:ǫbWjs] >3dTqQxܫ5k3Z~U糪tVo;>ZsjnM׺Ʌ7uEQmGn|F#QGx*uNAuw\}jU^yjSל5N͢3ŽTzQ?}:rF:k+\'> NUjӷj͵h.eEz7/ Hg~A}:k[y8$go]~JE_-#>RswDʐ84]=ͿnHk|Y}9wG+5]'^`  K{ To\s{.' :'u[u˙(>i{¿_Ś_n?C!"s?=#ZETaב-7ߵ~A~~k7n:}iHIkKvL좹+d9tjƂL9I7pEoeso<Ɵ;'ڮ9oO8]ͿL/la#EdN53r?*)%~K/??3ǟ^q.NY})U{X)?۾'OƝ&v@emI].[鏖++Oڊs쯭T(BW.7Daڕ!TvmcfǺu#%QG.D!bʲ RQ+.{{Ç.wE(.v 69 QFx*dFv9//"}H;H[H|׮5@stȆoo'ݻbw84_R'$Ꟛ#HQ׆?ő?ő?{ƟHE%Ucv 8?]ۘɃL{J-F7OM ak},<'N߅oV] lwHx<ͿdK]A߅;vofg| R!/oD@{~OOϸ~~'?#Gy䐃8)?y/#/N?ƭ?Ëf_3?1V{ {y=P=\NfezwzΙ]_r_=~oݷl_v+w+!?wtj wݺ{e74D\|B1_6 w,N4dCOhjtv&?2-##?S V AYm#0W=/XgȆH t?L0p[̳[H&5er31 R3'O>_wze/> xN͆of9YGqKz@?:~_4?Qhս}ȿ[̧F  7JTdCSI=OjgvO}g|?ǂVxIA&/1x98XR\v Oop_l&hOͯVx ƟhȆoߌ_]Ns]?@eCYlS[HHHn.?qW_w _4Hț;x$uL1ӘL2>nHpxxdD$ۈƗ4ߜD?:G3ϸ g۶08vvppno9>6_GF׹R_X ೩GI(/wMU;g?& {^OOO'.wkk3$Je($N)̎ѥm&vzw\X[K]}mimAuDOトz>yP߿thG9g^7 \>xջ6-߹#.8q(y9LPB4c^?VcZ0oi33anߎ?YRݖ^*q\GzDS/h]C{m<f8 id0FLcO91?Eό?$SZ>裏?NSO=ӦM{VB(Wt$hAK,O>Q瞛>}:%ܚs8?V7>Ѳv{<@ pĉgҖ.jpu~y? fΜݮ-qYSyhPc6^N+qcr㣫Dc>ƌ}}}~v'O>rf<@q=4<#qcrKMSO1磑_5kٳ_~eYFucF<sbz\r$Ln|thAÎ=? .yp>Ֆ1xɍzĝAKPDc>X$ O]-ixy^}c+T#3߯@K:ΏW^y|$yPo!gސt|tɳgg[e1ő|笅f}{ycsM}i3?>gVa_?o/ts;ot^M RI#ﶓ}{y?_'oٯ\|M~O7:7V\u 7R Yz r͝Ol)O?_ߞ5xٙ$Lti4Dz3n/‚ zѷ4ug̘Ƽ5?'O6,nH~QKPXs.\:6/ o/\.s׮'}̰ q8wyQHS7o<TS|ny{)}}(#T\$?#Gqxea;n[ŋȹ{ڵA1cPS2ga]Q7v0ONXS["W|r· ,E_a]Fg=MuVT# XT4~SR|>S΄C#jU Y9XTx$p?_|?_`7 U#*ÈE G7|?Fށc }m AAXB/|?_|dT?r-'kLXgk||A3d r П/@ П/?_|z۽ L ?A8wظϷ`~J@>=u(=⠿U@}}j HaA݋V>g߯sV-\y7N B!đ'1Ak?_|?_|?_|?_|?_|?_|?_|?_|?_|?_$S,^uT|Lf'D-4xgeRn]o࠿xNRƃL6ꯛiq9 Y7}27o,Χl'f|FϬB > a8b#E¨Dx4`#m Wc}vw4&fWSG=*P}6XIS(fםeiWp8<Gڕ!(KGQ8~?ȾN e| H`0 qqppno9>_pz"&=// 9hrT`L˝Ymj!"rs@E{^OOO\.-Ō쥗PEZkKk+T.WQEH>bŕo&Г8e#_QRo]⎍v}--BqN@OyOIAseVz`O;?xAosG~׮5$ $,,w脌F4#KJ-)9v_> v~q 2$AgƁf3_Q@/HHS 1Ycg7Fϣf4qP^()1Mo{p7^}!:"8 0y7P߿tH74s= el1J(ߍ ƟSc k'AF5@k*Vf'Cb̬dS?';n$=mwS%)Z5TH1E0GAݥ%5Yby v{ǁYs; B;3FS2fgNVa̵ "h7Z+`/ ֶY /-j-ۘ0\#= `z>Znv4 ۄBupG|y_0 M`Z#aduDl D?hD_^8|D=-v{]8̡gVK[Y tEKR A?SK獓9.O!Qrf QV%^SvR!IAM M.dKJdG1bPGl< "mцa ڤ>oz\+wjQC9R<-30㒡0 SmΔIƽ- D@&?_|'o @ П/2O?oQc?_|EfNgUm [yx {ƶ'ۨ^ľ*U<<1fa_PHMtOĤ|Hɗc}Mf'U_>F77_i?A=1&cKcF7П/@"#OiI П/@"Fwp-//QQtYG**pW/ktҝ'C o @ П/@*s&Wô1?_Km$VWUE8&G"m<IX,YRcjj: 䈈 o_U6$v{ gKkFIRISvTJʓcXuE)-*Hn4CÖb"A(Fdys6ہT\u_͖U7X|x?_$Sr|R2E~_CD9goA$޼<\Or@ П/@\lEg8-QpW;Yu7phoSKA(D+6noolx}}OwR$m͗aAs>_۰Q;sQ~Ť?ѰwW/OTCPEI9귣&WMQ^Rpј3> GFF_W3K@o68Lu;*DW;,֒:zO[njQ޲=|nXGGRS/iUё;-ۦ?OX?.5:1 ;7PLO П/@ П/@ П/@|14~-WJ<9]0X{7qIXOke>o>#e[qςI$yɵ7&X<Sp'G~<ɵG<"ڗҲ5g>& dԼ]~DR(by zY9Gp?x O72P(#% eǟ؟-<ߘ!sSοL~t b} _/ f3M8F=YN@ ~} . kȦE02/O `N aR _Dz9haރg[ /b Tof9?@ Ʋb Gr@ @ &ܿg9w @ @ @ L&J[qLDaýUΚ[~ w䣍;hWR0D877;v<*,3N ^>׷~OJU DH^yy"OD<v }CV<4m\~ /͝46jS-# n>P0O*Ԫ=)WHh'A'HB'(_8ER|q8?l QFW;zQPɻT @vtI# \AxХ[K4?9>4_su>ԋez>aau2/DW;脋|4 ËE@ @ '<Ƌ_Z[r)b}-g*JL?ߒl[o+w[SlX̃pcrE gJc}QKDXKUe1Z3*ы<DFҘ>fY)>UF)L?_O >fg2Mgo4$I"ʳsL?ZLQpcrٹBԜ3eR&OϿ-"@ rrt@ ,'@ Brr7@@ IcYY1#w @ @_;@ @ @ lEg8-QpoU6f/-h?)7e(ţT-l"'Nr{<;%(5 Kf*k K4Ƞ~SRفȦFμm"D<v }CV<1BtEc~$P('I9Qcp%H1s-t$~(t D_a$۔DRР\ۤBUm(Ɩ[L$j'C[F~˦I cT]R3##GDMMMti(֒:Oц#&mQf/Nru>ԋeY8E{L"_s5<#郭,I#.5:1 ;7@ @ @ @ @ _:mvaKlds7&s߹ K3s4ؾs֛Kҵl.zN3sYb.=3Y;ts`́902\Um Wb`Ֆ'\e1WY̛Ys rqǨ2űs`̥.5Yw ֈidٱ3wz̜is`́ ~s`́90s`e #sm/S)_)w7GzlwzNOwGQ] y)+ss[oʿ|EwWhqm&&i4ƖWl H$RW_[Z[ybuD?.⎿M7={<2)O{O_VTWJJbˑbJmD<AC$EIwmZsG;6.]q$v,_33_\[y`/4u<~vòZ2lAa}*k=~yj_I'nwddsO3<̧YW*eTeg}}*w&cp{x1?W@*r1? w=~un^ܕ'RAja~C[[ϞqnaSgL9FHhE ^o_uKWA$ (K}qic>Wq/- GPSWoL;zUKec8<<2BPpqPٔ{s?^I9޷/|kpp01@syygMLU.S\ɉ`@r<7o9g?S7n_~ό_i;gޱ-Qs̝HWTgSNϑ#]F@gSQWDܹǧvDuXÊa?#'/l58y֒Aej:„Qn|'} #]+~O˄3 7mީzN ϼad| !p??xpV 8]-߻j}n}/[.~}?291 ߽c߹dF/_q=F__kn4%C\/x~zus߱_~n=T~c/X؋$82xz^_K?5n:'n;#ldd$y2H#1q})(ܴ3E߹[6,>?n&k +6흶xӕ6V_9l>ηmi?⟾%~p ' B9MqK+.KBHkിuXw@xtpy+o| /8~77_|nfnw1~;NkZ-;7Gᩝ;_?Ӛ4/=}MOPp Œ]¬]#E#vfTn#UG|G,w 7N~iɳ)\FxjKLc5+D}%{ܿT_q40ũWG!G?7Z+޲㵿o7x?z}P7ٯWiK}c˟S]m8 'ի/_ڒ=FD?&{g쳺FsVW?ѩ/HﻋXIݭ>`􋡴߼gϢ1hsWU`e_T-ދ4qO! /?u\|xu0PE2KHkcnغ/[?444F i Zc>'giM!Kk ~??U? 0с2ǁʙ$N7Tק"rE&f(3Yz>&O)mR>QXp% * 8EkS!nJ#b2:JWِ,ㅈ>Rn>Y8Eۋ7m\T`GN)VIeKUgRe($ҢE1z sș x oIk_N21R^j8G>juuz#poofԿK}d^NμxyETz^䊡)4-e2I<@Lbݴ-dKiWALBAWrh˶LT SichqiRۅ.~%md9oq1IrPZ}tVKy]YRnZ'gt15"WFbr*{rwMs*hZ\,I9MCrwq8+͕߿E]!y__<~")Z#aRֶֶVhp`Eʰ1cq>L.oC#lhT(ul18,nV&NJZ&JRI\CWJ)ڨ.8Io6ViH+k5KEwJ (蔷٢$\x38 N'5TUcK:ٔ9q#duMw2y:SN8^JFg5Fz)'3%4lZKm1cPL6,il骋6M 7h5&ooohPQ/A &HH RS=V3&6/zUĒ 8 A 7q =ZHi١$-JiK j،ʤq&!iC4 HJa%iA:laʡ>NkwZjA PBlq&/I ME4mmm]!ش:Qˡ סuEX+R:&W*l_S tC[R_fvYg{5̪Fbk4ɩ2+k"ӗ2k\BI#;5P ?p<Õ?S_?`B3`6#ulgϴ}X<:\`Nvαz1꟔-0ϜFЛ#KpVK^'G*htmT2s_56\ ?Smʹ/n KjV.J',?y?H':D?HO4&S) e 3/hߑ |t{inӾ{t:3o8^Ն=ӷͱzvw9>] -N,쬸'4 OWQ)uL JGok BC=ËB!08[Lo:| _Wʠf)sAhЫLa`\>zJA8]R<{?_KAwS#BWV}ɶ{ߝ C[fg~v8AH넶+eBesJEl+oKK_>R[hXhKy^o4~K_^P#VpZrӜo|l߭?6ʩ&7}Bepf ]Y/{+}l'xy7N B!đ'1Q~T R^S?_|?_|?_|?_|?_|?_|?_|?_|%}}=ͽݵL П/Hޘ uzv˚‡jC{*;ʂێ l:G9Kk:`QG׶Gk{{+E񷗅**@9>.X#0R@0}LpW[ 9ØH#G|1XtE=UwGD18p8K|ѥIrqa#~ ׿/xML<氇с؀>yXuūTvE ?__!?& z` LtI_[:Yxx!Q'"vMtvW >E+ß >4Tx _=+w&:;+U#7dxPXw7m>:,~::hhsx]{dxBb_XG뉍|o>Da4#=0PϿfO] ʹzG[c&3gk?Ѳj_M+Qs 4x* >&*ơ??B.w],q@aD_k4`jqlU%TD$@TB tT1$Q.;ʕ(wwa(sKᮎR)PE¥(n;lRc*D)p -;۔tWvxte8>2+$arq*Zrlem8P&XJ<*SyDզ萈6;ZK:[ԿPSD`7Ѳ4˛dJ}R 8c$Fm${l{5l)st!&?rh p,_Al&!V!>O9ˆfK0La D#-%D2el݈ɱ|$JZ`<>##aD6 -8-L2K97N y)Os@ L2a/7n3ؖ2tHz8OaaJ?U0 I[FR%darcakB]-J wݛ0-lmtX)Lv >CА I2ŸCʦH !RvHo3) B%7h:Аb8R* Ƙf)V` ItvSyFjLA1UMZHO\1Gҕ}~ ,g5K{\҇#}r^9dIJ*-{SBLTdUn}O> ^+$^)/Id 9-+*fk2J%uRWi&ykzi.${ /ӆ1͕k"{UZ====J^MP1HTl+k]lj$mj/FF1."4Dҥ.bҤ:9]^F[C7nK[?M]TեN"nL.mcFu*Ƨ% .HHZp<.­uBrr).3yIXڭXrܪY=Rt䶹HrMm*SE6ӿ`ӿMDk[kk+YlmJh6JVRdkdmejlPJQR{\TZl_)ѦXPt!IƧ SwJtdlQ ggpNjƩ1Ɩt) rF*N')dd:uqt7*FŧSSSc#obH"Mcr2SB5*63djʲYɖm4p3JTP/HqS 5H8 lP"T(ɶR 60 xA ԫ$dȍYHjA-l`BJ5&mQE"Uħq8l8%ҿ-)V)d8MQ28]R-L"8]9iRQCm:ausSWHV;u菀0cF.*ib誎m IaH%\چױMKE-*Lڒ]Ojj-jU6F1j&:6\ G֨LYuLQeI}> lB6xz{k@՟of3q Ufg?^X33/:؉2w8kNX3|1lNm$wLIAm 8WF ϸo(?HLeVqC3+mi!;DDٜx55E2h]k6?|x]-"TۘC0fFX%@MX̒_;(~uxw8 qѱa< (?>*;NW:&4 Y5_2<` k5?š"7%9J9t7M7wT<cKM~οLxޣgSW[K}ǔKٛ?!v]׀!8tؔAo:d*f㮥{^,++G)y O?_Ĩe;**vq.kHCPEe!؁Bq-<?_|?_Xj*̜%5sVTL.e+bF9\eTsWWDɇ"H<4fl@>8Յrl)eѱ-FB?<<ѿKz[Q^0&4W)7Nʹ5;e4b%Dva%!XtGF_$5> ЁÚI)S&\AD-/<G&.>?yj?bRn8zIF!$՟tO&]|A>#S''VrPOkUu?F_ϗ5g'_|?_XsڑV=v-'S$_L/3ݗX'M~n+ @П#_fA=Q)] y O`SteӿBX2U 4s!o _ʤ ^|=G-9vNE◕o=렿%9"u哧o8[xyĜlw~p?/xY*?_p .;?_|?_|?_Ĩ?h1b?1F{`CKA|?_|Bp-oۙ 9 M-]]]欘%$րQ*1Sy `߰%/9$6Y$/ۖǷc B'4ɵ/᥹SqrUeL'aJYj?rcpKiMKQKBƨ+T c#Vi$.-?G Ors{*p$d){*[}H9n[kS d Lh^,H6sL*0 dŪ")__8e..[˨`RO%2? >(6d)"(*bp)WqO GyaMڦ-9yd+_K#O$gSE Ih{:QHd+O`L^w["19ȣxrsƉKb$4 'q~ibPf~r2NUu?3:eܨӖS%+fT?Aל}F>MBKqfU3H%Nيʌ-ݔd/tOGKEբ\tX"xU0bmIq1p6άGYyvY# OD'jN1̢6zP4jDžɣ'XƃCd"I]V j}䱈zŒ7('3tJϳqJ7Ɵ*哘+v@ @@ @ Lrr@ @ @ U<͐{;3Hƺft=w_(KfJ׎+)d[}1o>]aHy^q%f"~ 0Uk#(LgR0b)K\QIi]`pPr|JjjPz$As[~ΤB u~5'DNCӌS0B}ffSI*X:o-(ZNJdGX$ථLIlm7iI[od6vI&qwLv3Yı4h7M[Vd;uȖdG$?$˒,ɔ(_HI=ߗFhznƻodu'z#Sxjhns=}_cLکY⯬8]L#,*2V7eOj}yʻ~߈W] W{0[?nmc{n!G!8cO⯮zWİ4B : DN?x;jf)էX&zHX]~w!oLmX#[/dq8fڭHmu?   n1ZT   MۜwAAAAAAi}IDX÷Nۙп#ʅٹBqx?SFR%P|~#C;~'3݇@qRDYE?֥>7=0' X_zwӕj_|'9߂/ܶ/TI _B5ڽ|3?ke3]?`[ ?   ,Z~   MۜwAA#5Tݘ]+vRΟo^iNco?G֔!!\Db8DoRf16ur !!!!!\c7pV"tcmsC8kpٺx;C8C8C8kpM>ynY [2\2v µ\ڦ扎:[4׬I=wpp=}CsgnƷ.\?0FB#_=ǿhC+7+og{/Пx7wzهヽ/_nPz E+_#R/ş8wS_\>߆~?8ë^C_z3GS{>ػY ry|%^DRI&C-5LX̏粣⽝a]X9}ћ/m}3}N+t_v׃z鑁DWϩzϟ8[ |pikD}>8׼oOaOp@i?U;Ѻ Ȩ9Y8/8E3.AO@A79lDF~p;"8XzZS->8C~pi70jDZ-H`0_G`.0o-=gqSLlADQ֝mE1_v(;c?#`6HHI7"8hs-w!ۙ?x~>av og?.A3(]GQB)Sr8oo6U;EQ;CCIsA}#sJ:6c$"?M"c?]Uo]4+K߯ 6(riE[no\3Boq?Ap#`6HHan(ֿ>?B-~88~@V6.WoE`s?loO sAoi6S54$ׂ\dSOk"-pylSڇk4 ׂMo'ZH_Z6H`[c-տF4#9[_7Z~ /DQf]8_O~"(߼H|A ۹S+]w(߬h~M Qa?GNwZ5@ c?h;Q|}oѿ~G`BDQVy-4fZO@oӿ~G`Zjw֛C~s'{O/W/qw;ܙ僯ɒN[*MǦ -37.]0~rE} z:./:G)8v9,?oLϟwNCЉ+ҳLxCϮBzãaпw]7?ӿCs8`  ̿ o o8 o.pc.r3]M҅Tu9C ]xDʒdٓsN'[G5?y4͞/_/=J{ |o<|ᎇ{残w=~޽ə /,a07;=?WTʋ E•˗} o.]@v o.]@v o.]z>vA?a_ʾ_w~6n_vпatnjqXҿ݋oAK]@v o.]@v o.]@v_(LL' o.]@v o.]@v o.]@v o.]@v o.]@v+~Ri8=6=5TWF?]M҅T7.]@v o.]-1{߷;۶}kf稣b U}t{c;;kVר/{meze>tww~ ĆZ|x{5Wp s-rk[xFL`KPzA}֔n6nm9ӺtF/wmkdmG'岪[s4xEO{ϳ#*X˭m9<\hǍ%N1߳}Ƕm'WAnm јO z\[^_m{MgGC^2[s_v o.]@v o.]@h-IWK;}lw5PU7@{ {nq BJ*8e6C|:osKG' b*P~43Qok YjGUE#1y]G'֤+*wšq[M "M"v$q[ W)WXd8om9]@v o.]x/L&G& п v o.l꿱}6y}yG˝L]mj6[]?i슸u\6]jڭ}8} o _m}Wu'`' =u[ 6.]@v o.]S#ukgϟ?}Ժtm$=uw^O#Y:m ϱm  o.w[{7r3Íocw|Ӷ6L5Z}]v o@wޝ]l XITVOŮZbzׅD* x4D퇸m96?7tOT.nI$6+'h'iX ~}Pm}M+^{4٘Q*qx/Վ?vPҞ;~D=G>#kwO4q?#Ǿ j&#?.]@vۅGdn8M@&^?Ѣm9꨿D.]@v o.]@vѶ AAV}ּu o.]@Q XIM?k пǟ XOv֋A9V}ּu o.]@ov׿مWs\OSv o7? ͧsčoy o.]@v׿ пǟ׿? o.6?X/n@AA#si}AA"vkojiA}wgw [/=tsc6mpWﮋ1ұM>)h=aw*Igvzq:ŜtorVCy5KQ˧,wݕ[cף>q ;@tz7 p%mye__.q3Uӻ/LpP ןw#e3wHՔeݝ2?p_n=baI.=cgžS>?d,8kKR{]o5<ς簰IZ1GKG$,mg}+ӎ?굿{s~ǿe%h'k_=噗?{w:=x]f}0NS|s}~ছ??tefGw<n&>y3.w. 8CF=A<ɩ 2\vt@3l?+o;zs?-wF7p?wwˎzw@љoς+v!E鑁DW)2';t|!Lz.{S>G^O?==ܷ;߁ǟq֟>;vg;t1qWQԿ>z৯x'?~߿??p3&;Dw]9睂Vn&*j^zG?SOϯԯz_̟wgz?5yc(̼CcOog~W VR⯈(5@ o_#65/NI!r7w_Ll}9:oL/[Wf96@gѷk"}AA;v8̿ss3EQ&f??t៚&14B*eq5s{7}(} ֈos/_?( i5@ o_#\_gotޢ )ϼ`/ } 7OvURRԴOoEwg&*st  *7i?cIM#WWҺhe tdo |r۵ {fBy"cݿAE[1]"֘[kGWa?5LFNW>71]S9{> [7`W?-1Z{.WSDQ7gFkkomPDQkƷ|_A*mx97f6H`68_̆ytDNC 4ojlkl?ogB΄п [Aw~n=o܆6^Ro~q[1)ސ$ooH~صP[ܵ K]ǮEX49KX.N+beyyayypeeeFbOzAu0QNf/L^.]@vE3.8Wħ-aM6u;NnQ4}dz27&z׺ o.]@h1szhg0㏸S&f0oa8 o.]@vFX[ CcmE@vGOmQwJcmE]K(ϛt+mQwϜ~!ڊ]@v{~9X[ZŠ" @=_]2]5lsvN/9Wyl3s^g_s|61H,S#ii<Ԗӟ?<8~ˆsʹs6rz`d^h٥IJϝF]塶$d':V=/s^4XjKO31G d<ϑ^|Υgy- Oλg;Rv%gχwG A6<Ԗk<3JZfҳ'VׯCmI0zum՞Up|ygO/;tt4M<Ԗ9rIW_>ԳL\~d$5B\GϿx٥.rs9E"'+{ϬwXaP[L'JNyI2opD7}Gbwk!(e9+ N 2,oʲǜw3IrNfk3p$Dkƌ8a{c)룿2čSzԛ2-*Jx|pMf/ 4D9*M֡ acS w)IM%aKU+M r6r IOo@  =̰rكr0VJr;7mZ Y↺Nk jRֽB.|^ fr{ns{gٶힳy%wm qZ-'󴋻ipܶ'/D,Qʩ֞͜0 sΉ֐#`r%̮9nEU9#QU&Sy#}ݓ2»g3 ]d9mO=;YC~";'&n'dݞ3}3vY4Lhi*+}iʞdxlVQOp“Sպf2cd$5WVbH"# _=@ʟ㻿:RJn)Ťq;&ң'X>%OjF'Vd۵MaO:\FԋQV~l.Mn9*ёL#"P+Jc%Qc' \pFR)wʬ4mn7HSg8т=SJ(ŒTTwM驧4۔/T*+\2Fkx)<<<<44.0-K,1ۆCk ;$›qrH!s'*Y iS1]~De‰ LHkH$U%OԜU-)XVLj lyG} NfN*'>LIJLJ6 EY6(w1AJq۔8M݅.[A|PǕޙWƙ\UA=νetJQՃ-oaITd8Rp a@o> <@,<5r5@.zs@0LE|3-{ mhfEH*^^[}4K'osyJY$C.sA4rI݆lRrRgNc> ̹K*7yAҳXm 󦟼[).s&e%7n}ned`e03`?,>s2Wj%̌L7ݚեRX:[3hҴ&ϸy$cSr3ش +7ӔuGZ Z߷;lO<;.S\^ +%뾢5XM|qC݉ZÎWu`5Fo%x]XgE++VI׎Yfq.w授sc=fȅYtt TD=3W QxyYv+p<1L4 U9z=J3Zsdb;"[O>O7p)8»a"+bbkhF "hveCX--^ԃii,jJ"2Z\R|-.K"EMSXT,nŒڬpeaBlU2%Fza͕[XV* ^?UFhFZS*oLN˾QjE(QH-b-| uܔ=ROӖ8 16zͅGz:|C'S||D gg˳QvtYVGlh6eJ.Y 2+MWWY9p}e1#I-+-k1vc^-)\)UrtZ:ыJYb%a+-7bMbJے 7#M<yFgF DQ ^f@ȡ=KF_4}+(-tkZ5tWQpSZ}\E՛mGжbQZ"Xg*i-]቏2VRؕCWKj-A O Zmm ^a/* !eݻ6 "+ׂI?<[*Xmʉ}oj9C^޴ҿnfs9!Y*Rպ渭YVDVlNU{G<)#} {u3 E6#JQͺVb,ψ]<4[^V*RVDβFDثxܹ0+e]0wRxzZ׌Qf٬,)1f!f$B@ VNGGك-U*-JLF\K47<eAGUW=-z2iO]zU>JʓOZ*56Qyɩ0i.Y+1S7 l7)jUɍ<5ܐbTwMh4۔/T*+\2FkxA Qx`hhXǐBoRVz1s:CF-< nV*hHC!#*e־ '/%RNRjNL-%E/&NpOI ax_n-dन&xʉ()S2@jI9LGVbri)l⢝N(7:G*^ⲏJGƌf:qc`(A͖$xZ2B)Hp?ŀ|[o3倧FEB{hVo4z|Bi oO'ϐiV\pooo`0z>,j+Z3 'R094B1L^Ea۟;_  ` 0aҾqCfW0}dS s[ ͍zn"m}9AAܹàEZ@A\v 2tѱ_Qgbo,ث8!Xi2*/dsbbrbLzB_q)Zi9}4[3ic= Rvkz'V4BY|rTke燓 &(+k$=nrꛞuQ3_- h}WJ@In{DmZ &_PwְUtةJp6:fU5\VYqHYkwI[mn& Gpgap#|ΑpZRZ+Tg <>QPd(?\G-v9xQ5Qp>ZvaxzjV\֓vϓ {@ nHvu\,RĢHkGKn=+vah8fvzQƪfȬ("E\2|-.K"EMdwˮjS&S3peZeME*ݬͲRY2ZE3MҟTxcuZ- FVd(QH-*9Nƣ üsy%s~os\xݭs`a7Z8}g/WMt.Гjfu˳ec[.d}XzrY-]ѮbŹӟ:.!Y-tke1vc,פʑԯ G15c@@3y*KV [nĚ&m%o Gl!x3* wQjrCc(i#&r(iyjJ`FKEB+69\ZiDiaO[&a[mXV8i'2+_]!{wvAdZ!9P |]UX/IÜi"e r4[^+eBL,ǝg3=+e]0wRxzZ׌Qf٬,)1f!f$B@3bb4%&%V䕣(_minJLu]*&kU Zy<IKV%#*O<9&٥5QHE3DT@9JrJo)oϔi&MJқS)55"|Ru,_Q\2FkxA4>iu%Voc>Ls; )!s?(*Y iS1]~DߗP( e2I ` ZJ ^Lj l]2C ޗp 8)ꒉ+$UdR+!3I$x-UOʁde:"vR:R%Ue2!Wc Sx0N0g eLz0q~*M%νetJUfzz\tГ#Y)?D—֦uU_bW3 hFf5`ՀDZǧ-{T<!WcWj"KY*Zl%~>}"#lC#dPôo A!}X}0   6JMޘ! &1i_M{hڂW Z/~+ ScdJr|~v:mX||vh;r/xffv:m.*& mvNdܩSGmv`OL  mv`'i;7L8m>iN? \REZ  MsA  6YHy{|=Z!ݔzGƻ]JxҬ? f'\ sYw魔RNO>&GϹ\2X bV3&Ux@NNFC׆&YQ9- m)qVs\t9^ 5z*=f9.yx-@1r5L^z(GrـUSxDf)ۤ(JYb$lkUږ/e+h̨3܁JG%}Cc(i#&r(iyf4%'J2OH V0]&iVv |A[YžVGjf[mXV8i'2+˻ $Zv\NȇQA]rfCG+`vq[=7-2ٜ랔>='iRWtǨp6QdՃԹ,kÌFꀮҗfIGfeMd w)<Y=UkFx(3HFYqe!f$2"'>L8`Q JSGYmѴnJJ7lRDGSEiZV#,y}*MOn7H!m} |wRC|.ȿ:TuJVf됷F94#*e־4BGZxN$ Ew!ؚ5-f.iM`5.HBREN O&2Dr[2T#b'#YRU&25Vm`\!{A "kZBǵ733sys/qه12pH'na\%afE=A9RK_ZYOQ7S``¿/bWw2qib@ !7=<fOEH*Ut= 2+ZA |i&}}!}kx m={}} 0   6JMސ\7oLl7a}ټfƹлZW Zd0%RLfxbbh|<9:ڿyhަ8d͛8ѣ\= ʤ($$1WwOLN1'%~J 7?WTʋ E•˗ٽVGQeOO!%( G!A=r)sBaHPhxD,ŚO1 H $POcQ$YԩX%pgμXpDFBmp{SXD=yi]Ȯ(X"\;XpzDE4"y1=DI}ñ$X5L枉=3G{&$n?oQSdϬjY j s# s6q_#k؈np̍wQʮҙLNn"tTr\mL)#' 3F嫔xESr°pMqZۜ] n,zMrn.TczKpuLu 5 QczpAwk g|z_ٮ1\vkجQ}Pcz}pe¿Ƿo^_1\;Vcz}UpUF}}_5Lg"!|7DC/p$kݹ_]ᗓ="_q󯤺zE1]bP#wb%i[G݅--w{?F+io;Z[k};~㶯э7׾~sw{Q`_p]ͷ?&{1N:o;~v5W$r6M3;>Bl>L?y)ͬo/v_fM߿#Oϛh71}ƹQ7W}&8܆̛8K{ j7zELgwQͯ<WH  }Wt_n{3.W: [߻7| _x/y>n'X?'ϹO]m7GOOd dm1 _.µ^L?{:<%6xʹ߿=cd>Cgng7::H|7^~g5۷|C7.]S=}{ ypyit`t?Gυ;c"۟џ7|_­ysq~{3 W|Hy'gx~_ǟ y7߿.鈉}m/'/?p8n?n ߿?&m2tr#<x`e_B7*'n-Ke Ȳl"A@Q2,do-{BYm'=7IZB6˛i ]0f+ng5emwemE M5nn& T;Ar:OÞb- ge!e"U}{˙oϿo?qMǢ.{9_>'UG734~}gի&zZj6 [/y0iav+kqߓ7NÌ]c~PtL25!}cax<O'Si x/yx^Wku? >O -6x @C4MطaC_GL|2ZVc Z6-hڃtb{.+'>ޠ >? +q  ` F` 9 <L$0LS`~3L0 ~+y70, ";X `xOjւu`=6M`3m`;v?p#(8 N)pg9΃ \ep\ Ѓk @(; D( b@, $$ R@*H d, ru @>(] T5m ;j;]npuA ꁇ#Qx<O3Y/Ke x^oMx!h&)4G-A+1AA :Π  zOg7A?@0 CW p0h0| 4- x0Ld0L߃i`:3,# ?_` |,`1Xe ? X ց`6` `  {^ApZ 8N?/8 ip?8.p\p  t@`  @4 ă@2H @6A."`쬡$v6jZ.p7 : x(x <O,xσ%2x ^7@&x 4A|#xx֠ h ځt@gt@w3}_` !+a`8FQ`4 ߁q`<&I`240f`f/W0o`>XEw,K2`X V` zlflvv=`/ 8-GQp 'S48΂s@. A:@0PAQ ĀXAHI TAY  |P Ajۀ jwp;wp/!PG18x< Og9P<^/*x  -6x @C4M@S!h@ ZVc Z6-hڃtAtA@o~ | `  ` F` h7[0|Ɓ`&` tfYG ~_0`Xb,,`%XV5/ll >` `8 G1p~_pN 8 p\".+*A \!BA DhbA $dRAH dl\A(E@Da8n/v b4ƇwZxvAqluf5GkN}-yiH5#I\T/j1cN-vnfXK`!d! ѫ0Mūl6lmr*dnl˪t\ҷw[i/i'xTgYP2t7o5e7I}me[l*|-N?Z_ږ§*cο*QOzZ7OjiL&ɕaDďR>pK$d#L&fg2LV)d2Y|&deLv^'Rb2SsRT*Vi9CR\x)d8nZ:izL~KL&;âV`tmkN>~1˻7s^ Y.~dLHz_^1_  5?@o8{UwnWtZ/3> Q F'F;qaqᑗ“\x)d5ϫx869%,6>(<KL&;y^%H-8.%%">A -%]xM3|yԲ/$Oyhv ;ῠ}7ȊLHGD9^A!F=G7%d*w`E{dUrz:fG#ǐ^0wwɇt#RِJE{dڔW0U;ӛ#.-Z]J!fGR /i-JF2*1ZdLY\<(~\͙o4;F-RtjLv^J̄yjſ]#9OF06˻[0a ш䐨2|kyPR;c|l|y:xZKL&;y^ff)=-+W2 r"ш2|{r[,{-ãHE1uH06Rj< -_$5ݏLv^JN7F kWp{4ʊpFhO;ʾEdŧ&9^\F1iR>kWٙR1NHM /3v<3~f-g2Y*l8+''9-#:>|v)[83|y_K̊ON-#]x)dkax_.(W3q\뉸R>k'?-R t8$?^g2yڰhIݮ jQ2h c\x)d9ChDʮǷ/3F uZ*+ʳ8./3L&+Ӕd2LS>d2ML&ʴy>S 2LVKSI$UZ>/ݰL&Ɏr=L&)d2Y|&deL&ig2LV)d2Y|&de,d2Y|޷| >pdrU`g*ELV7(IN!g |֔ݔ$3Y|&RdJQ>U`g*ELV)I3Y|&RdJQ>U`g*ELV)I3Yg}7I |&U`g*ELV)I3Y|&RdJQ>U`g*ELV)I3Y|&RdJQ>U`g*ELVw7e+)I3Y|&RdICO-y< ^K' Hx22|v|;yq&geGE榄^O ^U`'SF]ަ?Q~%8zI3Yv|^3unuݫ;=keD/eV0< ha-3J >d 8؊.fH&)MdIypAݑ=:ߺ[oXtBY-y Rzzx[#<=oF,|&Nϛ/|LuG|}Ѕߨ?1?+~YhE{2OޑF,Oc 4k|V(*y-7wCWB;~Hg-M >CViBo |v.Q>U`峍>w*n efd'1qX[FF+ 0gF6 9o$3YDA,gù3CNr'֐Û '/cq),}c( xyxP(g |Q;M5.tAnfnfrjl &T/g |g,|]?md yzK /I|&Jgwɏ4.*sdI |&Jg| LL(ɪF!as&[~ 6Ar5Q>U`峍glQ>U`3dQ>U`峍gL*[dXil3lQ>U`峍gL*[dؔϏ+%mT?˫!I?dUuGVRKuX8"Ud+-m?eQ$&T,l yzK6)mgNJ+-mT?%T,Znf)&g |fɩsXti> 7PY|&JgU϶Yg TZQ|&JJ|KfEז-f.DLV6|ͮW%xI3YVZ>Wjg1r-g |QTT(*?"g ,^ [w(L*[dXiLIv^))'9F&Jg.|&JgL(*FQgR٢|&JgL(*Fe#ƟrY$*D|&J*,o1gbJ[\ >FZQ>U`峍`g&e>{zk&PP'3YVZ>WMg~u*~y>3AZ*f:vS[䳻S+RY+t˻Zcuh)/\|&J*-/.zgV:.b$3YVZ>ۨr =5ҥŴRQdXi\\bꁖ$9(*FUFg?IdXiLIv3YVZ>(L*[dXiLIv3YVZ>Hv3YVZ>Sg]DLV6?3Yݔz\)LIv3YVZ>(*&u4Vg|ΚV(*فy;H(ZYɢ|&JgeϞ[\ò,_)DLṼW~)+gg3YVZ>(Ff<[Y(K*PdXiX2whGk3Zm!tB+-mTe.C4t|&Jg=)EdXil*3IM|&JgLBMLKJI IJ7\7:_ L*[dXiLIv3YVZ>Hv3YVZ>Sg]DLV6?3YVZ>Sg]DLV6"HwܼݬT׸\ n(_dXi\ee?KWfA*_dXil*XY~ײ3fJk~팢|&J窩j]*Srv 0cҸI|&JgUϖ, 23NI-9/|&J*lyU7Z>EbELV6gȯBR(* ?K*3YVZ>(L*[dXiLIv3YVZ>(L*[dXiLIv3YVZ>Hv3YVB>+بfˊ;<__t.(55alac6k[?g$g3Yc>_#v:DLVψb홀m6=~xMEgmM{E*\h&4  ^;kwF2[g&zYM'ɋgɋ I?߶d֢ HI 3Yo>EoU W|8_F>טowV>gG7Q'tF -Åbbʆ4[ʲWl|}cse`&^I(j>[`~xpc.g l|NNOOLMIJNH 8sEWZ>Y[;} ?-f Dw#',_>kL{vy5$j Ri[11訢DLViYYF <-86f}|m 0P)O- ؄GǬ5P%島Tв3:f-Y|&笜8;;;!5-8,sKCx@/\aF09KspAӮ7[,9 F3kgliRj>c)_{kbDLV&dd甖wǯه%eψHz;OXx])37U`-Kb ɜ1i_a󣺋GǙ"W0(*؂S ֞mS !ZB!Nn6u8A" 5%=-&%54)%vG[2yO"|&,C~>gk>\DdXig.6 MƘA"TdXg|&?H3Yv.<[$xeN G#|&c eƙz=)xGDLV]zH^; ڝ6_dG#|&^3Uݱ{utw~ڼ,"Fse%3TՓfQ>U`W?o%\Q#{tڿuߠ?>?3v+W&EJťak RY]DLV]Ĉ>qXwt]hY~,9-zz-BlQ>U`-K[BLVwZϛ@>'Z=,9ңT-`q,J3YvSq[UXXT_0/ 7 ' ;鏉,=|46ߐWq-_.|&*?T< Ξ9r|[Co.N8r[@rK R"/h|&9o-v r3s3ScCWO0<=^bELV]g,|]?md˥*NS8+_d{(M1袂˅|pV(* as&[~ [ 9(*I."g jgsTEDLV+)+"|&."g jr,s[ʨgjU,g jֲ3׈jU,g j 29-H\|&*?Wvg>X/by*ggZ"A*l9lYYTjDLVU*R[P_y{kxVYØA2OoosZ5gO4, 4(ᅚvL.]\Z Z. fU&g l^Z?Sg3Y [i|Vl?(*p%bE]Dd$3Yv3EDLV]L]DdTEDLV]L]Dd,AfşGƝTpDLV]\Z2K şiF+uH3 I6oTeg̀9Е ZoO ہ|&jj]*Srv 0cҸRELV]\ϖ, 23NI-9/]|&*?TlyU7Z>EReZgȯBR(*+RYFpV(*Z?(* +Z"|&&(*S`WQUH%g |^_t.(55alac69zHJ3Y|ţ;v-h/czI;o / N{-l۷NR(*ψb홀m6=~xMEgmM{E*\h&4  ^;kwF2[ ۬ 55wf i^Y*,=$CjJQ>U`%Aa.p3N5۝Ͼّ#Mz cBpe+͖BZj54" RrF-o,ln){y lrRU+q抮|fXw&~[ F ^)—Bx1G Nb#WQ~AkY LdX!紬,vtϖeo}p>> U`rrLԴన~>|*+/  Bf s_r,iqpx|ĘjG-7̊6Ė ;R7gpBHLKJN7\+_P_XhrAA^AAFvNi\}{|}XRx]׽ׅ12scOZ/XRag3MAU#~ZKnSPW(*BϷ..'s7Ǥ})z迆~Ϗ. B goV Lk5 L롘]@Q>U`|vD =fgϧdG B Br of>bl9-ELV7U`W?*^[w~ѽ:?Cۃl ޻Vom^F^KYTI5wGU^dg{TwDwo7ό]:4ZLi)MOq2Yr߽Ĉ>qXwt]hY~|xn%hO IA|~\g2і9Sp???$泖kωVߐ"'E,Ԡ$YhT|&)Ygjܩ-*,,*/̿^]QZaKBZt˻ZYSK;J$%57gù3CNr'֐Û '\ǬC/W6h^|tTQ>,?[ySwh ]xag䳧F䷘֮MR(IJjY~(ɖKtU,w=Y|{N ?4o_rLI4 ƚPv=Cs[gQ>ji>]T9+z, YVE]h%|քzs9?S>;lgՑYf]\ICMO/{|PZ rl>+VL쌲e9]x-eRiD-"u.?[U9?S>;l}J4OHK'ݕXSYkq~V7DrlU Y,8?x1""."ȫ/?"faqq 3p)+IAEg*Ggy&F J}/o?pw.h:,wb >CEELRlU,PHl!wa˻0G̚!OD!¬%sdr>1(f2?[3U|(,)"gEg*Gg,aΉgyͰ@>HB\|&)YQj>#u7R ^ יi jʓLϖ*Gt~2OaL&'~MP>+MdXєruҴ+#)+[dYr|vFQ>U`?jggg3Yvs9DRZ>;l|&}gG?%$ɱ\5`6|%WER(IJϯ/:oms皀o1S$d9Q|giT{٤R7B…O'Wی=l6z['R$%ˉψb홀m6=~xMEgmM{E*\h&4  ^;kwF2[ 3y%snF y eKԖ~8Rif/lU|v@ pPX\pLesivg}v}qBm2\h*&lJWh1ҵؐ¼]r!o|i,v'߽HUEY~E4)^˫tnRY?4gzJRWtm [ԘĈЈ3Wt3ź0al0*MJLzNjY=h@plAy>kh6h-;B3X泼E.iAeKS{>c?z/-_<嗝koLK>ًV4_|l)MϷNb7*@glY7R )~e 33aB"61k6$/6p;R6Z̏n %rT,ի~Ko4ezl/ch=iMZ[>i/TOϕ-?g iaQ|TV^^W? *򅅹/9Œlar8"lAy?"7FX^f\P~RU, nH%%i->Y-l7x*I/(/,4 #;|>ؽ M>~>t,)k.~FDyMۙ?#@-_ꘖ147oA-=zAU#ݵ !U\ϫ<8̇#^VeK>ö|?-ϕ-?R$o >?(1xtV@RχYyy6fM-3?>9i,o'wTq9Q|?Clk϶qq)i-!G'n7n+bIe|lM-q0/0|4+ϥ}+>r]G[2yX;;yZB!lχLӔ.}JYѵKr.=jg.6 MƘArI%?H\$%5$3Ir3q&]$%YϕWƙ"qeQ>gq|ve)0d8RY~)՞K=[#3Gyi/ˉҊ}ET 53C稔T}L.U_Y[\}K:TYj=[f5K+lQ>U`s՗q]KkݖiYlUuo˥W}gP5+åDjŻ̖ VF)-k,]Z/bb5x1N'T?[4#*pnGqcZ{G9\ώ~JH ҭvg%qQϪ3Iɪ|3.|&)Yg*Lr(IJ3|&)YN&*([Y~q.)gKt}X/kI..?H-jCR\yY>FۇްB[m"Ս1+  H߆PU.<[$xeN*H.[g1e)`y$/Fa[o f࿨|V4m^fy1yyi)ד\/SIŶY`sHlQ2YM a,0nlW˪_JY'PO-|^=e$naNmK _2nHU5tk6e{>3ۇZ^^Lar{u6gF\GEwْԗvP>;!9ZU爍ZCb>ky>ovhg4|v))44ʪ|;E\E r3 rR 8r)g銁eR6{Fc Tl.,c7,7HbDφsg gO 9?O!7d'{OnTij)Fl9{+r-bӬlАBDLR2wΛ*kE]箟6JRY,>ELR2.QcEy<ƒvΙl#$ELRr!$-IL&] ,3 XTڧ|&a|.I$#OS>T%g \|&”dg3L&Ɣd2LS>d2ML&43L&+Ӕd2LS>d2ML&  mdt[߂y[V/y03_ +hb]xW_iy|>D|T| C8 ַڑEgMR2͍Gdrڊlem?o͌nbrpL- j(:};nsq9ѕEГ%fX,m` !%΃p PMt?FV ʶ_!䛸ԛ]Ų>e=YvS4&2Nŷ|ةXJ;?Nt,3mZp(]05,]UMV/)L1re>Vz$F-V7s,UC,i\81&)YS&󔶗ΦuOh^v}wL&-:kW_u+{c 6?X-uzomwvͧ;k >mO6){fg)39hb>ϥ]|`Y\çeuk}^UdrE8ػ |v9n{6ڠ{^^K#nU3QFV?{vy><)\~cՈRt܀k&|%:jpDܸx &ZZMw - (o·ѯ~SG]w_nM"uy>K~ |`L[ Ͽ5{hvg7_m\,{uz/'B))[<AXkyn%Lj\viL½O}14]0]~mjl[;o3jH~̬qDnmC^lOqW̘xtә"A6r4pA?Sr?KJ,\Ƅ/kiuO-"=oطbm7?Y}v $Ϳ,}3^;5Q]Gb`tMD?~/{Wc L&;ҽKnbp=npsQRZ|pL1}oԎ.]ѵ]Nψbsx s$zsy>ùlc Z={XV[wm#7]-gs+fř| XITp49ݘhknK9WNmEޞݴп| |)m܄OjfY\~f_%8%[-dk5;y>GBGOLpZ7xoڤoâ;!1Ƽ?VjycCb|yw&3ueS>뛈miDc3>۩:OfKM,k h-ڳ?3S|kD&{LwfJr'9kV+ w\no̅C;( ׭]>ts]&=Ýpq+B?sz6YgrجE\Nӿ8i|&-kvy3"V<)̓9C_$C;22ӈn20Oe=5юkGWi7fw|>B1;s gOv֯Q%d>IўiLF=L3]33.6| hJrƉM+Br>4xn|X[r\Oޞ3MZJ8GHMny'OG AH;D=X &⺵Xf6-?@n 2;[]ٲCV vXy,wL&WX:]~uTL1F"+h<9я~]c8n,8| oB۞ϗzc>FL-0;zD_x6LШ5o {#7% \g|Ksz7ߤ'խ--|+(VވU7M^g;3Yb }kwsKؒ$kyK`L xJfQ|mYYqG{Vޞ!4OYrǂ07/%m ]jV=D86,܊ٓ2Gu29ޤD^cb0$^'Ox}DO극{b>Hd3ϓ.g}㶺qeؗsb8N(x;v=8Lgwuc{'w3? {귉VM$^k#Ɋp'YbQ;$IQ4]GHܰw4\gچoRЗ]zmR>#O>%9Qϖgx..dX=T.|&d5|<2fo$pLZQ1V"#^b/z끌bx|g|>=]Ώ`15.v0gH^W!L&K瞚؟'*eʢ^Iq}uLב1GfHǗlЗ{wKi|MVW?f]Sv;SԍS7v8wM?x߹ack~b&A, Lƿd%; Y6-SoL]% )=1?' ?cObB\4GFje{^l[bf<Ϸ|⿨t0ƾ%,gdg|Sx P8oMu3%kˆYASΟ;.7tzHov }7΋B85y3|-Tsv]5|FK,7o)r8?!h#:AN7!^ў>"Ȧn;~{8Fۇ>Rv)Y0YgL[泡|N$KYmK2A&/#Ftg7Dt~Rn*Fn@8AqZ߆mx8[g)ӿ*YV'c܉JwLAj޵#Da܁2_X>Ҽی|Ft|,giêsgQhd 9K _T-{ƯJ\ט@\#73C>g 休54 f:|_7 SJ%%$ɷnJ5ǝU-w`uGWM"է|f6C EK|7S27))yk":="E0/l`L&]CnϚi(ˣU2u Gւ3z?6FDÈh,3/(EMD/TJv>WxnK3<)V3C+ҾF<ۖCCgJΎ6Y'-6xubree[9FVMor ңRx n5#m+܇#wŇڊWD8r f]wh]CPkމބ;oc.p7 : x(x <O,xσ%2x ^7@&x 4A|#xx֠ h ځt@gt@w3}_` !+a`8FQ`4 ߁q`<&I`2[=݈*Uc҄l0 L?`&~?g s<`,KR r'XVU`5Xk:l&l[6;v` 8@ |p '8 ΀.K2@5 p"A1 āxAH) t2A9:y B1c@uP@MP 6{}~P<x<Ix<ρyx^Wku?ho;]x|F1hA3|ZOmA;t z|z>/_K0 `0|P0 #H0 c@߂;0D0 LST= 0?l3 怹`  B%`)X`9+*`X6` `von~pa8 ?p gYp%p\WA @ @8 D @@sh<@K | (T5m ;j;]npuA ꁇ#Qx<O3Y/Ke x^oMx!h&)4G-A+1AA :Π  zOg7A?@0 CW p0h0| 4- x0Ld0L߃i`:3,# ?_` |,`1Xe ? X ց`6` `  {^ApZ 8N?/8 ip?8.p\p  t@`  @4 ă@2H @6A." ?jۀ jؐ+hT]HݒpcR= BVC0 j1s n3?D?0D||u|%MnZ/v{SgMLDq_tGNJw/+k{Z06&w e]اo E<>aĉ@3ϟ3k)3^xdgg/*4EhPh&DT6ZzÓ_}XZ-MOOWxe^7a1sbYj`68#j_}]XciJ|7]lM۳SCnoQGdx`F76zlO L*R$q~&N$߂O}RfϹ؂xGw{Fms=V9=1i |(Y|anoL(=> Si|RZ['Q,Qx4b\J** K@ U0%$kggg'~?oͷ3Lf85xR5b볪Zn BZgIcI[%˘yUTѾ~}^;@Pʷ 6HiTœ+sN:؄a(7Pert'Z'p{ed0&2![ߪ%wKߕb{u^R7b<嬅v^W̔ƙG)}tX97FXݷY)lf:1[ƔsK;| x c#_d2^}td<$YpdzqT‚WF0a6%$&EZ, Bʦ$U?-|/e|3ZHooY*-cFi@K|:0Lb@{v&= ,TO#}'t$$ȥ_!+ql\ oXa .!ℊ<=/!|Ce=^Nyߋ)%=X,cZGi|”Y I?s]rRݶN)Lƍz>xGU0~.ٌII-=&rKgus bT4 h n_WZݦvk4U@Oj9lo BBmuKE7G—)c!nO-ڬ] 3oD0! T7G"~WxV'~ꥵ 2MlG(~wI| äXa|b &Zc5x "MBN?&rgP=ACV||"S%dS*Pւ.bՀA(xYM e p涪fwI͌oLϤO;ԃǺב׽߻m=[ؑ5rۦI7DBIzj^JZZ5S=NSɌ̱5%Xt6Z*ۦi6?B4d4^Sb t#O%XfCx7cY_~ؼӑXcǪ9 ׫ TT[;3x݈e[C^w}cnvhtKB_~X;8ʱi,_8Vn9VgI}'-n=ض]o3HȃmBAuMg폥 3G^rlLl=A6;ZRg93#Ӏ#C׿o }hfU+,t>"w;sls`-|oˤǗuq^Ռ:?8^K[DJZO׸}9} k.׭[(KJmmYS|Iד]{&:vyk} ^?.ѿxD~ʜkxj|K|s|S|lfJ?uk[5z\ca<6Rkkjj**+=ec#{->98o3T~ntlGxwqk?Kʌ.M}yǜGϏ>Þ{g` 3|8 7A57=ؿe Ĩ{DלkvNEEfڳ퓝+wd~Dؾ][V|&y[}?޷m>?ヨw_j9Oߙf|ZmKQ*=נ"mt&({Nwo?żr>9mz:i,nHe}k9|˿6ʼn`/bt3p"@3m ª[0NDWD]ɀO­ѿm뿅[E­ѿm뿅[~?,ޗ =e2nUgiQAA4mp"]6ʟ7~~+WSz_<k:V ϩ>H:%" k'}bnUW O*[MєٿmcVE:Ri/S^ voVE~MJ ݼ%fˇIdmP-ݪHUyeo'-8XQ%[UQ85}iXUQ4mphKosӶ*oGIWC]J[*P]&ݖkxxTmJ wU%kWjKKEWy`nbF軚\kO`*P jTYJ;?36ď* ٙGk4TQPxv~TA<;'꿝??./zt6tכ W0߃Lޕ$xtwY!o?NtG t`bT߮.<a~woѵ7U@|a)b3S&zC+XP $.bl❲Zy5}V7Kۭ5{}^)7VEK@[AWF0?_bܖ1׸""ߵ~O {>F>#̗>Jh/MVOXL] ۗ|Tb侹؟M]?QE6)'e0S} O„Meɷ7K|UY>O- d&ɷs) ܴKjH-E,!BެTPwr8fnYOG;/ڙ$or;cPc m? 1<̗Z"7H9jC C<܀l s@1fBފrfN1gggggggggg3o_Rzg9bM{?1R߅ǬңR?1t엯22]_Qd.ntъu ~ _/*HF*)ρ٦ HcFN}?<1d}p%yLoq*ʘuR-XrL_}7lBs+66666666666666666666sc%q KyxKz̴# S:!ݥ%cKFؑ߆01FňjXR@TKsW[/X20$;MhS;l7=N`0;0B -#€l7F] ַd{mmmm"ߕ"<})%pisaZJ0/|_X{%.C\xt& lR`UxpODjJ6mIjV {au(}FL[ǥSJ*OّvQz]2Z)=ZͩZP<ʶT6'S^ _]we/n:TUJO[z۟[=U?;۟4ն+:}}_8_ztCIϨnG#O7ggggp  0??1+g~1 EIQ,dGKUt(4i--{ :">^J:D߿-]FHe]MAY2ll4.SU+Y O ^ҍߔ:ݼ.uwrpAW` -^w7ĿBN-XIDeKQoy-Xoc0-+y\n]X],K|i>Wwst_4Nok߲GXђ.OvpWUc 666@a~tallll)3%,4jxCv3=RIrH2e| o3HkvΒ^Re8S iw;Ј5ZԢt7Z֝ +?/߽$.L]d!M Ŀ> 7@'LŮ^[%^xEJӹFЧvZN?Sm-v7eo-TȪn>u:߀t26D%hȲx@wloQL NE_X܅"[rWD9-jOD?6666 (JƖ[΍)=BGA % AAzh2~G+7,\k0傧)g=E\=?,J~/ [q1 Č :TtD#=f9i'U!!%qbsI=&z&4pk;׻j[dB.0p$~xb+('[xO)Í-. .r[e0J8#t9W}ǝ.VkU,l@ !6dosoK&+_Uv<惋\I}3}P3l~UG/ex>-DNKGJyxtqТS k _O(/!?Qn="MەGET7~|. fo=Ǫ[\ᒪ7.ףe=9ts+y||J3iË&R8+`ˋZoޏDLΟXjwU+xev 3˞Z䤒y'-uOIG)@W:ns7e]aOIXbU>}<>xꈢI&Jqn(ZWrڿEEC?3}d+W6iڻ̼3IC T8Ƃ-jR^}\]~p?}?oE4C勦??e$ȹp|"'+F^vph~S4qЯռ%)* PxOᗸGK>lX)=k]i!dk3?B k~%Q?eQR{DKT=בI=vOh0`킂! M.<|ϏX!b)*%3ǔcGcm+ ur?Asr?_^"uE{f<|{ɌdwV_ύ%\<2'sy$QY"|a~EOVQC ~.GGvw3YƜ~AbyuM~[4qWs?tԯɗT %S%P?C*D򧿚Z"x;3ܑ'+ݣowe/).ˢE~Vx_nGTD/ZEEnhս^g|aͿ7_àt~ugp'|'켄[sݯ~~z|C&G#?xч{MV]U_>ng^vJƥ.O~]v(׼~o=BԒ5=FU9I~-߅ 2gI;1& ]Ok*v(TWSeA3 v > XB^ɯ-Y*gO€(  a¥xǹWq_d>36~~~ =m 4lx6%Eu8c1~?Ɓq8c1~?Ɓq8c ~7۷ܷq~~V0ߡ|$q8c1~?Ɓq8c1 ~wr?~ca?~o/;>$h8c1~?Ɓq8]񃿿m8c1~?ƁXüAخ/???~LɁ'_qԪ9'?{ʹ]|S?}r ʨԯ_<Rs m~Ƨ|#|͔ N2+N#-wr-y,uoJwwRڪJOEyqYiA^`,pl'Ƿmg|u*_q?_v7_:;=E¼cΣG_aρ۳?z6lxs3/ĻodDJ7CR&ү_+ygaXڳ퓝+wd~Dؾ][V|&y[}?޷m>?ヨw_j9OߙX[Y,-]Vգy3fEm:y Yr|b}9qwx6=va-Mê[˶/x6tlȁ~dr vVrgDv%rRc/!v!O;koJ2%ngn_96tdd9}XűjkNEC.l7]G<ϭ!vڱm;YF3X4FTSlwZՉ SǢU߱WM;f9>±r:K['?7?UfUMZf,xnزˑzlv׵lhhSf/A7P~3G!6窭8Lz|Y4h?8^K[DJZi ߭%Ӂ[ly֜ "S C p+7{J]^Ͽubw_sy){?S5+ =Ч}y|yrosB߶Ήo6ot۲?oc}|?6G?HZ9_?wտ&MN- CJQ- C}۷xG?,Pr6)(اo{ki7̃=sB) \tӿx|>ߚoacbɮ=;c&c-c6>c;GT)ht?[oo9v;7;r?no9vo2v rd|˱GEG1;GT)ht?"6";7?MWΊudBy(rNfM:TͿ:vo2o_݁lW};oI$@M&Oykձ8ogdb8og?cqܿj?sqܿ7Xs_MΏe{cD u5555yՕǂg5g9lllllllllllllllllllllllllllllC{kk=Օhllllllllllllllc o RqŊ???mmmmmmmmmmoEMuQuenU?????????????????????????????5eUU9e?????????????????????????????PU?Krrsz|fl1 ???v~~~ 'ӹ뉟w~~V={???~~~ '??cO~~Ǟ={???~~';~~~O???cO~~Ǟ=~rs/ae}Z<:'XWlÙ+wJ2uungn_96tdd9}XűjkNEC9+=%%{ƥe n;HחMfsk뮯;vl-N"pQo 1cƶ*_~l/+58X;8ʱi,_8Vn9VgI}'gT~REUG'˱=uc.GNgg2Y\ג:;N̪aɊ+A;7Y~3G!6窭8Lz|YX3ypݽַԵxZk[ -'z|)yrd'7S筘:/]bn餐:IO,?w?c&LMee澴0ٵO}z֬M"_҆Qb&NoU`&o*hm+Te'RXc&`_ hmonovXV5vo/x>מosUnƎ܏ٖ[6uNU>|%fG0=M]Ɉ;w^VV6W`lYiR3^DXJ݈x赪 2v5^kZtOnd,+Q5Z Dt5[nW5ۋoG6hg#! lllllllll#?V1 3A0?Vg+x<۟Sx?g?3 <?3 <6H\'S/|QSn9vҍG;>s9#&cP͒iH3v'ܹo #wwLi"B5-S/s_`1+6WWy**ʏW2e=1gggggggggggggggggggggg⿲U^zs#ggggggggggggggggggggggggggggg⿼g"|=;aIhcj?Gͷg} 5xR3.ڏ ֖ZR+]cyfWG~Pښ2M;pE[UYVl'6ofy~ħ74zkK ycǭ k_SޚՏe"˫]*Iy>\;KO-7^^)۵UU"?LjF6N}&M(X2P.Q5~b~HWUozM Fx,/ڏʊ"Oaxm%Jf$/ڏ隚#?-,ϑp 6L[» ڇ,ڏ=vʋח55ViY^ՃzkOԞhVWjY^G~~&~LhȹtGq}k$cnZWw{ԏ~5&dO$oS3WBcN8./ȿspӹK!]}?z>+AxYOb2p ]&:A7D:?!g]&)/GWkt;uC}Ν.\8|}woyC~I姑ӹ+N~eΙ) WJt&w^iYU\Mj묓afu%J>KR C5=_SNqL0KXN>7ɪe۩Ԟ?t·􃒞r2U币q~k.3_st.ǩt2!$<C8I;VL⍢:eiU%<9dw\?jz~i ӡ8~fqkӿRnjEmd|l,:=GJ?k<.Z/h?r꣗ӹ⼜t~o8Sȸ'g]I}`+Q+t,MH SzƓէq3~ʜ7N_EGH^J\_}GO1ao5kIo=\DQ%:̽@7~!q:4G?IYʼ{IM^sxX,}9K_8'_5W ` _O6FF?̟+r` #Ϣ'S_;gCoKw'S[SCGIsK+ak%>jAmŢ DcN)0x. SJFHVJtrtw4y6sV@m/w[- n 3z+-/i *4( > Ii LT_.aҁ q(2`3D8p:j|~{€gxyevѨϬMOQ#TOV{XZ\^/1N 1(   060@0 E0 I0J0Oh+'0T `hx  Slide 1Jon-Eric SteinbomerDavid C. Morrill226Microsoft PowerPoint@Ø- @0Xs@rߨ GSg  )'    """)))UUUMMMBBB999|PP3f333f3333f3ffffff3f̙3ff333f333333333f33333333f33f3ff3f3f3f3333f33̙33333f333333f3333f3ffffff3f33ff3f3f3f3fff3ffffffffff3ffff̙fff3fffff3fff333f3f3ff3ff33f̙̙3̙ff̙̙̙3f̙3f333f3333f3ffffff3f̙3f3f3f333f3333f3ffffff3f̙3f3ffffffffff!___www4'A x(xKʦ """)))UUUMMMBBB999|PP3f3333f333ff3fffff3f3f̙f3333f3333333333f3333333f3f33ff3f3f3f3333f3333333f3̙33333f333ff3ffffff3f33f3ff3f3f3ffff3fffffffff3fffffff3f̙ffff3ff333f3ff33fff33f3ff̙3f3f3333f333ff3fffff̙̙3̙f̙̙̙3f̙3f3f3333f333ff3fffff3f3f̙3ffffffffff!___wwwCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCmCmCmCmmmmmmmmmmmmmmmmmmmmmmmmmmmmmCmCmCmCmCCCmCCCCCCCmCCCmCmCmCmCmCmmmC?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~                           ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~                            ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~                            ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~                            ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~                            ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b d e f g h i j k l m n o p q r s t u v w x y z { | } ~  Root EntrydO)ߨ Picturesȷ Current UserPSummaryInformation(c TPowerPoint Document(DocumentSummaryInformation8 L0R0S0T0V0PW0X0[0]0a0g0i0k0m0q04t06|07`/ 0DArialUnicode MShh 0DArial Unicode MSh 0"@ .  @n?" dd@  @@`` x|    !"#$%&'()*+,-./0@12345678:<=>?@ABDEFGHIJK  OPQRS   XYZ\^_`bdefikmoqrstvwx yz{  ~eFxR$؛ Rz 8ݎb$= y]vƈ@b$\:1r5Fb$DUMi$rNy$h? b$6pl;P8M;';Lb$pjDb5xS"sb$fY1hVC.ߖb$i%/!ɷ!!b$(6<0`:z"b$.Q cyy( b$}Eu@+ M3b$FS?ƊGTb$heia*mb$ˆGDƣ#+Eb$hȕ=֔e**0qb$|&y#zsHb$̕T;c&á!4b$ViӤkO}_5Vb$er.`J3b$虲NÛ,]b"Y?b$ŷ\XH({;c_NRab$xu\~*yE!:l.>b$:6$9J.Z@b$m+eu-,m%H3Gn<$R$~I)hn?36 0e0e    ̙ A@ A5% 8c8c     ?1 d0u0@Ty2 NP'p<'pA)BCD|E||s " 0e@        @ABC DEEFGHIJK5%LMNOPQRSTUWYZ[ \]^_ `abN E5%  N E5%  N F   5%    !"?N@ABC DEFFGHIJK5%LMNOPQRSTUWYZ[ \]^_ `abp̙@8ʚ;ʚ;g4\d\d' 04ppp@ <4dddd4w 0h <4KdKd4x 0h(0___PPT10 f___PPT9H@?(?  %O  =0ik4What We re Going To Cover& `The MVC programming model Creating Traits UI Views Creating Traits UI Handlers Defining Editors 4GUI Design 101: The Model, View, Controller ApproachThe Traits UI supports, and is based on, the MVC design pattern. The MVC pattern defines a UI in terms of three components: Models Views Controllers&||GUI Design 101: ModelsA model is the data and behavior that represents (i.e. models) some aspect of a particular problem domain. For example: A well log contains measurements that model a particular physical property of a lithological column. Models do not have an inherent visual representation.$v ?GUI Design 101: ViewsA view is the visual representation of some aspects of a model. For example: A line plot can be used as a view of a well log model. It s possible, and common, for a model to have more than one view (e.g. a plot and spreadsheet view of a well log model). GUI Design 101: ControllersA controller defines behavior that mediates and controls the flow of information between the user, the view and the model. Having a controller helps prevent the model from becoming cluttered with view specific details and code.  Defining a ModeljDefining a model using Traits is easy& Any object with traits is a model that can be used with the Traits UI. The object s traits define the data and events that the model provides. Defining a ViewA Traits UI defines an MVC view using View objects. A View object defines the general characteristics of a particular user interface view. A View also contains content which describes the individual items displayed in the view. A View does not reference a model directly. In general, a View is a reusable object that can be used to create multiple, simultaneous views for different model object instances.Z The Kinds of ViewstThere are seven basic types of views supported by the Traits UI: Modal Live Livemodal Nonmodal Wizard Panel Subpanel*AZ4ZA4>L  Modal Views&  Suspend the application until the user dismisses them. Are displayed in a separate dialog window. Always make a copy of the model, interact with the copy, then update the original model from the copy when the user clicks OK. If the user cancels, no changes are made to the original model. Live Views& Allow the user to continue working with other parts of the application (they are not modal). Are always displayed in a separate window. Interact directly with the specified model. Changes made to the model in a view are immediately seen by other parts of the application.Z  Livemodal Views&  QAre a cross between live and modal views. Suspend the application until the user dismisses them (i.e. they are modal). Always appear in a separate window. Do not make copies of the model. Changes made to the model by the view are immediately seen by other parts of the application (even though the user cannot interact with those parts).RZR Nonmodal Views& Are the inverse of livemodal views& Allow the user to continue working with other parts of the application (they are not modal). Are always displayed in a separate window. Always make a copy of the model, interact with the copy, then update the original model from the copy when the user clicks OK. If the user cancels, no changes are made to the original model.kk O Wizard Views& Organize their contents into a series of  wizard pages which the user must process sequentially. Suspend the application until the user dismisses them (i.e. they are modal). Are displayed in a separate window. Operate directly on the model.Panel Views& Are displayed as part of a containing window or panel. Allow a non-Traits UI window to intermix Traits UI and non-Traits UI elements together (e.g. within a wx.Frame window). Can contain the normal buttons that the other View kinds allow. Operate directly on the model.68-iSubpanel Views& Are nearly identical to panel views. The only difference is that a subpanel view never displays any of the standard Traits UI buttons, even if the View object specifies them.6Q=CdjVET: View Editing Tool VET is a tool for building Traits user interfaces. We ll be using it today to interactively illustrate many of the Traits UI features&  View ButtonsdViews (except for subpanel) support a standard set of optional buttons: OK: Allows the user to close a view after having successfully edited the model. Cancel: Allows the user to close a view, discarding any changes made to the model. Undo/Redo: Allows the user to undo or redo any or all changes made to the model. Revert: Allows a user to undo and discard all changes made to the model without closing the View window. Apply: Allows the user to apply all changes made to a copy of the model to the original model without closing the View window. Help: Allows the user to display View specific help information.HZZ.NM HV m KLControlling a View Window s AppearanceA View defines several traits that can be used to control the appearance of a window: width, height: Window size. It can be: an absolute pixel value (e.g. width = 400 means width is 400 pixels) a fraction of the screen size (e.g. width = 0.5 means 0.5 * screen width) x, y: Window position. It can be: an absolute pixel value (e.g. x = 50 means left edge is 50 pixels from the left edge of the display, and x= -50 means the right edge is 50 pixels from the right edge of the display) a fraction of the screen size (e.g. x = 0.1 means the left edge is at 0.1 * screen width, and x = -0.1 means the right edge is 0.1 * screen width from the right edge of the display).VP'PP"PmPP m  u\Controlling a View Window s Appearance (cont.)Additional View traits that affect the window s appearance are: title: Specifies the contents of the window s title bar. resizable: If False (the default), the window has a fixed size. If True, the window will have a sizing border. @ 14 0(8Specifying a View s ContentsA View has three primary types of content: The actual editors (i.e. widgets) that appear in the view, specified using Item, Group and Include objects. A menu bar, specified using Menu, Action and Separator objects. A tool bar, specified using Action and Separator objects. It can also have various optional buttons (e.g. Undo, OK, Cancel) specified using the buttons trait on the View itself.4+ZZxZ%K& &  V The Item ObjectAn Item defines a single editor or control that appears in a view. In some cases, an Item corresponds to a single object trait to be edited. In other cases, an Item represents a non-editable, visual element in the view, such as a separator line, or extra space between fields. The type of Item is determined by the value of its traits, which can be divided up into several categories& nZNG}\8Specifying an Item s Content<name: A string that specifies the name of the trait the Item will edit. If empty, the Item defines a label only (using the label trait). If =   (a blank), the Item simply inserts extra space into the view. If =  _ , the Item inserts a separator line into the view. If =  nn , the Item inserts nn pixels of space into the view. object: A string that specifies the name of the view context object the name trait belongs to. Unless you are editing multiple objects in a single View, this is typically left to its default value of  object .6IZZZ4 !":9  / G;,\Controlling an Item s Presentation and Editingeditor: The editor (factory) used to edit the contents of the trait. If not specified, the editor will be obtained from the trait itself. format_str: A string containing standard Python formatting sequences (e.g.  %5d ) that can be used in conjunction with most text-based trait editors to format the trait value for editing. format_func: An alternative to format_str that specifies a callable that can be used with most text-based trait editors to format the trait value for editing.Z Ek  \>   v@Controlling an Item s Appearancelabel: A string specifying the label to display next to the editor. The default is to use the trait name to automatically define the label (e.g. a trait name of employee_name becomes a label of Employee name). style: A string specifying the style of editor to use. The possible values are: simple: A property sheet style editor, fits on a single line custom: A custom editor that usually presents a more elaborate UI that may require a larger amount of screen real estate. text: A single line text editor (i.e. the user must always type in a value) readonly: A non-editable (i.e. display only) editor. The default is to use the style specified by the containing Group or View.&#Z8ZKZ  L%tHi, xxvPControlling an Item s Appearance (cont.)Cwidth/height: An integer value (default: -1) specifying the desired width/height of an item. If the value is positive, max( value, minimum_needed ) is used. If the value is < -1, abs( value ) is used, even if it is less than what the item says it needs. A value of -1 means use the size requested by the item itself. resizable: A boolean (default False) specifying whether the item benefits from extra space (e.g. lists, tables, trees, multi-line text editors). padding: An integer value (default 0) specifying the amount of extra padding that should be added around an item. ^ZZZ R!  nl,VControlling an Item s Visibility and Statusdefined_when: A Python expression evaluated when the UI for a View is created. If the value of the expression is true, the item is included in the UI; otherwise the item is omitted. visible_when: A Python expression evaluated when the UI for a View is created, and also whenever any trait belonging to any object in the UI s context is changed. If the value of the expression is true, the editor for the item is visible; otherwise the editor is hidden. enabled_when: A Python expression evaluated when the UI for a View is created, and also whenever any trait belonging to any object in the UI s context is changed. If the value of the expression is true, the editor for the item is enabled; otherwise the editor is disabled. Note: These expressions are useful for relatively simple cases. For more complex cases, a Handler subclass should be used.P{P 2t 2My 2M{V6   %Providing User Assistance for an Itemtooltip: A string specifying information that should be displayed as a tooltip whenever the mouse pointer is positioned over the item s editor. The default is that no tooltip is displayed. help: A string specifying a complete help description of the item. This description is used when the Help button is clicked to automatically synthesize a complete help page for the UI.bv@oaP6@YThe Group Object{The Group object is used to organize Item or other Group objects visually and logically. Groups can be nested to any depth.H| D 8Specifying a Group s ContentfThe contents of a group are specified as any number of positional arguments to the Group constructor, or by assigning a list of values to the group s content trait. Each item added to a group can be an: Item Group Include The contents of the group are laid out in the same order they are added to the group.pZZVZS>.VNOrganizing a View s Layout using Groupsorientation: A string specifying the layout orientation used by the group. The possible values are: vertical: The contents of the group are laid out in a single column. This is the default. horizontal: The contents of the group are laid out in a single row. layout: A string specifying the layout method used by the group. The possible values are: normal: The contents of the group are laid out normally, with no special handling. This is the default. split: Similar to normal, but splitter bars are inserted between group items to allow the user to adjust the space devoted to each item. Note: the position of the splitter bars can be made a user preference item by assigning a value to the group s id trait. tabbed: Each item contained in the group is displayed on its own separate notebook page. More complex layouts are accomplished by appropriate nesting of groups.4dPPZPPHP YR :Tb qkSH!@Controlling a Group s Appearance$show_labels: A boolean (default: True) specifying whether or not labels should be displayed next to each group item. show_left: A boolean (default: True) specifying whether labels, if shown, should be displayed to the left (True) or right (False) of the group s items. show_borders: A boolean (default: False) specifying whether or not a border should be drawn ar      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz|}~ound the contents of the group. label: A string specifying a label used to describe the entire group. If the value is the empty string (the default), no label is displayed. Otherwise. if show_borders is True, the label is displayed as part of the border drawn around the contents of the group. If show_borders is False, the label is displayed as a fancy text label if style is  custom , or a simple text label if it is not.P P u W Z j _   b swPControlling a Group s Appearance (cont.)style: A string specifying the default style to use for each item in the group. As with an Item, the possible values are: simple, custom, text, readonly. The group s style value is only used for items contained in the group that do not explicitly specify their own style value. padding: An integer value (default: 0) in the range from 0 to 15, specifying the amount of extra padding to insert between each group item as well as around the outside of the group. selected: A boolean (default: False) specifying whether the group should be the selected notebook page when the containing View is displayed. Obviously, this only applies when the group represents a page within a notebook, and only one group at most within the notebook should have a True value. PV~X ,A"VControlling a Group s Visibility and Statusdefined_when: A Python expression evaluated when the UI for a View is created. If the value of the expression is True, the group and its contents are included in the UI. Otherwise the group and its contents are omitted. visible_when: A Python expression evaluated when the UI for a View is created, and also whenever any trait belonging to any object in the UI s context is changed. If the value of the expression is True, the group and its contents are visible. Otherwise they are hidden.PZZZkZ 2"g 2M"E$  xfControlling a Group s Visibility and Status (cont.)enabled_when: A Python expression evaluated when the UI for a View is created, and also whenever any trait belonging to any object in the UI s context is changed. If the value of the expression is True, the group and all editors for items contained in the group are enabled Otherwise the group and all contained editors are disabled. Note that this can be used to control a user s progress through a wizard View, by enabling and disabling the groups defining each wizard page. These expressions are useful for relatively simple cases. For more complex cases, a Handler subclass should be used. Z;ZvZZ 2M"BU K#%Providing User Assistance for a Grouphelp: A string (default   ) specifying a user-oriented description of the group s contents. This information is used to automatically create a help page for the containing View when the Help button is clicked. The help information for the group will be combined with the information provided by the help traits of the group s content items.n^ m&zSpecial Group SubtypesHGroup: A group of horizontally laid out items VGroup: A group of vertically laid out items HSplit: A group of horizontally split items VSplit: A group of vertically split items Tabbed: A group of tabbed notebook itemsd)'&$#H)'&M$The Include ObjectInclude objects are references to other view elements, namely Items and Groups. Include objects allow for factoring views into smaller pieces that are dynamically included when a user interface is constructed from a View. This allows for several interesting capabilities, including: Parameterized views  Visual inheritanceZ)Z7L-?)% How Include Objects are Handled When a user interface is being constructed from a View, any imbedded Include objects are logically replaced by the Item or Group object they refer to. For example: The process is recursive, and will continue until no Include objects remain in the resulting View. PPeP2'^!&!!Creating Implicit Include ObjectsA class View containing Group or Item objects with non-default id traits is automatically refactored into an equivalent View using Include objects. For example:P 7Z ='"!Using Include Objects EffectivelyThere are several possible uses for Include objects. One example is creating  parameterized views. For example, the traits TableFilter class contains the following view: This allows TableFilter subclasses to define a new version of the filter_view Group containing their custom content without having to redefine the main TableFilter view. ZZ$R 3 + E P} 3 + K (#*View Objects as Part of a Class DefinitionJView elements, like View, Group and Item objects, can be created and used in any context, such as module level variables or dynamically created within methods or functions. However, there are some additional semantics that apply when they are created statically as part of a class definition& J&Z)$/Defining Views, Groups and Items within a ClassViews elements created within a class definition have semantics similar to methods. In particular: They are inherited by subclasses They can be overridden by subclasses This leads to a feature referred to as  visual inheritance & 6cF=cF=*%( Visual InheritanceJust like methods can be overridden in subclasses to customize behavior without rewriting an entire class, so to can view elements be overridden. For example:P.)( Visual Inheritance +&The trait_view Method$ The trait_view method allows you to get or set view element related information on an object. For example: obj.trait_view() returns the default View associated with obj. obj.trait_view(  my_view ) returns the view element named my_view (or none if my_view is not defined). obj.trait_view(  my_group , Group(  a ,  b ) ) defines a Group with the name my_group. This group can either be retrieved using trait_view or as the view element referred to by an Include object imbedded within a View.XlZZ ^  / + * ^,# 5+ Q,'The trait_views Method$  #The trait_views method can be used to return the list of names of some or all view elements associated with a class. For example: obj.trait_views() returns the names of all View objects associated with obj. obj_trait_views( Group ) returns the names of all Group objects associated with obj. sb s9AlEventsnIn the context of the Traits UI and user interface creation, an event is something that happens while a user is interacting with a user interface. More specifically, events include: Button clicks. Menu selections. Window/Dialogs being opened or closed. Changes made to a field or value by the user. Changes made to a field or value by some other part of the program.@@qmEvent HandlersOAn event handler is a method or function that is called whenever a specific event occurs (e.g. the OK button being pressed). Proper event handling is the key to writing flexible and powerful user interfaces. In a traits UI, event handlers can either be written: As methods on the model. As methods on a special object called a Handler.XJ AnThe Handler ClassnIn the MVC programming model, a Handler class instance is a controller. If you are using the VET tool, it automatically builds a Handler for you. The main purpose of a Handler subclass is: To handle events common to every traits UI view. To handle events specific to a particular model and view. To help keep model code separate from user interface specific details.  ; o The Handler Class: Common EventsJThe events (and methods) common to every Handler subclass are: init ( info ): Handle view initialization close (info, is_ok ): Handle a user request to close a dialog or window. closed ( info, is_ok ): Handles a dialog or window being closed. setattr ( info, object, name, value ): Handles a request to change a model trait value.~? ) 5+%3>vF-Qp'The Handler Class: View Specific EventsEvent handlers specific to a particular View fall into the following categories: Trait change handlers. Menu and toolbar action handlers.8Q9(%9q(The Handler Class: Trait Change HandlersA trait change handler is called for each model trait when a view is initialized or when the trait changes value. A trait change handler is optional. If one is not defined, its corresponding event is ignored. A handler always has the following method signature: object_trait_changed ( info ) where: object: The name of the context object containing the trait. trait: The name of the trait. info: A UIInfo object containing information about the current state of the user interface.ZZZZ7N,tNr/The Handler Class: Menu/Toolbar Action HandlerskMenu and toolbar action handlers are not optional. They are explicitly referenced by Action objects specified in a View. The signature for an action handler is always: method_name( info ) where: method_name: The method name specified in the corresponding Action object. info: A UIInfo object containing information about the current state of the user interface.ZZZZ%.1   1 N>  HNsThe UIInfo ObjecthA UIInfo object is automatically created whenever a View is displayed. The UIInfo object is passed on every call to a Handler method (referred to as the info argument). The UIInfo object contains all the View specific information defined by the View. It is basically a namespace containing: Each context object, referenced using its context name. Each trait editor, referenced using its Item name or id. The traits UI created UI object, referenced using the name  ui . It is your responsibility to ensure that context objects and editors don t use duplicate names.v#ZZ`Z,%%  `$`PC\ct The UI ObjectZA UI object is also created automatically each time a traits UI View is displayed. The UI object contains all the traits UI information common to every View. The UI object is returned as the result of a call to the edit_traits, configure_traits or ui method (on a View object). Although the UI object contains lots of information, the parts of most interest to a traits UI developer are: result: A boolean value indicating the result of a modal dialog (i.e. True = user clicked OK; False = user clicked Cancel). dispose(): A method that can be used to close the dialog or window under program control.^ZZ<@3 _@ QP -(The Traits UI Object Model 2-What Editors DoEditors are the heart of the traits UI. Editors create a UI toolkit specific user interface for displaying and entering a specific type of data (e.g. floats, colors, fonts, file names, & ) Every trait has a default editor associated with it. However, the default editor can be overridden either in the trait definition or in a view Item definition.*\K 3.What Editors DoOEditors and traits are loosely coupled: the editor only ensures that the type of data it understands is entered, and relies on the associated trait to actually validate the data entered. In some cases, the data allowed by the editor is a subset of the data allowed by the trait, so no user errors can occur. In other cases, the editor allows a superset of the data allowed by the trait, and catches exceptions thrown by the trait when invalid values are entered. The editor then provides feedback to the user to indicate that the entered value is not valid (e.g. the entry field turns red). PZP4/Editors and Editor FactoriesWhat we call an editor is in fact an editor factory (but editor is a less intimidating term). An editor factory can be thought of as a template for creating the real editors when needed (i.e. when a View is displayed). Because they are templates, the same editor factory object can often be re-used in multiple views, or even multiple times within the same view. When a View is displayed, the editor factory for each Item in the View is called to create an editor for that Item.BP50The Basic Editor StylesEditor factories can create any one of four different editor styles, based on the value of the corresponding Item s  style trait. The four editor styles are: simple: Fits on a single line. Can be used to create Visual Basic style property sheets. custom: Provides the richest user experience, and can use as much screen real estate as necessary. text: Fits on a single line, and is always a text entry field. readonly: Displays the current value of a trait, but does not allow the user to edit it.PTPm,S];QQ71The Basic Editor Styles82The Standard Trait EditorsThe Traits UI package comes with a large set of predefined editor factories, and an open architecture that allows for creating new ones as needed. The current set of predefined editor factories are: 93The Standard Trait EditorsIn this presentation we ll focus on six of the predefined editor factories& Three that are simple, yet very useful: ButtonEditor CustomEditor EnumEditor And three that are extremely useful, but require more setup to use properly: InstanceEditor TableEditor TreeEditor^tP%PMP&Pt%M&tt   N  :4The ButtonEditor Editor Factory The  buttons trait of a View object allows you to define standard and custom buttons along the bottom edge of a window or dialog. However, there may be other cases where it would be useful to define buttons at other points in a view. This is where the ButtonEditor comes in handy. Traits defines a Button trait, which is an Event trait combined with a ButtonEditor. It is a parameterized type whose argument is the label you want to appear on the button in a view. Z " f, X f?9The ButtonEditor Editor Factory  For example:  A:The ButtonEditor Editor Factory There are several ways to handle the button being clicked. Here s one that treats  spell check as a model function:uZuB;The ButtonEditor Editor Factory xHere s another that treats it as a view/controller function:=Z=;5The CustomEditor Editor Factory :While the Traits UI can handle most user interface requirements, occasionally there are cases where it is useful to imbed a non-traits widget in the middle of a traits View. One solution is to write a new traits EditorFactory subclass that creates the needed widget. However, in many  one of cases it may be faster and easier to simply use a CustomEditor to imbed the  foreign control into a particular View. Z, x 9C<The CustomEditor Editor Factory Using a CustomEditor requires specifying a callable function plus any additional arguments the function may require. The signature for the function must be:,P  D=The CustomEditor Editor Factory EThe following is an example of using a CustomEditor to create a view:,FP' ' F>The CustomEditor Editor Factory Which results in the following display& Note that in practice, more code is required than this, since among other things, event handlers to handle input from the control and set the appropriate trait value also need to be set up.sYThe EnumEditor Editor Factory Let s start with a trivial example of using an EnumEditor: Fruit = Enum(  apple ,  pear ,  peach ) Unsurprisingly, the EnumEditor is the default editor for the Enum trait, and will automatically yield the following results when used in a traits UI:r;Z)ZZ/ ) UP/  1 UuZThe EnumEditor Editor Factory 4Now, let s make the example a little more  real world & We re doing an interactive menu, and fruit is a trait in an Order object that represents the diner s choice from among the fruit currently on hand. Current stock is maintained in a separate Stock class instance that has a fruits trait that lists the fruit currently available. The diner should only be able to choose a fruit that is currently available. nP]}v[The EnumEditor Editor Factory We can still use the EnumEditor to create the UI, but we ll have to provide more information to help it tie things together. In this case, we ll focus on three of the EnumEditor traits that are of interest for this example: values: The values to enumerate (can be a list, tuple, dict, or a CTrait or TraitHandler than is mapped). name: Extended trait name of the trait containing the enumeration data. The values and name traits provide complementary means of accomplishing the same task: providing the set of enumeration values independently of the trait being edited. In this case, we ll use the name trait because we have access to a Stock object whose fruits trait contains the enumeration of available fruit. dPP8PP  /<  D#4t  _ w\The EnumEditor Editor Factory 8The resulting Order view would then look something like:J9Z &<6!The InstanceEditor Editor Factory;The following type of trait declaration occurs frequently: manager = Instance( Employee ) Amazingly enough, the InstanceEditor is designed to edit these types of traits. There are multiple usage scenarios for editing this type of trait though: The instance is fixed, but the user needs to edit the contents of the instance. The user needs to select from a fixed or varying set of instances, but does not need to modify the contents of the instance once selected. The user needs to select or create an instance, and then be able to edit the contents of the selected instance. The InstanceEditor is designed to handle all of these scenarios, along with several variations on how the editing should be performed. However, in order to do this, the InstanceEditor requires a more complex definition than do most other trait editors.;PPPKPP;vKF>pFG?!The InstanceEditor Editor FactoryLet s start with the easiest case: The user only needs to edit the contents of the current instance object. In this case, there are two choices: Allow the user to edit the object contents in a separate pop-up dialog. Edit the contents of the instance object  in-line , as if it were part of the main object being edited.R$I% $I%H@!The InstanceEditor Editor FactorynFor case 1, use the  simple editor style and specify some or all of the following traits: label: The label on the button that displays the pop-up editor dialog. It defaults to the trait name. view: The View object or name to display in the pop-up editor dialog. It defaults to the default View for the instance object. kind: How the pop-up editor should be displayed (e.g.  modal ). It defaults to the value specified on the view itself. [][aS3<KA!The InstanceEditor Editor Factory For example:  =7!The InstanceEditor Editor FactoryFor case 2, use the  custom editor style and ignore the label trait:.FZ9NC!The InstanceEditor Editor Factory6Now let s move on to the next case: The user needs to select from a fixed or varying set of instances, but does not need to modify the contents of the instance once selected. Within this case there are several important sub-cases: The user must select from a known set of existing instances. The set may change over time. The user must select from several different types (i.e. classes) of objects, which are only created once the user selects them. The user must select from an unknown set of existing instances (e.g. by drag and drop). t$PP8P4PP$84OD!The InstanceEditor Editor FactoryThe InstanceEditor supports all of these sub-cases, and in fact allows any combination of them to be used together in the same editor. It does this by allowing you to specify one or more InstanceChoiceItem subclasses as part of the InstanceEditor definition. There are three predefined InstanceChoiceItem subclasses, each handling one of the three previously described sub-cases: InstanceChoice: Describes a single instance object the user can select. Note: If an instance has a suitable name trait, the instance can be used instead of an InstanceChoice object. InstanceFactoryChoice: Describes a  factory (e.g. a class) which can create instance objects the user can select. InstanceDropChoice: Describes a class of object the user can drag and drop on the editor to select it. |PP(L^/ HU(L ^UPE!The InstanceEditor Editor FactorybThe list of InstanceChoiceItems can either be specified as part of the InstanceEditor itself, using the values trait, or as an external model, specified using the name trait. Or they can be used together to create a composite set. In any case, changes made to the set of InstanceChoiceItems are immediately reflected in the InstanceEditor user interface.c (5h"P ("QF!The InstanceEditor Editor Factory For example: P MB!The InstanceEditor Editor FactoryHAnd a slightly more complex example& %P%ZH!The InstanceEditor Editor FactorylAnd here s an example showing  drag and drop support:7P7\I!The InstanceEditor Editor FactoryWhich looks like:P^J!The InstanceEditor Editor FactoryFinally, it is possible to combine instance selection and editing in a single editor by simply combining the editing and selection traits:PYGThe TableEditor Editor Factory TAnother common type of trait declaration is: department = List( Employee ) In the case of a list of objects with traits, the TableEditor can be used to display the list as a table, with one object per row, and one object trait per column. In fact, the TableEditor is the default editor for a List trait whose values are objects with traits.r-ZZ Z-2 t -,} t N_KThe TableEditor Editor Factory Some of the features of the TableEditor are: Supports  editable and  read-only modes. Allows object editing either in-place within the table, or separately, in an external  inspector view. In-place editing supports many of the common trait editors, including drag and drop. Supports ascending/descending sorting on any column. Sorting can either affect the underlying model or just the view. Allows the user re-order/include/exclude any of the object columns, and persist the resulting set across application sessions. Allows searching the table contents in a wide variety of ways. Allows filtering the table contents using a wide variety of user customizable and persistable filters. Table/column/cell level context menus All changes made to the table are fully undoable/redoable. Colors, fonts and grid lines are fully customizable. R-PPP > t a9bMThe TableEditor Editor Factory An example of a TableEditor:&  `LThe TableEditor Editor Factory 0All of these features and flexibility come at a price& in this case, the amount of work needed to correctly define a TableEditor. Out of the box, a TableEditor will display many lists of objects without any extra work& but the results will often be non-optimal. The traits that can be defined for a TableEditor include: Table Attributes: Colors, fonts, sorting rules, & Table Columns: What object traits can be displayed as columns and how. Table Filters: What standard and custom filters can be applied to the table. Table Search: What filter can be used to search the table. Table Factory: An optional callable that can be used to add new object rows to the table.>P[Pa      " : @ / M>t   ecN0The TableEditor Editor Factory: Table Attributes " >8-The TableEditor Editor Factory: Table Columns fYou define the content, appearance and behavior of a table by providing ordered sets of TableColumn objects. Each TableColumn object describes a single column/object trait. You can provide two sets of columns: columns: The columns you see initially other_columns: The remaining columns These are the default columns, the user s most recent preference setting overrides them. There are two basic types of TableColumn: ObjectColumn: Used for objects with traits ListColumn: For lists and tuples You can also define subclasses to get state dependent column behavior PLPPLPGPX  U  v   GX  |    HdO-The TableEditor Editor Factory: Table Columns ObjectColumn traits: name: Name of the object trait to display/edit label: Column label to use for the column type: The type of data contained by the column text_color: Text color for this column text_font: Text font for this column cell_color: Cell background color for this column read_only_cell_color: Cell background color for non-editable columns horizontal_alignment: Horizontal alignment of text in the column vertical_alignment: Vertical alignment of text in the column visible: Is the table column visible (i.e. viewable)? editable: Is this column editable? droppable: Can external objects be dropped on the column? editor: Editor factory to use when editing the column  in-place menu: Context menu to display when this column is right-clickeddPP  +%,   (1-+/ 4;<~    (1-BeP-The TableEditor Editor Factory: Table Columns For almost every ObjectColumn trait there is a corresponding  get or  is method. For example,  editor and  get_editor() ,  editable and  is_editable() . Defining a method overrides the corresponding trait. This allows subclasses to define values that are dependent upon the state of each table object or other values.RTJ 7J> R  fQ-The TableEditor Editor Factory: Table Filters When applied to a table, a filter reduces the set of visible rows to only those objects which match the filter s criteria. A TableEditor defines two filter related traits: filter: The filter initially in effect (defaults to None =  No filter ) filters: A list of TableFilter objects that the user can choose from using the  View drop down list. ~} $.  I,}  Iy-The TableEditor Editor Factory: Table Filters There are two basic types of filters: Normal filter: An actual filter that can be applied and modified. Template filter: A filter which cannot be applied or modified, but which is used to create new normal filter objects of the same type as the template and with the same initial filter values. A template filter is simply a normal filter with its template trait set to True. User created filters are automatically persisted across application sessions as part of the TableEditor s user preference handling. You can create your own TableFilter subclasses, or use any of the standard subclasses: EvalTableFilter RuleTableFilter MenuTableFilter &PP,P0PP& 55^ 5 40b 3 4hR-The TableEditor Editor Factory: Table Filters (The EvalTableFilter: Allows a user to enter a Python expression whose value determines whether or not an object meets the filter criteria. Its use is obviously best suited to users already familiar with Python. Trait references on the object being tested do not need to be explicitly qualified. BjS-The TableEditor Editor Factory: Table Filters The RuleTableFilter: Allows users to define  rules using drop down value entry for trait names and operations. Rules can be  and ed or  or ed together. Rules can be added, deleted and modified. Introspection based& requires no set-up by the developer.:ZZ>knlT-The TableEditor Editor Factory: Table Filters The MenuTableFilter: Is similar to the RuleTableFilter The differences are: A rule is automatically created for each object trait. Rules cannot be added or deleted. Rules are implicitly  and ed together. Rules can be turned on and off.hZ7ZZ>+nU,The TableEditor Editor Factory: Table Search VMaking a table searchable allows the user to search for (and optionally select) object rows which match a specified search criteria. A table is made searchable by setting the TableEditor s search trait to a TableFilter object. Doing so adds a  search icon to the table s toolbar, which displays a pop-up search dialog. The search dialog allows the user to search for the next or previous match, or to select all matching rows.BP  ,  oV-The TableEditor Editor Factory: Table Factory If users can add new rows to a table, then a factory must be provided to create the new table objects. The TableEditor traits that specify the object factory are: row_factory: A callable that creates and returns a new object instance when the user adds a new row to the table. row_factory_args: An optional tuple that contains any positional arguments that need to be passed to the factory. row_factory_kw: An optional dictionary that contains any keyword arguments that need to be passed to the factory. PWP-7 - gbebk - gOepW*The TableEditor Editor Factory: An Example  rX*The TableEditor Editor Factory: An Example The resulting view looks like:x]The TreeEditor Editor Factory RObjects often are connected together in such a way that a hierarchical or tree view of them is a useful user interface feature. Common examples: File system explorer: files are contained in directories, which are contained in other directories& Organizational chart: Employees belong to departments, which in turn belong to the company itself. A TreeEditor allows interconnected objects with traits to be displayed as a tree.XZZRZ FZ Fy^The TreeEditor Editor Factory DUsing a TreeEditor, each connected object in the graph of objects to be displayed becomes a separate tree item. Some of the features supported by the TreeEditor include: Full drag and drop support: Objects can be dragged into the tree. Objects can be dragged out of the tree. Objects can be dragged within the tree. Structural relationships between objects are enforced. Objects can be: Added Deleted Renamed The contents of objects can be edited in a separate  inspector view if desired. Each object can have a standard or custom context menu. PPPPPPP     ,  {_The TreeEditor Editor Factory AHere are some examples of TreeEditors being used in the VET tool:.BZ  }`The TreeEditor Editor Factory hLike the TableEditor, in order to provide such a rich set of user interactions, the TreeEditor needs additional information to perform its task. The extra information is divided into two parts: General information about the editor s behavior defined by traits on the TreeEditor itself. Specific information about each of the object types that can appear in the tree, provided by a set of TreeNode objects associated with the TreeEditor.  @ dI o b @  o ~aThe TreeEditor Editor Factory "The general TreeEditor traits are:.#P     cThe TreeEditor Editor Factory \A TreeNode provides information about one or more types (i.e. classes) of object that can appear in the tree: The object classes the TreeNode applies to. Which object trait (if any) contains the children of the object. Can the object s children be renamed, copied deleted or inserted? What object class instances can be added to, copied to or moved to the children of the object. The icons used to represent the object in the tree. The context menu to display when the object is right-clicked on. The view to display when the object is selected for editing. tnZZd6d,{bThe TreeEditor Editor Factory The traits for a TreeNode are:.PdThe TreeEditor Editor Factory In addition, there are several different types of and ways to use TreeNodes: If all the information about an object type is static, simply use a TreeNode and initialize its traits. If some of the information is not known until run-time, create a subclass of TreeNode and override the necessary methods. Each trait has a corresponding method that can be used to override the trait value (e.g.  get_children() overrides  children and  can_delete() overrides  delete ). Sometimes you have data that is not explicitly or conveniently hierarchical, so you need to build a model that exposes the hierarchy. In this case, you can create your model classes as subclasses of TreeNodeObject and create corresponding ObjectTreeNodes for use with the model s TreeEditor. An ObjectTreeNode simply delegates all its methods to the object it describes.4MPPB Di   >B Fi   >eThe TreeEditor Editor Factory An example (Part 1):PfThe TreeEditor Editor Factory An example (Part 2): "PgThe TreeEditor Editor Factory An example (Part 3):hThe TreeEditor Editor Factory The resulting view looks like:P/*)Saving and Restoring User GUI PreferenceseThe Traits UI allows some user preference settings to be saved without writing any code. The preferences that can be saved automatically are defined by a View and the individual editors contained in a View. Some of the user preference settings that can be saved currently are: Window/Dialog size and position Splitter bar position User defined table filtersZZQZ+HQ0+)Saving and Restoring User GUI PreferencesUser preferences are only saved when you request them to be saved. You request a preference to be saved simply by assigning a non-empty  id trait to the corresponding View, Group or Item object. In order for any preferences to be saved, a View must have a non-empty  id . The user preference values for a View are saved in a global  database under the view s  id , so the View  id should also be unique across applications and views. For example: View( & , id =  enthought.graph.vpl.graph_canvas , & )Z> ~ 1,)Saving and Restoring User GUI PreferencesNGroup and Item  id values only need to be unique within the containing View. The currently supported preference items are: View (Window/Dialog size and position) Group (Splitter bar position when layout =  split ) Item (Splitter bar position when editor = TreeEditor) Item (User defined filters when editor = TableEditor) New editors can save their preferences by implementing the  save_prefs and  restore_prefs methods.|ZZeZH0#/& % eP + >   r ,s 1traitsui-4.1.0/docs/api.css0000644000175100001440000001103211674463545016570 0ustar ischnellusers00000000000000 /* Body color */ body {background: #ffffff; color: #000000; font-family: "Lucida Sans", Verdana, Arial, sans-serif;} /* Tables */ table.summary, table.details, table.index { background: #e8f0f8; color: #000000; } tr.summary, tr.details, tr.index { background: #70b0f0; color: #000000; text-align: left; font-size: 120%; } tr.group { background: #c0e0f8; color: #000000; text-align: left; font-size: 120%; font-style: italic; } /* Documentation page titles */ h2.module { margin-top: 0.2em; } h2.class { margin-top: 0.2em; } /* Headings */ h1.heading { font-size: +125%; font-style: italic; font-weight: bold; } h2.heading { font-size: +110%; font-style: italic; font-weight: bold; } h3.heading { font-style: italic; font-weight: normal; } /* Base tree */ pre.base-tree { font-size: 80%; margin: 0; } /* Details Sections */ table.func-details { background: #e8f0f8; color: #000000; border: 2px groove #c0d0d0; padding: 0 1em 0 1em; margin: 0.4em 0 0 0; } h3.func-detail { background: transparent; color: #000000; margin: 0 0 1em 0; } table.var-details { background: #e8f0f8; color: #000000; border: 2px groove #c0d0d0; padding: 0 1em 0 1em; margin: 0.4em 0 0 0; } h3.var-details { background: transparent; color: #000000; margin: 0 0 1em 0; } /* Function signatures */ .sig { background: transparent; color: #000000; font-weight: bold; font-size: +125%; } .sig-name { background: transparent; color: #006080; } .sig-arg, .sig-kwarg, .sig-vararg { background: transparent; color: #008060; } .sig-default { background: transparent; color: #602000; } .summary-sig { background: transparent; color: #000000; } .summary-sig-name { background: transparent; color: #204080; } .summary-sig-arg, .summary-sig-kwarg, .summary-sig-vararg { background: transparent; color: #008060; } /* Doctest blocks */ .py-src { background: transparent; color: #000000; } .py-prompt { background: transparent; color: #005050; font-weight: bold;} .py-string { background: transparent; color: #006030; } .py-comment { background: transparent; color: #003060; } .py-keyword { background: transparent; color: #600000; } .py-output { background: transparent; color: #404040; } pre.doctest-block { background: #f4faff; color: #000000; padding: .5em; margin: 1em; border: 1px solid #708890; } table pre.doctest-block { background: #dce4ec; color: #000000; padding: .5em; margin: 1em; border: 1px solid #708890; } /* Variable values */ pre.variable { background: #dce4ec; color: #000000; padding: .5em; margin: 0; border: 1px solid #708890; } .variable-linewrap { background: transparent; color: #604000; } .variable-ellipsis { background: transparent; color: #604000; } .variable-quote { background: transparent; color: #604000; } .re { background: transparent; color: #000000; } .re-char { background: transparent; color: #006030; } .re-op { background: transparent; color: #600000; } .re-group { background: transparent; color: #003060; } .re-ref { background: transparent; color: #404040; } /* Navigation bar */ table.navbar { background: #a0c0ff; color: #0000ff; border: 2px groove #c0d0d0; } th.navbar { background: #a0c0ff; color: #0000ff; } th.navselect { background: #70b0ff; color: #000000; } .nomargin { margin: 0; } /* Links */ a:link { background: transparent; color: #0000ff; } a:visited { background: transparent; color: #204080; } a.navbar:link { background: transparent; color: #0000ff; text-decoration: none; } a.navbar:visited { background: transparent; color: #204080; text-decoration: none; } code { font-family: "Lucida Console", "Courier New", Courier, monospace; } pre { font-family: "Lucida Console", "Courier New", Courier, monospace; } .pre { font-family: "Lucida Console", "Courier New", Courier, monospace; } pre.literal-block { margin-left: 1em; }traitsui-4.1.0/docs/Traits UI User Guide.doc0000644000175100001440000707300011674463545021467 0ustar ischnellusers00000000000000ࡱ> 68 !"#$%&'()*+,-./012345%` bjbjٕ L0 v7888|V9XO$ SHhSlD $$$8\ _ <"< Sd#A {Mbdddddd$C hiO2FT1"SFTFTOO2nnnFT>2OObnFTbnnNXOO WS$9T-# <_ (1 F1P1R $_S"SnSS_S_S_SR_S_S_S_ FTFTFTFTUd|U c l9 2GtOOOO  TITLE Traits UI User Guide Traits 3.0 Lyn Pierce Janet Swisher Document  SUBJECT Version 4 3-Mar-2008 2005, 2008 Enthought, Inc. All Rights Reserved. Redistribution and use of this document in source and derived forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source or derived format (for example, Portable Document Format or Hypertext Markup Language) must retain the above copyright notice, this list of conditions and the following disclaimer. Neither the name of Enthought, Inc., nor the names of contributors may be used to endorse or promote products derived from this document without specific prior written permission. THIS DOCUMENT IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS DOCUMENT, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. All trademarks and registered trademarks are the property of their respective owners. Enthought, Inc. 515 Congress Avenue Suite 2100 Austin TX 78701 1.512.536.1057 (voice) 1.512.536.1059 (fax)  HYPERLINK "http://www.enthought.com/"http://www.enthought.com  HYPERLINK "mailto:info@enthought.com"info@enthought.com Table of Contents  TOC \o "1-9" \t "Heading 9;9;Heading 8;8;Heading 7;7;Heading 6;6;Heading 5;5;Heading 4;4;Heading 3;3;Heading 2;2;Heading 1;1;Heading 1;1;Heading 1;1;Heading 1;1;Heading 1;1;Appendix;1;Appendix;1;Appendix;1;Appendix;1;Appendix;1;Heading 2;2;Heading 2;2;Heading 2;2;Heading 2;2;Heading 3;3;Heading 3;3;Heading 3;3;Heading 3;3;Heading 4;4;Heading 4;4;Heading 4;4;Heading 4;4;Heading 5;5;Heading 5;5;Heading 5;5;Heading 5;5;Heading 6;6;Heading 6;6;Heading 6;6;Heading 6;6;Heading 7;7;Heading 7;7;Heading 7;7;Heading 7;7;Heading 8;8;Heading 8;8;Heading 8;8;Heading 8;8;Heading 9;9;Heading 9;9;Heading 9;9;Heading 9;9" \h HYPERLINK \l "_toc736"1 Introduction 1  HYPERLINK \l "_toc738"1.1 The Model-View-Controller (MVC) Design Pattern 1  HYPERLINK \l "_toc745"1.1.1 The Model: HasTraits Subclasses and Objects 2  HYPERLINK \l "_toc747"1.1.2 The View: View Objects 2  HYPERLINK \l "_toc750"1.1.3 The Controller: Handler Subclasses and Objects 2  HYPERLINK \l "_toc752"1.2 Toolkit Selection 3  HYPERLINK \l "_toc763"1.3 Structure of this Guide 4  HYPERLINK \l "_toc765"2 The View and Its Building Blocks 5  HYPERLINK \l "_toc786"2.1 The View Object 6  HYPERLINK \l "_toc815"2.2 Contents of a View 7  HYPERLINK \l "_toc818"2.2.1 The Item Object 7  HYPERLINK \l "_toc919"2.2.2 Subclasses of Item 10  HYPERLINK \l "_toc925"2.2.3 The Group Object 10  HYPERLINK \l "_toc954"2.2.3.1 Content of a Group 11  HYPERLINK \l "_toc956"2.2.3.2 Group Attributes 11  HYPERLINK \l "_toc1041"2.2.4 Subclasses of Group 13  HYPERLINK \l "_toc1164"3 Customizing a View 16  HYPERLINK \l "_toc1166"3.1 Specifying Window Type: the kind Attribute 16  HYPERLINK \l "_toc1176"3.1.1 Stand-alone Windows 16  HYPERLINK \l "_toc1209"3.1.2 Wizards 17  HYPERLINK \l "_toc1212"3.1.3 Panels and Subpanels 17  HYPERLINK \l "_toc1216"3.2 Command Buttons: the buttons Attribute 18  HYPERLINK \l "_toc1295"3.3 Other View Attributes 20  HYPERLINK \l "_toc1376"4 Advanced View Concepts 22  HYPERLINK \l "_toc1383"4.1 Internal Views 22  HYPERLINK \l "_toc1386"4.1.1 Defining a Default View 23  HYPERLINK \l "_toc1415"4.1.2 Defining Multiple Views Within the Model 24  HYPERLINK \l "_toc1453"4.2 Separating Model and View: External Views 25  HYPERLINK \l "_toc1462"4.3 Displaying a View 26  HYPERLINK \l "_toc1464"4.3.1 configure_traits() 26  HYPERLINK \l "_toc1467"4.3.2 edit_traits() 26  HYPERLINK \l "_toc1469"4.3.3 ui() 27  HYPERLINK \l "_toc1479"4.4 The View Context 27  HYPERLINK \l "_toc1483"4.4.1 Multi-Object Views 28  HYPERLINK \l "_toc1541"4.5 Include Objects 30  HYPERLINK \l "_toc1562"5 Controlling the Interface: the Handler 32  HYPERLINK \l "_toc1567"5.1 Backstage: Introducing the UIInfo Object 32  HYPERLINK \l "_toc1571"5.2 Assigning Handlers to Views 33  HYPERLINK \l "_toc1576"5.2.1 Binding a Singleton Handler to a View 34  HYPERLINK \l "_toc1578"5.2.2 Linking Handler and View at Edit Time 34  HYPERLINK \l "_toc1580"5.2.3 Creating a Default View Within a Handler 34  HYPERLINK \l "_toc1583"5.3 Handler Subclasses 35  HYPERLINK \l "_toc1594"5.3.1 Controller Class 35  HYPERLINK \l "_toc1600"5.3.2 ModelView Class 36  HYPERLINK \l "_toc1606"5.4 Writing Handler Methods 36  HYPERLINK \l "_toc1608"5.4.1 Overriding Standard Methods 36  HYPERLINK \l "_toc1682"5.4.2 Reacting to Trait Changes 38  HYPERLINK \l "_toc1734"5.4.3 Implementing Custom Window Commands 40  HYPERLINK \l "_toc1736"5.4.3.1 Actions 40  HYPERLINK \l "_toc1743"5.4.3.2 Custom Command Buttons 41  HYPERLINK \l "_toc1750"5.4.3.3 Menus and Menu Bars 41  HYPERLINK \l "_toc1762"5.4.3.4 Toolbars 42  HYPERLINK \l "_toc1777"6 Traits UI Themes 43  HYPERLINK \l "_toc1787"6.1 Theme Data 44  HYPERLINK \l "_toc1792"6.2 Themeable Traits UI Elements 45  HYPERLINK \l "_toc1800"6.3 Adding Themes to a UI 46  HYPERLINK \l "_toc1864"7 Introduction to Trait Editor Factories 48  HYPERLINK \l "_toc1901"7.1 Specifying an Alternate Trait Editor Factory 49  HYPERLINK \l "_toc1979"7.1.1 Initializing Editors 52  HYPERLINK \l "_toc1983"7.2 Specifying an Editor Style 53  HYPERLINK \l "_toc1985"7.2.1 The simple Style 53  HYPERLINK \l "_toc1994"7.2.2 The custom Style 54  HYPERLINK \l "_toc2000"7.2.3 The text Style 54  HYPERLINK \l "_toc2011"7.2.4 The readonly style 55  HYPERLINK \l "_toc2016"7.2.5 Using Editor Styles 55  HYPERLINK \l "_toc2062"8 The Predefined Trait Editor Factories 58  HYPERLINK \l "_toc2067"8.1 Basic Trait Editor Factories 58  HYPERLINK \l "_toc2069"8.1.1 ArrayEditor() 58  HYPERLINK \l "_toc2133"8.1.2 BooleanEditor() 60  HYPERLINK \l "_toc2180"8.1.3 ButtonEditor() 61  HYPERLINK \l "_toc2212"8.1.4 CheckListEditor() 62  HYPERLINK \l "_toc2250"8.1.5 CodeEditor() 63  HYPERLINK \l "_toc2281"8.1.6 ColorEditor() 64  HYPERLINK \l "_toc2318"8.1.7 CompoundEditor() 67  HYPERLINK \l "_toc2351"8.1.8 DirectoryEditor() 67  HYPERLINK \l "_toc2387"8.1.9 EnumEditor() 69  HYPERLINK \l "_toc2443"8.1.10 FileEditor() 70  HYPERLINK \l "_toc2479"8.1.11 FontEditor() 72  HYPERLINK \l "_toc2514"8.1.12 HTMLEditor() 73  HYPERLINK \l "_toc2567"8.1.13 ImageEnumEditor() 75  HYPERLINK \l "_toc2614"8.1.14 InstanceEditor() 77  HYPERLINK \l "_toc2642"8.1.14.1 Editing a Single Instance 78  HYPERLINK \l "_toc2648"8.1.14.2 Selecting Instances 79  HYPERLINK \l "_toc2703"8.1.14.3 Allowing Instances 80  HYPERLINK \l "_toc2705"8.1.15 ListEditor() 81  HYPERLINK \l "_toc2744"8.1.16 ListStrEditor() 83  HYPERLINK \l "_toc2774"8.1.17 NullEditor() 84  HYPERLINK \l "_toc2802"8.1.18 RangeEditor() 84  HYPERLINK \l "_toc2934"8.1.19 RGBColorEditor() 86  HYPERLINK \l "_toc2962"8.1.20 SetEditor() 86  HYPERLINK \l "_toc2998"8.1.21 ShellEditor() 87  HYPERLINK \l "_toc3028"8.1.22 TextEditor() 88  HYPERLINK \l "_toc3064"8.1.23 TitleEditor() 89  HYPERLINK \l "_toc3092"8.1.24 TupleEditor() 90  HYPERLINK \l "_toc3124"8.1.25 ValueEditor() 91  HYPERLINK \l "_toc3154"8.2 Advanced Trait Editors 91  HYPERLINK \l "_toc3156"8.2.1 CustomEditor() 92  HYPERLINK \l "_toc3189"8.2.2 DropEditor() 92  HYPERLINK \l "_toc3220"8.2.3 DNDEditor() 93  HYPERLINK \l "_toc3287"8.2.4 KeyBindingEditor() 93  HYPERLINK \l "_toc3357"8.2.5 TableEditor() 96  HYPERLINK \l "_toc3395"8.2.5.1 Specifying Columns 97  HYPERLINK \l "_toc3401"8.2.5.2 Managing Items 98  HYPERLINK \l "_toc3403"8.2.5.2.1 Organizing Items 98  HYPERLINK \l "_toc3413"8.2.5.2.2 Filtering and Searching 99  HYPERLINK \l "_toc3418"8.2.5.2.3 Interacting with Items 100  HYPERLINK \l "_toc3437"8.2.5.3 Editing the Table 101  HYPERLINK \l "_toc3439"8.2.5.3.1 Adding Items 101  HYPERLINK \l "_toc3442"8.2.5.3.2 Deleting Items 102  HYPERLINK \l "_toc3444"8.2.5.3.3 Modifying Items 102  HYPERLINK \l "_toc3448"8.2.5.4 Defining the Layout 102  HYPERLINK \l "_toc3455"8.2.5.5 Defining the Format 103  HYPERLINK \l "_toc3458"8.2.5.6 Other User Interactions 103  HYPERLINK \l "_toc3463"8.2.6 TabularEditor() 104  HYPERLINK \l "_toc3505"8.2.6.1 TabularAdapter 105  HYPERLINK \l "_toc3520"8.2.6.2 The Tabular Editor User Interface 106  HYPERLINK \l "_toc3536"8.2.7 TreeEditor() 108  HYPERLINK \l "_toc3762"8.2.7.1 Defining Nodes 113  HYPERLINK \l "_toc3765"8.2.7.1.1 A Node Type without Children 113  HYPERLINK \l "_toc3774"8.2.7.1.2 A Node Type with Children 114  HYPERLINK \l "_toc3782"8.2.7.1.3 Setting the Label of a Tree Node 114  HYPERLINK \l "_toc3787"8.2.7.2 Defining Operations on Nodes 114  HYPERLINK \l "_toc3789"8.2.7.2.1 Shortcut Menus on Nodes 114  HYPERLINK \l "_toc3808"8.2.7.2.2 Allowing the Hierarchy to Be Modified 115  HYPERLINK \l "_toc3821"8.2.7.2.3 Behavior on Nodes 116  HYPERLINK \l "_toc3825"8.2.7.2.4 Expanding and Collapsing Nodes 116  HYPERLINK \l "_toc3830"8.2.7.2.5 Editing Objects 117  HYPERLINK \l "_toc3851"8.2.7.3 Defining the Format 118  HYPERLINK \l "_toc3863"8.3 Extra Trait Editor Factories 119  HYPERLINK \l "_toc3865"8.3.1 AnimatedGIFEditor() 119  HYPERLINK \l "_toc3893"8.3.2 ArrayViewEditor() 119  HYPERLINK \l "_toc3923"8.3.3 FlashEditor() 120  HYPERLINK \l "_toc3951"8.3.4 HistoryEditor() 120  HYPERLINK \l "_toc3979"8.3.5 IEHTMLEditor() 121  HYPERLINK \l "_toc4013"8.3.6 ImageEditor() 122  HYPERLINK \l "_toc4041"8.3.7 LEDEditor() 122  HYPERLINK \l "_toc4072"8.3.8 ThemedButtonEditor() 123  HYPERLINK \l "_toc4103"8.3.9 ThemedCheckboxEditor() 123  HYPERLINK \l "_toc4134"8.3.10 ThemedSliderEditor() 124  HYPERLINK \l "_toc4164"8.3.11 ThemedTextEditor() 125  HYPERLINK \l "_toc4194"8.3.12 ThemedVerticalNotebookEditor() 125  HYPERLINK \l "_toc4233"9 Tips, Tricks and Gotchas 127  HYPERLINK \l "_toc4235"9.1 Getting and Setting Model View Elements 127  HYPERLINK \l "_toc4237"9.1.1 trait_views() 127  HYPERLINK \l "_toc4247"9.1.2 trait_view() 128 Appendix I: Glossary of Terms 129 Appendix II: Editor Factories for Predefined Traits 133 Introduction This guide is designed to act as a conceptual guide to Traits UI, an open-source package built and maintained by Enthought, Inc. The Traits UI package is a set of GUI (Graphical User Interface) tools designed to complement Traits, another Enthought open-source package that provides manifest typing, validation, and change notification for Python. This guide is intended for readers who are already moderately familiar with Traits; those who are not may wish to refer to the Traits User Manual for an introduction. This guide discusses many but not all features of Traits UI. For complete details of the Traits UI API, refer to the Traits API Reference. The Model-View-Controller (MVC) Design Pattern A common and well-tested approach to building end-user applications is the MVC (Model-View-Controller) design pattern. In essence, the MVC pattern the idea that an application should consist of three separate entities: a model, which manages the data, state, and internal (business) logic of the application; one or more views, which format the model data into a graphical display with which the end user can interact; and a controller, which manages the transfer of information between model and view so that neither needs to be directly linked to the other. In practice, particularly in simple applications, the view and controller are often so closely linked as to be almost indistinguishable, but it remains useful to think of them as distinct entities. The three parts of the MVC pattern correspond roughly to three classes in the Traits and Traits UI packages. Model: HasTraits class (Traits package) View: View class (Traits UI package) Controller: Handler class (Traits UI package) The remainder of this section gives an overview of these relationships. The Model: HasTraits Subclasses and Objects In the context of Traits, a model consists primarily of one or more subclasses or instances of the HasTraits class, whose trait attributes (typed attributes as defined in Traits) represent the model data. The specifics of building such a model are outside the scope of this manual; please see the Traits User Manual for further information. The View: View Objects A view for a Traits-based application is an instance of a class called, conveniently enough, View. A View object is essentially a display specification for a GUI window or panel. Its contents are defined in terms of instances of two other classes: Item and Group. These three classes are described in detail in Chapter  REF _Ref183856870 \n \h 2 of this manual; for the moment, it is important to note that they are all defined independently of the model they are used to display. Note that the terms view and View are distinct for the purposes of this document. The former refers to the component of the MVC design pattern; the latter is a Traits UI construct. The Controller: Handler Subclasses and Objects The controller for a Traits-based application is defined in terms of the Handler class. Specifically, the relationship between any given View instance and the underlying model is managed by an instance of the Handler class. For simple interfaces, the Handler can be implicit. For example, none of the examples in Chapters  REF _Ref161136726 \n \h 2 through  REF _Ref161136737 \n \h 4 includes or requires any specific Handler code; they are managed by a default Handler that performs the basic operations of window initialization, transfer of data between GUI and model, and window closing. Thus, a programmer new to Traits UI need not be concerned with Handlers at all. Nonetheless, custom handlers can be a powerful tool for building sophisticated application interfaces, as discussed in Chapter  REF _Ref161136752 \n \h 5. Toolkit Selection The Traits UI package is designed to be toolkit-independent. Programs that use Traits UI do not need to explicitly import or call any particular GUI toolkit code unless they need some capability of the toolkit that is not provided by Traits UI. However, some particular toolkit be installed on the system in order to actually display GUI windows. Traits UI uses a separate package, enthought.etsconfig, to determine which GUI toolkit to use. This package is also used by other Enthought packages that need GUI capabilities, so that all such packages agree on a single GUI toolkit per application. The enthought.etsconfig package contains a singleton object, ETSConfig, which has a string attribute, toolkit, that signifies the GUI toolkit. The values of ETSConfig.toolkit that are supported by Traits UI version 3 are: wx HYPERLINK "http://www.wxpython.org/"wxPython, which provides Python bindings for the  HYPERLINK "http://wxwidgets.org/"wxWidgets toolkit. qt4 HYPERLINK "http://www.riverbankcomputing.co.uk/pyqt/"PyQt, which provides Python bindings for the  HYPERLINK "http://trolltech.com/products/qt"Qt framework version 4. nullA do-nothing toolkit, for situations where neither of the other toolkits is installed, but Traits is needed for non-UI purposes. The default behavior of Traits UI is to search for available toolkit-specific packages in the order listed, and uses the first one it finds. The programmer or the user can override this behavior in any of several ways, in the following order of precedence: The program can explicitly set ETSConfig.toolkit. It must do this before importing from any other Enthought Tool Suite component, including enthought.traits. The user can specify a -toolkit flag on the command line of the program. The user can define a value for the ETS_TOOLKIT environment variable. Structure of this Guide The intent of this guide is to present the capabilities of the Traits UI package in usable increments, so that you can create and display gradually more sophisticated interfaces from one chapter to the next. Thus, Chapters  REF _Ref161136762 \n \h 2 through  REF _Ref161136774 \n \h 4 show how to construct and display views from the simple to the elaborate, while leaving such details as GUI logic and widget selection to system defaults. Chapter  REF _Ref161136788 \n \h 5 explains how to use the Handler class to implement custom GUI behaviors, as well as menus and toolbars. Chapter  REF _Ref161136802 \n \h 6 described how to customize the appearance of GUIs through themes. Chapters  REF _Ref192072556 \n \h 7 and  REF _Ref192072575 \n \h 8 show how to control GUI widget selection by means of trait editors. Chapter  REF _Ref161136850 \n \h 9 covers miscellaneous additional topics. Further reference materials, including a glossary of terms and an API summary for the Traits UI classes covered in this Guide, are located in the Appendices. The View and Its Building Blocks A simple way to edit (or simply observe) the attribute values of a HasTraits object in a GUI window is to call the objects configure_traits() method. This method constructs and displays a window containing editable fields for each of the objects trait attributes. For example, the following sample code defines the SimpleEmployee class, creates an object of that class, and constructs and displays a GUI for the object: Example  SEQ "Example" \*Arabic 1: Using configure_traits() # configure_traits.py -- Sample code to demonstrate # configure_traits() from enthought.traits.api import HasTraits, Str, Int import enthought.traits.ui class SimpleEmployee(HasTraits): first_name = Str last_name = Str department = Str employee_number = Str salary = Int sam = SimpleEmployee() sam.configure_traits() Unfortunately, the resulting form simply displays the attributes of the object sam in alphabetical order with little formatting, which is seldom what is wanted:  Figure  SEQ "Figure" \*Arabic 1: User interface for  REF _Ref161043988 \h Example 1 The View Object In order to control the layout of the interface, it is necessary to define a View object. A View object is a template for a GUI window or panel. In other words, a View specifies the content and appearance of a TraitsUI window or panel display. For example, suppose you want to construct a GUI window that shows only the first three attributes of a SimpleEmployee (e.g., because salary is confidential and the employee number should not be edited). Furthermore, you would like to specify the order in which those fields appear. You can do this by defining a View object and passing it to the configure_traits() method: Example  SEQ "Example" \*Arabic 2: Using configure_traits() with a View object # configure_traits_view.py -- Sample code to demonstrate # configure_traits() from enthought.traits.api import HasTraits, Str, Int from enthought.traits.ui.api import View, Item import enthought.traits.ui class SimpleEmployee(HasTraits): first_name = Str last_name = Str department = Str employee_number = Str salary = Int view1 = View(Item(name = 'first_name'), Item(name = 'last_name'), Item(name = 'department')) sam = SimpleEmployee() sam.configure_traits(view=view1) The resulting window has the desired appearance:  Figure  SEQ "Figure" \*Arabic 2: User interface for  REF _Ref117064775 \h Example 2 Chapters  REF _Ref161137195 \n \h 2.2 through  REF _Ref161137204 \n \h 4 explore the contents and capabilities of Views. Refer to the Traits API Reference for details of the View class. Except as noted, all example code uses the configure_traits() method; a detailed description of this and other techniques for creating GUI displays from Views can be found in Section  REF _Ref117066165 \n \h 4.3 on page  PAGEREF _Ref117066165 \h 26. Contents of a View The contents of a View are specified primarily in terms of two basic building blocks: Item objects (which, as suggested by  REF _Ref117064775 \h Example 2, correspond roughly to individual trait attributes), and Group objects. A given View definition can contain one or more objects of either of these types, which are specified as arguments to the View constructor, as in the case of the three Items in  REF _Ref117064775 \h Example 2. The remainder of this chapter describes the Item and Group classes. The Item Object The simplest building block of a View is the Item object. An Item specifies a single interface widget, usually the display for a single trait attribute of a HasTraits object. The content, appearance, and behavior of the widget are controlled by means of the Item objects attributes, which are usually specified as keyword arguments to the Item constructor, as in the case of name in  REF _Ref117064775 \h Example 2. The remainder of this section describes the attributes of the Item object, grouped by categories of functionality. It is not necessary to understand all of these attributes in order to create useful Items; many of them can usually be left unspecified, as their default values are adequate for most purposes. Indeed, as demonstrated by earlier examples, simply specifying the name of the trait attribute to be displayed is often enough to produce a usable result.  REF _Ref161037664 \h Table 1 lists the attributes of the Item class, organized by functional categories. Refer to the Traits API Reference for details on the Item class. Table  SEQ "Table" \*Arabic 1: Attributes of Item, by category CategoryAttributesDescriptionContentnameThese attributes specify the actual data to be displayed by an item. Because an Item is essentially a template for displaying a single trait, its name attribute is nearly always specified. Display formatlabel resizable emphasized padding height width dock image item_theme label_theme export show_label resizable springy emphasizedIn addition to specifying which trait attributes are to be displayed, you might need to adjust the format of one or more of the resulting widgets. If an Items label attribute is specified but not its name, the value of label is displayed as a simple, non-editable string. (This feature can be useful for displaying comments or instructions in a Traits UI window.)Content formatformat_str format_func In some cases it can be desirable to apply special formatting to a widgets contents rather than to the widget itself. Examples of such formatting might include rounding a floating-point value to two decimal places, or capitalizing all letter characters in a license plate number.Widget overrideeditor styleThese attributes override the widget that is automatically selected by Traits UI. These options are discussed in Chapters  REF _Ref161137236 \n \h 6 through  REF _Ref161036858 \n \h Error! Reference source not found..Visibility and statusenabled_when  visible_when  defined_when has_focusUse these attributes to create a simple form of a dynamic GUI, which alters the display in response to changes in the data it contains. More sophisticated dynamic behavior can be implemented using a custom Handler (see Chapter  REF _Ref161037026 \n \h 5).User helptooltip help help_idThese attributes provide guidance to the user in using the user interface. If the help attribute is not defined for an Item, a system-generated message is used instead. The help_id attribute is ignored by the default help handler, but can be used by a custom help handler.Unique identifieridThe id attribute is used as a key for saving user preferences about the widget. If id is not specified, the value of the name attribute is used.Subclasses of Item The Traits UI package defines the following subclasses of Item: Label Heading Spring These classes are intended to help with the layout of a Traits UI View, and need not have a trait attribute associated with them. See the Traits API Reference for details. The Group Object The preceding sections have shown how to construct windows that display a simple vertical sequence of widgets using instances of the View and Item classes. For more sophisticated interfaces, though, it is often desirable to treat a group of data elements as a unit for reasons that might be visual (e.g., placing the widgets within a labeled border) or logical (activating or deactivating the widgets in response to a single condition, defining group-level help text). In Traits UI, such grouping is accomplished by means of the Group object. Consider the following enhancement to  REF _Ref117064775 \h Example 2: Example  SEQ "Example" \*Arabic 3: Using configure_traits() with a View and a Group object # configure_traits_view_group.py -- Sample code to demonstrate # configure_traits() from enthought.traits.api import HasTraits, Str, Int from enthought.traits.ui.api import View, Item, Group import enthought.traits.ui class SimpleEmployee(HasTraits): first_name = Str last_name = Str department = Str employee_number = Str salary = Int view1 = View(Group(Item(name = 'first_name'), Item(name = 'last_name'), Item(name = 'department'), label = 'Personnel profile', show_border = True)) sam = SimpleEmployee() sam.configure_traits(view=view1) The resulting window shows the same widgets as before, but they are now enclosed in a visible border with a text label:  Figure  SEQ "Figure" \*Arabic 3: User interface for  REF _Ref117066209 \h Example 3 Content of a Group The content of a Group object is specified exactly like that of a View object. In other words, one or more Item or Group objects are given as arguments to the Group constructor, e.g., the three Items in  REF _Ref117066209 \h Example 3. The objects contained in a Group are called the elements of that Group. Groups can be nested to any level. Group Attributes  REF _Ref161037777 \h Table 2 lists the attributes of the Group class, organized by functional categories. As with Item attributes, many of these attributes can be left unspecified for any given Group, as the default values usually lead to acceptable displays and behavior. See the Traits API Reference for details of the Group class. Table  SEQ "Table" \*Arabic 2: Attributes of Group, by category CategoryAttributesDescriptionContentobject contentThe object attribute references the object whose traits are being edited by members of the group; by default this is 'object', but could be another object in the current context. The content attribute is a list of elements in the group.Display formatlabel show_border show_labels show_left padding layout selected orientation style columns dock dock_theme group_theme item_theme label_theme image export springyThese attributes define display options for the group as a whole.Visibility and statusenabled_when visible_when defined_whenThese attributes work similarly to the attributes of the same names on the Item class. User helphelp help_idThe help text is used by the default help handler only if the group is the only top-level group for the current View. For example, suppose help text is defined for a Group called group1. The following View shows this text in its help window:View(group1) The following two do not: View(group1, group2) View(Group(group1))  The help_id attribute is ignored by the default help handler, but can be used by a custom help handler.Unique identifieridThe id attribute is used as a key for saving user preferences about the widget. If id is not specified, the id values of the elements of the group are concatenated and used as the group identifier.Subclasses of Group The Traits UI package defines the following subclasses of Group, which are helpful shorthands for defining certain types of groups. Refer to the Traits API Reference for details. Table  SEQ "Table" \*Arabic 3 Subclasses of Group SubclassDescriptionEquivalent ToHGroupA group whose items are laid out horizontally.Group(orientation= 2 horizontal2 )HFlowA horizontal group whose items  wrap when they exceed the available horizontal space.Group(orientation= 2 horizontal2 , layout=2 flow2 , show_labels= False)HSplitA horizontal group with splitter bars to separate it from other groups.Group(orientation= 2 horizontal2 , layout=2 split2 )TabbedA group that is shown as a tab in a notebook.Group(orientation= 2 horizontal2 , layout=2 tabbed2 )VGroupA group whose items are laid out vertically.Group(orientation= 2 vertical2 )VFlowA vertical group whose items  wrap when they exceed the available vertical space.Group(orientation= 2 vertical2 , layout=2 flow2 , show_labels= False)VFoldA vertical group in which items can be collapsed (i.e., folded) by clicking their titles.Group(orientation= 2 vertical2 , layout=2 fold2 , show_labels= False)VGridA vertical group whose items are laid out in 2 columns.Group(orientation= 2 vertical2 , columns=2)VSplitA vertical group with splitter bars to separate it from other groups.Group(orientation= 2 vertical2 , layout=2 split2 ) Customizing a View As shown in the preceding two chapters, it is possible to specify a window in Traits UI simply by creating a View object with the appropriate contents. In designing real-life applications, however, you usually need to be able to control the appearance and behavior of the windows themselves, not merely their content. This chapter covers a variety of options for tailoring the appearance of a window that is created using a View, including the type of window that a View appears in, the command buttons that appear in the window, and the physical properties of the window. Specifying Window Type: the kind Attribute Many types of windows can be used to display the same data content. A form can appear in a window, a wizard, or an embedded panel; windows can be modal (i.e., stop all other program processing until the box is dismissed) or not, and can interact with live data or with a buffered copy. In Traits UI, a single View can be used to implement any of these options simply by modifying its kind attribute. There are seven possible values of kind: modal live livemodal nonmodal wizard panel subpanel These alternatives are described below. If the kind attribute of a View object is not specified, the default value is modal. Stand-alone Windows The behavior of a stand-alone Traits UI window can vary over two significant degrees of freedom. First, it can be modal, meaning that when the window appears, all other GUI interaction is suspended until the window is closed; if it is not modal, then both the window and the rest of the GUI remain active and responsive. Second, it can be live, meaning that any changes that the user makes to data in the window is applied directly and immediately to the underlying model object or objects; otherwise the changes are made to a copy of the model data, and are only copied to the model when the user commits them (usually by clicking an OK or Apply button; see Section  REF _Ref161204588 \n \h 3.2 on page  PAGEREF _Ref161644929 \h 18). The four possible combinations of these behaviors correspond to four of the possible values of the kind attribute of the View object, as shown  REF _Ref161039433 \h Table 4. Table  SEQ "Table" \*Arabic 4: Matrix of Traits UI windows not modalmodalnot livenonmodalmodallivelivelivemodalAll of these window types are identical in appearance. Also, all types support the buttons attribute, which is described in Section  REF _Ref161204588 \n \h 3.2. Usually, a window with command buttons is called a dialog box. Wizards Unlike a window, whose contents generally appear as a single page or a tabbed display,  a wizard is presented as a series of pages that a user must navigate sequentially.  Traits UI Wizards are always modal and live. They always display a standard wizard button set; i.e., they ignore the buttons View attribute. In short, wizards are considerably less flexible than windows, and are primarily suitable for highly controlled user interactions such as software installation. Panels and Subpanels Both dialog boxes and wizards are secondary windows that appear separately from the main program display, if any. Often, however, you might need to create a window element that is embedded in a larger display. For such cases, the kind of the corresponding View object should be panel or subpanel. A panel is very similar to a window, except that it is embedded in a larger window, which need not be a Traits UI window. Like windows, panels support the buttons View attribute, as well as any menus and toolbars that are specified for the View (see Section  REF _Ref161204620 \n \h 5.4.3 on page  PAGEREF _Ref161644958 \h 40). Panels are always live and nonmodal. A subpanel is almost identical to a panel. The only difference is that subpanels do not display command buttons even if the View specifies them.  Command Buttons: the buttons Attribute A common feature of many windows is a row of command buttons along the bottom of the frame. These buttons have a fixed position outside any scrolled panels in the window, and are thus always visible while the window is displayed. They are usually used for window-level commands such as committing or cancelling the changes made to the form data, or displaying a help window. In Traits UI, these command buttons are specified by means of the View objects buttons attribute, whose value is a list of buttons to display. Consider the following variation on  REF _Ref117066209 \h Example 3: Example  SEQ "Example" \*Arabic 4: Using a View object with buttons # configure_traits_view_buttons.py -- Sample code to demonstrate # configure_traits() from enthought.traits.api import HasTraits, Str, Int from enthought.traits.ui.api import View, Item from enthought.traits.ui.menu import OKButton, CancelButton class SimpleEmployee(HasTraits): first_name = Str last_name = Str department = Str employee_number = Str salary = Int view1 = View(Item(name = 'first_name'), Item(name = 'last_name'), Item(name = 'department'), buttons = [OKButton, CancelButton]) sam = SimpleEmployee() sam.configure_traits(view=view1) The resulting window has the same content as before, but now two buttons are displayed at the bottom: OK and Cancel:  Figure  SEQ "Figure" \*Arabic 4: User interface for  REF _Ref161039990 \h Example 4 There are six standard buttons defined by Traits UI. Each of the standard buttons has matching a string alias. You can either import and use the button names, or simply use their aliases: Table  SEQ "Table" \*Arabic 5 Command button aliases Button NameButton AliasUndoButton UndoApplyButton ApplyRevertButton RevertOKButton.OK (case sensitive!)CancelButton CancelAlternatively, there are several pre-defined button lists that can be imported from enthought.traits.ui.menu and assigned to the buttons attribute: OKCancelButtons = [OKButton, CancelButton ] ModalButtons = [ ApplyButton, RevertButton, OKButton, CancelButton, HelpButton ] LiveButtons = [ UndoButton, RevertButton, OKButton, CancelButton, HelpButton ] Thus, one could rewrite the highlighted lines in  REF _Ref161039990 \h Example 4 as follows, and the effect would be exactly the same: from enthought.traits.ui.menu import OKCancelButtons buttons = OKCancelButtons The special constant NoButtons can be used to create a window or panel without command buttons. While this is the default behavior, NoButtons can be useful for overriding an explicit value for buttons. You can also specify buttons = [] to achieve the same effect. Setting the buttons attribute to an empty list has the same effect as not defining it at all. It is also possible to define custom buttons and add them to the buttons list; see Section  REF _Ref161204653 \n \h 5.4.3.2 on page  PAGEREF _Ref161204653 \h 41 for details. Other View Attributes Table  SEQ "Table" \*Arabic 6: Attributes of View, by category CategoryAttributesDescriptionWindow displayx y width height title resizable scrollable style dock icon image export item_theme label_themeThese attributes control the visual properties of the window itself, regardless of its content.Commandhandler menubar toolbar key_bindings on_apply updated close_resultTraits UI menus and toolbars are generally implemented in conjunction with custom Handlers; see Section  REF _Ref161204620 \n \h 5.4.3 on page  PAGEREF _Ref161204653 \h 41 for details. The key_bindings attribute references the set of global key bindings for the view.Contentcontent object imports drop_classThe content attribute is the top-level Group object for the view. The object attribute is the object being edited. The imports and drop_class attributes control what objects can be dragged and dropped on the view.User helphelp help_idThe help attribute is a deprecated way to specify that the View has a Help button. Use the buttons attribute instead (see Section  REF _Ref161204588 \n \h 3.2 on page  PAGEREF _Ref161646665 \h 18 for details). The help_id attribute is not used by Traits, but can be used by a custom help handler.Unique identifierid The id attribute is used as a key to save user preferences about a view, such as customized size and position, so that they are restored the next time the view is opened. The value of id must be unique across all Traits-based applications on a system. If no value is specified, no user preferences are saved for the view. Advanced View Concepts The preceding chapters of this Guide give an overview of how to use the View class to quickly construct a simple window for a single HasTraits object. This chapter explores a number of more complex techniques that significantly increase the power and versatility of the View object. Internal views: Views can be defined as attributes of a HasTraits class; one class can have multiple views. View attributes can be inherited by subclasses. External views: A view can be defined as a module variable, inline as a function or method argument, or as an attribute of a Handler. Ways of displaying views: You can display a View by calling configure_traits() or edit_traits() on a HasTraits object, or by calling the ui() method on the View object. View context: You can pass a context to any of the methods for displaying views, which is a dictionary of labels and objects. In the default case, this dictionary contains only one object, referenced as object, but you can define contexts that contain multiple objects. Include objects: You can use an Include object as a placeholder for view items defined elsewhere. Internal Views In the examples thus far, the View objects have been external. That is to say, they have been defined outside the model (HasTraits object or objects) that they are used to display. This approach is in keeping with the separation of the two concepts prescribed by the MVC design pattern. There are cases in which it is useful to define a View within a HasTraits class. In particular, it can be useful to associate one or more Views with a particular type of object so that they can be incorporated into other parts of the application with little or no additional programming. Further, a View that is defined within a model class is inherited by any subclasses of that class, a phenomenon called visual inheritance. Defining a Default View It is easy to define a default view for a HasTraits class: simply create a View attribute called traits_view for that class. Consider the following variation on  REF _Ref117066209 \h Example 3: Example  SEQ "Example" \*Arabic 5: Using configure_traits() with a default View object # default_traits_view.py -- Sample code to demonstrate the use of # 'traits_view' from enthought.traits.api import HasTraits, Str, Int from enthought.traits.ui.api import View, Item, Group import enthought.traits.ui class SimpleEmployee2(HasTraits): first_name = Str last_name = Str department = Str employee_number = Str salary = Int traits_view = View(Group(Item(name = 'first_name'), Item(name = 'last_name'), Item(name = 'department'), label = 'Personnel profile', show_border = True)) sam = SimpleEmployee2() sam.configure_traits() In this example, configure_traits() no longer requires a view keyword argument; the traits_view attribute is used by default, resulting in the same display as in  REF _Ref161205517 \h Figure 3:  Figure  SEQ "Figure" \*Arabic 5: User interface for  REF _Ref161214128 \h Example 5 It is not strictly necessary to call this View attribute traits_view. If exactly one View attribute is defined for a HasTraits class, that View is always treated as the default display template for the class. However, if there are multiple View attributes for the class (as discussed in the next section), if one is named traits_view, it is always used as the default. Defining Multiple Views Within the Model Sometimes it is useful to have more than one pre-defined view for a model class. In the case of the SimpleEmployee class, one might want to have both a public information view like the one above and an all information view. One can do this by simply adding a second View attribute: Example  SEQ "Example" \*Arabic 6: Defining multiple View objects in a HasTraits class # multiple_views.py -- Sample code to demonstrate the use of # multiple views from enthought.traits.api import HasTraits, Str, Int from enthought.traits.ui.api import View, Item, Group import enthought.traits.ui class SimpleEmployee3(HasTraits): first_name = Str last_name = Str department = Str employee_number = Str salary = Int traits_view = View(Group(Item(name = 'first_name'), Item(name = 'last_name'), Item(name = 'department'), label = 'Personnel profile', show_border = True)) all_view = View(Group(Item(name = 'first_name'), Item(name = 'last_name'), Item(name = 'department'), Item(name = 'employee_number'), Item(name = 'salary'), label = 'Personnel database ' + 'entry', show_border = True)) sam = SimpleEmployee3() sam.configure_traits() sam.configure_traits(view='all_view') As before, a simple call to configure_traits() for an object of this class produces a window based on the default View (traits_view). In order to use the alternate View, use the same syntax as for an external view, except that the View name is specified in single quotes to indicate that it is associated with the object rather than being a module-level variable: configure_traits(view='all_view'). Note that if more than one View is defined for a model class, you must indicate which one is to be used as the default by naming it traits_view. Otherwise, Traits UI gives preference to none of them, and instead tries to construct a default View, resulting in a simple alphabetized display as described in Chapter  REF _Ref161137270 \n \h 2. For this reason, it is usually preferable to name a model's default View traits_view even if there are no other Views; otherwise, simply defining additional Viewseven if they are never usedcan unexpectedly change the behavior of the GUI. Separating Model and View: External Views In all the preceding examples in this guide, the concepts of model and view have remained closely coupled. In some cases the view has been defined in the model class, as in Section  REF _Ref117065824 \n \h 4.1 on page  PAGEREF _Ref117065824 \h 22; in other cases the configure_traits() method that produces a window from a View has been called from a HasTraits object. However, these strategies are simply conveniences; they are not an intrinsic part of the relationship between model and view in Traits UI. This section begins to explore how the Traits UI package truly supports the separation of model and view prescribed by the MVC design pattern. An external view is one that is defined outside the model classes. In Traits UI, you can define a named View wherever you can define a variable or class attribute. A View can even be defined in-line as a function or method argument, for example: object.configure_traits(view=View(Group(Item(name='a'), Item(name='b'), Item(name='c'))) However, this approach is apt to obfuscate the code unless the View is very simple.  REF _Ref117064775 \h Example 2 through  REF _Ref161039990 \h Example 4 demonstrate external Views defined as variables. One advantage of this convention is that the variable name provides an easily accessible handle for re-using the View. This technique does not, however, support visual inheritance. A powerful alternative is to define a View within the controller (Handler) class that controls the window for that View. This technique is described in Chapter  REF _Ref161137284 \n \h 5. Displaying a View Traits UI provides three methods for creating a window or panel from a View object. The first two, configure_traits() and edit_traits(), are defined on the HasTraits class, which is a superclass of all Traits-based model classes, as well as of Handler and its subclasses. The third method, ui(), is defined on the View class itself. configure_traits() The configure_traits() method creates a standalone window for a given View object, i.e., it does not require an existing GUI to run in. It is therefore suitable for building command-line functions, as well as providing an accessible tool for the beginning Traits UI programmer. The configure_traits() method also provides options for saving trait attribute values to and restoring them from a file. Refer to the Traits API Reference for details. edit_traits() The edit_traits() method is very similar to configure_traits(), with two major exceptions. First, it is designed to run from within a larger application whose GUI is already defined. Second, it does not provide options for saving data to and restoring data from a file, as it is assumed that these operations are handled elsewhere in the application. ui() The View object includes a method called ui(), which performs the actual generation of the window or panel from the View for both edit_traits() and configure_traits(). The ui() method is also available directly through the Traits UI API; however, using one of the other two methods is usually preferable. The ui() method has five keyword parameters: kind context handler parent view_elements The first four are identical in form and function to the corresponding arguments of edit_traits(), except that context is not optional; the following section explains why. The fifth argument, view_elements, is used only in the context of a call to ui() from a model object method, i.e., from configure_traits() or edit_traits(), Therefore it is irrelevant in the rare cases when ui() is used directly by client code. It contains a dictionary of the named ViewElement objects defined for the object whose configure_traits() (or edit_traits()) method was called.. The View Context All three of the methods described in Section  REF _Ref117066165 \n \h 4.3 have a context parameter. This parameter can be a single object or a dictionary of string/object pairs; the object or objects are the model objects whose traits attributes are to be edited. In general a context is a Python dictionary whose keys are strings; the key strings are used to look up the values. In the case of the context parameter to the ui() method, the dictionary values are objects. In the special case where only one object is relevant, it can be passed directly instead of wrapping it in a dictionary. When the ui() method is called from configure_traits() or edit_traits() on a HasTraits object, the relevant object is the HasTraits object whose method was called. For this reason, you do not need to specify the context argument in most calls to configure_traits() or edit_traits(). However, when you call the ui() method on a View object, you must specify the context parameter, so that the ui() method receives references to the objects whose trait attributes you want to modify. So, if configure_traits() figures out the relevant context for you, why call ui() at all? One answer lies in multi-object views. Multi-Object Views A multi-object view is any view whose contents depend on multiple independent model objects, i.e., objects that are not attributes of one another. For example, suppose you are building a real estate listing application, and want to display a window that shows two properties side by side for a comparison of price and features. This is straightforward in Traits UI, as the following example shows: Example  SEQ "Example" \*Arabic 7: Using a multi-object view with a context # multi_object_view.py -- Sample code to show multi-object view # with context from enthought.traits.api import HasTraits, Str, Int, Bool from enthought.traits.ui.api import View, Group, Item # Sample class class House(HasTraits): address = Str bedrooms = Int pool = Bool price = Int # View object designed to display two objects of class 'House' comp_view = View( Group( Group( Item('h1.address', resizable=True), Item('h1.bedrooms'), Item('h1.pool'), Item('h1.price'), show_border=True ), Group( Item('h2.address', resizable=True), Item('h2.bedrooms'), Item('h2.pool'), Item('h2.price'), show_border=True ), orientation = 'horizontal' ), title = 'House Comparison' ) # A pair of houses to demonstrate the View house1 = House(address='4743 Dudley Lane', bedrooms=3, pool=False, price=150000) house2 = House(address='11604 Autumn Ridge', bedrooms=3, pool=True, price=200000) # ...And the actual display command house1.configure_traits(view=comp_view, context={'h1':house1, 'h2':house2}) The resulting window has the desired appearance:  Figure  SEQ "Figure" \*Arabic 6: User interface for  REF _Ref161043936 \h Example 7 For the purposes of this particular example, it makes sense to create a separate Group for each model object, and to use two model objects of the same class. Note, however, that neither is a requirement. Notice that the Item definitions in Example 7 use the same type of extended trait attribute syntax as is supported for the on_trait_change() dynamic trait change notification method. In fact, Item name attributes can reference any trait attribute that is reachable from an object in the context. This is true regardless of whether the context contains a single object or multiple objects. For example: Item('object.axle.chassis.serial_number') Because an Item can refer only to a single trait, do not use extended trait references that refer to multiple traits, since the behavior of such references is not defined. Also, avoid extended trait references where one of the intermediate objects could be None, because there is no way to obtain a valid reference from None. Refer to the Traits User Manual, in the chapter on trait notification, for details of the extended trait name syntax. Include Objects In addition to the Item and Group class, a third building block class for Views exists in Traits UI: the Include class. For the sake of completeness, this section gives a brief description of Include objects and their purpose and usage. However, they are not commonly used as of this writing, and should be considered unsupported pending redesign. In essence, an Include object is a placeholder for a named Group or Item object that is specified outside the Group or View in which it appears. For example, the following two definitions, taken together, are equivalent to the third: Example  SEQ "Example" \*Arabic 8: Using an Include object # This fragment... my_view = View(Group(Item('a'), Item('b')), Include('my_group')) # ...plus this fragment... my_group = Group(Item('c'), Item('d'), Item('e')) #...are equivalent to this: my_view = View(Group(Item('a'), Item('b')), Group(Item('c'), Item('d'), Item('e')) This opens an interesting possibility when a View is part of a model class: any Include objects belonging to that View can be defined differently for different instances or subclasses of that class. This technique is called view parameterization. Controlling the Interface: the Handler Most of the material in the preceding chapters is concerned with the relationship between the model and view aspects of the MVC design pattern as supported by Traits UI. This chapter examines the third aspect: the controller, implemented in Traits UI as an instance of the Handler class. A controller for an MVC-based application is essentially an event handler for GUI events, i.e., for events that are generated through or by the program interface. Such events can require changes to one or more model objects (e.g., because a data value has been updated) or manipulation of the interface itself (e.g., window closure, dynamic interface behavior). In Traits UI, such actions are performed by a Handler object. In the preceding examples in this guide, the Handler object has been implicit: Traits UI provides a default Handler that takes care of a common set of GUI events including window initialization and closure, data value updates, and button press events for the standard Traits UI window buttons (see Section  REF _Ref161204588 \n \h 3.2 on page  PAGEREF _Ref161645084 \h 18). This chapter explains the features of the Traits UI Handler, and shows how to implement custom GUI behaviors by building and instantiating custom subclasses of the Handler class. The final section of the chapter describes several techniques for linking a custom Handler to the window or windows it is designed to control. Backstage: Introducing the UIInfo Object Traits UI supports the MVC design pattern by maintaining the model, view, and controller as separate entities. A single View object can be used to construct windows for multiple model objects; likewise a single Handler can handle GUI events for windows created using different Views. Thus there is no static link between a Handler and any particular window or model object. However, in order to be useful, a Handler must be able to observe and manipulate both its corresponding window and model objects. In Traits UI, this is accomplished by means of the UIInfo object. Whenever Traits UI creates a window or panel from a View, a UIInfo object is created to act as the Handlers reference to that window and to the objects whose trait attributes are displayed in it. Each entry in the Views context (see Section  REF _Ref161204772 \n \h 4.4 on page  PAGEREF _Ref161645097 \h 27) becomes an attribute of the UIInfo object. For example, the UIInfo object created in  REF _Ref161043936 \h Example 7 (on page  PAGEREF _Ref161645426 \h 28) has attributes h1 and h2 whose values are the objects house1 and house2 respectively. In  REF _Ref161043988 \h Example 1 through  REF _Ref117066572 \h Example 6, the created UIInfo object has an attribute object whose value is the object sam. Whenever a window event causes a Handler method to be called, Traits UI passes the corresponding UIInfo object as one of the method arguments. This gives the Handler the information necessary to perform its tasks. Assigning Handlers to Views In accordance with the MVC design pattern, Handlers and Views are separate entities belonging to distinct classes. In order for a custom Handler to provide the control logic for a window, it must be explicitly associated with the View for that window. The Traits UI package provides three ways to accomplish this: Make the Handler an attribute of the View. Provide the Handler as an argument to a display method such as edit_traits(). Define the View as part of the Handler. Binding a Singleton Handler to a View To associate a given custom Handler with all windows produced from a given View, assign an instance of the custom Handler class to the Views handler attribute. The result of this technique  REF _Ref161205081 \h Example 9 is that the window created by the View object is automatically controlled by the specified handler instance. Linking Handler and View at Edit Time It is also possible to associate a custom Handler with a specific window without assigning it permanently to the View. Each of the three Traits UI window-building methods (the configure_traits() and edit_traits() methods of the HasTraits class and the ui() method of the View class) has a handler keyword argument. Assigning an instance of Handler to this argument gives that handler instance control only of the specific window being created by the method call. This assignment overrides the Views handler attribute. Creating a Default View Within a Handler You seldom need to associate a single custom Handler with several different Views or vice versa, although you can in theory and there are cases where it is useful to be able to do so. In most real-life scenarios, a custom Handler is tailored to a particular View with which it is always used. One way to reflect this usage in the program design is to define the View as part of the Handler. The same rules apply as for defining Views within HasTraits objects; for example, a view named trait_view is used as the default view. The Handler class, which is a subclass of HasTraits, overrides the standard configure_traits() and edit_traits() methods; the subclass versions are identical to the originals except that the Handler object on which they are called becomes the default Handler for the resulting windows. Note that for these versions of the display methods, the context keyword parameter is not optional. Handler Subclasses Traits version 3.0 provides two Handler subclasses: ModelView and Controller. Both of these classes are designed to simplify the process of creating an MVC-based application. Both ModelView and Controller extend the Hander class by adding the following trait attributes: modelThe model object for which this handler defines a view and controller. infoThe UIInfo object associated with the actual user interface window or panel for the model object. The model attribute provides convenient access to the model object associated with either subclass. Normally, the model attribute is set in the constructor when an instance of ModelView or Controller is created. The info attribute provides convenient access to the UIInfo object associated with the active user interface view for the handler object. The info attribute is automatically set when the handler objects view is created. Both classes constructors accept an optional model parameter, which is the model object. They also can accept metadata as keyword parameters. ModelView( model = None, **metadata ) Controller( model = None, **metadata ) The difference between the ModelView and Controller classes lies in context dictionary that each one passes to its associated user interface, as described in the following sections. Controller Class The Controller class is normally used when implementing a standard MVC-based design, and plays the controller role in the MVC design pattern. The model role is played by the object referenced by the Controllers model attribute; and the view role is played by the View object associated with the model object. The context dictionary that a Controller object passes to the Views ui() method contains the following entries: objectThe Controllers model object. controllerThe Controller object itself. Using a Controller as the handler class assumes that the model object contains most, if not all, of the data to be viewed. Therefore, the model object is used for the object key in the context dictionary, so that its attributes can be easily referenced with unqualified names (such as Item('name')). ModelView Class The ModelView class is useful when creating a variant of the standard MVC design pattern. In this variant, the ModelView subclass reformulates a number of trait attributes on it model object as properties on the ModelView, usually to convert the models data into a format that is more suited to a user interface. The context dictionary that a ModelView object passes to the Views ui() method contains the following entries: objectThe ModelView object itself. modelThe ModelViews model object. In effect, the ModelView object substitutes itself for the model object in relation to the View object, serving both the controller role and the model role (as a set of properties wrapped around the original model). Because the ModelView object is passed as the contexts object, its attributes can be referenced by unqualified names in the View definition. Writing Handler Methods If you create a custom Handler subclass, depending on the behavior you want to implement, you might override the standard methods of Handler, or you might create methods that respond to changes to specific trait attributes. Overriding Standard Methods The Handler class provides methods that are automatically executed at certain points in the lifespan of the window controlled by a given Handler. By overriding these methods, you can implement a variety of custom window behaviors. The following sequence shows the points at which the Handler methods are called. A UIInfo object is created The Handlers init_info() method is called. Override this method if the handler needs access to viewable traits on the UIInfo object whose values are properties that depend on items in the context being edited. The UI object is created, and generates the actual window. The init() method is called. Override this method if you need to initialize or customize the window.  The position() method is called. Override this method to modify the position of the window (if setting the x and y attributes of the View is insufficient). The window is displayed. Table  SEQ "Table" \*Arabic 7: When Handler methods are called, and when to override them MethodCalled WhenOverride When?apply(self, info)The user clicks the Apply button, and after the changes have been applied to the context objects.To perform additional processing at this point.close(self, info, is_ok)The user requests to close the window, clicking OK, Cancel, or the window close button, menu, or icon.To perform additional checks before destroying the window.closed(self, info, is_ok)The window has been destroyedTo perform additional clean-up tasks.revert(self, info)The user clicks the Revert button, or clicks Cancel in a live window.To perform additional processing.setattr(self, info, object, name, value)The user changes a trait attribute value through the user interface.To perform additional processing, such as keeping a change history. Make sure that the overriding method actually sets the attribute.show_help(self, info, control= None)The user clicks the Help button.To call a custom help handler in addition to or instead of the global help handler, for this window.Reacting to Trait Changes The setattr() method described above is called whenever any trait value is changed in the UI. However, Traits UI also provides a mechanism for calling methods that are automatically executed whenever the user edits a particular trait. While you can use static notification handler methods on the HasTraits object, you might want to implement behavior that concerns only the user interface. In that case, following the MVC pattern dictates that such behavior should not be implemented in the model part of the code. In keeping with this pattern, Traits UI supports user interface notification methods, which must have a signature with the following format: extended_traitname_changed(self, info) This method is called whenever a change is made to the attribute specified by extended_traitname in the context of the View used to create the window (see Section  REF _Ref161204772 \n \h 4.4 on page  PAGEREF _Ref161645115 \h 27), where the dots in the extended trait reference have been replaced by underscores. For example, for a method to handle changes on the salary attribute of the object whose context key is object (the default object), the method name should be object_salary_changed(). By contrast, a subclass of Handler for  REF _Ref161205069 \h Example 8 (on page  PAGEREF _Ref161645485 \h 30) might include a method called h2_price_changed() to be called whenever the price of the second house is edited. Important: These methods are called on window creation. User interface notification methods are called when the window is first created. To differentiate between code that should be executed when the window is first initialized and code that should be executed when the trait actually changes, use the initialized attribute of the UIInfo object (i.e., of the info argument): def object_foo_changed(self, info): if not info.initialized: #code to be executed only when the window is #created else: #code to be executed only when 'foo' changes after #window initialization} #code to be executed in either case The following script, which annotates its windows title with an asterisk (*) the first time a data element is updated, demonstrates a simple use of both an overridden setattr() method and user interface notification method. Example  SEQ "Example" \*Arabic 9: Using a Handler that reacts to trait changes # handler_override.py -- Example of a Handler that overrides # setattr(), and that has a user interface # notification method from enthought.traits.api import HasTraits, Bool from enthought.traits.ui.api import View, Handler class TC_Handler(Handler): def setattr(self, info, object, name, value): Handler.setattr(self, info, object, name, value) info.object._updated = True def object__updated_changed(self, info): if info.initialized: info.ui.title += "*" class TestClass(HasTraits): b1 = Bool b2 = Bool b3 = Bool _updated = Bool(False) view1 = View('b1', 'b2', 'b3', title="Alter Title", handler=TC_Handler(), buttons = ['OK', 'Cancel']) tc = TestClass() tc.configure_traits(view=view1)   Figure  SEQ "Figure" \*Arabic 7: Before and after views of Example 9 Implementing Custom Window Commands Another purpose that you can use a Handler for is to define custom window actions, which can be presented as buttons, menu items, or toolbar buttons. Actions In Traits UI, window commands are implemented as instances of the Action class. Actions can be used in command buttons, menus, and toolbars. Suppose you want to build a window with a custom Recalculate action. Suppose further that you have defined a subclass of Handler called MyHandler to provide the logic for the window. To create the action: Add a method to MyHandler that implements the command logic. This method can have any name (e.g., do_recalc()), but must accept exactly one argument: a UIInfo object. Create an Action instance using the name of the new method, e.g.: recalc = Action(name = "Recalculate", action = "do_recalc") Custom Command Buttons The simplest way to turn an Action into a window command is to add it to the buttons attribute for the View. It appears in the button area of the window, along with any standard buttons you specify. Define the handler method and action, as described in Section  REF _Ref161116897 \n \h 5.4.3.1. Include the new Action in the buttons attribute for the View: View ( #view contents, # , buttons = [ OKButton, CancelButton, recalc ]) Menus and Menu Bars Another way to install an Action such as recalc as a window command is to make it into a menu option. Define the handler method and action, as described in Section  REF _Ref161116897 \n \h 5.4.3.1. If the View does not already include a MenuBar, create one and assign it to the View's menubar attribute. If the appropriate Menu does not yet exist, create it and add it to the MenuBar. Add the Action to the Menu. These steps can be executed all at once when the View is created, as in the following code: View ( #view contents, # , menubar = MenuBar( Menu( my_action, name = 'My Special Menu'))) Toolbars A third way to add an action to a Traits View is to make it a button on a toolbar. Adding a toolbar to a Traits View is similar to adding a menu bar, except that toolbars do not contain menus; they directly contain actions. Define the handler method and the action, as in Section  REF _Ref161116897 \n \h 5.4.3.1 on page  PAGEREF _Ref161116897 \h 40, including a tooltip and an image to display on the toolbar. The image must be a Pyface ImageResource instance; if a path to the image file is not specified, it is assumed to be in an images subdirectory of the directory where ImageResource is used. From enthought.pyface.api import ImageResource recalc = Action(name = "Recalculate", action = "do_recalc", toolip = "Recalculate the results", image = ImageResource("recalc.png")) If the View does not already include a ToolBar, create one and assign it to the View's toolbar attribute. Add the Action to the ToolBar. As with a MenuBar, these steps can be executed all at once when the View is created, as in the following code: View ( #view contents, # , toolbar = ToolBar( my_action)) Traits UI Themes Beginning in Traits 3.0, Traits UI supports using themes to customize the appearance of user interfaces, by applying graphical elements extracted from simple images. For example,  REF _Ref191725456 \h Figure 8 shows an unthemed Traits user interface.  Figure  SEQ "Figure" \*Arabic 8: Unthemed Traits user interface  REF _Ref191725518 \h Figure 9 shows the same user interface with a theme applied to it.  Figure  SEQ "Figure" \*Arabic 9: Themed Traits user interface  REF _Ref191725588 \h Figure 10 shows the same user interface with a different theme applied.  Figure  SEQ "Figure" \*Arabic 10: Theme Traits user interface with alternate theme Theme Data All of the data used by Traits UI for themes is in the form of simple images, a few examples of which are shown in  REF _Ref191726098 \h Figure 11:  Figure  SEQ "Figure" \*Arabic 11: Theme images Any type of JPEG or Portable Network Graphics (PNG) file is supported. In particular, PNG files with alpha information allow smooth compositing of multiple theme images. The left-most image in  REF _Ref191726098 \h Figure 11 is an example of a PNG file containing alpha information. That is, the interior of the rectangle is not gray, but transparent, with a thin alpha gradient shadow around its edges. Themeable Traits UI Elements Theme information can be applied to the following classes of Traits UI objects: Group Item View All of these classes have item_theme and label_theme attributes, which specify the themes for an editor and its label, respectively; the Group class also has a group_theme attribute, which specifies the theme for the group itself. These attributes are defined to be Theme traits, which accept values which are either PyFace ImageResource objects, or strings that specify an image file to use. In the case of string values, no path information need be included. The path to the image file is assumed to be the images subdirectory or images.zip file located in the same directory as the source file containing the string. However, if the string begins with an @ (at-sign), the string is assumed to be a reference to an image in the default image library provided with PyFace. The item_theme and label_theme attributes are transferred via containment. That is, if an Item object has an item_theme defined, that value is used for the Item objects editor. If item_theme is not defined on the Item object, the item_theme value from the containing Group is used, and so on up to the item_theme value on containing View, if necessary. Therefore, it is possible to set the item and label themes for a whole user interface at the view level. The group_theme attribute value is not transferred through containment, but nested groups automatically visually inherit the theme of the containing group. You can, of course, explicitly specify theme information at each level of a nested group hierarchy. Adding Themes to a UI To add themes to a Traits user interface, you add the theme-related attributes to the View, Group, and Item definitions.  REF _Ref191728658 \h Example 10 shows the code for the user interface shown in  REF _Ref191725456 \h Figure 8. Example  SEQ "Example" \*Arabic 10: Traits UI without themes # unthemed.py -- Example of a Traits UI without themes from enthought.traits.api import HasTraits, Str, Range, Float, Enum from enthought.traits.ui.api import View, Group, Item, Label class Test ( HasTraits ): name = Str age = Range( 1, 100 ) weight = Float gender = Enum( 'Male', 'Female' ) view = View( Group( Label( 'An Unthemed Label' ), Item( 'name' ), Item( 'age' ), Item( 'weight' ), Item( 'gender' ) ), title = 'Unthemed Traits UI', ) Test().configure_traits()  REF _Ref191794618 \h Example 11 shows the code for the user interface shown in  REF _Ref191725518 \h Figure 9, which is essentially the same as in  REF _Ref191728658 \h Example 10, but with theme data added. Example  SEQ "Example" \*Arabic 11: Traits UI with themes # themed.py -- Example of a Traits UI with themes from enthought.traits.api import HasTraits, Str, Range, Float, Enum from enthought.traits.ui.api import View, Group, Item, Label from enthought.traits.ui.wx.themed_text_editor import \ ThemedTextEditor class Test ( HasTraits ): name = Str age = Range( 1, 100 ) weight = Float gender = Enum( 'Male', 'Female' ) view = View( Group( Group( Label( 'A Themed Label', '@GF6' ), Item( 'name' ), Item( 'age' ), Item( 'weight', editor=ThemedTextEditor()), Item( 'gender' ), group_theme = '@GD0' ), group_theme = '@G', item_theme = '@B0B', label_theme = '@BEA' ), title = 'Themed Traits UI', ) Test().configure_traits() This example uses the following theme-related items: The group_theme, item_theme, and label_theme attributes are explicitly specified. The Label constructor takes an optional second argument (in this case '@GF6'), which specifies the item_theme information for the Label object. (Label is a subclass of Item.) The item for weight uses a ThemedTextEditor factory; this isnt strictly necessary, but illustrates the use of a themed editor factory. For more information on themed editor factories, refer to Section  REF _Ref191800790 \n \h 8.3,  REF _Ref191800801 \h Extra Trait Editor Factories, and to the Traits API Reference. The example contains an extra Group level, and shows the results of two nested group_theme values ('@G' and '@GD0'). The outermost group_theme value ('@G') specifies the gray background, while the innermost group_theme value ('@GD0') specifies the light gray rectangle drawn over it. This combination demonstrates the automatic compositing of themes, since the rounded rectangle is transparent except where the light gray band appears. The theme data strings use the @ prefix to reference images from the default image library. Introduction to Trait Editor Factories The preceding code samples in this User Guide have been surprisingly simple considering the sophistication of the interfaces that they produce. In particular, no code at all has been required to produce appropriate widgets for the Traits to be viewed or edited in a given window. This is one of the strengths of Traits UI: usable interfaces can be produced simply and with a relatively low level of UI programming expertise. An even greater strength lies in the fact that this simplicity does not have to be paid for in lack of flexibility. Where a novice Traits UI programmer can ignore the question of widgets altogether, a more advanced one can select from a variety of predefined interface components for displaying any given Trait. Furthermore, a programmer who is comfortable both with Traits UI and with UI programming in general can harness the full power and flexibility of the underlying GUI toolkit from within Traits UI. The secret behind this combination of simplicity and flexibility is a Traits UI construct called a trait editor factory. A trait editor factory encapsulates a set of display instructions for a given trait type, hiding GUI-toolkit-specific code inside an abstraction with a relatively straightforward interface. Furthermore, every predefined trait type in the Traits package has a predefined trait editor factory that is automatically used whenever the trait is displayed, unless you specify otherwise. Consider the following script and the window it creates: Example  SEQ "Example" \*Arabic 12: Using default trait editors # default_trait_editors.py -- Example of using default # trait editors from enthought.traits.api import HasTraits, Str, Range, Bool from enthought.traits.ui.api import View, Item class Adult(HasTraits): first_name = Str last_name = Str age = Range(21,99) registered_voter = Bool traits_view = View(Item(name='first_name'), Item(name='last_name'), Item(name='age'), Item(name='registered_voter')) alice = Adult(first_name='Alice', last_name='Smith', age=42, registered_voter=True) alice.configure_traits()  Figure  SEQ "Figure" \*Arabic 12: User interface for  REF _Ref161214237 \h Example 12 Notice that each trait is displayed in an appropriate widget, even though the code does not explicitly specify any widgets at all. The two Str traits appear in text boxes, the Range is displayed using a combination of a text box and a slider, and the Bool is represented by a checkbox. Each implementation is generated by the default trait editor factory (TextEditor, RangeEditor and BooleanEditor respectively) associated with the trait type. Traits UI is by no means limited to these defaults. There are two ways to override the default representation of a trait attribute in a Traits UI window: Explicitly specifying an alternate trait editor factory Specifying an alternate style for the editor generated by the factory The remainder of this chapter examines these alternatives more closely. Specifying an Alternate Trait Editor Factory As of this writing the Traits UI package includes the following predefined trait editor factories:  REF ArrayEditor() \h ArrayEditor(), page  PAGEREF _Ref182908620 \h 58  REF _Ref182908648 \h BooleanEditor(), page  PAGEREF _Ref182908661 \h 60  REF _Ref182908700 \h ButtonEditor(), page  PAGEREF _Ref182908717 \h 61  REF _Ref182908732 \h CheckListEditor(), p.  PAGEREF _Ref182908747 \h 62  REF _Ref182908763 \h CodeEditor(), page  PAGEREF _Ref182908779 \h 63  REF _Ref161644779 \h ColorEditor(), page  PAGEREF _Ref161644779 \h 64  REF _Ref182908817 \h CompoundEditor(), p.  PAGEREF _Ref182908830 \h 67  REF _Ref182908935 \h CustomEditor(), page  PAGEREF _Ref182908948 \h 92  REF _Ref182908979 \h NDEditor() Suitable forInstance traitsDefault for(none)Required parameters(none)Optional parametersdrag_target, drop_target, image DNDEditor() generates an editor that represents a file or a HasTraits instance as an image that supports dragging and dropping. Depending on the editor style, the editor can be a drag source (the user can set the value of the trait attribute by dragging a file or object onto the editor, for example, from a tree editor), or drop target (the user can drag from the editor onto another target). Table 9: Drag-and-drop editor style variations Editor StyleDrag Source?Drop Target?SimpleYesYesCustomNoYesRead-onlyYesNoKeyBindingEditor() The KeyBindingEditor() factory differs from other trait editor factories because it generates an editor, not for a single attribute, but for an object of a particular class, enthought.traits.ui.key_bindings.KeyBindings. A KeyBindings object is a list of bindings between key codes and handler methods. You can specify a KeyBindings object as an attribute of a View. When the user presses a key while a View has input focus, the user interface searches the View for a KeyBindings that contains a binding that corresponds to the key press; if such a binding does not exist on the View, it searches enclosing Views in order, and uses the first matching binding, if any. If it does not find any matching bindings, it ignores the key press. A key binding editor is a separate dialog box that displays the string representation of each key code and a description of the corresponding method. The user can click a text box, and then press a key or key combination to associate that key press with a method.  Figure 50: Key binding editor dialog box The following code example creates a user interface containing a code editor with associated key bindings, and a button that invokes the key binding editor. Example 17: Code editor with key binding editor # key_bindings.py -- Example of a code editor with a # key bindings editor from enthought.traits.api \ import Button, Code, HasPrivateTraits, Str from enthought.traits.ui.api \ import View, Item, Group, Handler, CodeEditor from enthought.traits.ui.key_bindings \ import KeyBinding, KeyBindings key_bindings = KeyBindings( KeyBinding( binding1 = 'Ctrl-s', description = 'Save to a file', method_name = 'save_file' ), KeyBinding( binding1 = 'Ctrl-r', description = 'Run script', method_name = 'run_script' ), KeyBinding( binding1 = 'Ctrl-k', description = 'Edit key bindings', method_name = 'edit_bindings' ) ) # Traits UI Handler class for bound methods class CodeHandler ( Handler ): def save_file ( self, info ): info.object.status = "save file" def run_script ( self, info ): info.object.status = "run script" def edit_bindings ( self, info ): info.object.status = "edit bindings" key_bindings.edit_traits() class KBCodeExample ( HasPrivateTraits ): code = Code status = Str kb = Button(label='Edit Key Bindings') view = View( Group ( Item( 'code', style = 'custom', resizable = True ), Item('status', style='readonly'), 'kb', orientation = 'vertical', show_labels = False, ), id = 'KBCodeExample', key_bindings = key_bindings, title = 'Code Editor With Key Bindings', resizable = True, handler = CodeHandler() ) def _kb_fired( self, event ): key_bindings.edit_traits() if __name__ == '__main__': KBCodeExample().configure_traits() TableEditor() Suitable forList(InstanceType)Default for(none)Required parameterscolumns or columns_nameOptional parametersSee Traits API Reference, enthought.traits.ui.wx.table_editor .ToolkitEditorFactory attributes.TableEditor() generates a editor that displays instances in a list as rows in a table, with attributes of the instances as values in columns. You must specify the columns in the table. Optionally, you can provide filters for filtering the set of displayed items, and you can specify a wide variety of options for interacting with and formatting the table.  Figure 51: Table editor To see the code that results in Figure 51, refer to TableEditor_demo.py in the demos/TraitsUIDemo/StandardEditors subdirectory of the Traits UI package. This example demonstrates object columns, expression columns, filters, searching, and adding and deleting rows. The parameters for TableEditor() can be grouped in several broad categories, described in the following sections. Specifying Columns Managing Items Editing the Table Defining the Layout Defining the Format Other User Interactions Specifying Columns You must provide the TableEditor() factory with a list of columns for the table. You can specify this list directly, as the value of the columns parameter, or indirectly, in an extended context attribute referenced by the columns_name parameter. The items in the list must be instances of enthought.traits.ui.api.TableColumn, or of a subclass of TableColumn. Some subclasses of TableColumn that are provided by the Traits UI package include ObjectColumn, ListColumn, NumericColumn, and ExpressionColumn. (See the Traits API Reference for details about these classes.) In practice, most columns are derived from one of these subclasses, rather than from TableColumn. For the usual case of editing trait attributes on objects in the list, use ObjectColumn. You must specify the name parameter to the ObjectColumn() constructor, referencing the name of the trait attribute to be edited. You can specify additional columns that are not initially displayed using the other_columns parameter. If the configurable parameter is True (the default), a Set user preferences for table icon () appears on the tables toolbar. When the user clicks this icon, a dialog box opens that enables the user to select and order the columns displayed in the table, as shown in Figure 52. (The dialog box is implemented using a set editor; see Section 8.1.20 on page 86.) Any columns that were specified in the other_columns parameter are listed in the left list box of this dialog box, and can be displayed by moving them into the right list box.  Figure 52: Column selection dialog box for a table editor Managing Items Table editors support several mechanisms to help users locate items of interest. Organizing Items Table editors provide two mechanisms for the user to organize the contents of a table: sorting and reordering. The user can sort the items based on the values in a column, or the user can manually order the items. Usually, only one of these mechanisms is used in any particular table, although the Traits UI package does not enforce a separation. If the user has manually ordered the items, sorting them would throw away that effort. If the reorderable parameter is True, Move up () and Move down () icons appear in the table toolbar. Clicking one of these icons changes the position of the selected item. If the sortable parameter is True (the default), then the user can sort the items in the table based on the values in a column by Control-clicking the header of that column. On the first click, the items are sorted in ascending order. The characters >> appear in the column header to indicate that the table is sorted ascending on this columns values. On the second click, the items are sorted descending order. The characters << appear in the column header to indicate that the table is sorted descending on this columns values. On the third click, the items are restored to their original order, and the column header is undecorated. If the sort_model parameter is true, the items in the list being edited are sorted when the table is sorted. The default value is False, in which case, the list order is not affected by sorting the table. If sortable is True and sort_model is False, then a Do not sort columns icon () appears in the table toolbar. Clicking this icon restores the original sort order. If the reverse parameter is True, then the items in the underlying list are maintained in the reverse order of the items in the table (regardless of whether the table is sortable or reorderable). Filtering and Searching You can provide an option for the user to apply a filter to a table, so that only items that pass the filter are displayed. This feature can be very useful when dealing with lengthy lists. You can specify a filter to apply to the table either directly, or via another trait. Table filters must be instances of enthought.traits.ui.api.TableFilter, or of a subclass of TableFilter. Some subclasses of TableFilter that are provided by the Traits UI package include EvalTableFilter, RuleTableFilter, and MenuTableFilter. (See the Traits API Reference for details about these classes.) The Traits UI package also provides instances of these filter classes as templates, which cannot be edited or deleted, but which can be used as models for creating new filters. The filter parameter specifies a filter that is applied to the table when it is first displayed. The filter_name parameter specifies an extended trait name for a trait that is either a table filter object or a callable that accepts an object and returns True if the object passes the filter criteria, or false if it does not. You can use filter_name to embed a view of a table filter in the same view as its table. You can specify use the filters parameter to specify a list of table filters that are available to apply to a table. When filters is specified, a drop-down list box appears in the table toolbar, containing the filters that are available for the user to apply. When the user selects a filter, it is automatically applied to the table. A status message to the right of the filters list indicates what subset of the items in the table is currently displayed. A special item in the filter list, named Customize, is always provided; clicking this item opens a dialog box that enables the user to create new filters, or to edit or delete existing filters (except templates). You can also provide an option for the user to use filters to search the table. If you set the search parameter to an instance of TableFilter (or of a subclass), a Search table icon () appears on the table toolbar. Clicking this icon opens a Search for dialog box, which enables the user to specify filter criteria, to browse through matching items, or select all matching items. Interacting with Items As the user clicks in the table, you may wish to enable certain program behavior. The selection_mode parameter specifies how the user can make selections in the grid: cellA single cell at a time cellsMultiple cells columnA single column at a time columnsMultiple columns rowA single row at a time rowsMultiple rows You can use the selected parameter to specify the name of a trait attribute in the current context to synchronize with the users current selection. For example, you can enable or disable menu items or toolbar icons depending on which item is selected. The synchronization is two-way; you can set the attribute referenced by selected to force the table to select a particular item. You can use the selected_indices parameter to specify the name of a trait attribute in the current context to synchronize with the indices of the table editor selection. The content of the selection depends on the selection_mode value: cellThe selection is a tuple of the form (object, column_name), where object is the object contains the selected cell, and column_name is the name of the column the cell is in. If there is no selection, the tuple is (None, ''). cellsThe selection is a list of tuples of the form (object, column_name), with one tuple for each selected cell, in order from top to bottom and left to right. If there is no selection, the list is empty. columnThe selection is the name of the selected column, or the empty string if there is no selection. columnsThe selection is a list containing the names of the selected columns, in order from left to right. If there is no selection, the list is empty. rowThe selection is either the selected object or None if nothing is selected in the table. rowsThe selection is a list of the selected objects, in ascending row order. If there is no selection, the list is empty. The on_select and on_dclick parameters are callables to invoke when the user selects or double-clicks an item, respectively. You can define a shortcut menu that opens when the user right-clicks an item. Use the menu parameter to specify a Traits UI or PyFace Menu, containing Action objects for the menu commands. Editing the Table The Boolean editable parameter controls whether the table or its items can be modified in any way. This parameter defaults to True, except when the style is readonly. Even when the table as a whole is editable, you can control whether individual columns are editable through the editable attribute of TableColumn. Adding Items To enable users to add items to the table, specify as the row_factory parameter a callable that generates an object that can be added to the list in the table; for example, the class of the objects in the table. When row_factory is specified, an Insert new item icon () appears in the table toolbar, which generates a new row in the table. Optionally, you can use row_factory_args and row_factory_kw to specify positional and keyword arguments to the row factory callable. To save users the trouble of mousing to the toolbar, you can enable them to add an item by selecting the last row in the table. To do this, set auto_add to True. In this case, the last row is blank until the user sets values. Pressing Enter creates the new item and generates a new, blank last row. Deleting Items The deletable parameter controls whether items can be deleted from the table. This parameter can be a Boolean (defaulting to False) or a callable; the callable must take an item as an argument and handle deleting it. If deletable is not False, a Delete current item icon () appears on the table toolbar; clicking it deletes the item corresponding to the row that is selected in the table. Modifying Items The user can modify items in two ways. For columns that are editable, the user can change an items value directly in the table. The editor used for each attribute in the table is the simple style of editor for the corresponding trait. Alternatively, you can specify a View for editing instances, using the edit_view parameter. The resulting user interface appears in a sub-panel to the right or below the table (depending on the orientation parameter). You can specify a handler to use with the view, using edit_view_handler. You can also specify the subpanels height and width, with edit_view_height and edit_view_width. Defining the Layout Some of the parameters for the TableEditor() factory affect global aspects of the display of the table. auto_sizeIf True, the cells of the table automatically adjust to the optimal size based on their contents. orientationThe layout of the table relative to its associated editor pane. Can be horizontal or vertical. rowsThe number of visible rows in the table. show_column_labelsIf True (the default), displays labels for the columns. You can specify the labels to use in the column definitions; otherwise, a user friendly version of the trait attribute name is used. show_toolbarIf False, the table toolbar is not displayed, regardless of whether other settings would normally create a toolbar. The default is True. Defining the Format The TableEditor() factory supports a variety of parameters to control the visual formatting of the table, such as colors, fonts, and sizes for lines, cells, and labels. For details, refer to the Traits API Reference, enthought.traits.ui.wx.table_editor.ToolkitEditorFactory attributes. You can also specify formatting options for individual table columns when you define them. Other User Interactions The table editor supports additional types of user interaction besides those controlled by the factory parameters. Column draggingThe user can reorganize the column layout of a table editor by clicking and dragging a column label to its new location. If you have enabled user preferences for the view and table editor (by specifying view and item IDs), the new column layout is persisted across user sessions. Column resizingThe user can resize a column by dragging the column separator (in one of the data rows) to a new position. Because of the column-dragging support, clicking the column separator in the column label row does not work. Data draggingThe user can drag the contents of any cell by clicking and dragging. TabularEditor() Suitable forlists, arrays, and other large sequences of objectsDefault for(none)Required parametersadapterOptional parametersactivated, clicked, column_clicked, dclicked, drag_move, editable, horizontal_lines, images, multi_select, operations, right_clicked, right_dclicked, selected, selected_row, show_titles, vertical_linesThe TabularEditor() factory can be used for many of the same purposes as the TableEditor() factory, that is, for displaying a table of attributes of lists or arrays of objects. While similar in function, each editor has its own advantages and disadvantages. Some of the advantages of the tabular editor are: Very fast: The tabular editor uses a virtual model, which accesses data from the underlying model only as needed. For example, if you have a million-element array, but can display only 50 rows at a time, the editor requests only 50 elements of data at a time. Very flexible data model: The editor uses an adapter model to interface with the underlying data. This strategy allows it to easily deal with many types of data representation, from list of objects, to arrays of numbers, to tuples of tuples, and many other formats. Supports useful data operations, including: Moving the selection up and down using the keyboard arrow keys. Moving rows up and down using the keyboard. Inserting and deleting items using the keyboard. Initiating editing of items using the keyboard. Dragging and dropping of table items to and from the editor, including support for both copy and move operations for single and multiple items. Visually appealing: The tabular editor, in general, uses the underlying operating systems native table or grid control, and as a result often looks better than the control used by the table editor. Supports displaying text and images in any cell. However, the images displayed must be all the same size for optimal results. Some of the disadvantages of the tabular editor relative to the table editor are: Not as full-featured: The table editor includes support for arbitrary data filters, searches, and different types of sorting. These differences may narrow as features are added to the tabular editor. Limited data editing capabilities: The tabular editor supports editing only textual values, whereas the table editor supports a wide variety of column editors, and can be extended with more as needed. This is due to limitations of the underlying native control used by the tabular editor. TabularAdapter The tabular editor works in conjunction with an adapter class, derived from TabularAdapter. The tabular adapter interfaces between the tabular editor and the data being displayed. The tabular adapter is the reason for the flexibility and power of the tabular editor to display a wide variety of data. The most important attribute of TabularAdapter is columns, which is list of columns to be displayed. Each entry in the columns list can be either a string, or a tuple consisting of a string and another value, which can be of any type. The string is used as the label for the column. The second value in the tuple, called the column ID, identifies the column to the adapter. It is typically a trait attribute name or an integer index, but it can be any value appropriate to the adapter. If only a string is specified for an entry, then the index of the entry within the columns list is used as that entrys column ID. Attributes on TabularAdapter control the appearance of items, and aspects of interaction with items, such as whether they can be edited, and how they respond to dragging and dropping. Setting any of these attributes on the adapter subclass sets the global behavior for the editor. Refer to the Traits API Reference for details of the available attributes. You can also specify these attributes for a specific class or column ID, or combination of class and column ID. When the TabularAdapter needs to look up the value of one of its attributes for a specific item in the table, it looks for attributes with the following naming conventions in the following order: classname_columnid_attribute classname_attribute columnid_attribute attribute For example, to find the text_color value for an item whose class is Person and whose column ID is age, the get_text_color() method looks for the following attributes in sequence, and returns the first value it finds: Person_age_text_color Person_text_color age_text_color text_color Note that the classname can be the name of a base class, searched in the method resolution order (MRO) for the items class. So for example, if the item were a direct instance of Employee, which is a subclass of Person, then the Person_age_text_color attribute would apply to that item (as long as there were no Employee_age_text_color attribute). The Tabular Editor User Interface Error! Reference source not found. shows an example of a tabular editor on Microsoft Windows, displaying information about source files in the Traits package. This example includes a column that contains an image for files that meet certain conditions.  Figure 53: Tabular editor on MS Windows Depending on how the tabular editor is configured, certain keyboard interactions may be available. For some interactions, you must specify that the corresponding operation is allowed by including the operation name in the operations list parameter of TabularEditor(). Up arrow: Selects the row above the currently selected row. Down arrow: Selects the row below the currently selected row. Page down: Appends a new item to the end of the list (append operation). Left arrow: Moves the currently selected row up one line (move operation). Right arrow: Moves the currently selected row down one line (move operation). Backspace, Delete: Deletes from the list all items in the current selection (delete operation). Enter, Escape: Initiates editing on the current selection (edit operation). Insert: Inserts a new item before the current selection (insert operation). The append, move, edit, and insert operations can occur only when a single item is selected. The delete operation works for one or more items selected. Depending on how the editor and adapter are specified, drag and drop operations may be available. If the user selects multiple items and drags one of them, all selected items are included in the drag operation. If the user drags a non-selected item, only that item is dragged. The editor supports both drag-move and drag-copy semantics. A drag-move operation means that the dragged items are sent to the target and are removed from the list displayed in the editor. A drag-copy operation means that the dragged items are sent to the target, but are not deleted from the list data. TreeEditor() Suitable forInstanceDefault for(none)Required parametersnodes (required except for shared editors; see Section 8.2.7.2.5)Optional parametersauto_open, editable, editor, hide_root, icon_size, lines_mode, on_dclick, on_select, orientation, selected, shared_editor, show_icons TreeEditor() generates a hierarchical tree control, consisting of nodes. It is useful for cases where objects contain lists of other objects. The tree control is displayed in one pane of the editor, and a user interface for the selected object is displayed in the other pane. The layout orientation of the tree and the object editor is determined by the orientation parameter of TreeEditor(), which can be horizontal or vertical. You must specify the types of nodes that can appear in the tree using the nodes parameter, which must be a list of instances of TreeNode (or of subclasses of TreeNode).  Figure 54: Tree editor The following example shows the code that produces the editor shown in Figure 54. Example 18: Code for example tree editor # tree_editor.py -- Example of a tree editor from enthought.traits.api \ import HasTraits, Str, Regex, List, Instance from enthought.traits.ui.api \ import TreeEditor, TreeNode, View, Item, VSplit, \ HGroup, Handler, Group from enthought.traits.ui.menu \ import Menu, Action, Separator from enthought.traits.ui.wx.tree_editor \ import NewAction, CopyAction, CutAction, \ PasteAction, DeleteAction, RenameAction # DATA CLASSES class Employee ( HasTraits ): name = Str( '' ) title = Str phone = Regex( regex = r'\d\d\d-\d\d\d\d' ) def default_title ( self ): self.title = 'Senior Engineer' class Department ( HasTraits ): name = Str( '' ) employees = List( Employee ) class Company ( HasTraits ): name = Str( '' ) departments = List( Department ) employees = List( Employee ) class Owner ( HasTraits ): name = Str( '' ) company = Instance( Company ) # INSTANCES jason = Employee( name = 'Jason', title = 'Engineer', phone = '536-1057' ) mike = Employee( name = 'Mike', title = 'Sr. Marketing Analyst', phone = '536-1057' ) dave = Employee( name = 'Dave', title = 'Sr. Engineer', phone = '536-1057' ) susan = Employee( name = 'Susan', title = 'Engineer', phone = '536-1057' ) betty = Employee( name = 'Betty', title = 'Marketing Analyst' ) owner = Owner( name = 'wile', company = Company( name = 'Acme Labs, Inc.', departments = [ Department( name = 'Marketing', employees = [ mike, betty ] ), Department( name = 'Engineering', employees = [ dave, susan, jason ] ) ], employees = [ dave, susan, mike, betty, jason ] ) ) # View for objects that aren't edited no_view = View() # Actions used by tree editor context menu def_title_action = Action(name='Default title', action = 'object.default') dept_action = Action( name='Department', action='handler.employee_department(editor,object)') # View used by tree editor employee_view = View( VSplit( HGroup( '3', 'name' ), HGroup( '9', 'title' ), HGroup( 'phone' ), id = 'vsplit' ), id = 'enthought.traits.doc.example.treeeditor', dock = 'vertical' ) class TreeHandler ( Handler ): def employee_department ( self, editor, object ): dept = editor.get_parent( object ) print '%s works in the %s department.' %\ ( object.name, dept.name ) # Tree editor tree_editor = TreeEditor( nodes = [ TreeNode( node_for = [ Company ], auto_open = True, children = '', label = 'name', view = View( Group('name', orientation='vertical', show_left=True )) ), TreeNode( node_for = [ Company ], auto_open = True, children = 'departments', label = '=Departments', view = no_view, add = [ Department ] ), TreeNode( node_for = [ Company ], auto_open = True, children = 'employees', label = '=Employees', view = no_view, add = [ Employee ] ), TreeNode( node_for = [ Department ], auto_open = True, children = 'employees', label = 'name', menu = Menu( NewAction, Separator(), DeleteAction, Separator(), RenameAction, Separator(), CopyAction, CutAction, PasteAction ), view = View( Group ('name', orientation='vertical', show_left=True )), add = [ Employee ] ), TreeNode( node_for = [ Employee ], auto_open = True, label = 'name', menu=Menu( NewAction, Separator(), def_title_action, dept_action, Separator(), CopyAction, CutAction, PasteAction, Separator(), DeleteAction, Separator(), RenameAction ), view = employee_view ) ] ) # The main view view = View( Group( Item( name = 'company', id = 'company', editor = tree_editor, resizable = True ), orientation = 'vertical', show_labels = True, show_left = True, ), title = 'Company Structure', id = \ 'enthought.traits.ui.tests.tree_editor_test', dock = 'horizontal', drop_class = HasTraits, handler = TreeHandler(), buttons = [ 'Undo', 'OK', 'Cancel' ], resizable = True, width = .3, height = .3 ) if __name__ == '__main__': owner.configure_traits( view = view ) Defining Nodes For details on the attributes of the TreeNode class, refer to the Traits API Reference. You must specify the classes whose instances the node type applies to. Use the node_for attribute of TreeNode to specify a list of classes; often, this list contains only one class. You can have more than one node type that applies to a particular class; in this case, each object of that class is represented by multiple nodes, one for each applicable node type. In Figure 54, one Company object is represented by the nodes labeled Acme Labs, Inc., Departments, and Employees. A Node Type without Children To define a node type without children, set the children attribute of TreeNode to the empty string. In Example 16, the following lines define the node type for the node that displays the company name, with no children: TreeNode( node_for = [ Company ], auto_open = True, children = '', label = 'name', view = View( Group('name', orientation='vertical', show_left=True )) ), A Node Type with Children To define a node type that has children, set the children attribute of TreeNode to the (extended) name of a trait on the object that it is a node for; the named trait contains a list of the nodes children. In Example 16, the following lines define the node type for the node that contains the departments of a company. The node type is for instances of Company, and departments is a trait attribute of Company. TreeNode( node_for = [ Company ], auto_open = True, children = 'departments', label = '=Departments', view = no_view, add = [ Department ] ), Setting the Label of a Tree Node The label attribute of Tree Node can work in either of two ways: as a trait attribute name, or as a literal string. If the value is a simple string, it is interpreted as the extended trait name of an attribute on the object that the node is for, whose value is used as the label. This approach is used in the code snippet in Section 8.2.7.1.1. If the value is a string that begins with an equals sign (=), the rest of the string is used as the literal label. This approach is used in the code snippet in Section 8.2.7.1.2. You can also specify a callable to format the label of the node, using the formatter attribute of TreeNode. Defining Operations on Nodes You can use various attributes of TreeNode to define operations or behavior of nodes. Shortcut Menus on Nodes Use the menu attribute of TreeNode to define a shortcut menu that opens when the user right-clicks on a node. The value is a Traits UI or PyFace menu containing Action objects for the menu commands. In Example 16, the following lines define the node type for employees, including a shortcut menu for employee nodes: TreeNode( node_for = [ Department ], auto_open = True, children = 'employees', label = 'name', menu = Menu( NewAction, Separator(), DeleteAction, Separator(), RenameAction, Separator(), CopyAction, CutAction, PasteAction ), view = View( Group ('name', orientation='vertical', show_left=True )), add = [ Employee ] ), Allowing the Hierarchy to Be Modified If a node contains children, you can allow objects to be added to its set of children, through operations such as dragging and dropping, copying and pasting, or creating new objects. Two attributes control these operations: add and move. Both are lists of classes. The add attribute contains classes that can be added by any means, including creation. The code snippet in the preceding section (8.2.7.2.1) includes an example of the add attribute. The move attribute contains classes that can be dragged and dropped, but not created. The move attribute need not be specified if all classes that can be moved can also be created (and therefore are specified in the add value). NOTE: The add attribute alone is not enough to create objects. Specifying the add attribute makes it possible for objects of the specified classes to be created, but by itself, it does not provide a way for the user to do so. In the code snippet in the preceding section (8.2.7.2.1), NewAction in the Menu constructor call defines a New > Employee menu item that creates Employee objects. In the example tree editor, users can create new employees using the New > Employee shortcut menu item, and they can drag an employee node and drop it on a department node. The corresponding object becomes a member of the appropriate list. You can specify the label that appears on the New submenu when adding a particular type of object, using the name attribute of TreeNode. Note that you set this attribute on the tree node type that will be added by the menu item, not the node type that contains the menu item. For example, to change New > Employee to New > Worker, set name = 'Worker' on the tree node whose node_for value contains Employee. If this attribute is not set, the class name is used. You can determine whether a node or its children can be copied, renamed, or deleted, by setting the following attributes on TreeNode: copy: If True, the objects children can be copied. delete: If True, the objects children can be deleted. delete_me: If True, the object can be deleted. rename: If True, the objects children can be renamed. rename_me: If True, the object can be renamed. All of these attributes default to True. As with add, you must also define actions to perform these operations. Behavior on Nodes As the user clicks in the tree, you may wish to enable certain program behavior. You can use the selected parameter to specify the name of a trait attribute on the current context object to synchronize with the users current selection. For example, you can enable or disable menu items or toolbar icons depending on which node is selected. The synchronization is two-way; you can set the attribute referenced by selected to force the tree to select a particular node. The on_select and on_dclick parameters are callables to invoke when the user selects or double-clicks a node, respectively. Expanding and Collapsing Nodes You can control some aspects of expanding and collapsing of nodes in the tree. The integer auto_open parameter of TreeEditor() determines how many levels are expanded below the root node, when the tree is first displayed. For example, if auto_open is 2, then two levels below the root node are displayed (whether or not the root node itself is displayed, which is determined by hide_root). The Boolean auto_open attribute of TreeNode determines whether nodes of that type are expanded when they are displayed (at any time, not just on initial display of the tree). For example, suppose that a tree editor has auto_open setting of 2, and contains a tree node at level 3 whose auto_open attribute is True. The nodes at level 3 are not displayed initially, but when the user expands a level 2 node, displaying the level 3 node, thats nodes children are automatically displayed also. Similarly, the number of levels of nodes initially displayed can be greater than specified by the tree editors auto_open setting, if some of the nodes have auto_open set to True. If the auto_close attribute of TreeNode is set to True, then when a node is expanded, any siblings of that node are automatically closed. In other words, only one node of this type can be expanded at a time. Editing Objects One pane of the tree editor displays a user interface for editing the object that is selected in the tree. You can specify a View to use for each node type using the view attribute of TreeNode. If you do not specify a view, then the default view for the object is displayed. To suppress the editor pane, set the editable parameter of TreeEditor() to False; in this case, the objects represented by the nodes can still be modified by other means, such as shortcut menu commands. You can define multiple tree editors that share a single editor pane. Each tree editor has its own tree pane. Each time the user selects a different node in any of the sharing tree controls, the editor pane updates to display the user interface for the selected object. To establish this relationship, do the following: Call TreeEditor() with the shared_editor parameter set to True, without defining any tree nodes. The object this call returns defines the shared editor pane. For example: my_shared_editor_pane = TreeEditor(shared_editor=True) For each editor that uses the shared editor pane: Set the shared_editor parameter of TreeEditor() to True. Set the editor parameter of TreeEditor() to the object returned in Step 1. For example: shared_tree_1 = TreeEditor(shared_editor = True, editor = my_shared_editor_pane, nodes = [ TreeNode( # ) ] ) shared_tree_2 = TreeEditor(shared_editor = True, editor = my_shared_editor_pane, nodes = [ TreeNode( # ) ] ) Defining the Format Several parameters to TreeEditor() affect the formatting of the tree control: show_icons: If True (the default), icons are displayed for the nodes in the tree. icon_size: A two-integer tuple indicating the size of the icons for the nodes. lines_mode: Determines whether lines are displayed between related nodes. The valid values are on, off, and appearance (the default). When set to appearance, lines are displayed except on Posix-based platforms. hide_root: If True, the root node in the hierarchy is not displayed. If this parameter were specified as True in Example 16, the node in Figure 54 that is labeled Acme Labs, Inc. would not appear. Additionally, several attributes of TreeNode also affect the display of the tree: icon_path: A directory path to search for icon files. This path can be relative to the module it is used in. icon_item: The icon for a leaf node. icon_open: The icon for a node with children whose children are displayed. icon_group: The icon for a node with children whose children are not displayed. The wxWidgets implementation automatically detects the bitmap format of the icon. Extra Trait Editor Factories The enthought.traits.ui.wx package defines a few editor factories that are specific to the wxWidgets toolkit, some of which are also specific to the Microsoft Windows platform. These editor factories are not necessarily implemented for other GUI toolkits or other operating system platforms. AnimatedGIFEditor() Suitable forFileDefault for(none)Required parameters(none)Optional parametersplayingAnimatedGIFEditor() generates a display of the contents of an animated GIF image file. The playing parameter determines whether the image is animated or static. ArrayViewEditor() Suitable for2-D Array, 2-D CArrayDefault for(none)Required parameters(none)Optional parametersformat, show_index, titles, transposeArrayViewEditor() generates a tabular display for an array. It is suitable for use with large arrays, which do not work well with the editors generated by ArrayEditor(). All styles of the editor have the same appearance.  Figure 55: Array view editor FlashEditor() Suitable forstring traits, Enum(string values)Default for(none)Required parameters(none)Optional parameters (none)FlashEditor() generates a display of an Adobe Flash Video file, using an ActiveX control (if one is installed on the system). This factory is available only on Microsoft Windows platforms. The attribute being edited must have a value whose text representation is the name or URL of a Flash video file. If the is a Unicode string, it must contain only characters that are valid for filenames or URLs. HistoryEditor() Suitable forstring traitsDefault for(none)Required parameters(none)Optional parameters entriesHistoryEditor() generates a combo box, which allows the user to either enter a text string or select a value from a list of previously-entered values. The same control is used for all editor styles. The entries parameter determines how many entries are preserved in the history list. This type of control is used as part of the simple style of file editor; see Section 8.1.10. IEHTMLEditor() Suitable forstring traits, Enum(string values)Default for(none)Required parameters(none)Optional parameters back, forward, home, html, page_loaded, refresh, search, status, stop, titleIEHTMLEditor() generates a display of a web page, using Microsoft Internet Explorer (IE) via ActiveX to render the page. This factory is available only on Microsoft Windows platforms. The attribute being edited must have value whose text representation is a URL. If the value is a Unicode string, it must contain only characters that are valid for URLs. The back, forward, home, refresh, search and stop parameters are extended names of event attributes that represent the user clicking on the corresponding buttons in the standard IE interface. The IE buttons are not displayed by the editor; you must create buttons separately in the View, if you want the user to be able to actually click buttons. The html, page_loaded, status, and title parameters are the extended names of string attributes, which the editor updates with values based on its own state. You can display these attributes elsewhere in the View. htmlThe current page content as HTML (as would be displayed by the View > Source command in IE). page_loadedThe URL of the currently displayed page; this may be different from the URL represented by the attribute being edited. statusThe text that would appear in the IE status bar. titleThe title of the currently displayed page. ImageEditor() Suitable for(any)Default for(none)Required parameters(none)Optional parametersimageImageEditor() generates a read-only display of an image. The image to be displayed is determined by the image parameter, or by the value of the trait attribute being edited, if image is not specified. In either case, the value must be a PyFace ImageResource (enthought.pyface.api.ImageResource), or a string that can be converted to one. If image is specified, then the type and value of the trait attribute being edited are irrelevant and are ignored. LEDEditor() Suitable fornumeric traitsDefault for(none)Required parameters(none)Optional parametersalignment, format_strLEDEditor() generates a display that resembles a digital display using light-emitting diodes. All styles of this editor are the same, and are read-only. The alignment parameter can be left, center, or right to indicate how the value should be aligned within the display. The default is right-alignment.  Figure 56: LED Editor with right alignment ThemedButtonEditor() Suitable forEventDefault for(none)Required parameters(none)Optional parameterslabel, theme, down_theme, hover_theme, disabled_theme, image, position, spacing, viewThe ThemedButtonEditor() factory generates a button that is formatted according to specified or default themes. All editor styles have the same appearance.  Figure 57: Themed buttons in various states The theme-related parameters determine the appearance of the button in various states. Figure 57 shows the default theme. ThemedCheckboxEditor() Suitable forBooleanDefault for(none)Required parameters(none)Optional parameterslabel, theme, hover_off_image, hover_off_theme, hover_on_image, hover_on_theme, image, on_image, on_theme, position, spacingThe ThemedCheckboxEditor() factory generates a checkbox that is formatted according to specified or default themes. All editor styles have the same appearance.  Figure 58: Themed checkbox in various states The theme-related parameters determine the appearance of the checkbox in the various states. shows the default theme. If label is not specified for the editor factory, the value is inherited from the label value of the enclosing Item. Both labels may be displayed, if the Items label is not hidden. ThemedSliderEditor() Suitable forRangeDefault for(none)Required parameters(none)Optional parametersalignment, bg_color, high, increment, low, show_value, slider_color, text_color, tip_colorThe ThemedSliderEditor() factory generates a slider control that is formatted according to specified or default themes. All editor styles have the same appearance. The value is edited by modifying its textual representation. The background of the control updates to reflect the value relative to the total range represented by a slider. For example, if the range is from -2 to 2, a value of 0 is represented by a bar covering the left half of the control area, as shown in Figure 59.  Figure 59: Themed slider without focus, and with focus ThemedTextEditor() Suitable forStr, String, Unicode, CStr, CUnicode, and any trait whose value is a stringDefault for(none)Required parameters(none)Optional parametersauto_set, enter_set, evaluate, evaluate_name, mapping, multi_line, password, themeThe ThemedTextEditor() factory generates a text editor that is formatted according to a specified theme. If no theme is specified, the editor uses the theme, if any, specified by the surrounding Group or View. Thus, there is no default theme. All editor styles have the same appearance, except the read-only style, which is not editable.   Figure 60: Themed text editor, without focus and with focus ThemedVerticalNotebookEditor() Suitable forLists of InstancesDefault for(none)Required parameters(none)Optional parametersclosed_theme, double_click, open_theme, page_name, multiple_open, scrollable, viewThe ThemedVerticalNotebookEditor() factory generates a notebook editor, containing tabs that can be vertically expanded or collapsed. It can be used for lists of instances, similarly to the ListEditor() factory, with the use_notebook parameter. You can specify themes to use for the open and closed states of the tabs.  Figure 61: Themed vertical notebook, with tabs for Person instances closed  Figure 62: Themed vertical notebook, with one tab open Tips, Tricks and Gotchas Getting and Setting Model View Elements For some applications, it can be necessary to retrieve or manipulate the View objects associated with a given model object. The HasTraits class defines two methods for this purpose: trait_views() and trait_view(). trait_views() The trait_views() method, when called without arguments, returns a list containing the names of all Views defined in the object's class. For example, if sam is an object of type SimpleEmployee3 (from Example 6 on page 24), the method call sam.trait_views() returns the list ['all_view', 'traits_view']. Alternatively, a call to trait_views(view_element_type) returns a list of all named instances of class view_element_type defined in the objects class. The possible values of view_element_type are: View Group Item, ViewElement ViewSubElement Thus calling trait_views(View) is identical to calling trait_views(). Note that the call sam.trait_views(Group) returns an empty list, even though both of the Views defined in SimpleEmployee contain Groups. This is because only named elements are returned by the method. Group and Item are both subclasses of ViewSubElement, while ViewSubElement and View are both subclasses of ViewElement. Thus, a call to trait_views(ViewSubElement) returns a list of named Items and Groups, while trait_views(ViewElement) returns a list of named Items, Groups and Views. trait_view(), page  PAGEREF _Ref182908995 \h 93  REF _Ref182909009 \h DirectoryEditor(), p.  PAGEREF _Ref182909033 \h 67  REF _Ref182909072 \h DropEditor() Suitable forInstance traitsDefault for(none)Required parameters(none)Optional parametersbinding, klass, readonlyDropEditor() generates an editor that is a text field containing a string representation of the trait attributes value. The user can change the value assigned to the attribute by dragging and dropping an object on the text field, for example, a node from a tree editor (See Section 9.2.6). If the readonly parameter is True (the default), the user cannot modify the value by typing in the text field. You can restrict the class of objects that can be dropped on the editor by specifying the klass parameter. You can specify that the dropped object must be a binding (enthought.naming.api.Binding) by setting the binding parameter to True. If so, the bound object is retrieved and checked to see if it can be assigned to the trait attribute. If the dropped object (or the bound object associated with it) has a method named drop_editor_value(), it is called to obtain the value to assign to the trait attribute. Similarly, if the object has a method named drop_editor_update(), it is called to update the value displayed in the text editor. This method requires one parameter, which is the GUI control for the text editor. DNDEditor() Suitable forInstance traitsDefault for(none)Required parameters(none)Optional parametersdrag_target, drop_target, image DNDEditor() generates an editor that represents a file or a HasTraits instance as an image that supports dragging and dropping. Depending on the editor style, the editor can be a drag source (the user can set the value of the trait attribute by dragging a file or object onto the editor, for example, from a tree editor), or drop target (the user can drag from the editor onto another target). Table 9: Drag-and-drop editor style variations Editor StyleDrag Source?Drop Target?SimpleYesYesCustomNoYesRead-onlyYesNoKeyBindingEditor() The KeyBindingEditor() factory differs from other trait editor factories because it generates an editor, not for a single attribute, but for an object of a particular class, enthought.traits.ui.key_bindings.KeyBindings. A KeyBindings object is a list of bindings between key codes and handler methods. You can specify a KeyBindings object as an attribute of a View. When the user presses a key while a View has input focus, the user interface searches the View for a KeyBindings that contains a binding that corresponds to the key press; if such a binding does not exist on the View, it searches enclosing Views in order, and uses the first matching binding, if any. If it does not find any matching bindings, it ignores the key press. A key binding editor is a separate dialog box that displays the string representation of each key code and a description of the corresponding method. The user can click a text box, and then press a key or key combination to associate that key press with a method.  Figure 50: Key binding editor dialog box The following code example creates a user interface containing a code editor with associated key bindings, and a button that invokes the key binding editor. Example 17: Code editor with key binding editor # key_bindings.py -- Example of a code editor with a # key bindings editor from enthought.traits.api \ import Button, Code, HasPrivateTraits, Str from enthought.traits.ui.api \ import View, Item, Group, Handler, CodeEditor from enthought.traits.ui.key_bindings \ import KeyBinding, KeyBindings key_bindings = KeyBindings( KeyBinding( binding1 = 'Ctrl-s', description = 'Save to a file', method_name = 'save_file' ), KeyBinding( binding1 = 'Ctrl-r', description = 'Run script', method_name = 'run_script' ), KeyBinding( binding1 = 'Ctrl-k', description = 'Edit key bindings', method_name = 'edit_bindings' ) ) # Traits UI Handler class for bound methods class CodeHandler ( Handler ): def save_file ( self, info ): info.object.status = "save file" def run_script ( self, info ): info.object.status = "run script" def edit_bindings ( self, info ): info.object.status = "edit bindings" key_bindings.edit_traits() class KBCodeExample ( HasPrivateTraits ): code = Code status = Str kb = Button(label='Edit Key Bindings') view = View( Group ( Item( 'code', style = 'custom', resizable = True ), Item('status', style='readonly'), 'kb', orientation = 'vertical', show_labels = False, ), id = 'KBCodeExample', key_bindings = key_bindings, title = 'Code Editor With Key Bindings', resizable = True, handler = CodeHandler() ) def _kb_fired( self, event ): key_bindings.edit_traits() if __name__ == '__main__': KBCodeExample().configure_traits() TableEditor() Suitable forList(InstanceType)Default for(none)Required parameterscolumns or columns_nameOptional parametersSee Traits API Reference, enthought.traits.ui.wx.table_editor .ToolkitEditorFactory attributes.TableEditor() generates a editor that displays instances in a list as rows in a table, with attributes of the instances as values in columns. You must specify the columns in the table. Optionally, you can provide filters for filtering the set of displayed items, and you can specify a wide variety of options for interacting with and formatting the table.  Figure 51: Table editor To see the code that results in Figure 51, refer to TableEditor_demo.py in the demos/TraitsUIDemo/StandardEditors subdirectory of the Traits UI package. This example demonstrates object columns, expression columns, filters, searching, and adding and deleting rows. The parameters for TableEditor() can be grouped in several broad categories, described in the following sections. Specifying Columns Managing Items Editing the Table Defining the Layout Defining the Format Other User Interactions Specifying Columns You must provide the TableEditor() factory with a list of columns for the table. You can specify this list directly, as the value of the columns parameter, or indirectly, in an extended context attribute referenced by the columns_name parameter. The items in the list must be instances of enthought.traits.ui.api.TableColumn, or of a subclass of TableColumn. Some subclasses of TableColumn that are provided by the Traits UI package include ObjectColumn, ListColumn, NumericColumn, and ExpressionColumn. (See the Traits API Reference for details about these classes.) In practice, most columns are derived from one of these subclasses, rather than from TableColumn. For the usual case of editing trait attributes on objects in the list, use ObjectColumn. You must specify the name parameter to the ObjectColumn() constructor, referencing the name of the trait attribute to be edited. You can specify additional columns that are not initially displayed using the other_columns parameter. If the configurable parameter is True (the default), a Set user preferences for table icon () appears on the tables toolbar. When the user clicks this icon, a dialog box opens that enables the user to select and order the columns displayed in the table, as shown in Figure 52. (The dialog box is implemented using a set editor; see Section 8.1.20 on page 86.) Any columns that were specified in the other_columns parameter are listed in the left list box of this dialog box, and can be displayed by moving them into the right list box.  Figure 52: Column selection dialog box for a table editor Managing Items Table editors support several mechanisms to help users locate items of interest. Organizing Items Table editors provide two mechanisms for the user to organize the contents of a table: sorting and reordering. The user can sort the items based on the values in a column, or the user can manually order the items. Usually, only one of these mechanisms is used in any particular table, although the Traits UI package does not enforce a separation. If the user has manually ordered the items, sorting them would throw away that effort. If the reorderable parameter is True, Move up () and Move down () icons appear in the table toolbar. Clicking one of these icons changes the position of the selected item. If the sortable parameter is True (the default), then the user can sort the items in the table based on the values in a column by Control-clicking the header of that column. On the first click, the items are sorted in ascending order. The characters >> appear in the column header to indicate that the table is sorted ascending on this columns values. On the second click, the items are sorted descending order. The characters << appear in the column header to indicate that the table is sorted descending on this columns values. On the third click, the items are restored to their original order, and the column header is undecorated. If the sort_model parameter is true, the items in the list being edited are sorted when the table is sorted. The default value is False, in which case, the list order is not affected by sorting the table. If sortable is True and sort_model is False, then a Do not sort columns icon () appears in the table toolbar. Clicking this icon restores the original sort order. If the reverse parameter is True, then the items in the underlying list are maintained in the reverse order of the items in the table (regardless of whether the table is sortable or reorderable). Filtering and Searching You can provide an option for the user to apply a filter to a table, so that only items that pass the filter are displayed. This feature can be very useful when dealing with lengthy lists. You can specify a filter to apply to the table either directly, or via another trait. Table filters must be instances of enthought.traits.ui.api.TableFilter, or of a subclass of TableFilter. Some subclasses of TableFilter that are provided by the Traits UI package include EvalTableFilter, RuleTableFilter, and MenuTableFilter. (See the Traits API Reference for details about these classes.) The Traits UI package also provides instances of these filter classes as templates, which cannot be edited or deleted, but which can be used as models for creating new filters. The filter parameter specifies a filter that is applied to the table when it is first displayed. The filter_name parameter specifies an extended trait name for a trait that is either a table filter object or a callable that accepts an object and returns True if the object passes the filter criteria, or false if it does not. You can use filter_name to embed a view of a table filter in the same view as its table. You can specify use the filters parameter to specify a list of table filters that are available to apply to a table. When filters is specified, a drop-down list box appears in the table toolbar, containing the filters that are available for the user to apply. When the user selects a filter, it is automatically applied to the table. A status message to the right of the filters list indicates what subset of the items in the table is currently displayed. A special item in the filter list, named Customize, is always provided; clicking this item opens a dialog box that enables the user to create new filters, or to edit or delete existing filters (except templates). You can also provide an option for the user to use filters to search the table. If you set the search parameter to an instance of TableFilter (or of a subclass), a Search table icon () appears on the table toolbar. Clicking this icon opens a Search for dialog box, which enables the user to specify filter criteria, to browse through matching items, or select all matching items. Interacting with Items As the user clicks in the table, you may wish to enable certain program behavior. The selection_mode parameter specifies how the user can make selections in the grid: cellA single cell at a time cellsMultiple cells columnA single column at a time columnsMultiple columns rowA single row at a time rowsMultiple rows You can use the selected parameter to specify the name of a trait attribute in the current context to synchronize with the users current selection. For example, you can enable or disable menu items or toolbar icons depending on which item is selected. The synchronization is two-way; you can set the attribute referenced by selected to force the table to select a particular item. You can use the selected_indices parameter to specify the name of a trait attribute in the current context to synchronize with the indices of the table editor selection. The content of the selection depends on the selection_mode value: cellThe selection is a tuple of the form (object, column_name), where object is the object contains the selected cell, and column_name is the name of the column the cell is in. If there is no selection, the tuple is (None, ''). cellsThe selection is a list of tuples of the form (object, column_name), with one tuple for each selected cell, in order from top to bottom and left to right. If there is no selection, the list is empty. columnThe selection is the name of the selected column, or the empty string if there is no selection. columnsThe selection is a list containing the names of the selected columns, in order from left to right. If there is no selection, the list is empty. rowThe selection is either the selected object or None if nothing is selected in the table. rowsThe selection is a list of the selected objects, in ascending row order. If there is no selection, the list is empty. The on_select and on_dclick parameters are callables to invoke when the user selects or double-clicks an item, respectively. You can define a shortcut menu that opens when the user right-clicks an item. Use the menu parameter to specify a Traits UI or PyFace Menu, containing Action objects for the menu commands. Editing the Table The Boolean editable parameter controls whether the table or its items can be modified in any way. This parameter defaults to True, except when the style is readonly. Even when the table as a whole is editable, you can control whether individual columns are editable through the editable attribute of TableColumn. Adding Items To enable users to add items to the table, specify as the row_factory parameter a callable that generates an object that can be added to the list in the table; for example, the class of the objects in the table. When row_factory is specified, an Insert new item icon () appears in the table toolbar, which generates a new row in the table. Optionally, you can use row_factory_args and row_factory_kw to specify positional and keyword arguments to the row factory callable. To save users the trouble of mousing to the toolbar, you can enable them to add an item by selecting the last row in the table. To do this, set auto_add to True. In this case, the last row is blank until the user sets values. Pressing Enter creates the new item and generates a new, blank last row. Deleting Items The deletable parameter controls whether items can be deleted from the table. This parameter can be a Boolean (defaulting to False) or a callable; the callable must take an item as an argument and handle deleting it. If deletable is not False, a Delete current item icon () appears on the table toolbar; clicking it deletes the item corresponding to the row that is selected in the table. Modifying Items The user can modify items in two ways. For columns that are editable, the user can change an items value directly in the table. The editor used for each attribute in the table is the simple style of editor for the corresponding trait. Alternatively, you can specify a View for editing instances, using the edit_view parameter. The resulting user interface appears in a sub-panel to the right or below the table (depending on the orientation parameter). You can specify a handler to use with the view, using edit_view_handler. You can also specify the subpanels height and width, with edit_view_height and edit_view_width. Defining the Layout Some of the parameters for the TableEditor() factory affect global aspects of the display of the table. auto_sizeIf True, the cells of the table automatically adjust to the optimal size based on their contents. orientationThe layout of the table relative to its associated editor pane. Can be horizontal or vertical. rowsThe number of visible rows in the table. show_column_labelsIf True (the default), displays labels for the columns. You can specify the labels to use in the column definitions; otherwise, a user friendly version of the trait attribute name is used. show_toolbarIf False, the table toolbar is not displayed, regardless of whether other settings would normally create a toolbar. The default is True. Defining the Format The TableEditor() factory supports a variety of parameters to control the visual formatting of the table, such as colors, fonts, and sizes for lines, cells, and labels. For details, refer to the Traits API Reference, enthought.traits.ui.wx.table_editor.ToolkitEditorFactory attributes. You can also specify formatting options for individual table columns when you define them. Other User Interactions The table editor supports additional types of user interaction besides those controlled by the factory parameters. Column draggingThe user can reorganize the column layout of a table editor by clicking and dragging a column label to its new location. If you have enabled user preferences for the view and table editor (by specifying view and item IDs), the new column layout is persisted across user sessions. Column resizingThe user can resize a column by dragging the column separator (in one of the data rows) to a new position. Because of the column-dragging support, clicking the column separator in the column label row does not work. Data draggingThe user can drag the contents of any cell by clicking and dragging. TabularEditor() Suitable forlists, arrays, and other large sequences of objectsDefault for(none)Required parametersadapterOptional parametersactivated, clicked, column_clicked, dclicked, drag_move, editable, horizontal_lines, images, multi_select, operations, right_clicked, right_dclicked, selected, selected_row, show_titles, vertical_linesThe TabularEditor() factory can be used for many of the same purposes as the TableEditor() factory, that is, for displaying a table of attributes of lists or arrays of objects. While similar in function, each editor has its own advantages and disadvantages. Some of the advantages of the tabular editor are: Very fast: The tabular editor uses a virtual model, which accesses data from the underlying model only as needed. For example, if you have a million-element array, but can display only 50 rows at a time, the editor requests only 50 elements of data at a time. Very flexible data model: The editor uses an adapter model to interface with the underlying data. This strategy allows it to easily deal with many types of data representation, from list of objects, to arrays of numbers, to tuples of tuples, and many other formats. Supports useful data operations, including: Moving the selection up and down using the keyboard arrow keys. Moving rows up and down using the keyboard. Inserting and deleting items using the keyboard. Initiating editing of items using the keyboard. Dragging and dropping of table items to and from the editor, including support for both copy and move operations for single and multiple items. Visually appealing: The tabular editor, in general, uses the underlying operating systems native table or grid control, and as a result often looks better than the control used by the table editor. Supports displaying text and images in any cell. However, the images displayed must be all the same size for optimal results. Some of the disadvantages of the tabular editor relative to the table editor are: Not as full-featured: The table editor includes support for arbitrary data filters, searches, and different types of sorting. These differences may narrow as features are added to the tabular editor. Limited data editing capabilities: The tabular editor supports editing only textual values, whereas the table editor supports a wide variety of column editors, and can be extended with more as needed. This is due to limitations of the underlying native control used by the tabular editor. TabularAdapter The tabular editor works in conjunction with an adapter class, derived from TabularAdapter. The tabular adapter interfaces between the tabular editor and the data being displayed. The tabular adapter is the reason for the flexibility and power of the tabular editor to display a wide variety of data. The most important attribute of TabularAdapter is columns, which is list of columns to be displayed. Each entry in the columns list can be either a string, or a tuple consisting of a string and another value, which can be of any type. The string is used as the label for the column. The second value in the tuple, called the column ID, identifies the column to the adapter. It is typically a trait attribute name or an integer index, but it can be any value appropriate to the adapter. If only a string is specified for an entry, then the index of the entry within the columns list is used as that entrys column ID. Attributes on TabularAdapter control the appearance of items, and aspects of interaction with items, such as whether they can be edited, and how they respond to dragging and dropping. Setting any of these attributes on the adapter subclass sets the global behavior for the editor. Refer to the Traits API Reference for details of the available attributes. You can also specify these attributes for a specific class or column ID, or combination of class and column ID. When the TabularAdapter needs to look up the value of one of its attributes for a specific item in the table, it looks for attributes with the following naming conventions in the following order: classname_columnid_attribute classname_attribute columnid_attribute attribute For example, to find the text_color value for an item whose class is Person and whose column ID is age, the get_text_color() method looks for the following attributes in sequence, and returns the first value it finds: Person_age_text_color Person_text_color age_text_color text_color Note that the classname can be the name of a base class, searched in the method resolution order (MRO) for the items class. So for example, if the item were a direct instance of Employee, which is a subclass of Person, then the Person_age_text_color attribute would apply to that item (as long as there were no Employee_age_text_color attribute). The Tabular Editor User Interface Error! Reference source not found. shows an example of a tabular editor on Microsoft Windows, displaying information about source files in the Traits package. This example includes a column that contains an image for files that meet certain conditions.  Figure 53: Tabular editor on MS Windows Depending on how the tabular editor is configured, certain keyboard interactions may be available. For some interactions, you must specify that the corresponding operation is allowed by including the operation name in the operations list parameter of TabularEditor(). Up arrow: Selects the row above the currently selected row. Down arrow: Selects the row below the currently selected row. Page down: Appends a new item to the end of the list (append operation). Left arrow: Moves the currently selected row up one line (move operation). Right arrow: Moves the currently selected row down one line (move operation). Backspace, Delete: Deletes from the list all items in the current selection (delete operation). Enter, Escape: Initiates editing on the current selection (edit operation). Insert: Inserts a new item before the current selection (insert operation). The append, move, edit, and insert operations can occur only when a single item is selected. The delete operation works for one or more items selected. Depending on how the editor and adapter are specified, drag and drop operations may be available. If the user selects multiple items and drags one of them, all selected items are included in the drag operation. If the user drags a non-selected item, only that item is dragged. The editor supports both drag-move and drag-copy semantics. A drag-move operation means that the dragged items are sent to the target and are removed from the list displayed in the editor. A drag-copy operation means that the dragged items are sent to the target, but are not deleted from the list data. TreeEditor() Suitable forInstanceDefault for(none)Required parametersnodes (required except for shared editors; see Section 8.2.7.2.5)Optional parametersauto_open, editable, editor, hide_root, icon_size, lines_mode, on_dclick, on_select, orientation, selected, shared_editor, show_icons TreeEditor() generates a hierarchical tree control, consisting of nodes. It is useful for cases where objects contain lists of other objects. The tree control is displayed in one pane of the editor, and a user interface for the selected object is displayed in the other pane. The layout orientation of the tree and the object editor is determined by the orientation parameter of TreeEditor(), which can be horizontal or vertical. You must specify the types of nodes that can appear in the tree using the nodes parameter, which must be a list of instances of TreeNode (or of subclasses of TreeNode).  Figure 54: Tree editor The following example shows the code that produces the editor shown in Figure 54. Example 18: Code for example tree editor # tree_editor.py -- Example of a tree editor from enthought.traits.api \ import HasTraits, Str, Regex, List, Instance from enthought.traits.ui.api \ import TreeEditor, TreeNode, View, Item, VSplit, \ HGroup, Handler, Group from enthought.traits.ui.menu \ import Menu, Action, Separator from enthought.traits.ui.wx.tree_editor \ import NewAction, CopyAction, CutAction, \ PasteAction, DeleteAction, RenameAction # DATA CLASSES class Employee ( HasTraits ): name = Str( '' ) title = Str phone = Regex( regex = r'\d\d\d-\d\d\d\d' ) def default_title ( self ): self.title = 'Senior Engineer' class Department ( HasTraits ): name = Str( '' ) employees = List( Employee ) class Company ( HasTraits ): name = Str( '' ) departments = List( Department ) employees = List( Employee ) class Owner ( HasTraits ): name = Str( '' ) company = Instance( Company ) # INSTANCES jason = Employee( name = 'Jason', title = 'Engineer', phone = '536-1057' ) mike = Employee( name = 'Mike', title = 'Sr. Marketing Analyst', phone = '536-1057' ) dave = Employee( name = 'Dave', title = 'Sr. Engineer', phone = '536-1057' ) susan = Employee( name = 'Susan', title = 'Engineer', phone = '536-1057' ) betty = Employee( name = 'Betty', title = 'Marketing Analyst' ) owner = Owner( name = 'wile', company = Company( name = 'Acme Labs, Inc.', departments = [ Department( name = 'Marketing', employees = [ mike, betty ] ), Department( name = 'Engineering', employees = [ dave, susan, jason ] ) ], employees = [ dave, susan, mike, betty, jason ] ) ) # View for objects that aren't edited no_view = View() # Actions used by tree editor context menu def_title_action = Action(name='Default title', action = 'object.default') dept_action = Action( name='Department', action='handler.employee_department(editor,object)') # View used by tree editor employee_view = View( VSplit( HGroup( '3', 'name' ), HGroup( '9', 'title' ), HGroup( 'phone' ), id = 'vsplit' ), id = 'enthought.traits.doc.example.treeeditor', dock = 'vertical' ) class TreeHandler ( Handler ): def employee_department ( self, editor, object ): dept = editor.get_parent( object ) print '%s works in the %s department.' %\ ( object.name, dept.name ) # Tree editor tree_editor = TreeEditor( nodes = [ TreeNode( node_for = [ Company ], auto_open = True, children = '', label = 'name', view = View( Group('name', orientation='vertical', show_left=True )) ), TreeNode( node_for = [ Company ], auto_open = True, children = 'departments', label = '=Departments', view = no_view, add = [ Department ] ), TreeNode( node_for = [ Company ], auto_open = True, children = 'employees', label = '=Employees', view = no_view, add = [ Employee ] ), TreeNode( node_for = [ Department ], auto_open = True, children = 'employees', label = 'name', menu = Menu( NewAction, Separator(), DeleteAction, Separator(), RenameAction, Separator(), CopyAction, CutAction, PasteAction ), view = View( Group ('name', orientation='vertical', show_left=True )), add = [ Employee ] ), TreeNode( node_for = [ Employee ], auto_open = True, label = 'name', menu=Menu( NewAction, Separator(), def_title_action, dept_action, Separator(), CopyAction, CutAction, PasteAction, Separator(), DeleteAction, Separator(), RenameAction ), view = employee_view ) ] ) # The main view view = View( Group( Item( name = 'company', id = 'company', editor = tree_editor, resizable = True ), orientation = 'vertical', show_labels = True, show_left = True, ), title = 'Company Structure', id = \ 'enthought.traits.ui.tests.tree_editor_test', dock = 'horizontal', drop_class = HasTraits, handler = TreeHandler(), buttons = [ 'Undo', 'OK', 'Cancel' ], resizable = True, width = .3, height = .3 ) if __name__ == '__main__': owner.configure_traits( view = view ) Defining Nodes For details on the attributes of the TreeNode class, refer to the Traits API Reference. You must specify the classes whose instances the node type applies to. Use the node_for attribute of TreeNode to specify a list of classes; often, this list contains only one class. You can have more than one node type that applies to a particular class; in this case, each object of that class is represented by multiple nodes, one for each applicable node type. In Figure 54, one Company object is represented by the nodes labeled Acme Labs, Inc., Departments, and Employees. A Node Type without Children To define a node type without children, set the children attribute of TreeNode to the empty string. In Example 16, the following lines define the node type for the node that displays the company name, with no children: TreeNode( node_for = [ Company ], auto_open = True, children = '', label = 'name', view = View( Group('name', orientation='vertical', show_left=True )) ), A Node Type with Children To define a node type that has children, set the children attribute of TreeNode to the (extended) name of a trait on the object that it is a node for; the named trait contains a list of the nodes children. In Example 16, the following lines define the node type for the node that contains the departments of a company. The node type is for instances of Company, and departments is a trait attribute of Company. TreeNode( node_for = [ Company ], auto_open = True, children = 'departments', label = '=Departments', view = no_view, add = [ Department ] ), Setting the Label of a Tree Node The label attribute of Tree Node can work in either of two ways: as a trait attribute name, or as a literal string. If the value is a simple string, it is interpreted as the extended trait name of an attribute on the object that the node is for, whose value is used as the label. This approach is used in the code snippet in Section 8.2.7.1.1. If the value is a string that begins with an equals sign (=), the rest of the string is used as the literal label. This approach is used in the code snippet in Section 8.2.7.1.2. You can also specify a callable to format the label of the node, using the formatter attribute of TreeNode. Defining Operations on Nodes You can use various attributes of TreeNode to define operations or behavior of nodes. Shortcut Menus on Nodes Use the menu attribute of TreeNode to define a shortcut menu that opens when the user right-clicks on a node. The value is a Traits UI or PyFace menu containing Action objects for the menu commands. In Example 16, the following lines define the node type for employees, including a shortcut menu for employee nodes: TreeNode( node_for = [ Department ], auto_open = True, children = 'employees', label = 'name', menu = Menu( NewAction, Separator(), DeleteAction, Separator(), RenameAction, Separator(), CopyAction, CutAction, PasteAction ), view = View( Group ('name', orientation='vertical', show_left=True )), add = [ Employee ] ), Allowing the Hierarchy to Be Modified If a node contains children, you can allow objects to be added to its set of children, through operations such as dragging and dropping, copying and pasting, or creating new objects. Two attributes control these operations: add and move. Both are lists of classes. The add attribute contains classes that can be added by any means, including creation. The code snippet in the preceding section (8.2.7.2.1) includes an example of the add attribute. The move attribute contains classes that can be dragged and dropped, but not created. The move attribute need not be specified if all classes that can be moved can also be created (and therefore are specified in the add value). NOTE: The add attribute alone is not enough to create objects. Specifying the add attribute makes it possible for objects of the specified classes to be created, but by itself, it does not provide a way for the user to do so. In the code snippet in the preceding section (8.2.7.2.1), NewAction in the Menu constructor call defines a New > Employee menu item that creates Employee objects. In the example tree editor, users can create new employees using the New > Employee shortcut menu item, and they can drag an employee node and drop it on a department node. The corresponding object becomes a member of the appropriate list. You can specify the label that appears on the New submenu when adding a particular type of object, using the name attribute of TreeNode. Note that you set this attribute on the tree node type that will be added by the menu item, not the node type that contains the menu item. For example, to change New > Employee to New > Worker, set name = 'Worker' on the tree node whose node_for value contains Employee. If this attribute is not set, the class name is used. You can determine whether a node or its children can be copied, renamed, or deleted, by setting the following attributes on TreeNode: copy: If True, the objects children can be copied. delete: If True, the objects children can be deleted. delete_me: If True, the object can be deleted. rename: If True, the objects children can be renamed. rename_me: If True, the object can be renamed. All of these attributes default to True. As with add, you must also define actions to perform these operations. Behavior on Nodes As the user clicks in the tree, you may wish to enable certain program behavior. You can use the selected parameter to specify the name of a trait attribute on the current context object to synchronize with the users current selection. For example, you can enable or disable menu items or toolbar icons depending on which node is selected. The synchronization is two-way; you can set the attribute referenced by selected to force the tree to select a particular node. The on_select and on_dclick parameters are callables to invoke when the user selects or double-clicks a node, respectively. Expanding and Collapsing Nodes You can control some aspects of expanding and collapsing of nodes in the tree. The integer auto_open parameter of TreeEditor() determines how many levels are expanded below the root node, when the tree is first displayed. For example, if auto_open is 2, then two levels below the root node are displayed (whether or not the root node itself is displayed, which is determined by hide_root). The Boolean auto_open attribute of TreeNode determines whether nodes of that type are expanded when they are displayed (at any time, not just on initial display of the tree). For example, suppose that a tree editor has auto_open setting of 2, and contains a tree node at level 3 whose auto_open attribute is True. The nodes at level 3 are not displayed initially, but when the user expands a level 2 node, displaying the level 3 node, thats nodes children are automatically displayed also. Similarly, the number of levels of nodes initially displayed can be greater than specified by the tree editors auto_open setting, if some of the nodes have auto_open set to True. If the auto_close attribute of TreeNode is set to True, then when a node is expanded, any siblings of that node are automatically closed. In other words, only one node of this type can be expanded at a time. Editing Objects One pane of the tree editor displays a user interface for editing the object that is selected in the tree. You can specify a View to use for each node type using the view attribute of TreeNode. If you do not specify a view, then the default view for the object is displayed. To suppress the editor pane, set the editable parameter of TreeEditor() to False; in this case, the objects represented by the nodes can still be modified by other means, such as shortcut menu commands. You can define multiple tree editors that share a single editor pane. Each tree editor has its own tree pane. Each time the user selects a different node in any of the sharing tree controls, the editor pane updates to display the user interface for the selected object. To establish this relationship, do the following: Call TreeEditor() with the shared_editor parameter set to True, without defining any tree nodes. The object this call returns defines the shared editor pane. For example: my_shared_editor_pane = TreeEditor(shared_editor=True) For each editor that uses the shared editor pane: Set the shared_editor parameter of TreeEditor() to True. Set the editor parameter of TreeEditor() to the object returned in Step 1. For example: shared_tree_1 = TreeEditor(shared_editor = True, editor = my_shared_editor_pane, nodes = [ TreeNode( # ) ] ) shared_tree_2 = TreeEditor(shared_editor = True, editor = my_shared_editor_pane, nodes = [ TreeNode( # ) ] ) Defining the Format Several parameters to TreeEditor() affect the formatting of the tree control: show_icons: If True (the default), icons are displayed for the nodes in the tree. icon_size: A two-integer tuple indicating the size of the icons for the nodes. lines_mode: Determines whether lines are displayed between related nodes. The valid values are on, off, and appearance (the default). When set to appearance, lines are displayed except on Posix-based platforms. hide_root: If True, the root node in the hierarchy is not displayed. If this parameter were specified as True in Example 16, the node in Figure 54 that is labeled Acme Labs, Inc. would not appear. Additionally, several attributes of TreeNode also affect the display of the tree: icon_path: A directory path to search for icon files. This path can be relative to the module it is used in. icon_item: The icon for a leaf node. icon_open: The icon for a node with children whose children are displayed. icon_group: The icon for a node with children whose children are not displayed. The wxWidgets implementation automatically detects the bitmap format of the icon. Extra Trait Editor Factories The enthought.traits.ui.wx package defines a few editor factories that are specific to the wxWidgets toolkit, some of which are also specific to the Microsoft Windows platform. These editor factories are not necessarily implemented for other GUI toolkits or other operating system platforms. AnimatedGIFEditor() Suitable forFileDefault for(none)Required parameters(none)Optional parametersplayingAnimatedGIFEditor() generates a display of the contents of an animated GIF image file. The playing parameter determines whether the image is animated or static. ArrayViewEditor() Suitable for2-D Array, 2-D CArrayDefault for(none)Required parameters(none)Optional parametersformat, show_index, titles, transposeArrayViewEditor() generates a tabular display for an array. It is suitable for use with large arrays, which do not work well with the editors generated by ArrayEditor(). All styles of the editor have the same appearance.  Figure 55: Array view editor FlashEditor() Suitable forstring traits, Enum(string values)Default for(none)Required parameters(none)Optional parameters (none)FlashEditor() generates a display of an Adobe Flash Video file, using an ActiveX control (if one is installed on the system). This factory is available only on Microsoft Windows platforms. The attribute being edited must have a value whose text representation is the name or URL of a Flash video file. If the is a Unicode string, it must contain only characters that are valid for filenames or URLs. HistoryEditor() Suitable forstring traitsDefault for(none)Required parameters(none)Optional parameters entriesHistoryEditor() generates a combo box, which allows the user to either enter a text string or select a value from a list of previously-entered values. The same control is used for all editor styles. The entries parameter determines how many entries are preserved in the history list. This type of control is used as part of the simple style of file editor; see Section 8.1.10. IEHTMLEditor() Suitable forstring traits, Enum(string values)Default for(none)Required parameters(none)Optional parameters back, forward, home, html, page_loaded, refresh, search, status, stop, titleIEHTMLEditor() generates a display of a web page, using Microsoft Internet Explorer (IE) via ActiveX to render the page. This factory is available only on Microsoft Windows platforms. The attribute being edited must have value whose text representation is a URL. If the value is a Unicode string, it must contain only characters that are valid for URLs. The back, forward, home, refresh, search and stop parameters are extended names of event attributes that represent the user clicking on the corresponding buttons in the standard IE interface. The IE buttons are not displayed by the editor; you must create buttons separately in the View, if you want the user to be able to actually click buttons. The html, page_loaded, status, and title parameters are the extended names of string attributes, which the editor updates with values based on its own state. You can display these attributes elsewhere in the View. htmlThe current page content as HTML (as would be displayed by the View > Source command in IE). page_loadedThe URL of the currently displayed page; this may be different from the URL represented by the attribute being edited. statusThe text that would appear in the IE status bar. titleThe title of the currently displayed page. ImageEditor() Suitable for(any)Default for(none)Required parameters(none)Optional parametersimageImageEditor() generates a read-only display of an image. The image to be displayed is determined by the image parameter, or by the value of the trait attribute being edited, if image is not specified. In either case, the value must be a PyFace ImageResource (enthought.pyface.api.ImageResource), or a string that can be converted to one. If image is specified, then the type and value of the trait attribute being edited are irrelevant and are ignored. LEDEditor() Suitable fornumeric traitsDefault for(none)Required parameters(none)Optional parametersalignment, format_strLEDEditor() generates a display that resembles a digital display using light-emitting diodes. All styles of this editor are the same, and are read-only. The alignment parameter can be left, center, or right to indicate how the value should be aligned within the display. The default is right-alignment.  Figure 56: LED Editor with right alignment ThemedButtonEditor() Suitable forEventDefault for(none)Required parameters(none)Optional parameterslabel, theme, down_theme, hover_theme, disabled_theme, image, position, spacing, viewThe ThemedButtonEditor() factory generates a button that is formatted according to specified or default themes. All editor styles have the same appearance.  Figure 57: Themed buttons in various states The theme-related parameters determine the appearance of the button in various states. Figure 57 shows the default theme. ThemedCheckboxEditor() Suitable forBooleanDefault for(none)Required parameters(none)Optional parameterslabel, theme, hover_off_image, hover_off_theme, hover_on_image, hover_on_theme, image, on_image, on_theme, position, spacingThe ThemedCheckboxEditor() factory generates a checkbox that is formatted according to specified or default themes. All editor styles have the same appearance.  Figure 58: Themed checkbox in various states The theme-related parameters determine the appearance of the checkbox in the various states. shows the default theme. If label is not specified for the editor factory, the value is inherited from the label value of the enclosing Item. Both labels may be displayed, if the Items label is not hidden. ThemedSliderEditor() Suitable forRangeDefault for(none)Required parameters(none)Optional parametersalignment, bg_color, high, increment, low, show_value, slider_color, text_color, tip_colorThe ThemedSliderEditor() factory generates a slider control that is formatted according to specified or default themes. All editor styles have the same appearance. The value is edited by modifying its textual representation. The background of the control updates to reflect the value relative to the total range represented by a slider. For example, if the range is from -2 to 2, a value of 0 is represented by a bar covering the left half of the control area, as shown in Figure 59.  Figure 59: Themed slider without focus, and with focus ThemedTextEditor() Suitable forStr, String, Unicode, CStr, CUnicode, and any trait whose value is a stringDefault for(none)Required parameters(none)Optional parametersauto_set, enter_set, evaluate, evaluate_name, mapping, multi_line, password, themeThe ThemedTextEditor() factory generates a text editor that is formatted according to a specified theme. If no theme is specified, the editor uses the theme, if any, specified by the surrounding Group or View. Thus, there is no default theme. All editor styles have the same appearance, except the read-only style, which is not editable.   Figure 60: Themed text editor, without focus and with focus ThemedVerticalNotebookEditor() Suitable forLists of InstancesDefault for(none)Required parameters(none)Optional parametersclosed_theme, double_click, open_theme, page_name, multiple_open, scrollable, viewThe ThemedVerticalNotebookEditor() factory generates a notebook editor, containing tabs that can be vertically expanded or collapsed. It can be used for lists of instances, similarly to the ListEditor() factory, with the use_notebook parameter. You can specify themes to use for the open and closed states of the tabs.  Figure 61: Themed vertical notebook, with tabs for Person instances closed  Figure 62: Themed vertical notebook, with one tab open Tips, Tricks and Gotchas Getting and Setting Model View Elements For some applications, it can be necessary to retrieve or manipulate the View objects associated with a given model object. The HasTraits class defines two methods for this purpose: trait_views() and trait_view(). trait_views() The trait_views() method, when called without arguments, returns a list containing the names of all Views defined in the object's class. For example, if sam is an object of type SimpleEmployee3 (from Example 6 on page 24), the method call sam.trait_views() returns the list ['all_view', 'traits_view']. Alternatively, a call to trait_views(view_element_type) returns a list of all named instances of class view_element_type defined in the objects class. The possible values of view_element_type are: View Group Item, ViewElement ViewSubElement Thus calling trait_views(View) is identical to calling trait_views(). Note that the call sam.trait_views(Group) returns an empty list, even though both of the Views defined in SimpleEmployee contain Groups. This is because only named elements are returned by the method. Group and Item are both subclasses of ViewSubElement, while ViewSubElement and View are both subclasses of ViewElement. Thus, a call to trait_views(ViewSubElement) returns a list of named Items and Groups, while trait_views(ViewElement) returns a list of named Items, Groups and Views. trait_view(), page  PAGEREF _Ref182909085 \h 92  REF _Ref161645067 \h EnumEditor(), page  PAGEREF _Ref161645067 \h 69  REF _Ref182909127 \h FileEditor(), page  PAGEREF _Ref182909142 \h 70  REF _Ref161558251 \h FontEditor(), page  PAGEREF _Ref161558251 \h 72  REF _Ref182909187 \h HTMLEditor(), page  PAGEREF _Ref182909205 \h 73  REF _Ref182909229 \h ImageEnumEditor(), p.  PAGEREF _Ref182909240 \h 75  REF _Ref182909259 \h InstanceEditor(), page  PAGEREF _Ref182909274 \h 77  REF _Ref182909329 \h ListEditor(), page  PAGEREF _Ref182909342 \h 81  REF _Ref182910065 \h ListStrEditor(), page  PAGEREF _Ref182910065 \h 83  REF _Ref182909356 \h ListStrEditor() Suitable forListStr or List of values mapped to stringsDefault for(none)Required parameters(none)Optional parametersactivated, activated_index, adapter, adapter_name, auto_add, drag_move, editable, horizontal_lines, images, multi_select, operations, right_clicked, right_clicked_index, selected, selected_index, title, title_nameListStrEditor() generates a list of selectable items corresponding to items in the underlying trait attribute. All styles of the editor are the same. The parameters to ListStrEditor() control aspects of the behavior of the editor, such as what operations it allows on list items, whether items are editable, and whether more than one can be selected at a time. You can also specify extended references for trait attributes to synchronize with user actions, such as the item that is currently selected, activated for editing, or right-clicked.  Figure 41: List string editor NullEditor(), page  PAGEREF _Ref182909366 \h 83  REF _Ref182909383 \h RangeEditor(), page  PAGEREF _Ref182909397 \h 84  REF _Ref182909462 \h RGBColorEditor(), p.  PAGEREF _Ref182909462 \h 86  REF _Ref182909485 \h SetEditor(), page  PAGEREF _Ref182909485 \h 86  REF _Ref182909518 \h ShellEditor(), page  PAGEREF _Ref182909530 \h 87  REF _Ref161566483 \h TableEditor(), page  PAGEREF _Ref161566483 \h 96  REF TabularEditor() \h TabularEditor(), page  PAGEREF TabularEditor() \h 104  REF _Ref182909564 \h TextEditor(), page  PAGEREF _Ref182909578 \h 88  REF _Ref182909633 \h TitleEditor(), page  PAGEREF _Ref182909633 \h 89  REF _Ref182909666 \h TabularEditor() Suitable forlists, arrays, and other large sequences of objectsDefault for(none)Required parametersadapterOptional parametersactivated, clicked, column_clicked, dclicked, drag_move, editable, horizontal_lines, images, multi_select, operations, right_clicked, right_dclicked, selected, selected_row, show_titles, vertical_linesThe TabularEditor() factory can be used for many of the same purposes as the TableEditor() factory, that is, for displaying a table of attributes of lists or arrays of objects. While similar in function, each editor has its own advantages and disadvantages. Some of the advantages of the tabular editor are: Very fast: The tabular editor uses a virtual model, which accesses data from the underlying model only as needed. For example, if you have a million-element array, but can display only 50 rows at a time, the editor requests only 50 elements of data at a time. Very flexible data model: The editor uses an adapter model to interface with the underlying data. This strategy allows it to easily deal with many types of data representation, from list of objects, to arrays of numbers, to tuples of tuples, and many other formats. Supports useful data operations, including: Moving the selection up and down using the keyboard arrow keys. Moving rows up and down using the keyboard. Inserting and deleting items using the keyboard. Initiating editing of items using the keyboard. Dragging and dropping of table items to and from the editor, including support for both copy and move operations for single and multiple items. Visually appealing: The tabular editor, in general, uses the underlying operating systems native table or grid control, and as a result often looks better than the control used by the table editor. Supports displaying text and images in any cell. However, the images displayed must be all the same size for optimal results. Some of the disadvantages of the tabular editor relative to the table editor are: Not as full-featured: The table editor includes support for arbitrary data filters, searches, and different types of sorting. These differences may narrow as features are added to the tabular editor. Limited data editing capabilities: The tabular editor supports editing only textual values, whereas the table editor supports a wide variety of column editors, and can be extended with more as needed. This is due to limitations of the underlying native control used by the tabular editor. TabularAdapter The tabular editor works in conjunction with an adapter class, derived from TabularAdapter. The tabular adapter interfaces between the tabular editor and the data being displayed. The tabular adapter is the reason for the flexibility and power of the tabular editor to display a wide variety of data. The most important attribute of TabularAdapter is columns, which is list of columns to be displayed. Each entry in the columns list can be either a string, or a tuple consisting of a string and another value, which can be of any type. The string is used as the label for the column. The second value in the tuple, called the column ID, identifies the column to the adapter. It is typically a trait attribute name or an integer index, but it can be any value appropriate to the adapter. If only a string is specified for an entry, then the index of the entry within the columns list is used as that entrys column ID. Attributes on TabularAdapter control the appearance of items, and aspects of interaction with items, such as whether they can be edited, and how they respond to dragging and dropping. Setting any of these attributes on the adapter subclass sets the global behavior for the editor. Refer to the Traits API Reference for details of the available attributes. You can also specify these attributes for a specific class or column ID, or combination of class and column ID. When the TabularAdapter needs to look up the value of one of its attributes for a specific item in the table, it looks for attributes with the following naming conventions in the following order: classname_columnid_attribute classname_attribute columnid_attribute attribute For example, to find the text_color value for an item whose class is Person and whose column ID is age, the get_text_color() method looks for the following attributes in sequence, and returns the first value it finds: Person_age_text_color Person_text_color age_text_color text_color Note that the classname can be the name of a base class, searched in the method resolution order (MRO) for the items class. So for example, if the item were a direct instance of Employee, which is a subclass of Person, then the Person_age_text_color attribute would apply to that item (as long as there were no Employee_age_text_color attribute). The Tabular Editor User Interface Error! Reference source not found. shows an example of a tabular editor on Microsoft Windows, displaying information about source files in the Traits package. This example includes a column that contains an image for files that meet certain conditions.  Figure 53: Tabular editor on MS Windows Depending on how the tabular editor is configured, certain keyboard interactions may be available. For some interactions, you must specify that the corresponding operation is allowed by including the operation name in the operations list parameter of TabularEditor(). Up arrow: Selects the row above the currently selected row. Down arrow: Selects the row below the currently selected row. Page down: Appends a new item to the end of the list (append operation). Left arrow: Moves the currently selected row up one line (move operation). Right arrow: Moves the currently selected row down one line (move operation). Backspace, Delete: Deletes from the list all items in the current selection (delete operation). Enter, Escape: Initiates editing on the current selection (edit operation). Insert: Inserts a new item before the current selection (insert operation). The append, move, edit, and insert operations can occur only when a single item is selected. The delete operation works for one or more items selected. Depending on how the editor and adapter are specified, drag and drop operations may be available. If the user selects multiple items and drags one of them, all selected items are included in the drag operation. If the user drags a non-selected item, only that item is dragged. The editor supports both drag-move and drag-copy semantics. A drag-move operation means that the dragged items are sent to the target and are removed from the list displayed in the editor. A drag-copy operation means that the dragged items are sent to the target, but are not deleted from the list data. TreeEditor(), page  PAGEREF _Ref182909681 \h 104  REF _Ref182909697 \h TupleEditor(), page  PAGEREF _Ref182909697 \h 90  REF _Ref182909761 \h ValueEditor(), page  PAGEREF _Ref182909779 \h 91 Some additional editor factories are specific to the wxWidgets toolkit and are defined in one of the following packages: enthought.traits.ui.wx enthought.traits.ui.wx.extra enthought.traits.ui.wx.extra.windows (specific to Microsoft Windows) These editor factories include the following:  REF AnimatedGIFEditor() \h AnimatedGIFEditor(), page  PAGEREF _Ref182909796 \h 119  REF _Ref182909831 \h ArrayViewEditor, p.  PAGEREF _Ref182909831 \h 119  REF _Ref182909865 \h FlashEditor, page  PAGEREF _Ref182909865 \h 120  REF _Ref182909946 \h HistoryEditor(), page  PAGEREF _Ref182909946 \h 120  REF _Ref182909966 \h IEHTMLEditor(), p.  PAGEREF _Ref182909966 \h 121  REF _Ref182909994 \h LEDEditor(), page  PAGEREF _Ref182909994 \h 122  REF _Ref182977879 \h ThemedCheckboxEditor(), page  PAGEREF _Ref182977879 \h 123  REF _Ref191464188 \h ThemedSliderEditor(), page  PAGEREF _Ref191464244 \h 124  REF _Ref182977905 \h ThemedSliderEditor() Suitable forRangeDefault for(none)Required parameters(none)Optional parametersalignment, bg_color, high, increment, low, show_value, slider_color, text_color, tip_colorThe ThemedSliderEditor() factory generates a slider control that is formatted according to specified or default themes. All editor styles have the same appearance. The value is edited by modifying its textual representation. The background of the control updates to reflect the value relative to the total range represented by a slider. For example, if the range is from -2 to 2, a value of 0 is represented by a bar covering the left half of the control area, as shown in Figure 59.  Figure 59: Themed slider without focus, and with focus ThemedTextEditor(), page  PAGEREF _Ref182977905 \h 124  REF _Ref182977941 \h ThemedVerticalNotebookEditor(), page  PAGEREF _Ref182977941 \h 125 For a current complete list of editor factories, refer to the Traits API Reference. These editor factories are described in detail in Chapter  REF _Ref161136597 \n \h 10. Other packages can define their own editor factories for their own traits. For example, enthought.kiva.api.KivaFont uses a KivaFontEditor() and enthought.enable2.traits.api.RGBAColor uses an RGBAColorEditor(). For most predefined traits (see Traits User Manual), there is exactly one predefined trait editor factory suitable for displaying it: the editor factory that is assigned as its default. There are exceptions, however; for example, a Str trait defaults to using a TextEditor, but can also use a CodeEditor or an HTMLEditor. A List trait can be edited by means of ListEditor, TableEditor (if the List elements are HasTraits objects), CheckListEditor or SetEditor. Furthermore, the Traits UI package includes tools for building additional trait editors and factories for them as needed; these tools are described in Chapter  REF _Ref161136615 \n \h Error! Reference source not found.. To use an alternate editor factory for a trait in a Traits UI window, you must specify it in the View for that window. This is done at the Item level, using the editor keyword parameter. The syntax of the specification is editor = editor_name(). (Use the same syntax for specifying that the default editor should be used, but with certain keyword parameters explicitly specified; see Section  REF _Ref161204817 \n \h 9.1.5 on page  PAGEREF _Ref161645188 \h 52). For example, to display a Str trait called my_string using the default editor factory (TextEditor()), the View might contain the following Item: Item(name='my_string') The resulting widget would have the following appearance:  Figure  SEQ "Figure" \*Arabic 13: Default editor for an Str trait To use the HTMLEditor factory instead, add the appropriate specification to the Item: Item( name='my_string', editor=HTMLEditor() ) The resulting widget appears as in  REF _Ref161652944 \h Figure 14:  Figure  SEQ "Figure" \*Arabic 14: Editor generated by HTMLEditor() NOTE: Traits UI does not check editors for appropriateness. Traits UI does not police the editor argument to ensure that the specified editor is appropriate for the trait being displayed. Thus there is nothing to prevent you from trying to, say, display a Float trait using ColorEditor(). The results of such a mismatch are unlikely to be helpful, and can even crash the application; it is up to the programmer to choose an editor sensibly. Chapter  REF _Ref161136642 \n \h 10 is a useful reference for selecting an appropriate editor for a given task. It is possible to specify the trait editor for a trait in other ways: You can specify a trait editor when you define a trait, by passing the result of a trait editor factory as the editor keyword parameter of the callable that creates the trait. However, this approach commingles the view of a trait with its model. You can specify the editor attribute of a TraitHandler object. This approach commingles the view of a trait with its controller. Use these approaches very carefully, if at all, as they muddle the MVC design pattern. Initializing Editors Many of the Traits UI trait editors can be used straight from the box as in the example above. There are some editors, however, that must be initialized in order to be useful. For example, a checklist editor (from CheckListEditor()) and a set editor (from SetEditor()) both enable the user to edit a List attribute by selecting elements from a specified set; the contents of this set must, of course, be known to the editor. This sort of initialization is usually performed by means of one or more keyword arguments to the editor factory, for example: Item(name=my_list,editor=CheckListEditor(values=["opt1","opt2","opt3"])) The descriptions of trait editor factories in Chapter  REF _Ref161136666 \n \h 10 include a list of required and optional initialization keywords for each editor. Specifying an Editor Style In Traits UI, any given trait editor can be generated in one or more of four different styles: simple, custom, text or readonly. These styles, which are described in general terms below, represent different flavors of data display, so that a given trait editor can look completely different in one style than in another. However, different trait editors displayed in the same style (usually) have noticeable characteristics in common. This is useful because editor style, unlike individual editors, can be set at the Group or View level, not just at the Item level. This point is discussed further in Section  REF _Ref161204833 \n \h 9.2.5 on page  PAGEREF _Ref161645210 \h 55. The simple Style The simple editor style is designed to be as functional as possible while requiring minimal space within the window. In simple style, most of the Traits UI editors take up only a single line of space in the window in which they are embedded. In some cases, such as the text editor and Boolean editor (see Section  REF _Ref183843234 \n \h 10.1 on page  PAGEREF _Ref161645225 \h 58), the single line is fully sufficient. In others, such as the (plain) color editor and the enumeration editor, a more detailed interface is required; pop-up panels, drop-down lists, or dialog boxes are often used in such cases. For example, the simple version of the enumeration editor for the wxWidgets toolkit looks like this:  Figure  SEQ "Figure" \*Arabic 15: Simple style of enumeration editor However, when the user clicks on the widget, a drop-down list appears:  Figure  SEQ "Figure" \*Arabic 16: Simple enumeration editor with expanded list The simple editor style is most suitable for windows that must be kept small and concise. The custom Style The custom editor style generally generates the most detailed version of any given editor. It is intended to provide maximal functionality and information without regard to the amount of window space used. For example, in the wxWindows toolkit, the custom style the enumeration editor appears as a set of radio buttons rather than a drop-down list:  Figure  SEQ "Figure" \*Arabic 17: Custom style of enumeration editor In general, the custom editor style can be very useful when there is no need to conserve window space, as it enables the user to see as much information as possible without having to interact with the widget. It also usually provides the most intuitive interface of the four. Note that this style is not defined explicitly for all trait editor implementations. If the custom style is requested for an editor for which it is not defined, the simple style is generated instead. The text Style The text editor style is the simplest of the editor styles. When applied to a given trait attribute, it generates a text representation of the trait value in an editable box. Thus the enumeration editor in text style looks like the following:  Figure  SEQ "Figure" \*Arabic 18: Text style of enumeration editor For this type of editor, the end user must type in a valid value for the attribute. If the user types an invalid value, the validation method for the attribute (see Traits User Manual) notifies the user of the error (for example, by shading the background of the text box red). The text representation of an attribute to be edited in a text style editor is created in one of the following ways, listed in order of priority: The function specified in the format_func attribute of the Item (see Section  REF _Ref161204879 \n \h 2.2.1 on page  PAGEREF _Ref161645238 \h 7), if any, is called on the attribute value. Otherwise, the function specified in the format_func parameter of the trait editor factory, if any, is called on the attribute value. Otherwise, the Python-style formatting string specified in the format_str attribute of the Item (see Section  REF _Ref161204879 \n \h 2.2.1 on page  PAGEREF _Ref161645264 \h 7), if any, is used to format the attribute value. Otherwise, the Python-style formatting string specified in the format_str parameter of the trait editor factory, if any, is used to format the attribute value. Otherwise, the Python str() function is called on the attribute value. The readonly style The readonly editor style is usually identical in appearance to the text style, except that the value appears as static text rather than in an editable box:  Figure  SEQ "Figure" \*Arabic 19: Read-only style of enumeration editor This editor style is used to display data values without allowing the user to change them. Using Editor Styles As discussed in Chapters  REF _Ref161136679 \n \h 2.2 and  REF _Ref161136691 \n \h 3, the Item, Group and View objects of Traits UI all have a style attribute. The style of editor used to display the Items in a View is determined as follows: The editor style used to display a given Item is the value of its style attribute if specifically assigned. Otherwise the editor style of the Group or View that contains the Item is used. The editor style of a Group is the value of its style attribute if assigned. Otherwise, it is the editor style of the Group or View that contains the Group. The editor style of a View is the value of its style attribute if specified, and simple otherwise. In other words, editor style can be specified at the Item, Group or View level, and in case of conflicts the style of the smaller scope takes precedence. For example, consider the following script: Example  SEQ "Example" \*Arabic 13: Using editors styles at various levels # mixed_styles.py -- Example of using editor styles at # various levels from enthought.traits.api import HasTraits, Str, Enum from enthought.traits.ui.api import View, Group, Item class MixedStyles(HasTraits): first_name = Str last_name = Str department = Enum("Business", "Research", "Admin") position_type = Enum("Full-Time", "Part-Time", "Contract") traits_view = View(Group(Item(name='first_name'), Item(name='last_name'), Group(Item(name='department'), Item(name= 'position_type', style='custom'), style='simple')), title='Mixed Styles', style='readonly') ms = MixedStyles(first_name='Sam', last_name='Smith') ms.configure_traits() Notice how the editor styles are set for each attribute: position_type at the Item level department at the Group level first_name and last_name at the View level The resulting window demonstrates these precedence rules:  Figure  SEQ "Figure" \*Arabic 20: User interface for  REF _Ref161214456 \h Example 13 The Predefined Trait Editor Factories This chapter contains individual descriptions of the predefined trait editor factories provided by Traits UI. Most of these editor factories are straightforward and can be used easily with little or no expertise on the part of the programmer or end user; these are described in Section  REF _Ref183843334 \n \h 10.1. Section  REF _Ref161204527 \n \h 10.2 (on page  PAGEREF _Ref161645305 \h 91) covers a smaller set of specialized editors that have more complex interfaces or that are designed to be used along with complex editors. NOTE: Examples are toolkit-specific. The exact appearance of the editors depends on the underlying GUI toolkit. The screenshots and descriptions in this chapter are based on wxWindows. Another supported GUI toolkit is Qt, from TrollTech. Rather than trying to memorize all the information in this chapter, you might skim it to get a general idea of the available trait editors and their capabilities, and to use it as a reference thereafter. Basic Trait Editor Factories The editor factories described in the following sections are straightforward to use. You can pass the editor object returned by the editor factory as the value of the editor keyword parameter when defining a trait. ArrayEditor() Suitable for2-D Array, 2-D CArrayDefault forArray, CArray (if 2-D)Required parameters(none)Optional parameterswidthThe editors generated by ArrayEditor() provide text fields (or static text for the read-only style) for each cell of a two-dimensional Numeric array. Only the simple and read-only styles are supported by the wxWidgets implementation. You can specify the width of the text fields with the width parameter.  Figure  SEQ "Figure" \*Arabic 21: Array editors The following code generates the editors shown in  REF _Ref161718374 \h Figure 21. Example  SEQ "Example" \*Arabic 14: Demonstration of array editors # array_editor.py -- Example of using array editors from enthought.util.numerix import Int, Float from enthought.traits.api import HasPrivateTraits, Array from enthought.traits.ui.api \ import View, ArrayEditor, Item from enthought.traits.ui.menu import NoButtons class ArrayEditorTest ( HasPrivateTraits ): three = Array(Int, (3,3)) four = Array(Float, (4,4), editor = ArrayEditor(width = -50)) view = View( Item('three', label='3x3 Integer'), '_', Item('three', label='Integer Read-only', style='readonly'), '_', Item('four', label='4x4 Float'), '_', Item('four', label='Float Read-only', style='readonly'), buttons = NoButtons, resizable = True ) if __name__ == '__main__': ArrayEditorTest().configure_traits() BooleanEditor() Suitable forBool, CBoolDefault forBool, CBoolRequired parameters(none)Optional parametersmappingBooleanEditor is one of the simplest of the built-in editor factories in the Traits UI package. It is used exclusively to edit and display Boolean (i.e, True/False) traits. In the simple and custom styles, it generates a checkbox. In the text style, the editor displays the trait value (as one would expect) as the strings True or False. However, several variations are accepted as input: True True T Yes y False False F No n The set of acceptable text inputs can be changed by setting the BooleanEditor() parameter mapping to a dictionary whose entries are of the form str: val, where val is either True or False and str is a string that is acceptable as text input in place of that value. For example, to create a Boolean editor that accepts only yes and no as appropriate text values, you might use the following expression: editor=BooleanEditor(mapping={"yes":True, "no":False}) Note that in this case, the strings True and False would not be acceptable as text input.  REF _Ref161205317 \h Figure 22 shows the four styles generated by BooleanEditor().  Figure  SEQ "Figure" \*Arabic 22: Boolean editor styles ButtonEditor() Suitable forButton, Event, ToolbarButtonDefault forButton, ToolbarButtonRequired parameters(none)Optional parametersimage, label, orientation, style, value, view, width_paddingThe ButtonEditor() factory is designed to be used with an Event or Button trait. When a user clicks a button editor, the associated event is fired. Because events are not printable objects, the text and read-only styles are not implemented for this editor. The simple and custom styles of this editor are identical.  Figure  SEQ "Figure" \*Arabic 23: Button editor styles By default, the label of the button is the name of the Button or Event trait to which it is linked. However, this label can be set to any string by specifying the label parameter of ButtonEditor() as that string. You can specify a value for the trait to be set to, using the value parameter. If the trait is an Event, then the value is not stored, but might be useful to an event listener. CheckListEditor() Suitable forListDefault for(none)Required parametersOptional parameterscols, names, valuesThe editors generated by the CheckListEditor() factory are designed to enable the user to edit a List trait by selecting elements from a master list, i.e., a list of possible values. The list of values can be supplied by the trait being edited, or by the values parameter. The values parameter can take either of two forms: A list of strings A list of tuples of the form (element, label), where element can be of any type and label is a string. In the latter case, the user selects from the labels, but the underlying trait is a List of the corresponding element values. Alternatively, you can use the names parameter to specify the label strings for the values. The custom style of editor from this factory is displayed as a set of checkboxes. By default, these checkboxes are displayed in a single column; however, you can initialize the cols parameter of the editor factory to any value between 1 and 20, in which case the corresponding number of columns is used. The simple style generated by CheckListEditor() appears as a drop-down list; in this style, only one list element can be selected, so it returns a list with a single item. The text and read-only styles represent the current contents of the attribute in Python-style text format; in these cases the user cannot see the master list values that have not been selected. The four styles generated by CheckListEditor() are shown in  REF _Ref161205346 \h Figure 24. Note that in this case the cols parameter has been set to 4.   Figure  SEQ "Figure" \*Arabic 24: Checklist editor styles CodeEditor() Suitable forCode, Str, StringDefault forCodeRequired parameters(none)Optional parametersauto_setThe purpose of a code editor is to display and edit Code traits, though it can be used with the Str and String trait types as well. In the simple and custom styles (which are identical for this editor), the text is displayed in numbered, non-wrapping lines with a horizontal scrollbar. The text style displays the trait value using a single scrolling line with special characters to represent line breaks. The read-only style is similar to the simple and custom styles except that the text is not editable.  Figure  SEQ "Figure" \*Arabic 25: Code editor styles The auto_set keyword parameter is a Boolean value indicating whether the trait being edited should be updated with every keystroke (True) or only when the editor loses focus, i.e., when the user tabs away from it or closes the window (False). The default value of this parameter is True. ColorEditor() Suitable forColorDefault forColorRequired parameters(none)Optional parametersmappedThe editors generated by ColorEditor() are designed to enable the user to display a Color trait or edit it by selecting a color from the palette available in the underlying GUI toolkit. The four styles of color editor are shown in  REF _Ref161205358 \h Figure 26.  Figure  SEQ "Figure" \*Arabic 26: Color editor styles In the simple style, the editor appears as a text box whose background is a sample of the currently selected color. The text in the box is either a color name or a tuple of the form (r,g,b) where r, g, and b are the numeric values of the red, green and blue color components respectively. (Which representation is used depends on how the value was entered.) The text value is not directly editable in this style of editor; instead, clicking on the text box displays a pop-up panel similar in appearance and function to the custom style. The custom style includes a labeled color swatch on the left, representing the current value of the Color trait, and a palette of common color choices on the right. Clicking on any tile of the palette changes the color selection, causing the swatch to update accordingly. Clicking on the swatch itself causes a more detailed, platform-specific interface to appear in a dialog box, such as is shown in  REF _Ref161205371 \h Figure 27.  Figure  SEQ "Figure" \*Arabic 27: Custom color selection dialog box for Microsoft Windows XP The text style of editor looks exactly like the simple style, but the text box is editable (and clicking on it does not open a pop-up panel). The user must enter a recognized color name or a properly formatted (r,g,b) tuple. The read-only style displays the text representation of the currently selected Color value (name or tuple) on a minimally-sized background of the corresponding color. For advanced users: The mapped keyword parameter of ColorEditor() is a Boolean value indicating whether the trait being edited has a built-in mapping of user-oriented representations (e.g., strings) to internal representations. Since ColorEditor() is generally used only for Color traits, which are mapped (e.g., cyan to wx.Colour(0,255,255) ), this parameter defaults to True and is not of interest to most programmers. However, it is possible to define a custom color Trait that uses ColorEditor() but is not mapped (i.e., uses only one representation), which is why the attribute is available. CompoundEditor() Suitable forspecialDefault forcompound traitsRequired parameters(none)Optional parametersauto_setAn editor generated by CompoundEditor() consists of a combination of the editors for trait types that compose the compound trait. The widgets for the compound editor are of the style specified for the compound editor (simple, custom, etc.). The editors shown in  REF _Ref161205386 \h Figure 28 are for the following trait, whose value can be an integer between 1 and 6, or any of the letters a through f: compound_trait = Trait( 1, Range( 1, 6 ), 'a', 'b', 'c', 'd', 'e', 'f')  Figure  SEQ "Figure" \*Arabic 28: Example compound editor styles The auto_set keyword parameter is a Boolean value indicating whether the trait being edited should be updated with every keystroke (True) or only when the editor loses focus, i.e., when the user tabs away from it or closes the window (False). The default value of this parameter is True. DirectoryEditor() Suitable forDirectoryDefault forDirectoryRequired parameters(none)Optional parameters(none)A directory editor enables the user to display a Directory trait or set it to some directory in the local system hierarchy. The four styles of this editor are shown in  REF _Ref161205409 \h Figure 29.  Figure  SEQ "Figure" \*Arabic 29: Directory editor styles In the simple style, the current value of the trait is displayed in a combo box to the left of a button labeled . The user can type a new path directly into the text box, select a previous value from the droplist of the combo box, or use the button to bring up a directory browser panel similar to the custom style of editor. When the user selects a directory in this browser, the panel collapses, and control is returned to the original editor widget, which is automatically populated with the new path string. The user can also drag and drop a directory object onto the simple style editor. The custom style displays a directory browser panel, in which the user can expand or collapse directory structures, and click a folder icon to select a directory. The text style of editor is simply a text box into which the user can type a directory path. The readonly style is identical to the text style, except that the text box is not editable. No validation is performed on Directory traits; the user must ensure that a typed-in value is in fact an actual directory on the system. EnumEditor() Suitable forEnum, AnyDefault forEnumRequired parametersfor non-Enum traits: values or name Optional parameterscols, evaluate, modeThe editors generated by EnumEditor() enable the user to pick a single value from a closed set of values.  Figure  SEQ "Figure" \*Arabic 30: Enumeration editor styles The simple style of editor is a drop-down list box. The custom style is a set of radio buttons. Use the cols parameter to specify the number of columns of radio buttons. The text style is an editable text field; if the user enters a value that is not in enumerated set, the background of the field turns red, to indicate an error. You can specify a function to evaluate text input, using the evaluate parameter. The read-only style is the value of the trait as static text. If the trait attribute that is being edited is not an enumeration, you must specify either the trait attribute (with the name parameter), or the set of values to display (with the values parameter). The name parameter can be an extended trait name. The values parameter can be a list, tuple, or dictionary, or a mapped trait. By default, an enumeration editor sorts its values alphabetically. To specify a different order for the items, give it a mapping from the normal values to ones with a numeric tag. The enumeration editor sorts the values based on the numeric tags, and then strips out the tags. For example: Example  SEQ "Example" \*Arabic 15: Enumeration editor with mapped values # enum_editor.py -- Example of using an enumeration editor from enthought.traits.api import HasTraits, Enum from enthought.traits.ui.api import EnumEditor Class EnumExample(HasTraits): priority = Enum('Medium', 'Highest', 'High', 'Medium', 'Low', 'Lowest') view = View( Item(name='priority', editor=EnumEditor(values={ 'Highest' : '1:Highest', 'High' : '2:High', 'Medium' : '3:Medium', 'Low' : '4:Low', 'Lowest' : '5:Lowest', }))) The enumeration editor strips the characters up to and including the colon. It assumes that all the items have the colon in the same position; therefore, if some of your tags have multiple digits, you should use zeros to pad the items that have fewer digits. FileEditor() Suitable forFileDefault forFileRequired parameters(none)Optional parametersentries, filter, filter_name, reload_name, truncate_ext A file editor enables the user to display a File trait or set it to some file in the local system hierarchy. The styles of this editor are shown in  REF _Ref161205433 \h Figure 31.  Figure  SEQ "Figure" \*Arabic 31: File editor styles The default version of the simply style displays a text box and a Browse button. Clicking Browse opens a platform-specific file selection dialog box. If you specify the entries keyword parameter with an integer value to the factory function, the simple style is a combo box and a button labeled . The user can type a file path in the combo box, or select one of entries previous values. Clicking the button opens a browser panel similar to the custom style of editor. When the user selects a file in this browser, the panel collapses, and control is returned to the original editor widget, which is automatically populated with the new path string. For either version of the simple style, the user can drag and drop a file object onto the control. The custom style displays a file system browser panel, in which the user can expand or collapse directory structures, and click an icon to select a file. You can specify a list of filters to apply to the file names displayed, using the filter keyword parameter of the factory function. In  REF _Ref161205433 \h Figure 31, the Custom with Filter editor uses a filter value of [*.py] to display only Python source files. You can also specify this parameter for the simple style, and it will be used in the file selection dialog box or pop-up file system browser panel. Alternatively, you can specify filter_name, whose value is an extended trait name of a trait attribute that contains the list of filters. The reload_name parameter is an extended trait name of a trait attribute that is used to notify the editor when the view of the file system needs to be reloaded. The truncate_ext parameter is a Boolean that indicates whether the file extension is removed from the returned filename. It is False by default, meaning that the filename is not modified before it is returned. FontEditor() Suitable forFontDefault forFontRequired parameters(none)Optional parameters(none)A font editor enables the user to display a Font trait or edit it by selecting one of the fonts provided by the underlying GUI toolkit. The four styles of this editor are shown in  REF _Ref161205460 \h Figure 32.  Figure  SEQ "Figure" \*Arabic 32: Font editor styles In the simple style, the currently selected font appears in a display similar to a text box, except that when the user clicks on it, a platform-specific dialog box appears with a detailed interface, such as is shown in  REF _Ref161205478 \h Figure 33. When the user clicks OK, control returns to the editor, which then displays the newly selected font.  Figure  SEQ "Figure" \*Arabic 33: Example font dialog box for Microsoft Windows In the simple style, an abbreviated version of the font dialog box is displayed in-line. The user can either type the name of the font in the text box or use the two drop-down lists to select a typeface and size. In the text style, the user must type the name of a font in the text box provided. No validation is performed; the user must enter the correct name of an available font. The read-only style is identical except that the text is not editable. HTMLEditor() Suitable forHTML, string traitsDefault forHTMLRequired parameters(none)Optional parametersformat_textThe editor generated by HTMLEditor() interprets and displays text as HTML. It does not support the user editing the text that it displays. It generates the same type of editor, regardless of the style specified.  REF _Ref161552507 \h Figure 34 shows an HTML editor in the upper pane, with a code editor in the lower pane, displaying the uninterpreted text.  Figure  SEQ "Figure" \*Arabic 34: Example HTML editor, with code editor showing original text NOTE: HTML support is limited in the wxWidgets toolkit. The set of tags supported by the wxWidgets implementation of the HTML editor is a subset of the HTML 3.2 standard. It does not support style sheets or complex formatting. Refer to the  HYPERLINK "http://www.lpthe.jussieu.fr/~zeitlin/wxWindows/docs/wxwin_wxhtml.html"wxWidgets documentation for details. If the format_text argument is True, then the HTML editor supports basic implicit formatting, which it converts to HTML before passing the text to the HTML interpreter. The implicit formatting follows these rules: Indented lines that start with a dash (-) are converted to unordered lists. Indented lines that start with an asterisk (*) are converted to ordered lists. Indented lines that start with any other character are converted to code blocks. Blank lines are converted to paragraph separators. The following text produces the same displayed HTML as in  REF _Ref161552507 \h Figure 34, when format_text is True: This is a code block: def foo ( bar ): print 'bar:', bar This is an unordered list: - An - unordered - list This is an ordered list: * One * Two * Three ImageEnumEditor() Suitable forEnum, AnyDefault for(none)Required parametersfor non-Enum traits: values or name Optional parameterspath, klass, or module; cols, evaluate, suffixThe editors generated by ImageEnumEditor() enable the user to select an item in an enumeration by selecting an image that represents the item.  Figure  SEQ "Figure" \*Arabic 35: Editor styles for image enumeration The custom style of editor displays a set of images; the user selects one by clicking it, and it becomes highlighted to indicate that it is selected. The simple style displays a button with an image for the currently selected item. When the user clicks the button, a pop-up panel displays a set of images, similar to the custom style. The user clicks an image, which becomes the new image on the button. The text style does not display images; it displays the text representation of the currently selected item. The user must type the text representation of another item to select it. The read-only style displays the image for the currently selected item, which the user cannot change. The ImageEnumEditor() function accepts the same parameters as the EnumEditor() function (see Section  REF _Ref161645067 \n \h 10.1.9 on page  PAGEREF _Ref161645067 \h 69), as well as some additional parameters. NOTE: Image enumeration editors do not use ImageResource. Unlike most other images in the Traits and Traits UI packages, images in the wxWindows implementation of image enumeration editors do not use the PyFace ImageResource class. In the wxWidgets implementation, image enumeration editors use the following rules to locate images to use: Only GIF (.gif) images are currently supported. The base file name of the image is the string representation of the value, with spaces replaced by underscores and the suffix argument, if any, appended. Note that suffix is not a file extension, but rather a string appended to the base file name. For example, if suffix is _origin and the value is top left, the image file name is top_left_origin.gif. If the path parameter is defined, it is used to locate the file. It can be absolute or relative to the file where the image enumeration editor is defined. If path is not defined and the klass parameter is defined, it is used to locate the file. The klass parameter must be a reference to a class. The editor searches for an images subdirectory in the following locations: The directory that contains the module that defines the class. If the class was executed directly, the current working directory. If path and klass are not defined, and the module parameter is defined, it is used to locate the file. The module parameter must be a reference to a module. The editor searches for an images subdirectory of the directory that contains the module. If path, klass, and module are not defined, the editor searches for an images subdirectory of the enthought.traits.ui.wx package. If none of the above paths are defined, the editor searches for an images directory that is a sibling of the directory from which the application was run. InstanceEditor() Suitable forInstance, Property, self, ThisClass, ThisDefault forInstance, self, ThisClass, ThisRequired parameters(none)Optional parameterscachable, editable, id, kind, label, name, object, orientation, values, viewThe editors generated by InstanceEditor() enable the user to select an instance, or edit an instance, or both. Editing a Single Instance In the simplest case, the user can modify the trait attributes of an instance assigned to a trait attribute, but cannot modify which instance is assigned.  Figure  SEQ "Figure" \*Arabic 36: Editor styles for instances The custom style displays a user interface panel for editing the trait attributes of the instance. The simple style displays a button, which when clicked, opens a window containing a user interface for the instance. The kind parameter specifies the kind of window to open (see Section  REF _Ref190748021 \n \h 3.1.1 on page  PAGEREF _Ref162338878 \h 16). The label parameter specifies a label for the button in the simple interface. The view parameter specifies a view to use for the referenced instances user interface; if this is not specified, the default view for the instance is used (see Section  REF _Ref162338927 \n \h 4.1.1 on page  PAGEREF _Ref162338939 \h 23). The text and read-only styles display the string representation of the instance. They therefore cannot be used to modify the attributes of the instance. A user could modify the assigned instance if they happened to know the memory address of another instance of the same type, which is unlikely. These styles can useful for prototyping and debugging, but not for real applications. Selecting Instances You can add an option to select a different instance to edit. Use the name parameter to specify the extended name of a trait attribute in the context that contains a list of instances that can be selected or edited. (See Section  REF _Ref161204772 \n \h 4.4 on page  PAGEREF _Ref162083396 \h 27 for an explanation of contexts.) Using these parameters results in a drop-drown list box containing a list of text representations of the available instances. If the instances have a name trait attribute, it is used for the string in the list; otherwise, a user-friendly version of the class name is used. For example, the following code defines a Team class and a Person class. A Team has a roster of Persons, and a captain. In the view for a team, the user can pick a captain and edit that persons information. Example  SEQ "Example" \*Arabic 16: Instance editor with instance selection # instance_editor_selection.py -- Example of an instance editor # with instance selection from enthought.traits.api \ import HasStrictTraits, Int, Instance, List, Regex, Str from enthought.traits.ui.api \ import View, Item, InstanceEditor class Person ( HasStrictTraits ): name = Str age = Int phone = Regex( value = '000-0000', regex = '\d\d\d[-]\d\d\d\d' ) traits_view = View( 'name', 'age', 'phone' ) people = [ Person( name = 'Dave', age = 39, phone = '555-1212' ), Person( name = 'Mike', age = 28, phone = '555-3526' ), Person( name = 'Joe', age = 34, phone = '555-6943' ), Person( name = 'Tom', age = 22, phone = '555-7586' ), Person( name = 'Dick', age = 63, phone = '555-3895' ), Person( name = 'Harry', age = 46, phone = '555-3285' ), Person( name = 'Sally', age = 43, phone = '555-8797' ), Person( name = 'Fields', age = 31, phone = '555-3547' ) ] class Team ( HasStrictTraits ): name = Str captain = Instance( Person ) roster = List( Person ) traits_view = View( Item('name'), Item('_'), Item( 'captain', label='Team Captain', editor = InstanceEditor( name = 'roster', editable = True), style = 'custom', ), buttons = ['OK']) if __name__ == '__main__': Team( name = 'Vultures', captain = people[0], roster = people ).configure_traits()  Figure  SEQ "Figure" \*Arabic 37: User interface for  REF _Ref161833094 \h Example 16 If you want the user to be able to select instances, but not modify their contents, set the editable parameter to False. In that case, only the selection list for the instances appears, without the user interface for modifying instances. Allowing Instances You can specify what types of instances can be edited in an instance editor, using the values parameter. This parameter is a list of items describing the type of selectable or editable instances. These items must be instances of subclasses of enthought.traits.ui.api.InstanceChoiceItem. If you want to generate new instances, put an InstanceFactoryChoice instance in the values list that describes the instance to create. If you want certain types of instances to be dropped on the editor, use an InstanceDropChoice instance in the values list. ListEditor() Suitable forListDefault forListRequired parameters(none)Optional parameterseditor, rows, style, trait_handler, use_notebook The following parameters are used only if use_notebook is True: deletable, dock_style, export, page_name, select, viewThe editors generated by ListEditor() enable the user to modify the contents of a list, both by editing the individual items and by adding, deleting, and reordering items within the list.  Figure  SEQ "Figure" \*Arabic 38: List editor styles The simple style displays a single item at a time, with small arrows on the right side to scroll the display. The custom style shows multiple items. The number of items displayed is controlled by the rows parameter; if the number of items in the list exceeds this value, then the list display scrolls. The editor used for each item in the list is determined by the editor and style parameters. The text style of list editor is identical to the custom style, except that the editors for the items are text editors. The read-only style displays the contents of the list as static text. By default, the items use the trait handler appropriate to the type of items in the list. You can specify a different handler to use for the items using the trait_handler parameter. For the simple, custom, and text list editors, a button appears to the left of each item editor; clicking this button opens a context menu for modifying the list, as shown in  REF _Ref161566341 \h Figure 39.  Figure  SEQ "Figure" \*Arabic 39: List editor showing context menu In addition to the four standard styles for list editors, fifth list editor user interface option is available. If use_notebook is True, then the list editor displays the list as a notebook of tabbed pages, one for each item in the list, as shown in  REF _Ref161567129 \h Figure 40. This style can be useful in cases where the list items are instances with their own views. If the deletable parameter is True, a close box appears on each tab, allowing the user to delete the item; the user cannot add items interactively through this style of editor.  Figure  SEQ "Figure" \*Arabic 40: Notebook list editor ListStrEditor() Suitable forListStr or List of values mapped to stringsDefault for(none)Required parameters(none)Optional parametersactivated, activated_index, adapter, adapter_name, auto_add, drag_move, editable, horizontal_lines, images, multi_select, operations, right_clicked, right_clicked_index, selected, selected_index, title, title_nameListStrEditor() generates a list of selectable items corresponding to items in the underlying trait attribute. All styles of the editor are the same. The parameters to ListStrEditor() control aspects of the behavior of the editor, such as what operations it allows on list items, whether items are editable, and whether more than one can be selected at a time. You can also specify extended references for trait attributes to synchronize with user actions, such as the item that is currently selected, activated for editing, or right-clicked.  Figure  SEQ "Figure" \*Arabic 41: List string editor NullEditor() Suitable forcontrolling layoutDefault for(none)Required parameters(none)Optional parameters(none)The NullEditor() factory generates a completely empty panel. It is used by the Spring subclass of Item, to generate a blank space that uses all available extra space along its layout orientation. You can also use it to create a blank area of a fixed height and width. RangeEditor() Suitable forRangeDefault forRangeRequired parameters(none)Optional parametersauto_set, cols, enter_set, format, high_label, high_name, label_width, low_label, low_name, mode The editors generated by RangeEditor() enable the user to specify numeric values within a range. The widgets used to display the range vary depending on both the numeric type and the size of the range, as described in  REF _Ref161575760 \h Table 8 and shown in  REF _Ref161643228 \h Figure 42. If one limit of the range is unspecified, then a text editor is used. Table  SEQ "Table" \*Arabic 8: Range editor widgets SimpleCustomTextRead-onlyInteger: Small Range (Size 0-16)Slider with text fieldRadio buttonsText fieldStatic textInteger: Medium Range (Size 17-101)Slider with text fieldSlider with text fieldText fieldStatic textInteger: Large Range (Size > 101)Spin boxSpin boxText fieldStatic textFloating Point: Small Range (Size <= 100.0)Slider with text fieldSlider with text fieldText fieldStatic textFloating Point: Large Range (Size > 100.0)Large-range sliderLarge-range sliderText fieldStatic text Figure  SEQ "Figure" \*Arabic 42: Range editor widgets In the large-range slider, the arrows on either side of the slider move the editable range, so that the user can move the slider more precisely to the desired value. You can override the default widget for each type of editor using the mode parameter, which can have the following values: autoThe default widget, as described in  REF _Ref161575760 \h Table 8 sliderSimple slider with text field xsliderLarge-range slider with text field spinnerSpin box enumRadio buttons textText field You can set the limits of the range dynamically, using the low_name and high_name parameters to specify trait attributes that contain the low and high limit values; use low_label, high_label and label_width to specify labels for the limits. RGBColorEditor() Suitable forRGBColorDefault forRGBColorRequired parameters(none)Optional parametersmappedEditors generated by RGBColorEditor() are identical in appearance to those generated by ColorEditor(), but they are used for RGBColor traits. See Section  REF _Ref161644779 \n \h 10.1.6 on page  PAGEREF _Ref161644792 \h 64 for details. SetEditor() Suitable forListDefault fornoneRequired parametersEither values or name Optional parameterscan_move_all, left_column_title, object, ordered, right_column_title, In the editors generated by SetEditor(), the user can select a subset of items from a larger set. The two lists are displayed in list boxes, with the candidate set on the left and the selected set on the right. The user moves an item from one set to the other by selecting the item and clicking a direction button (> for left-to-right and < for right-to-left). Additional buttons can be displayed, depending on two Boolean parameters: If can_move_all is True, additional buttons appear, whose function is to move all items from one side to the other (>> for left-to-right and << for right-to-left). If ordered is True, additional buttons appear, labeled Move up and Move down, which affect the position of the selected item within the set in the right list box.  Figure  SEQ "Figure" \*Arabic 43: Set editor showing all possible buttons You can specify the set of candidate items in either of two ways: Set the values parameter to a list, tuple, dictionary, or mapped trait. Set the name parameter to the extended name of a trait attribute that contains the list. ShellEditor() Suitable forspecialDefault forPythonValueRequired parameters(none)Optional parameters(none)The editor generated by ShellEditor() displays an interactive Python shell.  Figure  SEQ "Figure" \*Arabic 44: Python shell editor TextEditor() Suitable forallDefault forStr, String, Password, Unicode, Int, Float, Dict, CStr, CUnicode, and any trait that does not have a specialized TraitHandlerRequired parameters(none)Optional parametersauto_set, enter_set, evaluate, evaluate_name, mapping, multi_line, passwordThe editor generated by TextEditor() displays a text box. For the custom style, it is a multi-line field; for the read-only style, it is static text. If password is True, the text that the user types in the text box is obscured.  Figure  SEQ "Figure" \*Arabic 45: Text editor styles for integers  Figure  SEQ "Figure" \*Arabic 46: Text editor styles for strings  Figure  SEQ "Figure" \*Arabic 47: Text editor styles for passwords You can specify whether the trait being edited is updated on every keystroke (auto_set=True) or when the user presses the Enter key (enter_set=True). If auto_set and enter_set are False, the trait is updated when the user shifts the input focus to another widget. You can specify a mapping from user input values to other values with the mapping parameter. You can specify a function to evaluate user input, either by passing a reference to it in the evaluate parameter, or by passing the extended name of a trait that references it in the evaluate_name parameter. TitleEditor() Suitable forstring traitsDefault for(none)Required parameters(none)Optional parameters(none)TitleEditor() generates a read-only display of a string value, formatted as a heading. All styles of the editor are identical. Visually, it is similar to a Heading item, but because it is an editor, you can change the text of the heading by modifying the underlying attribute. TupleEditor() Suitable forTupleDefault forTupleRequired parameters(none)Optional parameterscols, editors, labels, traitsThe simple and custom editors generated by TupleEditor() provide a widget for each slot of the tuple being edited, based on the type of data in the slot. The text and read-only editors edit or display the text representation of the tuple.  Figure  SEQ "Figure" \*Arabic 48: Tuple editor styles You can specify the number of columns to use to lay out the widgets with the cols parameter. You can specify labels for the widgets with the labels parameter. You can also specify trait definitions for the slots of the tuple; however, this is usually implicit in the tuple being edited. You can supply a list of editors to be used for each corresponding tuple slot. If the editors list is missing, or is shorter than the length of the tuple, default editors are used for any tuple slots not defined in the list. This feature allows you to substitute editors, or to supply non-default parameters for editors. ValueEditor() Suitable for(any)Default for(none)Required parameters(none)Optional parametersauto_openValueEditor() generates a tree editor that displays Python values and objects, including all the objects members. For example,  REF _Ref163470800 \h Figure 49 shows a value editor that is displayed by the pickle viewer utility in enthought.debug.  Figure  SEQ "Figure" \*Arabic 49: Value editor from Pickle Viewer Advanced Trait Editors The editor factories described in the following sections are more advanced than those in the previous section. In some cases, they require writing additional code; in others, the editors they generate are intended for use in complex user interfaces, in conjunction with other editors. CustomEditor() Suitable forSpecial casesDefault for(none)Required parametersfactoryOptional parametersargsUse CustomEditor() to create an editor that is a non-Traits-based custom control. The factory parameter must be a function that generates the custom control. The function must have the following signature: factory_function(window_parent, editor, *args, **kwargs) window_parentThe parent window for the control editorThe editor object created by CustomEditor() Additional arguments, if any, can be passed as a tuple in the args parameter of CustomEditor(). For an example of using CustomEditor(),examine the implementation of the NumericModelExplorer class in the enthought.model.numeric_model_explorer module; CustomEditor() is used to generate the plots in the user interface. DropEditor() Suitable forInstance traitsDefault for(none)Required parameters(none)Optional parametersbinding, klass, readonlyDropEditor() generates an editor that is a text field containing a string representation of the trait attributes value. The user can change the value assigned to the attribute by dragging and dropping an object on the text field, for example, a node from a tree editor (See Section  REF _Ref182909666 \n \h 9.2.6). If the readonly parameter is True (the default), the user cannot modify the value by typing in the text field. You can restrict the class of objects that can be dropped on the editor by specifying the klass parameter. You can specify that the dropped object must be a binding (enthought.naming.api.Binding) by setting the binding parameter to True. If so, the bound object is retrieved and checked to see if it can be assigned to the trait attribute. If the dropped object (or the bound object associated with it) has a method named drop_editor_value(), it is called to obtain the value to assign to the trait attribute. Similarly, if the object has a method named drop_editor_update(), it is called to update the value displayed in the text editor. This method requires one parameter, which is the GUI control for the text editor. DNDEditor() Suitable forInstance traitsDefault for(none)Required parameters(none)Optional parametersdrag_target, drop_target, image DNDEditor() generates an editor that represents a file or a HasTraits instance as an image that supports dragging and dropping. Depending on the editor style, the editor can be a drag source (the user can set the value of the trait attribute by dragging a file or object onto the editor, for example, from a tree editor), or drop target (the user can drag from the editor onto another target). Table  SEQ "Table" \*Arabic 9: Drag-and-drop editor style variations Editor StyleDrag Source?Drop Target?SimpleYesYesCustomNoYesRead-onlyYesNoKeyBindingEditor() The KeyBindingEditor() factory differs from other trait editor factories because it generates an editor, not for a single attribute, but for an object of a particular class, enthought.traits.ui.key_bindings.KeyBindings. A KeyBindings object is a list of bindings between key codes and handler methods. You can specify a KeyBindings object as an attribute of a View. When the user presses a key while a View has input focus, the user interface searches the View for a KeyBindings that contains a binding that corresponds to the key press; if such a binding does not exist on the View, it searches enclosing Views in order, and uses the first matching binding, if any. If it does not find any matching bindings, it ignores the key press. A key binding editor is a separate dialog box that displays the string representation of each key code and a description of the corresponding method. The user can click a text box, and then press a key or key combination to associate that key press with a method.  Figure  SEQ "Figure" \*Arabic 50: Key binding editor dialog box The following code example creates a user interface containing a code editor with associated key bindings, and a button that invokes the key binding editor. Example  SEQ "Example" \*Arabic 17: Code editor with key binding editor # key_bindings.py -- Example of a code editor with a # key bindings editor from enthought.traits.api \ import Button, Code, HasPrivateTraits, Str from enthought.traits.ui.api \ import View, Item, Group, Handler, CodeEditor from enthought.traits.ui.key_bindings \ import KeyBinding, KeyBindings key_bindings = KeyBindings( KeyBinding( binding1 = 'Ctrl-s', description = 'Save to a file', method_name = 'save_file' ), KeyBinding( binding1 = 'Ctrl-r', description = 'Run script', method_name = 'run_script' ), KeyBinding( binding1 = 'Ctrl-k', description = 'Edit key bindings', method_name = 'edit_bindings' ) ) # Traits UI Handler class for bound methods class CodeHandler ( Handler ): def save_file ( self, info ): info.object.status = "save file" def run_script ( self, info ): info.object.status = "run script" def edit_bindings ( self, info ): info.object.status = "edit bindings" key_bindings.edit_traits() class KBCodeExample ( HasPrivateTraits ): code = Code status = Str kb = Button(label='Edit Key Bindings') view = View( Group ( Item( 'code', style = 'custom', resizable = True ), Item('status', style='readonly'), 'kb', orientation = 'vertical', show_labels = False, ), id = 'KBCodeExample', key_bindings = key_bindings, title = 'Code Editor With Key Bindings', resizable = True, handler = CodeHandler() ) def _kb_fired( self, event ): key_bindings.edit_traits() if __name__ == '__main__': KBCodeExample().configure_traits() TableEditor() Suitable forList(InstanceType)Default for(none)Required parameterscolumns or columns_nameOptional parametersSee Traits API Reference, enthought.traits.ui.wx.table_editor .ToolkitEditorFactory attributes.TableEditor() generates a editor that displays instances in a list as rows in a table, with attributes of the instances as values in columns. You must specify the columns in the table. Optionally, you can provide filters for filtering the set of displayed items, and you can specify a wide variety of options for interacting with and formatting the table.  Figure  SEQ "Figure" \*Arabic 51: Table editor To see the code that results in  REF _Ref162689531 \h Figure 51, refer to TableEditor_demo.py in the demos/TraitsUIDemo/StandardEditors subdirectory of the Traits UI package. This example demonstrates object columns, expression columns, filters, searching, and adding and deleting rows. The parameters for TableEditor() can be grouped in several broad categories, described in the following sections.  REF _Ref192064881 \h Specifying Columns  REF _Ref192064901 \h Managing Items  REF _Ref192064917 \h Editing the Table  REF _Ref192064930 \h Defining the Layout  REF _Ref192064946 \h Defining the Format  REF _Ref192064954 \h Other User Interactions Specifying Columns You must provide the TableEditor() factory with a list of columns for the table. You can specify this list directly, as the value of the columns parameter, or indirectly, in an extended context attribute referenced by the columns_name parameter. The items in the list must be instances of enthought.traits.ui.api.TableColumn, or of a subclass of TableColumn. Some subclasses of TableColumn that are provided by the Traits UI package include ObjectColumn, ListColumn, NumericColumn, and ExpressionColumn. (See the Traits API Reference for details about these classes.) In practice, most columns are derived from one of these subclasses, rather than from TableColumn. For the usual case of editing trait attributes on objects in the list, use ObjectColumn. You must specify the name parameter to the ObjectColumn() constructor, referencing the name of the trait attribute to be edited. You can specify additional columns that are not initially displayed using the other_columns parameter. If the configurable parameter is True (the default), a Set user preferences for table icon () appears on the tables toolbar. When the user clicks this icon, a dialog box opens that enables the user to select and order the columns displayed in the table, as shown in  REF _Ref162087667 \h Figure 52. (The dialog box is implemented using a set editor; see Section  REF _Ref182909485 \n \h 8.1.20 on page  PAGEREF _Ref162087715 \h 86.) Any columns that were specified in the other_columns parameter are listed in the left list box of this dialog box, and can be displayed by moving them into the right list box.  Figure  SEQ "Figure" \*Arabic 52: Column selection dialog box for a table editor Managing Items Table editors support several mechanisms to help users locate items of interest. Organizing Items Table editors provide two mechanisms for the user to organize the contents of a table: sorting and reordering. The user can sort the items based on the values in a column, or the user can manually order the items. Usually, only one of these mechanisms is used in any particular table, although the Traits UI package does not enforce a separation. If the user has manually ordered the items, sorting them would throw away that effort. If the reorderable parameter is True, Move up () and Move down () icons appear in the table toolbar. Clicking one of these icons changes the position of the selected item. If the sortable parameter is True (the default), then the user can sort the items in the table based on the values in a column by Control-clicking the header of that column. On the first click, the items are sorted in ascending order. The characters >> appear in the column header to indicate that the table is sorted ascending on this columns values. On the second click, the items are sorted descending order. The characters << appear in the column header to indicate that the table is sorted descending on this columns values. On the third click, the items are restored to their original order, and the column header is undecorated. If the sort_model parameter is true, the items in the list being edited are sorted when the table is sorted. The default value is False, in which case, the list order is not affected by sorting the table. If sortable is True and sort_model is False, then a Do not sort columns icon () appears in the table toolbar. Clicking this icon restores the original sort order. If the reverse parameter is True, then the items in the underlying list are maintained in the reverse order of the items in the table (regardless of whether the table is sortable or reorderable). Filtering and Searching You can provide an option for the user to apply a filter to a table, so that only items that pass the filter are displayed. This feature can be very useful when dealing with lengthy lists. You can specify a filter to apply to the table either directly, or via another trait. Table filters must be instances of enthought.traits.ui.api.TableFilter, or of a subclass of TableFilter. Some subclasses of TableFilter that are provided by the Traits UI package include EvalTableFilter, RuleTableFilter, and MenuTableFilter. (See the Traits API Reference for details about these classes.) The Traits UI package also provides instances of these filter classes as templates, which cannot be edited or deleted, but which can be used as models for creating new filters. The filter parameter specifies a filter that is applied to the table when it is first displayed. The filter_name parameter specifies an extended trait name for a trait that is either a table filter object or a callable that accepts an object and returns True if the object passes the filter criteria, or false if it does not. You can use filter_name to embed a view of a table filter in the same view as its table. You can specify use the filters parameter to specify a list of table filters that are available to apply to a table. When filters is specified, a drop-down list box appears in the table toolbar, containing the filters that are available for the user to apply. When the user selects a filter, it is automatically applied to the table. A status message to the right of the filters list indicates what subset of the items in the table is currently displayed. A special item in the filter list, named Customize, is always provided; clicking this item opens a dialog box that enables the user to create new filters, or to edit or delete existing filters (except templates). You can also provide an option for the user to use filters to search the table. If you set the search parameter to an instance of TableFilter (or of a subclass), a Search table icon () appears on the table toolbar. Clicking this icon opens a Search for dialog box, which enables the user to specify filter criteria, to browse through matching items, or select all matching items. Interacting with Items As the user clicks in the table, you may wish to enable certain program behavior. The selection_mode parameter specifies how the user can make selections in the grid: cellA single cell at a time cellsMultiple cells columnA single column at a time columnsMultiple columns rowA single row at a time rowsMultiple rows You can use the selected parameter to specify the name of a trait attribute in the current context to synchronize with the users current selection. For example, you can enable or disable menu items or toolbar icons depending on which item is selected. The synchronization is two-way; you can set the attribute referenced by selected to force the table to select a particular item. You can use the selected_indices parameter to specify the name of a trait attribute in the current context to synchronize with the indices of the table editor selection. The content of the selection depends on the selection_mode value: cellThe selection is a tuple of the form (object, column_name), where object is the object contains the selected cell, and column_name is the name of the column the cell is in. If there is no selection, the tuple is (None, ''). cellsThe selection is a list of tuples of the form (object, column_name), with one tuple for each selected cell, in order from top to bottom and left to right. If there is no selection, the list is empty. columnThe selection is the name of the selected column, or the empty string if there is no selection. columnsThe selection is a list containing the names of the selected columns, in order from left to right. If there is no selection, the list is empty. rowThe selection is either the selected object or None if nothing is selected in the table. rowsThe selection is a list of the selected objects, in ascending row order. If there is no selection, the list is empty. The on_select and on_dclick parameters are callables to invoke when the user selects or double-clicks an item, respectively. You can define a shortcut menu that opens when the user right-clicks an item. Use the menu parameter to specify a Traits UI or PyFace Menu, containing Action objects for the menu commands. Editing the Table The Boolean editable parameter controls whether the table or its items can be modified in any way. This parameter defaults to True, except when the style is readonly. Even when the table as a whole is editable, you can control whether individual columns are editable through the editable attribute of TableColumn. Adding Items To enable users to add items to the table, specify as the row_factory parameter a callable that generates an object that can be added to the list in the table; for example, the class of the objects in the table. When row_factory is specified, an Insert new item icon () appears in the table toolbar, which generates a new row in the table. Optionally, you can use row_factory_args and row_factory_kw to specify positional and keyword arguments to the row factory callable. To save users the trouble of mousing to the toolbar, you can enable them to add an item by selecting the last row in the table. To do this, set auto_add to True. In this case, the last row is blank until the user sets values. Pressing Enter creates the new item and generates a new, blank last row. Deleting Items The deletable parameter controls whether items can be deleted from the table. This parameter can be a Boolean (defaulting to False) or a callable; the callable must take an item as an argument and handle deleting it. If deletable is not False, a Delete current item icon () appears on the table toolbar; clicking it deletes the item corresponding to the row that is selected in the table. Modifying Items The user can modify items in two ways. For columns that are editable, the user can change an items value directly in the table. The editor used for each attribute in the table is the simple style of editor for the corresponding trait. Alternatively, you can specify a View for editing instances, using the edit_view parameter. The resulting user interface appears in a sub-panel to the right or below the table (depending on the orientation parameter). You can specify a handler to use with the view, using edit_view_handler. You can also specify the subpanels height and width, with edit_view_height and edit_view_width. Defining the Layout Some of the parameters for the TableEditor() factory affect global aspects of the display of the table. auto_sizeIf True, the cells of the table automatically adjust to the optimal size based on their contents. orientationThe layout of the table relative to its associated editor pane. Can be horizontal or vertical. rowsThe number of visible rows in the table. show_column_labelsIf True (the default), displays labels for the columns. You can specify the labels to use in the column definitions; otherwise, a user friendly version of the trait attribute name is used. show_toolbarIf False, the table toolbar is not displayed, regardless of whether other settings would normally create a toolbar. The default is True. Defining the Format The TableEditor() factory supports a variety of parameters to control the visual formatting of the table, such as colors, fonts, and sizes for lines, cells, and labels. For details, refer to the Traits API Reference, enthought.traits.ui.wx.table_editor.ToolkitEditorFactory attributes. You can also specify formatting options for individual table columns when you define them. Other User Interactions The table editor supports additional types of user interaction besides those controlled by the factory parameters. Column draggingThe user can reorganize the column layout of a table editor by clicking and dragging a column label to its new location. If you have enabled user preferences for the view and table editor (by specifying view and item IDs), the new column layout is persisted across user sessions. Column resizingThe user can resize a column by dragging the column separator (in one of the data rows) to a new position. Because of the column-dragging support, clicking the column separator in the column label row does not work. Data draggingThe user can drag the contents of any cell by clicking and dragging. TabularEditor() Suitable forlists, arrays, and other large sequences of objectsDefault for(none)Required parametersadapterOptional parametersactivated, clicked, column_clicked, dclicked, drag_move, editable, horizontal_lines, images, multi_select, operations, right_clicked, right_dclicked, selected, selected_row, show_titles, vertical_linesThe TabularEditor() factory can be used for many of the same purposes as the TableEditor() factory, that is, for displaying a table of attributes of lists or arrays of objects. While similar in function, each editor has its own advantages and disadvantages. Some of the advantages of the tabular editor are: Very fast: The tabular editor uses a virtual model, which accesses data from the underlying model only as needed. For example, if you have a million-element array, but can display only 50 rows at a time, the editor requests only 50 elements of data at a time. Very flexible data model: The editor uses an adapter model to interface with the underlying data. This strategy allows it to easily deal with many types of data representation, from list of objects, to arrays of numbers, to tuples of tuples, and many other formats. Supports useful data operations, including: Moving the selection up and down using the keyboard arrow keys. Moving rows up and down using the keyboard. Inserting and deleting items using the keyboard. Initiating editing of items using the keyboard. Dragging and dropping of table items to and from the editor, including support for both copy and move operations for single and multiple items. Visually appealing: The tabular editor, in general, uses the underlying operating systems native table or grid control, and as a result often looks better than the control used by the table editor. Supports displaying text and images in any cell. However, the images displayed must be all the same size for optimal results. Some of the disadvantages of the tabular editor relative to the table editor are: Not as full-featured: The table editor includes support for arbitrary data filters, searches, and different types of sorting. These differences may narrow as features are added to the tabular editor. Limited data editing capabilities: The tabular editor supports editing only textual values, whereas the table editor supports a wide variety of column editors, and can be extended with more as needed. This is due to limitations of the underlying native control used by the tabular editor. TabularAdapter The tabular editor works in conjunction with an adapter class, derived from TabularAdapter. The tabular adapter interfaces between the tabular editor and the data being displayed. The tabular adapter is the reason for the flexibility and power of the tabular editor to display a wide variety of data. The most important attribute of TabularAdapter is columns, which is list of columns to be displayed. Each entry in the columns list can be either a string, or a tuple consisting of a string and another value, which can be of any type. The string is used as the label for the column. The second value in the tuple, called the column ID, identifies the column to the adapter. It is typically a trait attribute name or an integer index, but it can be any value appropriate to the adapter. If only a string is specified for an entry, then the index of the entry within the columns list is used as that entrys column ID. Attributes on TabularAdapter control the appearance of items, and aspects of interaction with items, such as whether they can be edited, and how they respond to dragging and dropping. Setting any of these attributes on the adapter subclass sets the global behavior for the editor. Refer to the Traits API Reference for details of the available attributes. You can also specify these attributes for a specific class or column ID, or combination of class and column ID. When the TabularAdapter needs to look up the value of one of its attributes for a specific item in the table, it looks for attributes with the following naming conventions in the following order: classname_columnid_attribute classname_attribute columnid_attribute attribute For example, to find the text_color value for an item whose class is Person and whose column ID is age, the get_text_color() method looks for the following attributes in sequence, and returns the first value it finds: Person_age_text_color Person_text_color age_text_color text_color Note that the classname can be the name of a base class, searched in the method resolution order (MRO) for the items class. So for example, if the item were a direct instance of Employee, which is a subclass of Person, then the Person_age_text_color attribute would apply to that item (as long as there were no Employee_age_text_color attribute). The Tabular Editor User Interface  REF _Ref184101438 \h Error! Reference source not found. shows an example of a tabular editor on Microsoft Windows, displaying information about source files in the Traits package. This example includes a column that contains an image for files that meet certain conditions.  Figure  SEQ "Figure" \*Arabic 53: Tabular editor on MS Windows Depending on how the tabular editor is configured, certain keyboard interactions may be available. For some interactions, you must specify that the corresponding operation is allowed by including the operation name in the operations list parameter of TabularEditor(). Up arrow: Selects the row above the currently selected row. Down arrow: Selects the row below the currently selected row. Page down: Appends a new item to the end of the list (append operation). Left arrow: Moves the currently selected row up one line (move operation). Right arrow: Moves the currently selected row down one line (move operation). Backspace, Delete: Deletes from the list all items in the current selection (delete operation). Enter, Escape: Initiates editing on the current selection (edit operation). Insert: Inserts a new item before the current selection (insert operation). The append, move, edit, and insert operations can occur only when a single item is selected. The delete operation works for one or more items selected. Depending on how the editor and adapter are specified, drag and drop operations may be available. If the user selects multiple items and drags one of them, all selected items are included in the drag operation. If the user drags a non-selected item, only that item is dragged. The editor supports both drag-move and drag-copy semantics. A drag-move operation means that the dragged items are sent to the target and are removed from the list displayed in the editor. A drag-copy operation means that the dragged items are sent to the target, but are not deleted from the list data. TreeEditor() Suitable forInstanceDefault for(none)Required parametersnodes (required except for shared editors; see Section  REF _Ref162942176 \n \h 8.2.7.2.5)Optional parametersauto_open, editable, editor, hide_root, icon_size, lines_mode, on_dclick, on_select, orientation, selected, shared_editor, show_icons TreeEditor() generates a hierarchical tree control, consisting of nodes. It is useful for cases where objects contain lists of other objects. The tree control is displayed in one pane of the editor, and a user interface for the selected object is displayed in the other pane. The layout orientation of the tree and the object editor is determined by the orientation parameter of TreeEditor(), which can be horizontal or vertical. You must specify the types of nodes that can appear in the tree using the nodes parameter, which must be a list of instances of TreeNode (or of subclasses of TreeNode).  Figure  SEQ "Figure" \*Arabic 54: Tree editor The following example shows the code that produces the editor shown in  REF _Ref162768942 \h Figure 54. Example  SEQ "Example" \*Arabic 18: Code for example tree editor # tree_editor.py -- Example of a tree editor from enthought.traits.api \ import HasTraits, Str, Regex, List, Instance from enthought.traits.ui.api \ import TreeEditor, TreeNode, View, Item, VSplit, \ HGroup, Handler, Group from enthought.traits.ui.menu \ import Menu, Action, Separator from enthought.traits.ui.wx.tree_editor \ import NewAction, CopyAction, CutAction, \ PasteAction, DeleteAction, RenameAction # DATA CLASSES class Employee ( HasTraits ): name = Str( '' ) title = Str phone = Regex( regex = r'\d\d\d-\d\d\d\d' ) def default_title ( self ): self.title = 'Senior Engineer' class Department ( HasTraits ): name = Str( '' ) employees = List( Employee ) class Company ( HasTraits ): name = Str( '' ) departments = List( Department ) employees = List( Employee ) class Owner ( HasTraits ): name = Str( '' ) company = Instance( Company ) # INSTANCES jason = Employee( name = 'Jason', title = 'Engineer', phone = '536-1057' ) mike = Employee( name = 'Mike', title = 'Sr. Marketing Analyst', phone = '536-1057' ) dave = Employee( name = 'Dave', title = 'Sr. Engineer', phone = '536-1057' ) susan = Employee( name = 'Susan', title = 'Engineer', phone = '536-1057' ) betty = Employee( name = 'Betty', title = 'Marketing Analyst' ) owner = Owner( name = 'wile', company = Company( name = 'Acme Labs, Inc.', departments = [ Department( name = 'Marketing', employees = [ mike, betty ] ), Department( name = 'Engineering', employees = [ dave, susan, jason ] ) ], employees = [ dave, susan, mike, betty, jason ] ) ) # View for objects that aren't edited no_view = View() # Actions used by tree editor context menu def_title_action = Action(name='Default title', action = 'object.default') dept_action = Action( name='Department', action='handler.employee_department(editor,object)') # View used by tree editor employee_view = View( VSplit( HGroup( '3', 'name' ), HGroup( '9', 'title' ), HGroup( 'phone' ), id = 'vsplit' ), id = 'enthought.traits.doc.example.treeeditor', dock = 'vertical' ) class TreeHandler ( Handler ): def employee_department ( self, editor, object ): dept = editor.get_parent( object ) print '%s works in the %s department.' %\ ( object.name, dept.name ) # Tree editor tree_editor = TreeEditor( nodes = [ TreeNode( node_for = [ Company ], auto_open = True, children = '', label = 'name', view = View( Group('name', orientation='vertical', show_left=True )) ), TreeNode( node_for = [ Company ], auto_open = True, children = 'departments', label = '=Departments', view = no_view, add = [ Department ] ), TreeNode( node_for = [ Company ], auto_open = True, children = 'employees', label = '=Employees', view = no_view, add = [ Employee ] ), TreeNode( node_for = [ Department ], auto_open = True, children = 'employees', label = 'name', menu = Menu( NewAction, Separator(), DeleteAction, Separator(), RenameAction, Separator(), CopyAction, CutAction, PasteAction ), view = View( Group ('name', orientation='vertical', show_left=True )), add = [ Employee ] ), TreeNode( node_for = [ Employee ], auto_open = True, label = 'name', menu=Menu( NewAction, Separator(), def_title_action, dept_action, Separator(), CopyAction, CutAction, PasteAction, Separator(), DeleteAction, Separator(), RenameAction ), view = employee_view ) ] ) # The main view view = View( Group( Item( name = 'company', id = 'company', editor = tree_editor, resizable = True ), orientation = 'vertical', show_labels = True, show_left = True, ), title = 'Company Structure', id = \ 'enthought.traits.ui.tests.tree_editor_test', dock = 'horizontal', drop_class = HasTraits, handler = TreeHandler(), buttons = [ 'Undo', 'OK', 'Cancel' ], resizable = True, width = .3, height = .3 ) if __name__ == '__main__': owner.configure_traits( view = view ) Defining Nodes For details on the attributes of the TreeNode class, refer to the Traits API Reference. You must specify the classes whose instances the node type applies to. Use the node_for attribute of TreeNode to specify a list of classes; often, this list contains only one class. You can have more than one node type that applies to a particular class; in this case, each object of that class is represented by multiple nodes, one for each applicable node type. In  REF _Ref162768942 \h Figure 54, one Company object is represented by the nodes labeled Acme Labs, Inc., Departments, and Employees. A Node Type without Children To define a node type without children, set the children attribute of TreeNode to the empty string. In Example 16, the following lines define the node type for the node that displays the company name, with no children: TreeNode( node_for = [ Company ], auto_open = True, children = '', label = 'name', view = View( Group('name', orientation='vertical', show_left=True )) ), A Node Type with Children To define a node type that has children, set the children attribute of TreeNode to the (extended) name of a trait on the object that it is a node for; the named trait contains a list of the nodes children. In Example 16, the following lines define the node type for the node that contains the departments of a company. The node type is for instances of Company, and departments is a trait attribute of Company. TreeNode( node_for = [ Company ], auto_open = True, children = 'departments', label = '=Departments', view = no_view, add = [ Department ] ), Setting the Label of a Tree Node The label attribute of Tree Node can work in either of two ways: as a trait attribute name, or as a literal string. If the value is a simple string, it is interpreted as the extended trait name of an attribute on the object that the node is for, whose value is used as the label. This approach is used in the code snippet in Section  REF _Ref162853460 \n \h 8.2.7.1.1. If the value is a string that begins with an equals sign (=), the rest of the string is used as the literal label. This approach is used in the code snippet in Section  REF _Ref162853521 \n \h 8.2.7.1.2. You can also specify a callable to format the label of the node, using the formatter attribute of TreeNode. Defining Operations on Nodes You can use various attributes of TreeNode to define operations or behavior of nodes. Shortcut Menus on Nodes Use the menu attribute of TreeNode to define a shortcut menu that opens when the user right-clicks on a node. The value is a Traits UI or PyFace menu containing Action objects for the menu commands. In Example 16, the following lines define the node type for employees, including a shortcut menu for employee nodes: TreeNode( node_for = [ Department ], auto_open = True, children = 'employees', label = 'name', menu = Menu( NewAction, Separator(), DeleteAction, Separator(), RenameAction, Separator(), CopyAction, CutAction, PasteAction ), view = View( Group ('name', orientation='vertical', show_left=True )), add = [ Employee ] ), Allowing the Hierarchy to Be Modified If a node contains children, you can allow objects to be added to its set of children, through operations such as dragging and dropping, copying and pasting, or creating new objects. Two attributes control these operations: add and move. Both are lists of classes. The add attribute contains classes that can be added by any means, including creation. The code snippet in the preceding section ( REF _Ref162866493 \n \h 8.2.7.2.1) includes an example of the add attribute. The move attribute contains classes that can be dragged and dropped, but not created. The move attribute need not be specified if all classes that can be moved can also be created (and therefore are specified in the add value). NOTE: The add attribute alone is not enough to create objects. Specifying the add attribute makes it possible for objects of the specified classes to be created, but by itself, it does not provide a way for the user to do so. In the code snippet in the preceding section ( REF _Ref162866493 \n \h 8.2.7.2.1), NewAction in the Menu constructor call defines a New > Employee menu item that creates Employee objects. In the example tree editor, users can create new employees using the New > Employee shortcut menu item, and they can drag an employee node and drop it on a department node. The corresponding object becomes a member of the appropriate list. You can specify the label that appears on the New submenu when adding a particular type of object, using the name attribute of TreeNode. Note that you set this attribute on the tree node type that will be added by the menu item, not the node type that contains the menu item. For example, to change New > Employee to New > Worker, set name = 'Worker' on the tree node whose node_for value contains Employee. If this attribute is not set, the class name is used. You can determine whether a node or its children can be copied, renamed, or deleted, by setting the following attributes on TreeNode: copy: If True, the objects children can be copied. delete: If True, the objects children can be deleted. delete_me: If True, the object can be deleted. rename: If True, the objects children can be renamed. rename_me: If True, the object can be renamed. All of these attributes default to True. As with add, you must also define actions to perform these operations. Behavior on Nodes As the user clicks in the tree, you may wish to enable certain program behavior. You can use the selected parameter to specify the name of a trait attribute on the current context object to synchronize with the users current selection. For example, you can enable or disable menu items or toolbar icons depending on which node is selected. The synchronization is two-way; you can set the attribute referenced by selected to force the tree to select a particular node. The on_select and on_dclick parameters are callables to invoke when the user selects or double-clicks a node, respectively. Expanding and Collapsing Nodes You can control some aspects of expanding and collapsing of nodes in the tree. The integer auto_open parameter of TreeEditor() determines how many levels are expanded below the root node, when the tree is first displayed. For example, if auto_open is 2, then two levels below the root node are displayed (whether or not the root node itself is displayed, which is determined by hide_root). The Boolean auto_open attribute of TreeNode determines whether nodes of that type are expanded when they are displayed (at any time, not just on initial display of the tree). For example, suppose that a tree editor has auto_open setting of 2, and contains a tree node at level 3 whose auto_open attribute is True. The nodes at level 3 are not displayed initially, but when the user expands a level 2 node, displaying the level 3 node, thats nodes children are automatically displayed also. Similarly, the number of levels of nodes initially displayed can be greater than specified by the tree editors auto_open setting, if some of the nodes have auto_open set to True. If the auto_close attribute of TreeNode is set to True, then when a node is expanded, any siblings of that node are automatically closed. In other words, only one node of this type can be expanded at a time. Editing Objects One pane of the tree editor displays a user interface for editing the object that is selected in the tree. You can specify a View to use for each node type using the view attribute of TreeNode. If you do not specify a view, then the default view for the object is displayed. To suppress the editor pane, set the editable parameter of TreeEditor() to False; in this case, the objects represented by the nodes can still be modified by other means, such as shortcut menu commands. You can define multiple tree editors that share a single editor pane. Each tree editor has its own tree pane. Each time the user selects a different node in any of the sharing tree controls, the editor pane updates to display the user interface for the selected object. To establish this relationship, do the following: Call TreeEditor() with the shared_editor parameter set to True, without defining any tree nodes. The object this call returns defines the shared editor pane. For example: my_shared_editor_pane = TreeEditor(shared_editor=True) For each editor that uses the shared editor pane: Set the shared_editor parameter of TreeEditor() to True. Set the editor parameter of TreeEditor() to the object returned in Step 1. For example: shared_tree_1 = TreeEditor(shared_editor = True, editor = my_shared_editor_pane, nodes = [ TreeNode( # ) ] ) shared_tree_2 = TreeEditor(shared_editor = True, editor = my_shared_editor_pane, nodes = [ TreeNode( # ) ] ) Defining the Format Several parameters to TreeEditor() affect the formatting of the tree control: show_icons: If True (the default), icons are displayed for the nodes in the tree. icon_size: A two-integer tuple indicating the size of the icons for the nodes. lines_mode: Determines whether lines are displayed between related nodes. The valid values are on, off, and appearance (the default). When set to appearance, lines are displayed except on Posix-based platforms. hide_root: If True, the root node in the hierarchy is not displayed. If this parameter were specified as True in Example 16, the node in  REF _Ref162768942 \h Figure 54 that is labeled Acme Labs, Inc. would not appear. Additionally, several attributes of TreeNode also affect the display of the tree: icon_path: A directory path to search for icon files. This path can be relative to the module it is used in. icon_item: The icon for a leaf node. icon_open: The icon for a node with children whose children are displayed. icon_group: The icon for a node with children whose children are not displayed. The wxWidgets implementation automatically detects the bitmap format of the icon. Extra Trait Editor Factories The enthought.traits.ui.wx package defines a few editor factories that are specific to the wxWidgets toolkit, some of which are also specific to the Microsoft Windows platform. These editor factories are not necessarily implemented for other GUI toolkits or other operating system platforms. AnimatedGIFEditor() Suitable forFileDefault for(none)Required parameters(none)Optional parametersplayingAnimatedGIFEditor() generates a display of the contents of an animated GIF image file. The playing parameter determines whether the image is animated or static. ArrayViewEditor() Suitable for2-D Array, 2-D CArrayDefault for(none)Required parameters(none)Optional parametersformat, show_index, titles, transposeArrayViewEditor() generates a tabular display for an array. It is suitable for use with large arrays, which do not work well with the editors generated by ArrayEditor(). All styles of the editor have the same appearance.  Figure  SEQ "Figure" \*Arabic 55: Array view editor FlashEditor() Suitable forstring traits, Enum(string values)Default for(none)Required parameters(none)Optional parameters (none)FlashEditor() generates a display of an Adobe Flash Video file, using an ActiveX control (if one is installed on the system). This factory is available only on Microsoft Windows platforms. The attribute being edited must have a value whose text representation is the name or URL of a Flash video file. If the is a Unicode string, it must contain only characters that are valid for filenames or URLs. HistoryEditor() Suitable forstring traitsDefault for(none)Required parameters(none)Optional parameters entriesHistoryEditor() generates a combo box, which allows the user to either enter a text string or select a value from a list of previously-entered values. The same control is used for all editor styles. The entries parameter determines how many entries are preserved in the history list. This type of control is used as part of the simple style of file editor; see Section  REF _Ref182909127 \n \h 8.1.10. IEHTMLEditor() Suitable forstring traits, Enum(string values)Default for(none)Required parameters(none)Optional parameters back, forward, home, html, page_loaded, refresh, search, status, stop, titleIEHTMLEditor() generates a display of a web page, using Microsoft Internet Explorer (IE) via ActiveX to render the page. This factory is available only on Microsoft Windows platforms. The attribute being edited must have value whose text representation is a URL. If the value is a Unicode string, it must contain only characters that are valid for URLs. The back, forward, home, refresh, search and stop parameters are extended names of event attributes that represent the user clicking on the corresponding buttons in the standard IE interface. The IE buttons are not displayed by the editor; you must create buttons separately in the View, if you want the user to be able to actually click buttons. The html, page_loaded, status, and title parameters are the extended names of string attributes, which the editor updates with values based on its own state. You can display these attributes elsewhere in the View. htmlThe current page content as HTML (as would be displayed by the View > Source command in IE). page_loadedThe URL of the currently displayed page; this may be different from the URL represented by the attribute being edited. statusThe text that would appear in the IE status bar. titleThe title of the currently displayed page. ImageEditor() Suitable for(any)Default for(none)Required parameters(none)Optional parametersimageImageEditor() generates a read-only display of an image. The image to be displayed is determined by the image parameter, or by the value of the trait attribute being edited, if image is not specified. In either case, the value must be a PyFace ImageResource (enthought.pyface.api.ImageResource), or a string that can be converted to one. If image is specified, then the type and value of the trait attribute being edited are irrelevant and are ignored. LEDEditor() Suitable fornumeric traitsDefault for(none)Required parameters(none)Optional parametersalignment, format_strLEDEditor() generates a display that resembles a digital display using light-emitting diodes. All styles of this editor are the same, and are read-only. The alignment parameter can be left, center, or right to indicate how the value should be aligned within the display. The default is right-alignment.  Figure  SEQ "Figure" \*Arabic 56: LED Editor with right alignment ThemedButtonEditor() Suitable forEventDefault for(none)Required parameters(none)Optional parameterslabel, theme, down_theme, hover_theme, disabled_theme, image, position, spacing, viewThe ThemedButtonEditor() factory generates a button that is formatted according to specified or default themes. All editor styles have the same appearance.  Figure  SEQ "Figure" \*Arabic 57: Themed buttons in various states The theme-related parameters determine the appearance of the button in various states.  REF _Ref184811508 \h Figure 57 shows the default theme. ThemedCheckboxEditor() Suitable forBooleanDefault for(none)Required parameters(none)Optional parameterslabel, theme, hover_off_image, hover_off_theme, hover_on_image, hover_on_theme, image, on_image, on_theme, position, spacingThe ThemedCheckboxEditor() factory generates a checkbox that is formatted according to specified or default themes. All editor styles have the same appearance.  Figure  SEQ "Figure" \*Arabic 58: Themed checkbox in various states The theme-related parameters determine the appearance of the checkbox in the various states.  REF _Ref191370312 \h  shows the default theme. If label is not specified for the editor factory, the value is inherited from the label value of the enclosing Item. Both labels may be displayed, if the Items label is not hidden. ThemedSliderEditor() Suitable forRangeDefault for(none)Required parameters(none)Optional parametersalignment, bg_color, high, increment, low, show_value, slider_color, text_color, tip_colorThe ThemedSliderEditor() factory generates a slider control that is formatted according to specified or default themes. All editor styles have the same appearance. The value is edited by modifying its textual representation. The background of the control updates to reflect the value relative to the total range represented by a slider. For example, if the range is from -2 to 2, a value of 0 is represented by a bar covering the left half of the control area, as shown in  REF _Ref191454702 \h Figure 59.  Figure  SEQ "Figure" \*Arabic 59: Themed slider without focus, and with focus ThemedTextEditor() Suitable forStr, String, Unicode, CStr, CUnicode, and any trait whose value is a stringDefault for(none)Required parameters(none)Optional parametersauto_set, enter_set, evaluate, evaluate_name, mapping, multi_line, password, themeThe ThemedTextEditor() factory generates a text editor that is formatted according to a specified theme. If no theme is specified, the editor uses the theme, if any, specified by the surrounding Group or View. Thus, there is no default theme. All editor styles have the same appearance, except the read-only style, which is not editable.   Figure  SEQ "Figure" \*Arabic 60: Themed text editor, without focus and with focus ThemedVerticalNotebookEditor() Suitable forLists of InstancesDefault for(none)Required parameters(none)Optional parametersclosed_theme, double_click, open_theme, page_name, multiple_open, scrollable, viewThe ThemedVerticalNotebookEditor() factory generates a notebook editor, containing tabs that can be vertically expanded or collapsed. It can be used for lists of instances, similarly to the ListEditor() factory, with the use_notebook parameter. You can specify themes to use for the open and closed states of the tabs.  Figure  SEQ "Figure" \*Arabic 61: Themed vertical notebook, with tabs for Person instances closed  Figure  SEQ "Figure" \*Arabic 62: Themed vertical notebook, with one tab open Tips, Tricks and Gotchas Getting and Setting Model View Elements For some applications, it can be necessary to retrieve or manipulate the View objects associated with a given model object. The HasTraits class defines two methods for this purpose: trait_views() and trait_view(). trait_views() The trait_views() method, when called without arguments, returns a list containing the names of all Views defined in the object's class. For example, if sam is an object of type SimpleEmployee3 (from  REF _Ref117066572 \h Example 6 on page  PAGEREF _Ref161645540 \h 24), the method call sam.trait_views() returns the list ['all_view', 'traits_view']. Alternatively, a call to trait_views(view_element_type) returns a list of all named instances of class view_element_type defined in the objects class. The possible values of view_element_type are: View Group Item, ViewElement ViewSubElement Thus calling trait_views(View) is identical to calling trait_views(). Note that the call sam.trait_views(Group) returns an empty list, even though both of the Views defined in SimpleEmployee contain Groups. This is because only named elements are returned by the method. Group and Item are both subclasses of ViewSubElement, while ViewSubElement and View are both subclasses of ViewElement. Thus, a call to trait_views(ViewSubElement) returns a list of named Items and Groups, while trait_views(ViewElement) returns a list of named Items, Groups and Views. trait_view() The trait_view() method is used for three distinct purposes: To retrieve the default View associated with an object To retrieve a particular named ViewElement (i.e., Item, Group or View) To define a new named ViewElement For example: obj.trait_view() returns the default View associated with object obj. For example, sam.trait_view() returns the View object called traits_view. Note that unlike trait_views(), trait_view() returns the View itself, not its name. obj.trait_view('my_view') returns the view element named my_view (or None if my_view is not defined). obj.trait_view('my_group', Group('a', 'b')) defines a Group with the name my_group. Note that although this Group can be retrieved using trait_view(), its name does not appear in the list returned by traits_view(Group). This is because my_group is associated with obj itself, rather than with its class. Appendix I: Glossary of Terms attribute: An element of data that is associated with all instances of a given class, and is named at the class level. In most cases, attributes are stored and assigned separately for each instance (for the exception, see class attribute). Synonyms include data member and instance variable. Bool: The trait type of a Boolean attribute. Boolean: Having only True or False as possible values. command button: A button on a window that globally controls the window. Examples include OK, Cancel, Apply, Revert, and Help. controller: The element of the MVC (model-view-controller) design pattern that manages the transfer of information between the data model and the view used to observe and edit it. data member: Synonym for attribute. dialog box: A secondary window whose purpose is for a user to specify additional information when entering a command. dictionary: A lookup table of the form: {key1: value1, key2: value2, key_n: value_n}, Dictionaries are a built-in type in the Python language. Values are inserted and retrieved by key rather than by offset (as they would be in Python lists or in C-style arrays). editor: A user interface component for editing the value of a trait attribute. Each type of trait has a default editor, but you can override this selection with one of a number of editor factories provided by the Traits UI package. In some cases an editor can include multiple widgets, e.g., a slider and a text box for a Range trait attribute. editor factory: An instance of the Traits class EditorFactory. Editor factories generate the actual widgets used in a user interface. You can use an editor factory without knowing what the underlying GUI toolkit is. factory: An object used to produce other objects at run time without necessarily assigning them to named variables or attributes. A single factory is often parameterized to produce instances of different classes as needed. Group: An object that specifies an ordered set of Items and other Groups for display in a Traits UI View. Various display options can be specified by means of attributes of this class, including a border, a group label, and the orientation of elements within the Group. An instance of the Traits UI class Group. Handler: A Traits UI object that implements GUI logic (data manipulation and dynamic window behavior) for one or more user interface windows. A Handler instance fills the role of controller in the MVC design pattern. An instance of the Traits UI class Handler. HasTraits: A class defined in the Traits package to specify objects whose attributes are typed (i.e., whose attributes are trait attributes). instance: A concrete entity belonging to an abstract category such as a class. In object-oriented programming terminology, an entity with allocated memory storage whose structure and behavior are defined by the class to which it belongs. Often called an object. instance method: A method that is performed on (and called through) a specific instance, usually using a syntax like object1.do_this(). instance variable: Synonym for attribute. Item: A non-subdividable element of a Traits user interface specification (View), usually specifying the display options to be used for a single trait attribute. An instance of the Traits UI class Item. live: A term used to describe a window that is linked directly to the underlying model data, so that changes to data in the interface are reflected immediately in the model. A window that is not live displays and manipulates a copy of the model data until the user confirms any changes. livemodal: A term used to describe a window that is both live and modal. MVC: A design pattern for interactive software applications. The initials stand for Model-View-Controller, the three distinct entities prescribed for designing such applications. (See the glossary entries for model, view, and controller.) modal: A term used to describe a window that causes the remainder of the application to be suspended, so that the user can interact only with the window until it is closed. model: A component of the MVC design pattern for interactive software applications. The model consists of the set of classes and objects that define the underlying data of the application, as well as any internal (i.e., non-GUI-related) methods or functions on that data. nonmodal: A term used to describe a window that is neither live nor modal. object: Synonym for instance. object method: Synonym for instance method. panel: A user interface region similar to a window except that it is embedded in a larger window rather than existing independently. predefined trait: Any trait type that is built into the Traits package. regular expression: A way of specifying a set of strings by encoding its syntax requirements as a single string rather than by enumerating all its members. subpanel: A variation on a panel that ignores (i.e., does not display) any command buttons. trait: A term used loosely to refer to either a trait type or a trait attribute. trait attribute: An attribute whose type is specified and checked by means of the Traits package. trait type: A type-checked data type, either built into or implemented by means of the Traits package. Traits: An open source package engineered by Enthought, Inc. to perform manifest typing in Python. Traits UI: A high-level user interface toolkit designed to be used with the Traits package. tuple: An ordered set of Python objects, not necessarily of the same type. The syntax for tuples differs from that of Python lists in that parentheses are used (and , in some contexts, omitted) rather than square brackets, e.g. tuple1 = ("hello", 3, True). View: A template object for constructing a GUI window or panel for editing a set of traits. The structure of a View is defined by one or more Group or Item objects; a number of attributes are defined for specifying display options including height and width, menu bar (if any), and the set of buttons (if any) that are displayed. A member of the Traits UI class View. view: A component of the MVC design pattern for interactive software applications. The view component encompasses the visual aspect of the application, as opposed to the underlying data (the model) and the applications behavior (the controller). ViewElement: A View, Group or Item object. The ViewElement class is the parent of all three of these subclasses. widget: An interactive element in a graphical user interface, e.g., a scrollbar, button, pull-down menu or text box. wizard: An interface composed of a series of dialog boxes, usually used to guide a user through an interactive task such as software installation. wx: A shorthand term for the low-level GUI toolkit on which TraitsUI and PyFace are currently based (wxWidgets) and its Python wrapper (wxPython). Appendix II: Editor Factories for Predefined Traits Predefined traits that are not listed in this table use TextEditor() by default, and have no other appropriate editor factories. TraitDefault Editor FactoryOther Possible Editor FactoriesAnyTextEditorEnumEditor, ImageEnumEditor, ValueEditorArrayArrayEditor (for 2-D arrays)BoolBooleanEditorThemedCheckboxEditorButtonButtonEditorCArrayArrayEditor (for 2-D arrays)CBoolBooleanEditorCComplexTextEditorCFloat, CInt, CLongTextEditorLEDEditorCodeCodeEditorColorColorEditorComplexTextEditorCStr, CUnicodeTextEditor (multi_line=True)CodeEditor, HTMLEditorDictTextEditorValueEditorDirectoryDirectoryEditorEnumEnumEditorImageEnumEditorEvent(none)ButtonEditor, ToolbarButtonEditorFileFileEditorAnimatedGIFEditorFloatTextEditorLEDEditorFontFontEditorHTMLHTMLEditorInstanceInstanceEditorTreeEditor, DropEditor, DNDEditor, ValueEditorListTableEditor for lists of HasTraits objects; ListEditor for all other lists. CheckListEditor, SetEditor, ValueEditor, ThemedVerticalNotebookEditorLongTextEditorLEDEditorPasswordTextEditor (password=True)PythonValueShellEditorRangeRangeEditorThemedSliderEditorRegexTextEditorCodeEditorRGBColorRGBColorEditorStrTextEditor (multi_line=True)CodeEditor, HTMLEditorStringTextEditorCodeEditor, ThemedTextEditorThisInstanceEditorToolbarButtonButtonEditorTupleTupleEditorUIDebuggerButtonEditor (button calls the UIDebugEditor factory)UnicodeTextEditor (multi_line=True)HTMLEditorWeakRefInstanceEditor  A third type of content object, Include, is discussed briefly in Section  REF _Ref161037022 \n \h 4.5, but presently is not commonly used.  Not to be confused with the TraitHandler class of the Traits package, which enforces type validation.  If the code is being run from a program that already has a GUI defined, then use edit_traits() instead of configure_traits(). These methods are discussed in more detail in Section  REF _Ref117066165 \n \h 4.3.  All code examples in this guide that include a file name are also available as examples in the tutorials/doc_examples/examples subdirectory of the Traits docs directory. You can run them individually, or view them in a tutorial program by running: python /tutorials/tutor.py /docs/tutorials/doc_examples  As with Views, it is possible for a Group to contain objects of more than one type, but not recommended.  Actually, the value of the buttons attribute is really a list of Action objects, from which GUI buttons are generated by Traits UI. The Action class is described in Section  REF _Ref161116897 \n \h 5.4.3.1.  Note that although the definition of a View within a HasTraits class has the syntax of a trait attribute definition, the resulting View is not stored as an attribute of the class.  Assuming there is one; not all GUIs require an explicitly defined Handler.  One possible exception is the case where a View object is defined as a variable (i.e., outside any class) or within a custom Handler, and is associated more or less equally with multiple model objects; see Section  REF _Ref183844204 \n \h 4.4.1.  If the script were designed to run within an existing GUI, it would make sense to replace the last line with "comp_view.ui(context={'h1': house1, 'h2': house2})", since neither object particularly dominates the view. However, the examples in this Guide are designed to be fully executable from the Python command line, which is why configure_traits() was used instead.  Except those implemented via the enabled_when, visible_when, and defined_when attributes of Items and Groups.  Other attributes of the UIInfo object include a UI object and any trait editors contained in the window (see Chapters 7-8).  This is very similar to the way that PyFace ImageResource objects work when no search path is specified.  PyFace is provided by the enthought.pyface package in the Traits GUI project (not to be confused with the Traits UI package, enthought.traits.ui, the subject of this document.)  Appendix II contains a table of the predefined trait types in the Traits package and their default trait editor types.  In Traits, a Button and an Event are essentially the same thing, except that Buttons are automatically associated with button editors.  Traits UI makes minor modifications to the name, capitalizing the first letter and replacing underscores with spaces, as in the case of a default Item label (see Section  REF _Ref161209075 \n \h 2.2.1).  If a List is made up of HasTraits objects, a table editor is used instead; see Section  REF _Ref161566483 \n \h 10.2.5 on page  PAGEREF _Ref162339134 \h 96.  This is not always the case in Python, where attributes can be added to individual objects.  A method can, of course, have arguments. They are omitted from the sample syntax for simplicity.      TITLE Traits UI User Guide    PAGE 4 3-Mar-2008 29-Feb-2008  PAGE 3 3-Mar-2008  PAGE i  TITLE Traits UI User Guide    TITLE Traits UI User Guide  PAGE 4 3-Mar-2008 3-Mar-2008  PAGE 3 3-Mar-2008  PAGE 1  TITLE Traits UI User Guide    TITLE Traits UI User Guide  PAGE 14 3-Mar-2008 3-Mar-2008  PAGE 13 3-Mar-2008  PAGE 5  TITLE Traits UI User Guide    TITLE Traits UI User Guide  PAGE 20 3-Mar-2008 3-Mar-2008  PAGE 19 3-Mar-2008  PAGE 15  TITLE Traits UI User Guide    TITLE Traits UI User Guide  PAGE 30 3-Mar-2008 3-Mar-2008  PAGE 29 3-Mar-2008  PAGE 21  TITLE Traits UI User Guide    TITLE Traits UI User Guide  PAGE 40 3-Mar-2008 3-Mar-2008  PAGE 41 3-Mar-2008  PAGE 31  TITLE Traits UI User Guide    TITLE Traits UI User Guide  PAGE 46 3-Mar-2008 3-Mar-2008  PAGE 45 3-Mar-2008  PAGE 42  TITLE Traits UI User Guide    TITLE Traits UI User Guide  PAGE 130 3-Mar-2008 3-Mar-2008  PAGE 131 3-Mar-2008  PAGE 47  TITLE Traits UI User Guide    TITLE Traits UI User Guide  PAGE 200 3-Mar-2008 3-Mar-2008  PAGE 199  TITLE Traits UI User Guide   PAGE 202 3-Mar-2008 3-Mar-2008  PAGE 201  TITLE Traits UI User Guide    TITLE Traits UI User Guide  PAGE 206 3-Mar-2008 3-Mar-2008  PAGE 205  TITLE   MNWY|}wyDEFG_`ajhjUjhjUj,hjUjhjUjJhjUjhjU hj0JAjhjUhjjhjU? +DcnA  FBVx   w   k   hgft !"#@ABC[\]789TUVWopqjhjUj%hjUjhjUjChjUjhjUjahjUjhjUhj hj0JAjhjUjhjU8V8m$_P+a.g1qw   k   x   6789RSTklmn"#$%>?@]^_`yj( hjUj hjUjB hjUjhjUj\hjUjhjUjxhjUhj hj0JAjhjUjhjU8yz{789NOPQjkl)*+,EFG_`ab{j hjUjM hjUj hjUjg hjUj hjUj hjUj hjUhj hj0JAjhjUj hjU8{|},-./HIJefgh/012KjXhjUjhjUjrhjUjhjUjhjUjhjUjhjUhj hj0JAjhjUj3hjU8KLMopqr  #$%VWXYrst6789RjhjUj}hjUj hjUjhjUj$hjUjhjUj>hjUhj hj0JAjhjUjhjU8 X8z4sBW C z 7!k   w   x   RSTxyz{ 2345NOPqrst-jhjUjhjUjhjUj/hjUjhjUjIhjUjhjUhj hj0JAjhjUjchjU8-./@ABC\]^ !"UVWXqrs $ j hjUjhjUj:hjUjhjUjThjUjhjUjnhjUhj hj0JAjhjUjhjU8$ % & A B C D ] ^ _ x y z { ! ! !5!6!7!8!Q!R!S!v!w!x!y!!!!!!!!!!!!!!!!jhjUjEhjUjhjUj_hjUjhjUjyhjUjhjUhj hj0JAjhjUjhjU87!x!!!"O""""%#X####0$h$$$$%X%%%%0&c&&&'6'x   w   !!!""""1"2"3"M"N"O"P"i"j"k"""""""""""""""""""## ###$#%#&#?#@#A#V#W#X#Y#r#s#t######jP#hjUj"hjUjj"hjUj!hjUj!hjUj!hjUj hjUhj hj0JAjhjUj+ hjU8##############$$$.$/$0$1$J$K$L$f$g$h$i$$$$$$$$$$$$$$$%%%"%#%$%%%>%?%@%V%W%X%Y%r%j&hjUju&hjUj&hjUj%hjUj%hjUj$hjUj6$hjUhj hj0JAjhjUj#hjU8r%s%t%%%%%%%%%%%%%%%%%%%&&&.&/&0&1&J&K&L&a&b&c&d&}&~&&&&&&&&&&&&&&&&&''''j*hjUj *hjUj)hjUj')hjUj(hjUjA(hjUj'hjUhj hj0JAjhjUj['hjU8'''4'5'6'7'P'Q'R'i'j'k'l'''''''''''''''''' ( ((((()(*(>(?(@(A(Z([(\(w(x(y(z(((((((((j.hjUj-hjUj2-hjUj,hjUjL,hjUj+hjUjf+hjUhj hj0JAjhjUj*hjU86'k'''(@(y((()Z)))*Q***+@++++;,o,,,4--   w   x   ((((((()))))) )9):);)X)Y)Z)[)t)u)v)))))))))))))))****3*4*5*O*P*Q*R*k*l*m******j1hjUj=1hjUj0hjUjW0hjUj/hjUjq/hjUj.hjUhj hj0JAjhjUj.hjU8**********+++++++>+?+@+A+Z+[+\+++++++++++++++++++ , , ,9,:,;,<,U,V,W,m,n,o,p,,jH5hjUj4hjUjb4hjUj3hjUj|3hjUj 3hjUj2hjUhj hj0JAjhjUj#2hjU8,,,,,,,,,,,,,, - - -2-3-4-5-N-O-P-~--------------.. . .#.$.%.X.Y.Z.[.t.u.v......j8hjUjm8hjUj7hjUj7hjUj7hjUj6hjUj.6hjUhj hj0JAjhjUj5hjU8-- .Z.../Y///0F0}0001W111 2T2223G3j33k   x   w      ..........////6/7/8/W/X/Y/Z/s/t/u///////////////0000+0,0-0D0E0F0G0`0a0b0{0|0}0~00jx<hjUj<hjUj;hjUj;hjUj:hjUj9:hjUj9hjUhj hj0JAjhjUjS9hjU8000000000000001111111516171U1V1W1X1q1r1s111111111111111 2 2 22'2(2)2R2S2T2U2n2j@hjUj?hjUj*?hjUj>hjUjD>hjUj=hjUj^=hjUhj hj0JAjhjUj<hjU8n2o2p2222222222222223333-3.3/3E3F33355*6>6N7S7778&8;<9=:=r=s======W?X?C@D@]@^@_@`@a@j@k@@jBhjUjOBhjUjhj0JPU hj0JJjAhjUjiAhjUj@hjUhj hj0JAjhjUj@hjU<333@6o6i999$:R:::<2<>>?GBYBC@EE'FFeGfH  n hh^h` ` @@@@@'B(BABBBCBDBEBWC[CCCDDEENE_EEEEEEEEEEFFFFF-F.FdFeFfFjFkFFFFFFFFHHI#IJJJ hj0JFjHFhjUjEhjUjDhjU hj0JAjCDhjU hj0JI hj0J@ hj0JJjChjUhjjhjUjIChjU8fHINIIIMNOOPIP~PPPPPPPPQ%Q&Q=QXQQQVRyb$ `  q & F hJJJJJJJJJJJJtKuKKKKKKLLLLL L!L\LbLmLnLLLLLLLLLLLLLLLLLMMMMMNN2Ojhj0JPUmHnHsHjIhjUjlIhjUjHhjU hj0JJjrHhjUjGhjUjxGhjUhjjhjUjFhjU52O3OOOOOOOQQQQRRRRRR2R3RIRJRKRSRTRURTTTTTTWWWWWWWWWWWWWWWWWWWXXXXXX(X)X*X+X,XjXjhjUjhjUjhjUjmjhjUjihjUjfJhjU hj0JIhjmHnHujhjUhjjhj0JTU>VRfR[ST#U]UUUUUVV0VEVYVnVVVVVVWW)WNWWWWyb$` jX~XVYWYpYqYrYuYvYYYYYYYY/Z0ZFZGZHZPZQZRZL[M[c[d[e[m[n[o[?]C]G]H]^]_]`]h]i]j]<_=_S_T_U_[_\_]_____` ` ` `V`[` hj0JIjhjUjrhjU hj0JGjhjUjxhjUhjmHnHujhjUj|hjUjhjUhj hj0JJ;WXYYr[[[l]<__-`6`A`M`N`\kdl$$If4F\ p    44 xax$G$Ifb$  `N`V`[`aa)a/a9aDaLaSaYa^adasssssss| L$If^`L^kd"$$If4F\ p    44 xaxf4| L$G$If^`L$G$If [```)aaKbPbbb(c2c4c?ckdxddd e eeeeee3e4eVeWepe|e}e~eeeeefffffffffggpgqgwg~gggggDhFhjhnhuiikkllllllhjmHnHujhjU hj0JJjShjUjhj0JQU hj5\j+hjUjhjU hj0JIhjDdaoa{aaaaaa>bcc(c4cp| L$G$If^`L[kdۈ$$IfF\ p    44 xax$If$G$If| L$If^`L 4cAcZd[dkdrdxdYes| L$G$If^`L^kd$$If4F\ p    44 xaxf4$G$If| L$If^`LYeZepeeeeefsss| L$If^`L| L$G$If^`L$G$If^kd$$If4F\ p    44 xaxf4ffffffgvv| L$If^`L| L$G$If^`L$G$If[kdЋ$$IfF\ p    44 xaxgggghh-[kd$$IfF\ p    44 xax| L$G$If^`L$G$If[kdu$$IfF\ p    44 xaxhhhhhhiiklqlllmSmnmommmmmmmmm)nVnb$` n hh^h``$ lll4l5l6l7lKmSmnnnnnnoooooooooooooooopppppppppp"q+qnqoqqqqqqqrrrrrrrr.s=sAsGsss;t hj0JIjUhjU hj0JJjhj0JPUjةhjUj[hjUj<hjU hj0JRhjmHnHujhjUhjAVnnnnnnoooop]qnqrrsss%s$G$Ifb$ `y`%s&s.s5s=s+tq| L$If^`L| L$G$If^`L$G$If_kdҪ$$If44F >(x    4+4 xaf4+t,t;tAtMt[tetotxttttttssssssssss| L$If^`L| L$G$If^`L$G$If^kd$$If4F >(x    4+4 xaf4 tttttttt&u'u=uJuWudus| L$G$If^`L^kdO$$If4F >(x    4+4 xaf4$G$If| L$If^`L ;tt=uduuuuuvvvvwww$wwwwwwwxx+y,yByCyDyEyZy}y~yzzzzz{{{*{,{4{6{4|6|J|L|^|`|j|l|}}}},}.}:}<}}}}}~~~~~~~~"$8 heZ1^JheZ1OJQJ^J heZ156heZ1hjmHnHu hj0JFjhjUhj hj0JIMduuuuuuvvwwwsmggm$If$If| L$If^`L| L$G$If^`L^kd$$If4F >(x    4+4 xaf4$G$If wwww]x| L$G$If^`L$G$If^kd$$If4F >(x    4+4 xaf4]x^xrx%yZycyoy}y$G$Ifb$` ^kd\$$If4F >(x    4+4 xaf4}y~yyyz $IfgdeZ1$G$Ifekd $$If4F, (      4lag DņyteZ1zz*zzn{ $IfgdeZ1$G$Ifckd$$IfF, (      4lag DņyteZ1n{p{~{|p| $IfgdeZ1$G$IfckdR$$IfF, (      4lag DņyteZ1p|r|||@} $IfgdeZ1$G$Ifckd$$IfF, (      4lag DņyteZ1@}B}P}}} $IfgdeZ1$G$Ifckdz$$IfF, (      4lag DņyteZ1}}}~( $IfgdeZ1$G$Ifckd$$IfF, (      4lag DņyteZ1(*6x $IfgdeZ1$G$Ifckd$$IfF, (      4lag DņyteZ18:BDH.0 "(68BDJ38!%TẊЇˊ̊NjȋɋҋӋΌόڻڻjhjUhjmHnHujohjUjhjUjhjU hj0JI hj0JJhjhH6heZ1 heZ1^JCxzL $IfgdeZ1$G$Ifckd6$$IfF, (      4lag DņyteZ1LN\H $IfgdeZ1$G$Ifckdʳ$$IfF, (      4lag DņyteZ1HJLrv[cjv}}}}}}} n ^` ` ckd^$$IfF, (      4lag DņyteZ10̋ %.4$G$If]kdk$$IfF 84    44 la$G$Ifb`  45:?IJ5]kd{$$IfF 84    44 la$G$If$G$If]kd$$IfF 84    44 la$.\cZ_Z[tuv{|ϑב^_OV˔͔̔Ք֔ה<Mq hj0JRjnhjUjhj0JPUhjmHnHujhjUjrhjU hj0JI hj0JJjhj0JQUhjjhjUjhjU >    4+4 xaf4 9@KWȟП؟s| L$G$If^`L^kd$$If4FF> >    4+4 xaf4$G$If| L$If^`L  (/7Bsss| L$If^`L| L$G$If^`L^kd$$If4FF> >    4+4 xaf4$G$If$)1bs| L$If^`L| L$G$If^`L$G$If^kd.$$If4FF> >    4+4 xaf4uy}13+ȧاߧ˨ۨ֬׬ج;?VaİŰưȰɰѰҰ߻߰ߨj1hjUjhjU hj0JGj7hjU hj0JJ6 hj0JJ hj0JIhjhjmHnHujhjUjZhjUAbcuy| L$G$If^`L$G$If^kd$$If4FF> >    4+4 xaf4Ԥ˨-<[}   n ^`` ^kd$$If4FF> >    4+4 xaf4>12Ti}.fүӯȰʰ%`b$"#$^i2=κٺtuV^HI_`aijktujQhjUjhj0JPU hj0JJjhjUjUhjUjhjU hj0JF hj0JIhjmHnHuhjjhjUj[hjU7²:xӴ $%G\p!YŶƶ/dϷb$` Ϸ 5de}'JSJHBTs  `"#<=>?@PdDn/<HObfszYk1234)*jEhjUjhj0JQUjhjU hj0JG hj0JJjKhjUjhj0JPUhjmHnHuhjjhjUjhjU?DIQY`n m_9:Iarb   n hh^h``>_|"?]z'C_||#d2x ?`b$ y`%&'/01!$%PQghiqrs}~j_%hjUj$hjUjc$hjUj#hjUjg#hjUjhj0JPU hj0JJhjmHnHujhjUj"hjUhj<1RrYqAi  n hh^h`  `~$%;<=EFGtz$MNdefnop%-$59tx{ hj0JF hj0JJ hj0JGjU'hjUj&hjUj[&hjU hj0JIhjmHnHujhjUj%hjUhjB 4D5pM),(cz n hh^h`  `{ & /5`a4567;HLNSU     V d h j ~         hj0JShjmHnHujhjUjhj0JQU hj0JF hj0JIhj hj0JGO~bt{$G$Ifb$ q & F hq$ & F hmm^m  ` n hh^h` ;<0^kd($$If4F ' $     4+4 xaf4$G$If z$$G$If_kd'$$If44F ' $     4+4 xaf4<U 0 V ^kdO)$$If4F ' $     4+4 xaf4$G$If z$$G$IfV W j    2^kd*$$If4F ' $     4+4 xaf4$G$If z$$G$If^kd)$$If4F ' $     4+4 xaf4                 g q "*+4=ACG  01245jkYdַַj3.hjUj-hjUhjmHnHuj7-hjUj,hjUjhjU hj0JG hj0JJ hj0JIhj hj0JF hj0JS?  A     s ^kd\+$$If4F ' $     4+4 xaf4$G$If z$$G$Ifs t  "IC*b+5t~z` ^kd ,$$If4F ' $     4+4 xaf4dBCFGOPghijHO$%ELvwu!v!!!!!!!!!!!!!{""#$(% hj0JFjEhjUjXEhjUjDhjUj^DhjU hj0JIjo9hjUj.hjUhjmHnHujhjU hj0JGhj=t2u"#U;IWe$b$`"BHJRT'e| q & F h q & F h `` by8Ws ' S \ =!"""#;#o##$-$$$ q & F h q & F h q & F h` `$$$$%%;&&&&='?'''8(<(n(*#*s*y*~**-Y/Y0 n hh^h` by` (%.%%%%%%%%%%%%&&&&&;&<&R&S&T&[&\&]&&&&&&&&&&&&&&&&&='>'F'G'^'_'a'b'((*(+(,(3(5(6(8(9(jhjUjAhjUjhjUjAhjUj2shjUjrhjUjFhjUhjmHnHujTFhjUjhjUhj hj0JJ;9(:(;(C(D([(\(^(_(/)0)F)G)H)O)Q)R)****#+/+,,,,,,-------.B.L.t.~...]/h/s/x///00011 1 1 1<1=1S1jhjU hj0JJjhj0J]Ujhj0JWU hj0JF hj0JIjhjUhjmHnHujhjUhjjhjUjhjU;Y0o0`1112X2r2s22222222%3A3\3z33333334575b` S1T1U1\1]1^1h1i1111133444 444?4@4V4W4X4_4`4a44444444444444466N7g77777788#8888888_9j9v:w::::jhjU hj0JI hj0JRjhjUjhjUjhjUhjmHnHuhjjhjUjhjUB75{55566 6!626O6b66666667.7j777778#8.8T8Z8[8[8u8889:<=/=>@BCICCCCCDD3DHD\DsDDDDb$  n ^``::::::::::::D;O;x;;;;9AMACC'C(C*C+CEEEE F FFF$F%F;FhjUj8>hjUj=hjUj>=hjUjhjUhjmHnHu hj0JI hj0JJj hjUjhjUhj?DDDEOEPEsEEEEEEEIFHHHIfIIIEJJJ7K n ^`  n hh^h``yuJvJJJJJJJJJJJJJJJJJJJJJJJJJKKKK1K2K3K5K6K7K8KNKOKPK\K]KdKeKKKKKKKKKKKKKKKjBhjUj(BhjUjAhjUj,AhjUj@hjUj0@hjUj?hjUhjmHnHuj4?hjUhjjhjU97KKK$LtLLLLLLLHkdF$$If0 D H44 la$G$If$G$If  n ^` KKKKKKKKKKKKKLLLL L"L#L$L%L;LT $$G$If  n hh^h`by `` q & F h¦Ȧ թ۩,"xz(y[c"'x,0hk{OR[fj)7BF$hjmHnHsH hj0JI hj0JJhjmHnHuj{hjU hj0JG hj0JFhjOթWKkds $$If40 D H44 laf4 $$G$IfKkd $$If40 D H44 laf4 $$G$If,Cg*YWWWUSy`Kkd#$$If40 D H44 laf4$G$If$G$IfKkd $$If40 D H44 laf4 *|ҭӭ ?vۮ4ghwxůAFfb$`ɰ6A\}ֱ "7^x~۲ "<BTjӳ &JvôHNPQw1H5iݷ:abqŸ 1dع'Tٺ(SԻ&Qw׼ :lν1e׾1U{Ϳ&Pz"Ly<g,?z4Lf~*+1 ` `1Uw D^'Kxx- $` `` 2c)Z-c[)]) n hh^h`~` $$+,2KS)-]cZ] IQw ~+4ISZb[h\ikuv wy mv-5QwUV^`j'hjUhjmHnHu hj0JG6 hj0JG hj0JIhj hj0JFSkB"@"TQ't o HH^H` q & F h` 'b k m- $$G$If $$G$If   n hh^h`` `_Hkd$$$If0 D @ 44 la$G$If$G$IfHkds$$$If0 D @ 44 la-56 _]W `Hkdi%$$If0 D @ 44 la$G$If$G$IfHkd%$$If0 D @ 44 la   !5<_Hkd &$$If0 D 44 la$G$If$G$IfHkd%$$If0 D 44 la<=QwxUWt_][YS b`Hkd&$$If0 D 44 la$G$If$G$IfHkd_&$$If0 D 44 la _HkdL$$If0 D H44 la$G$IfHkdxL$$If0 D H44 la$G$If_]W `HkdnM$$If0 D H44 la$G$If$G$IfHkdM$$If0 D H44 la` V)+17<.;MXY Y^*+35DFQjGfhjUjOYhjUhjmHnHujRhjU hj0JI hj0J@ hj0JGhjO_HkdN$$If0 D H44 la$G$If$G$IfHkdM$$If0 D H44 la  _]W `HkdN$$If0 D H44 la$G$If$G$IfHkddN$$If0 D H44 la_HkdZO$$If0 D H44 la$G$If$G$IfHkdO$$If0 D H44 laVWM_]]]OO n hh^h``HkdO$$If0 D H44 la$G$If$G$IfHkdO$$If0 D H44 la  ;IV\]ip$G$If$G$IfHkdPP$$If0 D @ 44 la $$G$If $$G$If  n hh^h`pq_HkdP$$If0 D @ 44 la$G$If$G$IfHkdP$$If0 D @ 44 lamyWHkdQ$$If0 D @ 44 la$G$If$G$If `HkdFQ$$If0 D @ 44 la_Hkd@47kluw1By, hj0JF hj0JIjhjUjhjUj׃hjUjzhjUjshjUj=nhjU hj0JGhjhjmHnHuEw_Hkdm$$If0 D H44 laHkdGm$$If0 D H44 la$G$If$G$If 7 J W    QHkdy$$If0 D H44 la $$G$If $$G$If by`Hkdm$$If0 D H44 la       ; ]UM$G$If$G$IfHkd2z$$If0 D H44 la $$G$IfHkdy$$If0 D H44 la $$G$If; <         SHkdk$$If0 D H44 la$G$If$G$If by`Hkdz$$If0 D H44 la  ! " 6 = > R  _Hkd$$If0 D H44 la$G$IfHkd$$If0 D H44 la$G$If    57nopqrst   by`Hkda$$If0 D H44 lapHkd($$If0 D H44 la$G$If$G$If  n ^` n hh^h``Tp 678IJOPjklnopq<DLhyLW     jxhjU hj0JI hj0JGjhjUj,hjUjhjUhjmHnHuj0hjUjhjU hj0JFhj hj0JJ>_Hkḑ$$If0 D H44 la$G$IfHkdz$$If0 D H44 la$G$IfwWHkdp$$If0 D H44 la$G$If$G$If `Hkd$$If0 D H44 la _Hkd$$If0 D H44 la$G$IfHkd¨$$If0 D H44 la$G$IfOG$G$If[kd$$IfFj D    4+4 xa$G$Ifb$`Hkdf$$If0 D H44 laA[kd&$$IfFj D    4+4 xa[kdo$$IfFj D    4+4 xa$G$If,   ?   !B!k!l!!!by` [kdϫ$$IfFj D    4+4 xa$G$If  ( )4);)?)L)e)y){))&+'+/+1+g+i+t++++--#./.g..G/[/N0R011(141X1v1}1~142622222;3<3D3F35555555555O6W6889999999jhjUjhjUjMhjUjhjU hj0JFjhjU hj0JI hj0JJ hj0JGhjhjmHnHuF!!"0"S"T"p""""#I#w###$$$C$b$g$$$$$%%7%d%%%%%%%%&$&=&]&&&&&*'P'd''''((:(J(l((((((((( ) ))) )4)L)RKkd$$If40 D H44 laf4KkdQ$$If40 D H44 laf4$G$If $$G$If  L)M)a)))&+(+@+L,,YWUSWWy`KkdY$$If40 D H44 laf4$G$If$G$IfKkd$$If40 D H44 laf4 ,,,,--2-E-<.0;3=3w33335H667a889=:;;> y` ` n hh^h`99D:K:O<r<'=;=>>w>>d?o???+@2@AABBBBCCACKC9DGDDDDDDDDDDDEE4E?NBCC5DDDDDDE$EFGsHAII@JJKKRLdLMMO ` n hh^h` `%K*K3KKKpLxL}MMMMNNNNNNO*O/O=OPPPPQQQQQQSSTTTTeTTTTTDUMUUUV#VMV_VW+WXXXX\\\]^^^___```absbtb(cWcXcc d ddd hj0JK5 hj0JK hj0JJ hj0JG6j*hjUj{&hjU hj0JI hj0JGhjNOPPGRWR~RDSTTDUUVMVWWWXCY[YYZ[3\C\P\ $$G$If  ` n hh^h` `P\\\\\\\\]Hkd-$$If0 D H44 la $$G$IfHkd-$$If0 D H44 la $$G$If\\\]]^^_`\ZZLL n hh^h``Kkd.$$If40 D H44 laf4$G$If$G$IfHkd@.$$If0 D H44 la`aDapaaaab(cccdeegijl;lOlblllHm q & F hq$ & F hmm^m `` o ^` n hh^h`ddOgVgggahkhVi]ijjlllllHmmmmonnnno*opppp qq;qCqDqwqqqqqqqqqr r8rj<b‰%WP‹@f;e 7dǎǎݎ'R{ɏ*eϐ7Qi ` `@b/I6c ~cKyȝ `` NEuܟN|FϤH n hh^h`~` $6>HNEH4<py~bkir4>EMFSGTV`aҹ۹ܹbdXa}Ȼһ |<b@AIKj[hjUhjmHnHu hj0JG6 hj0JG hj0JIhj hj0JFSlV- +ִ ?xõе<oĶt o HH^H` q & F h` M׷VҹX}Ȼjνӽ $$G$If $$G$If   n hh^h`` `ӽԽ_Hkd$$If0 D @ 44 la$G$If$G$IfHkdˆ$$If0 D @ 44 la !¾Ծ_]W `Hkd$$If0 D @ 44 la$G$If$G$IfHkdo$$If0 D @ 44 la   '_Hkde$$If0 D 44 la$G$If$G$IfHkd$$If0 D 44 la'(<bc@B_mz_][YS b`Hkd $$If0 D 44 la$G$If$G$IfHkd$$If0 D 44 la z_Hkd"$$If0 D H44 la$G$IfHkdЮ$$If0 D H44 la$G$If{_]W `HkdƯ$$If0 D H44 la$G$If$G$IfHkdt$$If0 D H44 laKA "'&8CDDI| /1<jhjUjhjUhjmHnHuj8hjU hj0JI hj0J@ hj0JGhjO_Hkdj$$If0 D H44 la$G$If$G$IfHkd$$If0 D H44 lao~_]W `Hkd$$If0 D H44 la$G$If$G$IfHkd$$If0 D H44 la_Hkd$$If0 D H44 la$G$If$G$IfHkd`$$If0 D H44 laAB8_]]]OO n hh^h``HkdV$$If0 D H44 la$G$If$G$IfHkd$$If0 D H44 la &4AGHT[$G$If$G$IfHkd$$If0 D @ 44 la $$G$If $$G$If  n hh^h`[\pwx_HkdL$$If0 D @ 44 la$G$If$G$IfHkd$$If0 D @ 44 laXdqWHkd$$If0 D @ 44 la$G$If$G$If `Hkd$$If0 D @ 44 la_Hkd$$If0 D @ 44 la$G$If$G$IfHkdB$$If0 D @ 44 laxBWdjkQHkdY$$If0 lD 44 la $$G$If $$G$If by`Hkd$$If0 D @ 44 la kw~]UM$G$If$G$IfHkd$$If0 lD 44 laHkd$$If0 lD 44 la $$G$If $$G$IfLcpxyPHkdQ$$If0 lD 44 la$G$If$G$If by`KkdO$$If40 lD 44 laf4 y<_Hkd$$If0 lD 44 laHkd$$If0 lD 44 la$G$If$G$If<= 9N[abPHkdM$$If0 D H44 la$G$If$G$If by`KkdG$$If40 lD 44 laf4  &yz{|=p| !)+"VW`bu-du hj0JF hj0JIjGhjUj hjUj/hjUj.hjUj3hjUjhjU hj0JGhjhjmHnHuEbnuv_Hkd$$If0 D H44 laHkd$$If0 D H44 la$G$If$G$If"5BQHkd$$If0 D H44 la $$G$If $$G$If by`HkdC$$If0 D H44 la &]UM$G$If$G$IfHkd$$If0 D H44 la $$G$IfHkd8$$If0 D H44 la $$G$If&'y}SHkd$$If0 D H44 la$G$If$G$If by`Hkd$$If0 D H44 la   !()=_Hkdg$$If0 D H44 la$G$IfHkd$$If0 D H44 la$G$If "YZ[\]^_xyx   by`Hkd$$If0 D H44 la{ XB3 $$G$If $$G$If  n ^` n hh^h``?[   !"#/078RSTVWXYopq}~j| hjUj hjUj hjUj hjUjhjUjhjUhjmHnHujhjUjhjU hj0JFhj hj0JJ9   !"<=>@ABCYZ[lmrs  -./1234jlhjUj hjUjp hjUj hjUjt hjUj hjUhjmHnHujx hjUj hjUhjjhjU94JKL[\cd~+!"*,MNUVpqrtuvwjW"hjUj!hjUj[!hjUj hjUjhjU hj0JG hj0J@jhjUhjmHnHujhhjUjhjUjhjUhj6WKkd$$If40 D H44 laf4 $$G$If $$G$IfKkdd$$If40 D H44 laf4+!#AYWUSy`Kkdl$$If40 D H44 laf4$G$If$G$IfKkd$$If40 D H44 laf4AvbV)]^jqHkd)$$If0 D H44 la $$G$If $$G$If  n ^`,-.9:AB\]^`abcyz{*+jG&hjUj%hjUjK%hjUj$hjUjO$hjUj#hjUjS#hjUhjmHnHuj"hjUhjjhjU9+23OPQTUVWmno{|   m:LM01 hj0JK5 hj0JK hj0JGjC)hjUj(hjUjG(hjUj'hjUjK'hjUhjmHnHuj&hjUjhjUhj;qrm]UM$G$If$G$IfHkdd*$$If0 D H44 la $$G$If $$G$IfHkd*$$If0 D H44 lamnqIz: o ^` n hh^h``Kkd*$$If40 D H44 laf41(/mt:D/6E^h!cqzH]PZ["-._cqz|hj0JFmH sH hj0JI5mH sH hjmHnHuj+hjU hj5\ hj0JG hj0JJ hj0JI hj0JK5 hj0JKhjE_(;E!7IXcP n hh^h`by q & F h q & F hq$ & F hmm^m` `"qjM!A;* n ^`` n hh^h` $%W]ntvz|YZab|}~ AB^ӿӿӿjmhjUjmhjUjlhjUjlhjUhjmHnHujkhjUjhjU hj0JFhj0JI5mH sH  hj0JIhj0JFmH sH hj9^_`st{|4569:;<RSTcdkljqhjUjqhjUjphjUjphjUjohjUjohjUhjmHnHujnhjUhjjhjUjnhjU8 #$%()*+ABCYZab|}~j{uhjUjthjUjthjUjthjUjshjUjshjUhjmHnHujrhjUhjjhjUj rhjU8`                    / 0 1 O P W X r s t w x     " # $ & ' .ij hj5\jhj0JPUjhjU hj0JJj hjUjhjUjhjUj]}hjUjwhjUhjmHnHu hj0JGhjjhjUjuhjU4    ( / 0 D K YHkdv$$If0 D H44 laHkdwv$$If0 D H44 la$G$If$G$If  K L `       _][YK n ^`by`Hkdmw$$If0 D H44 la$G$If$G$IfHkdw$$If0 D H44 la y z *  'ac,tw1+G ~y`n & F n ^`JPQ12KLMRS\]wxy{|abjkOPfghoqrtu~~?Ej>hjUjhjUjchjUjhjUhjmHnHujhjUjhjU hj0JF hj0JI hj0JGhjjhjU=E!P Q j k l p q z {      !!!!""" "u"v"~"""""";#jhjUj0hjUjhjUj4hjUhjmHnHujhjUj8hjU hj0JJjhjUjhjUhj>9T !!."u"w""$#7#$$$%&&''())r** q & F hy  `;#A#$$$$$$$$&&''''''''(((())*****&*'*A*B*C*D*E***e+f+++++++++++++ ,*,,,z-jhjUjhjU hj0JGj hjUjhjU hj0J@jhjUhjmHnHujhjUjhjUhj hj0JJ:*+,,,z-|--".6.0//0012:2^2_22222233b$ q & F hy`  q & F hz-{-------O.P.i.j.k.n.o.t.u........r/w/0!000111111 666,666J6T6Y6b66666666666777 7 7 7V8W8p8ƻjhhjUjShjUhj0JI5mH sH  hj0JIjhjUjYhjUhjmHnHujhjUhjjhjU?3H3n33333"4]444425^55555 6,6J6u666777y` n hh^h``$77787X9}9F:;/;<<!<7<8<D<[<Hkd^$$If0 D < 44 la$G$If$G$If  ~` p8q8r8v8w888888888888888;;<<==========+>,>B>C>D>K>M>N>X>Y>q>r>t>u>:CBCDDDDDDHEOE~EEEEEEEE1F4F9Fê hj0JFj 0hjUjhjU hj0JGhjmHnHujhjUjbhjUhjjhjUjhjUC[<\<p<w<x<<<_Hkd$$If0 D < 44 la$G$If$G$IfHkd$$If0 D < 44 la<<===P>>>>>2?Q?t??????@/@d@by`HkdT$$If0 D < 44 lad@m@@@@ A6AMAAAAAB7B[BmBBBBBBB$G$If$G$If BBB C CC%C_Hkd0$$If0 D < 44 la$G$If$G$IfHkd0$$If0 D < 44 la%C&C:CBCCCDDDDD_]OOOO n hh^h``Hkd|1$$If0 D < 44 la$G$If$G$IfHkd*1$$If0 D < 44 la DDDDDDDFFGjGlGGGGGGHkdJ:$$If0 lD 44 la$G$If$G$If y` n hh^h`9F;FFFFFFFGG)G*G+G2G4G5GjGkGsGtGGGGG4H@HBHMHOHqHHHIIIIIIIINJOJJJKKKKKKKKLLM MdMkMmMrM{MMhj5\aJjhj0JPUj;hjUjhj0JPUmHnHsH hj0JGjK2hjUhjmHnHuj1hjUjhjU hj0JJhj hj0JF=GGHHHH H4HqH_Hkd:$$If0 lD 44 laHkd:$$If0 lD 44 la$G$If$G$IfqHrHIIIJsKKKK$G$If$G$If `Hkd@;$$If0 lD 44 la KKKKKKK_Hkd0E$$If0 DD l 44 la$G$If$G$IfHkdD$$If0 DD l 44 laKKKKKM4MFMM,N_]]OO] n hh^h``HkdE$$If0 DD l 44 la$G$If$G$IfHkdE$$If0 DD l 44 la MMMN#NKNPN9O=ObQcQyQzQ{QQQQQQQQQQQQQQQQtR}RyTzTTTTTTTTT8V?V'W(W>W?W@WGWIWJWLWMWUWVWmWnWpWqW>X?X@XAXBXCXKXLXj|hjUjw|hjUjRhjUjhj0JQU hj0JQjFhjUhjmHnHuj&FhjUjhjU hj0JGhjB,NNO&QQQRRR1R2R>RCRHkdLQ$$If0 D  44 la$G$If$G$If ` CRDRXR_R`RtR}R_HkdQ$$If0 D  44 la$G$If$G$IfHkdQ$$If0 D  44 la}R~RyT{TTUUUUUOKkd{$$If40 D < 44 laf4$G$If $$G$If y`HkdBR$$If0 D  44 la UVVVV#V$V8V?VXKkd{$$If40 D < 44 laf4Kkdo{$$If40 D < 44 laf4$G$If $$G$If?V@VLWNWWYV[X[[\@]____ $$G$If $$G$If y`Kkd|$$If40 D < 44 laf4LXNXOXUXVX1[2[H[I[J[Q[S[T[V[W[_[`[w[x[z[{[\\\\\\@]S]X]^]y^}^ ``aa2a3a4a;a=a>a%b&b.b/bFbGbIbJbobwbdddddddddddjLhjUjyLhjUjAhjUj@hjU hj0JF hj0JKjlhjUhjmHnHujhjUjhjU hj0JGhj?_______]UM$G$If$G$IfHkd?$$If0 D < 44 la $$G$If $$G$IfHkdQ?$$If0 D < 44 la__ ```aa%b'bkbc_][[YW]y`HkdG@$$If0 D < 44 la$G$If$G$IfHkd?$$If0 D < 44 la ccccccccccYHkdK$$If0 TD |44 laHkd1K$$If0 TD |44 la$G$If$G$If  cccddddeZfgeg_][Y]]]`Hkd'L$$If0 TD |44 la$G$If$G$IfHkdK$$If0 TD |44 la ddddddiiiiiiiiiiTjUj]j^jujvjxjyjjkl&lll$m*m;m?mmmsmnnnnnncsrssssssss1t2tHtItJtQtStTtVtWt_t`twtxtzt{ttttt9u@uuvpxvxxx hj0JIj;ohjUjnhjUjbhjU hj0JGhjmHnHuhjjhjUMeghhMiZigiqiri~iiiWHkda$$If0 D H44 laHkda$$If0 D H44 la$G$If$G$If ` iiiiiiiTjVjjj_][Y]y`Hkdb$$If0 D H44 laHkdKb$$If0 D H44 la$G$If$G$If j@k2lplmn'obooooo p2p[pppppq5qeqqqqsss$G$If b$`s s!s-s2s3sGsNs_Hkdm$$If0 D H44 la$G$IfHkdvm$$If0 D H44 la$G$IfNsOscsssVtXtt wwx_][Y]]]y`Hkdln$$If0 D H44 la$G$If$G$IfHkdn$$If0 D H44 la xxxxxxxxxy yyyQz\zzz|||||}}}}}}}'}(}*}+}~~2~3~4~;~=~>~U~W~~~~~~~~~2>,-.je4hjU hj0JJj8hjU hj0JIjhjUjhjUjhhjU hj0JF hj0JGhjmHnHujhjUjhjUhj;xMzz{{{{{{{{WHkdr$$If0 D < 44 laHkd $$If0 D < 44 la$G$If$G$If ` {|||$|+|,|}}@}~_][Y]y`Hkd$$If0 D < 44 laHkdĔ$$If0 D < 44 la$G$If$G$If ~~~΀ۀHkd3$$If0 D < 44 la$G$If$G$If `y 2>_Hkd3$$If0 D < 44 la$G$If$G$IfHkdo3$$If0 D < 44 la>? FyO?r5> n hh^h`~$y`Hkd4$$If0 D < 44 la.578˂̂΂ςQRSjkÆĆņ̆Άφֆ379>CIKOQY[bRSlmntu~jhjUjdhjUj4bhjU hj0JG hj0JAj7ahjUj4hjUjhjUhjmHnHuhj@>Y_ltvŇχЇ܇Kkdb$$If40 D H44 laf4$G$If$G$If 3bYKkdac$$If40 D H44 laf4$G$If$G$IfKkd c$$If40 D H44 laf4bc>ԉҊȌLL% q hh^h`q$ hmm^m`~y`Kkdc$$If40 D H44 laf4&*ÎɎTZpuOSkpӑّ`fdjbjltvxz~Օ֕ޕߕ߽j(hjU hj0JI5 hj0JG hj0JG6 hj0JFhjhjmHnHujhjUjahjUJ%d!͓ړ1Hkd$$If0 D H44 la$G$If$G$If  r ^` 12FMNb_Hkd$$If0 D H44 la$G$If$G$IfHkd2$$If0 D H44 la :ՕוɘG[۝VWvўby ``Hkd֖$$If0 D H44 la56OPQVW`a{|}՗ٗ{|˜ØŘƘ@AZ[\_`ijAE hj0JIjļhjUjGhjUjȻhjUjKhjUj̺hjUjOhjU hj0JGhjjhjUhjmHnHu=2BRz-hޠTɡˡ̡ =FmYͣ3Sr$1>C $$G$If $$G$If  ``yäĤƤǤܤݤ]eY_ v|TU  "(*/  ԭխj?hjUjhj0JPUjhj0JQU hj0JI hj0JGjzhjUhjmHnHujhjUhjjChjUECDPVWkr_HkdI$$If0 D H44 la$G$If$G$IfHkd$$If0 D H44 lars/0&nYWUSWy`Hkd$$If0 D H44 la$If$G$If$G$IfHkd$$If0 D H44 la n%AnpǰKkdZ $$If40 D H44 laf4 $$G$If $$G$If y` խ=>TUV]_`įͯnowx#8./78OPRSS[]aclntvj=\ hjU hj0J@j:D hjUjC hjU hj0JGj/ hjUhjmHnHujhjUj/ hjUhjE#$8WOG$G$If$G$IfKkd[ $$If40 D H44 laf4 $$G$If $$G$IfKkd5[ $$If40 D H44 laf4.0huGJkdUk $$If0 HD p 44 la $$$G$If $$$G$If y`Kkd[ $$If40 D H44 laf4ŴƴڴVHkdl $$If0 TD |44 laJkdk $$If0 HD p 44 la $$$G$If $$$G$If "THkdl $$If0 D H44 la$G$If$G$If `$$HkdUl $$If0 TD |44 la"#7>?S_HkdKm $$If0 D H44 la$G$If$G$IfHkdl $$If0 D H44 la*abipu$G$Ifb$`Hkdm $$If0 D H44 laַ׷ط߷01GHIJtu}~U^`joz ǾȾɾϾоپھSYj4 hjUj hjUj hjU hj0JGjr hjUjln hjUhjmHnHuhjjhjUjm hjUAƸѸݸ|ttttt$G$Ifkdn $$If4r(d44 laݸ޸1<H{sssss$G$Ifkdo $$If4r(d44 laf4HImv{sssss$G$Ifkd6p $$If4r(d44 laf4Ĺ۹ {sssss$G$Ifkdp $$If4r(d44 laf4  6I\gs{sssss$G$Ifkdq $$If4r(d44 laf4stvVѻEr{ywuugggggg n hh^h``ykd.r $$If4r(d44 laf4 ĽŽѽڽ۽VHkd $$If0 D  44 laHkdo $$If0 D  44 la$G$If $$G$If `   _]WN $$G$If `Hkde $$If0 D  44 la$G$IfHkd $$If0 D  44 la$G$If %&278LcYKkd $$If40 D H44 laf4$G$IfKkd $$If40 D H44 laf4$G$IfY]cxx#PWX\eU[=j hjUj6 hjUhjmHnHujhjUj hjUhj0JI5mH sH  hj0JI hj0JGhjJcdx+uYWWII n hh^h``Kkd $$If40 D H44 laf4$G$If$G$IfKkdc $$If40 D H44 laf4 M *Hkd $$If0 D H44 la$G$If$G$If  n hh^h``y *+?FG[b_Hkd $$If0 D H44 la$G$If$G$IfHkd@ $$If0 D H44 labc SHkd $$If0 D H44 la$G$If$G$If y`Hkd $$If0 D H44 la _Hkd8 $$If0 D H44 la$G$IfHkd $$If0 D H44 la$G$If=?)$G$If$G$If y`Hkd $$If0 D H44 la =>FG^_ab!&PY^dmpz$nu "# j hjUj hjU hj0J@ hj0JG hj0JF hj0JSj hjUhjmHnHujhjUhjjX hjUB)*6=>RY_Hkd $$If0 dD  44 la$G$If$G$IfHkd_ $$If0 dD  44 laYZnuv_]W `HkdU $$If0 dD  44 la$G$If$G$IfHkd $$If0 dD  44 la_Hkd $$If0 dD  44 la$G$If$G$IfHkd $$If0 dD  44 la9X_][Y]]y`Hkd $$If0 dD  44 la$G$If$G$IfHkdK $$If0 dD  44 la XP$G$IfHkd $$If0 D H44 laHkd $$If0 D H44 la$G$If $$G$If     Of_][YS] y`Hkd $$If0 D H44 la$G$If$G$IfHkd1 $$If0 D H44 la  )*,-QX280V "+GHabchis{6;=*VdemnNOgjn, hjU hj0JJj' hjU hj0JGhjmHnHujhjUjR hjUhj hj0JIKYHkd% $$If0 HD p44 laHkdY% $$If0 HD p44 la$G$If$G$If  2e_][MM n hh^h`z`HkdO& $$If0 HD p44 la$G$If$G$IfHkd% $$If0 HD p44 laeWHkd& $$If0 D H44 laHkd& $$If0 D H44 la$G$If$G$If ` +,H1_]]]]W `Hkd' $$If0 D H44 la$G$IfHkdE' $$If0 D H44 la$G$If _Hkd( $$If0 D H44 laHkdf( $$If0 D H44 la$G$If$G$If=>*7_]ZRRR$G$Ifb$`Hkd\) $$If0 D H44 la$G$If$G$IfHkd ) $$If0 D H44 la 78?CGHORA[kde* $$IfFj D    4+4 xa$G$If[kd) $$IfFj D    4+4 xaRVWaehiA[kd+ $$IfFj D    4+4 xa[kd+ $$IfFj D    4+4 xa$G$Ifi|\dfF <[Mz$Wby` ghjk:!"-@Hmwxjc hjUj3c hjUjb hjUj9b hjU hj0JFja hjUjI hjU hj0JI hj0JJ hj0JGhjhjmHnHujhjU:7@c$NSev:m:r ;bp}KkdGH $$If40 D H44 laf4$G$If $$G$If FXP$G$IfKkdH $$If40 D H44 laf4KkdH $$If40 D H44 laf4$G$If $$G$IfFGw'U ` n hh^h`y`KkdOI $$If40 D H44 laf4%&'(>?@STUVlmn#*x]j} -./12\ijj hjUj+j hjUhjmHnHuji hjUj'e hjU hj0JJ hj0JI hj0JGjd hjUj-d hjUhjjhjU<  ep_gt~6<G)4gprx PT hj0JFj hjU hj0JJjhj0JQUj hjUj hjUj hjU hj0JI hj0JGhjmHnHujhjUhjj'k hjU?;J^ p%\vPm n hh^h` ` `Tmr/ 7 x  > L T X         - 4 6 7 9 > n t v    n u   c g     6>CKLWixcl}QZjد hjUjU hjU hj0JIhj0JFmH sH  hj0JG hj0JFhjQh T 9  n  c  [*fsMx D  v  `` n hh^h`+hx} v%Rfhs{Z !!!"""###'%9%:%%&&&&&'''**Z*a*'+1+,#,r--.2/K/U/0P0^0g051J11111112 22 hj5\jhjU hj0JK5 hj0JK hj0JI hj0JJ hj0JGhj hj0JG6K{ ! JKHkdv $$If0 D H44 la $$G$If $$G$If ` ` n hh^h`KW^_s{|Z ]UM$G$If$G$IfHkd $$If0 D H44 laHkdȲ $$If0 D H44 la $$G$If $$G$IfZ [ ^!!"## $6$g$$'%%l&&'( o ^` n hh^h``Kkdl $$If40 D H44 laf4(()L,-.//(/2/0$060E0P01122(344p44 n hh^h`by q & F h q & F hq$ & F hmm^m` `2222333 34444<4=4p4z4{4444444551555B5M5N555555555555555,606>6D6E6w6}666666666669999 : : :::-:j hjU hj0JFhj0JFmH sH hj0JI5mH sH  hj0JI hj0JGhjmHnHujhjUhjjij hjUE44B555>66"788m9z999999KkdM $$If40 D H44 laf4 $$G$If $$G$If ` n hh^h`999::-::WOG$G$If$G$IfKkdz $$If40 D H44 laf4 $$G$If $$G$IfKkd $$If40 D H44 laf4-::<#<<<====3=4=6=7===============dUxUUUVVWWW W W WWWYZ\\]]]]]]]^^^^^^^_%___;e>ej hjUj hjUj hjU hj0JI hj0JJj" hjUhjmHnHujhjUj* hjUhj hj0JGA::D;h<==E===">#>?>p>>>>?+?U??b$y`Kkd $$If40 D H44 laf4??????@@E@J@j@@@@@@@@A>AcAAAAAAAAABB&B@BZB`BrBBBBBBBC+C1CCCYCrCCCCCCCC D#DED]DvDvDDDDDEGEUE`EEEEEEEEFF5FjFkFFFFFFGG0GQGQGlGGGGGGG-HXHHHHHHHI9I[IIII(JSJwJJJJ)KTKTKxKKKK$LRLvLLLL'MYMMMMNNNNNN'OUOOOOOPLPvPvPPPPQGQrQQQQQQQ RR,RBRhRRRR S.SSS|SSSST4T4TfTTTTTTU"UzUxWWpXXXXY:YvYYYf[[[[\7\g\ ` `g\\\]^=_Z___a2aVaaaab9bjbbbb.cacccd5d[d$ `` >eCeGehekeeefff f f)f,fЎ֎?Dڏ,1 ɑYZbcz{}~ c  "jD hjUhjmHnHujw> hjU hj0J@ hj0JI hj0JGj": hjUjhjUhjK"#7_HkdC; $$If0 D H44 la$G$If$G$IfHkd: $$If0 D H44 laC|8jx $$G$If $$G$If  n hh^h``Hkd; $$If0 D H44 la _Hkd9< $$If0 D @ 44 la$G$If$G$IfHkd; $$If0 D @ 44 laЎ֎׎Đ_]W `Hkd< $$If0 D @ 44 la$G$If$G$IfHkd< $$If0 D @ 44 laĐŐѐِؐ_Hkd= $$If0 D @ 44 la$G$If$G$IfHkd/= $$If0 D @ 44 la  Y[_]][YS by`Hkd%> $$If0 D @ 44 la$G$If$G$IfHkd= $$If0 D @ 44 la ’ȒɒՒܒݒ]HkdC $$If0 lD 44 laHkdC $$If0 lD 44 la $$G$If $$G$If cdIޔ\ZXVZP by`KkdD $$If40 lD 44 laf4$G$If$G$IfHkd hjU hj0JIj hjUjz hjU hj0JGhjmHnHujhjUjp hjUhjjg hjU?   4;_Hkdy $$If0 D H44 la$G$IfHkdyy $$If0 D H44 la$G$If;<PMO_][Y[Y]by`Hkdoz $$If0 D H44 la$G$If$G$IfHkdz $$If0 D H44 la ͡4 &6Ta֦@M n hh^h`   ` ڥ "M]Чۧ1Jjq~¨ ,_q]^ƪժ*1=Ftͫϫѫ׫٫ޫy~¬ˬͬ٬COMU^e hj0J@jhj0JPU hj0JIhj0JFmH sH  hj0JG hj0JFhj hj0JJPM1ǩɩ=tͬCkM^+3з` n & F^ n hh^h`IS+53Dϵ۵з۷   ѹչǺѺ '/1@L[^e+?ǼѼ#*S]cru׽>Fpvjhj0JPU hj0JF hj0JJhj hj0JIXз Ǻ1^+Ǽ#u׽>pgMt)/Ff$G$If`v/4ZdgtMUz)*+./UVuv48QRov$%'(*_h# hjCJj hjU hj0JFj@ hjUjë hjUjhjUjhj0JPU hj0JI hj0JJhjBfgkv7_kd $$IfTFh    4+4 xaT$G$If`kd: $$IfT4Fh    4+4 xaT$G$If_kd $$IfTFh    4+4 xaT D$G$If 9_kd $$IfTFh    4+4 xaT$G$If_kdQ $$IfTFh    4+4 xaT ()*0>?_kd $$IfTFh    4+4 xaT$G$If?@ITUVj9_kd $$IfTFh    4+4 xaT$G$If_kdI $$IfTFh    4+4 xaTju_kd $$IfTFh    4+4 xaT$G$If9_kd $$IfTFh    4+4 xaT$G$If_kdA $$IfTFh    4+4 xaT_kd $$IfTFh    4+4 xaT$G$If-_kd $$IfTFh    4+4 xaT $G$If$G$If_kd9 $$IfTFh    4+4 xaT&678=HX_kd $$IfTFh    4+4 xaT$G$IfXY_f9_kdٝ $$IfTFh    4+4 xaT$G$If_kd1 $$IfTFh    4+4 xaT_kd $$IfTFh    4+4 xaT$G$If9_kdџ $$IfTFh    4+4 xaT$G$If_kd) $$IfTFh    4+4 xaT3_kdy $$IfTFh    4+4 xaT$G$If3496_kdϡ $$IfTFh    4+4 xaT$G$Ifbkd! $$IfT4Fh    4+4 xaf4T  _kdw $$IfTFh    4+4 xaT$G$If &'(-_kdǣ $$IfTFh    4+4 xaT $G$If$G$If_kd $$IfTFh    4+4 xaT(.:MNT_j_kdo $$IfTFh    4+4 xaT$G$Ifjkt9_kdͥ $$IfTFh    4+4 xaT$G$If_kd $$IfTFh    4+4 xaT_kd $$IfTFh    4+4 xaT$G$If9_kdӧ $$IfTFh    4+4 xaT$G$If_kd+ $$IfTFh    4+4 xaT !'34_kd{ $$IfTFh    4+4 xaT$G$If45@vwx9_kd˩ $$IfTFh    4+4 xaT$G$If_kd# $$IfTFh    4+4 xaT_kds $$IfTFh    4+4 xaT$G$IfUQ',)){y_kd $$IfTFh    4+4 xaT#*,- !&')*Vc)*`az{|  &'(j hjUj4 hjUj hjU hj0JJ hj0JIhjOJQJ^Jj: hjUjhjUjhj0JPUhjhjOJQJ;-   -.d` d&dP{(*+-.  ()+,./34:;<=Z[abcduv|}~jhj0JNUj hjUj hjUheZ1mHnHuj hjUj0 hjUjhj0JPUhjjhjUhjmHnHuB.23KLefgh67YZs d&dPed 124578:;BCWXZ[abdeٷj hjUj4 hjUhH60JNmHnHuhH6mHnHuj^ hjUj hjUheZ1mHnHujhjUhjheZ10JNmHnHujhj0JNU hj0JN=st "#$%>?abd d&dPe !239:<=?@GH\]_`bcefmnjb hjUj hjUj hjUj hjUhH6mHnHuheZ10JNmHnHu hj0JNjhj0JNUheZ1mHnHuhjjhjUA45NOPQjkde d&dP"#%&BCIJLM^_efhiklst  !"$%'(/0Dj3 hjUj* hjUj" hjUj8 hjUheZ10JNmHnHu hj0JNjhj0JNUheZ1mHnHujhjUhjE#$FGab|}~789:TU d&dPedDEGHNORSopvwz{2356:;ABEFbcijmnpqxyjDEHIeflmpqtu؁فabппjq hjUjh hjUUheZ10JNmHnHu hj0JNjhj0JNUheZ1mHnHuj_ hjUjW hjUhjjhjUDTraits UI User Guide    TITLE Traits UI User Guide  PAGE 208 3-Mar-2008 3-Mar-2008  PAGE 207 Add example here. Add example here. Add sample help screen Does Item-level or Group-level take precedence? Find out and document. The document needs to include material on organizing Views by means of Groups, including the implied top-level group of every View. If we do this earlier in the document, it will probably simplify the explanation here. Add diagrams and/or examples to clarify. Add a reference to the section on the organization of Views via Groups, once it's been added. Add code and screenshot for a simple tabbed display and of the same View presented as a Wizard. Do subpanels support menus and toolbars? If not, add this to the documentation. (If so, why do they?) This is a bit asymmetrical. Can we clean it up without complicating the example overly? Add a nontrivial example here. Change the demo and update the figure(s) accordingly the (value, label) option should also be demonstrated. Need an example here. Add an example. Provide more detail on how these table filters work. Add an screenshot of the dialog when it actually works. b‚Â+,*+;<qrjhjUhj*;qy,1h/ =!@ "p#$% 6001hP/ =!@ "p#$% 9 0001hP/ =!@ "p#$% / 01h/ =!@ "p#$% 5 0 001h/ =!@ "p#$% 6 001hP/ =!@ "p#$% / 01h/ =!@ "p#$% / 01h/ =!@ "p#$% / 01h/ =!@ "p#$% / 01h/ =!@ "p#$% / 01h/ =!@ "p#$% / 01h/ =!@ "p#$% / 01h/ =!@ "p#$% / 01h/ =!@ "p#$% / 01h/ =!@ "p#$% / 01h/ =!@ "p#$% / 01h/ =!@ "p#$% / 01h/ =!@ "p#$% 3 01h/ =!@ "p#$% P / 01h/ =!@ "p#$% 3 01h/ =!@ "p#$% P 3 01h/ =!@ "p#$% P / 01h/ =!@ "p#$% / 01h/ =!@ "p#$% 2 0 01h/ =!@ "p#$% ,1h/ =!@ "p#$% 3 01h/ =!@ "p#$% P / 01h/ =!@ "p#$% / 01h/ =!@ "p#$% / 01h/ =!@ "p#$% ,1h/ =!@ "p#$% ,1h/ =!@ "p#$% ,1h/ =!@ "p#$% n3tU03DPNG  IHDRx gAMA7tEXtSoftwareAdobe ImageReadyqe<3RIDATxb?(`Q0 hi4F(`hG(`hG(`hG(`hG(`hG(`hG(`hG(`hG(`hG(`_[opI]X`Q@7@U{ON^_xrCF~Q0 F@ 5֞zSJ_U;'Pc4Q0 F()Y>|؋t~eaݹB`Q0 F@ ×oKO^ǯĨ* u`cM `Q0 hXUgv2;In溣 bQ0 Fu@ v˥W|CXy d1 F(Z |E \U,il%^@4:< F(* pEǖfoOuŅ][?[1 F(B@Cջznlq3΍PM%`Q0 4*MϕN^XW])5VF(`h(U-4B-6eQ0 F FEG`/vޓ3mErfQ0 F {EK#ɣ`Q0 4+4ֲX㎦Q0 F(@ ҊSV\hX3m44 F(AWR Zk F(`4*_4yk JG(`L@,M)`Q0 FV@_ ?[ű#ɣ`Q0 xQN:z-(`d@SѾ|fۏ `΍`Q0 F@ѻwm@D(U劣<8F̣Q0 F( V,P/tskn`Q0b@ѩ(\uZ%LCѭW-.چ9&Q0 F(i h^>|؋#1ö?P;'bZQ0 F(Q hX}$miH2N(` V-~ Xk2t$yZQ0 F(9 _:yt򊛏'?lܓ1z-(` o@Ԭh/~T;k-'Ezڴ&5 F(u*Z`2zZ Z^n o{Q0 FDiEɫwk&OG{+'tx<R]Nrrq,w>(G(`8]d̵ ߱&яíI`Q0  2+SWLY$\oEH2I`Q0  +Z`vP`'c?,/!`Q0@Pۏ\Kϑd`E nhJ`! vنӷ| s6΍gt~ujꚬlld߻ [ïHOcǥkS7gJS^*t\9Y,vЅ[o>}ǿr23ۙ&Qw7RjIkN]GR|;{=_Tá"ZIc@SbjH j'p.:WŅI@,TN*|ھ/Z)C+ Ԗ 7oj?(()2> Lׯ_;133Sb^DjEUzTx=g>}IR{ݽҝGn[0@znt0ˏ&ꧯ n4-y9oBIFE @,Tt񋤆t,vͺdNJih(&1k'YXR٧Ծy6OY͇8ִO3@^㘗^w^%0.NmǛikXLsq}bq~a^YkPn ђYr0:y77p)0p`/6~o?pˈuRG.$xPwR>|!XMn>2hO^+JtD C~:%Ë.l=;mZvޓ1յ3Ҵ`cIkPԲ@kW޾5CUO(Z2PP&2I[|`o$U4ʑjX[!Dg#(ן? skGV^x4 /ERCeʡ7Jx-=Ę*=sGBRj4L9v¬SpD(ݞmKm'A1R1>}i8$+F2 Y$U]8.,W<1 ky]=N#a`-kS [ P-u-:#H\z#-ѽҽd/ e w@ݑ}cV"Z[4ν߿sv A_bh,'; Ґz7f3UõEe1H,7~^h1(!y `Hqڽgo<<8j4H_{nz7W<1Z;CVE%eyEI0u|s-Aꢭ(Mc]ԕF!C7Oj-˥ mk ͇: @EupY׃ٗU3 ʩ+W?1Sj"#cɐ "U{ؘQ8iѥ2[Ju9܈!w;;O9HZ@GI6eb s ʿtZZG t[ubv+HQ3s5{h1jxlo/ )fMvhK)sΚ ҈1mձ˷qUZ F8tyrCjk!hdUo?+wú0gKZKGgdieo|hh ˷%jh- 섽1죌3'9\X`my %Ѧ T)dg;1n`dZ)CkM7]CPa׮spkXۅę0FY؆9뱥 (jHoSY 49IaF,L5c hWO@d.DPфE]_`R* psHˌ2`˸yNo-쌵6ە{?m 75jY\YI 1 V2#jXOKZGkYZ9y b]ıo߼  1ZߑO%=D Òlxs\R Ҩ[)Mehhw\:yG`X3mD;`jnw0@6=27*J7?}l87И6էu$ctjAs x:փc쬁`v7)4PaX^t \4NJ^R9LKk033[ݽӧh+ׯ{wZ:lt%SV _K=3(;^EԂu`×oCdq\R i.@ê}c̵u/ti?~|zׯ_Z'WZohKьiUQ pAU|}t6"ssS͡;=@ ؆HX 0VɉcŃcnn;`]{_7}ıֶ#& S^141 WE{áXΧ:X`@ p$o_0P CE _{nO ck}Ѥ3P@@PX:HΝ102 +&ehuM)<$7V$G y@Ct\̵YC岿a$$MϞ9ɀ1n^\KpS\RJ4, W?qȅ!H>סhVޭ>+cœbUFB ^7F PVUkWp9`ts-X%O9?dgz3xh> >ڏrR2}'J@o\% /͵@CÊ:^\Ue$bDŽED'ލVTCP'6L^u&]rW]92NJAn'[m1r6BġАwa;tJ|"hȡ h{Of99~}nzoL9+KK Rb§//~8\s(@ 9PXOڙk~Xu9SPTD\ kNkLH2P{+jf.)mš"|# 3Б›]>\s(@ Uc=J8u. wF9w K|KhXѴCh.a}T0[PZ w`gCdDb ÞZCgm0w >Z3mCӫږ YW:a1&NE^VDd$ (q!~A6!*u-xGS2-@ hǗhi7VY7s],+N@[WXݢP *Q@e$j5! iff|qrH xv+8fU&cT5n9rWJp%R+ˆGԵDӕ{f%kc6ih_L P..'%DFSF&R؊ю.mb`mKV -%&vdê'M,4"%WfC- X.ꅍiȵ% w*OClC2!i$xXX5XݓѸV@Ph4(~^un׎\1/.)M#̈YIk:T?\R (`Hdu Tflӎp!aB&F\%3n}l qk7vq\2@U~4񪟭\,񀤋Inbb4u<+G@k}g{2ӗ 2{JIpCO{O_|KԾCN"ɝ-!}vt< n8ĄTdL5z[n?} g02g6`߷.%[m@t ; Dś|;.L#@,A0 %ֵ͵t MqԵ- b%TZ=k٫ڕV2e**?x D+$d!PoEy"WBO@GB61: k>k^N;@LA0 00kAa] E׺6~)?f7MZ|l?hR !.$P'Lk.>M $+),@( hE; 3@l?ڧw];4F?5.'Kahr 7ٵdl+hRZ h1e/nM44ZюakFd6M0VA8Ph̃)T]Hb wPxӀM XזJ jB}#2zhG08C4FzL4(y,NZ\!'.a&1?';[VM8xbn}I GebdV5S6) `͍,;=M\X>R@hE; 9v1|s⣀ u6X#UD?#r/!% %=Otځ<:66,5>(l@$G"\hrfAVdgQZ/4xȀ>?Q< ,"B Xq% u8q߿i5e)ыwasq~ix`*{bnx=EYFB[)ˆZ#MYkW<}3 F&q!>U9 ?k d%Ņ}Ѕu{8 twlRBD"/\I7kġl0 N`>~@=lݴ]t79ؖn>zNޣ` *ՀN]lZ7G 8 6 BpRZIRThcoC/t(?ъvP~C 3ZюQ0 F4:t7`Q0<@V|gɫw(` '@~ޥ?|6`Q0@V V=Y;sot;UTd 5%Dm?r-.S-E7s]u9I\q͜PW\m-:XշRle#P|ݘz*XMx#c=qD ?'Vہ1xQ_C}U9<ݧ|\KlD(Ci^jD3+T .ė,4O5xvcpßx0cršp$mIih8ăo=zt'0KLc'̞C jh9 !`4I œT}Dd˧"q!~598Og @ u6l v`, "`h0pݒ)+䀻$z |V~֦B`~U.+b=m&b$̜4q /`a}΍Yoh`YҝG@W(@*^>T ,jq?~+{qy @ͮLe Jm_2e͞խ9x/H r{CG.ed`4`zÕ6bršp$mIiLpomUAV܁(!mF (le6cUl_J ہi)44S1t ]}Rq,!X`H!gK6RH zT_|aGYex@tջWLsi+$e[Hϲ@t U J(I K`_` h2|[~L/ St\,5̽%ў<ih,F] ~`j)>PeBjgvbgܺ Y͵ LZl,0M;)!%'# X:eŋ!H ,`H<cɎc%#XA"X-W=5``kD?!3S7VO9530x+/PRՒ@ns0 kY`SX*}c5(aJ$<7<yy)hxѰ񛹹M1w&4 i̜;azRZ? 6DIJhN\Y-oi.RCn' _`6owTm>~ LꜢ)ڃq׆[nUG)oX b= (hYt熍5jc7 O,3Og Pul42[t :ڥJ?4 9zAEV7ՂXږ[J\JK,' w.>u2_Om˶5IM +crN[PeHjdx@t:~َ5uXFf- iWOR6l U | 1!1-E L62 ,nO"ܰ_j&^y\|l GTBUEFjmd{kVaQ;K#`a!n0%!\ +0>٭%-I^]儺 Qiա]`3G/tzsHF0*Q(`@Fˆ;rL`'@tuwu3TQ# +6 ֠~6\6w1֊= VIpd:fU&>`]K@SRC@" t8 jAVp? e1l Lh-`G Z-Km &)d t0rN|Ǻ H /~#,O-Z2e&G)<`L}QL Wv͓lc vb2Dk~u`#5hkY %0gC MM?o`L YR:`l`b5ֲSҕ3dȋ; {#'S`U$Q`_XkYuyI#"|ΌAKw3$:s&A@p/x|r.0}zZm)0e  HzyH3ۏX`lCEF0I| ;n?"Zo@'ri PpS;ÊI &.a`h, (4,X`T7|ڠN#n T}#5ZS/~!@vF '{b&E^#UC 󻀹DR XD@A`4%5@ r Re6{2>ⶇ `Q}}F+F3[#`xt2<_M'Vc:пȱ4 k >CCs(12 ܾ (O`;[= umN }?XѮ{ RF{ٌ̠;xH"`;d gsCCJo߼/Vw +pd׳t[T4{ &%Mc\ZO h,'ۏ߿?iNU~o?~V_+ KF0g3N .y 22R Cn;n:G/$EL{7|m %p,$-1zLGY`"/3ș%@c Pg3`M L7>J],#*Dd`;47=?JPf}z=#ų}9Q rOɹ qisֵ"ffpdea6V.$X>v߄(` So߼>y35uM Myŏ_{nz;`Q0 "a1ܿw?~|T9F+P`Q0@\2t۷J>>~# ICoNYAO<\]1 F(`@SB7/?KdVx3^_k(`@_B_ ts'l[M^3Ή筏Q0 F(Ҋ-sV66 Mm5uMZpȕ;#ɾpQ0 F D޾y}O>DZFFCn.\qEOZDr(`ZE ׯ]q*=GED $q \; Wi+D"9 F(`~E /?VILI|]}]?Ⱥn{XoY`Q0@Ѫe_pkW.tSF.`ڳt;`O憺U'NǎQ0 FpDÊ~~1`"f]'/N^&g?[#`GG(` @4h!Xў=}F2xQ twNh`aN-x$xM2=G@M]S[GyvI=IqQ0 F U y$~3 'tlqh`-<}tg' p3΍PMp`Q0@ 2bb7_~ ,;kY` bhR` e,fec7WT:wԫ/_ pU'冺&Q0 F( Xz>>~'W:_&O;:; F( X#edd^tvcGcG(`@@ w((*=sSKtF^l7 F(ˠr/<\ўn')Q0 F(@2ݤ&'k5TǚDыF(``28flbItFwNh2`Q `vׯ^4FG/`Q@$ D5uM9y_&pD{t(`b@ WrppZX*;}ɣ`ؑ`Q@< !V11qo׮2y 0Vɉ)fQ0 FI X5tϞ>c:X7:; F(@,Cֶ/?p FG/`Q@9 t I)Wo]&gkK&Q0 F(bҮgffW$S2y}U;C1 F(r@,WT|埏v[5d *Jd+_ wn@J4Jn[7g; b}Ƈgc/)o/|4k},2)It抻yh_0L>::y}/X̀mء` 8їFs SwغqȞv׷anܭ~<@-#fM]f5yE'zn ?ᐑ[eLD4D&9ɹ.v%e3TFp3<pzW CΈga8h$Wj&Ds{XH+1; 7 Ǝı R{͛>zFWn}˾ G*XHyy\kŲZ+V!*# XdU#jRHa8G"=y0gRsYr*#Y҄[NԵ{O&Μmwg4ӈ 1^7觮#=KO:ey_w?[s򁳖^zmמt 8uT4Px[r/QHw.P}Ų6+c<צ݉T6xn_Nע6 2pq +?xgs|??2^ة oD.L@Gy]~CSYTf@xFy\McKXo/fy{C8vcQO}ttv3΃еLjЌfOOP'z{2|'fޔUcUcZ ~;c'*Str#C:"@Gd\[3h〹a= gf|+Wv%Dŋ)ySn)yG8kB'Hqa 4f/ea"I]3<9a4㘹O6 3y0 =zׁãǞ*{SNnӜ;/8RqԥXa[y$e,x1glj,K/K$Bh10X/Jrl]{$-v C;ę_~c2SwYf5gkWCl;綼rز:mgHLhO! '6ixi*v6gJ*qXo<Ɉ#ߧ'Ϳd 5Ӗ<1J(?~1J5cd#F5sf,EM`JyJ.TMեW-t+$a "lGqhyJN6łgPC$Re6"(M,;K(L$LO48W{[sH;3OƏ\2l߾ "c@;kIN[co)9"([l;n)c[8֠u,.o RE!Iѝq`f8"a?)3{>C룏}Qjls 3~Ѐ4UМ?EJ;^XĜ|"1QƋ38i,ġ.p6Ub ?x"`Ƅ&jl8l#"  T$#\ lwgS3铉a%V>Vgl zeD<}}}HЍt!M%8-5$.Y<鐱~oPi y{*R2y}\P]Y> Qẑ~?"p^h4DE4h+fLO#;G։W5*|75Cy h?{`.DFpSZ&fT&;%;M M2<8ٳl"I2-cn[c9QۓŤzmK=R1duޥ eĠar3KL ֋Д Wַ>$զDNLyμ@d0`"/UԗɨIMeRɸs]2.!Ita^bs IAȾob-Ҵ|%oXUmEXWъҪQx7$e.CP&GDD{CVC=#'WFGBIH|U;t1Pb5z@n`f5D2LژL W^<}:d4+(yJ#%0 S1r+\So=xD5az hOPS/|xdoL˦ tAmd.H_ *ET>ͯU.#;i3w (-@OdxR?;8,ɮ=QE2l$kzCWMMwLd]ɅZxwejd]Y-"YsKY'tE[%3IrW5ڑ4*]&ʄgVe(ʗa<8RE=u M2{ݻ͛3 Ĥ)o?W-*[?.JU %-#3gcVVc6Y 8q4E)Vv;Tu%MjYͶdtn-b5g4dVew'g#eyj.bҋ.bD1%~~]5UT^s} /n%?%өd[H֩r5d /km '{˅oMGWܝ7iQdd^+~ђӼvkE'CcX9w鷅-L/.Y|V3P$k&]Yc׀Z뱂^dؘ"GZŽd^ ˨K/]Hf ֋%+ǿԔlU(UI2)a*u̾.MPTrQ`XIhutLbf ŕ\k]*(BڝVX ;}R>YrU_>Pp=nwyyˁҙ,ϗ+UgɬZFzJ-Y6o5 ׳wYQܞ_|%T , 5cFںta֫-PR`VXĿGvq-؀ ޺X[:%RyU>A$ *F_$s/e+LJśjqoyS~̱V-.}+/dU`VZnɊ-/Já6.iɊ9oQ{#ZL2{^zB˨>^H {AJ {AIoc*"H۪霌)k]Ž- ݏZ9zFjnq"Y)jX|ed'>u')UM%E2Op)ZP$=u'TLR{="^( 1 Z/ 9ܡnO{ҵ2jKջܫ^L6%S3BdRkFcIEZnPЮ$+&Tsb&d4-If_*Ҝm[;x[ rŖv룪*q|lK\o[_nJ$ P:Wh-JJf?(R_ڕd-ho}U5GZDGY6"SYҒ+^_-] aTtW % ~qcY$H$YQP @L٭K*v5MBԤEP{="QE2ЩŽ^+>HVnJb,)b "HV)bJ;Tq%E2)*swCUP)\`me| +@(@2*U"LW !!@.$i (JuPT#HpZ~EKNkxZGo|❱ oj 'IU#Y]ҒT"efI=]|EU'k-Yw[d-ےT$/P޲kJ;~ F#[c/fDm~2/ͧ6}O3KHv5lMGB3IV6eXߢ8xQi_u$+H TaXtޱ~aXMg-^V5/%ՙ֦JhRIIA48*A UP\12dv(_!b xD/šP4#J s-x$   aM> 1*Rt8?TH-[/ѳUh(TĈ}>@|>___hѢh7HAK[\=^Ӊ Wݓ= 2` G8腼u7,>WA`N` 2w?}VR"Cem%DW;|F/"ef趡 3 G_O?{-[ sԕwLl!̈́a5785]o\}ރoeYgw~g}v Щ&,6xl A- Es~ƕ2"#KdyV$da΍*}S66O-*re# .^,Ȟ(u)Zh<6SMKYy gbQ7tŒ (R0B0a ea иTЈ:V rza Po$SLL?Ntܓً63Uθ-od~,a`i '&oF1d޺ᩜo' 0= iW QcԯO[3G"M|vAmvљ[oU}*]K*G\*f`]e8J6=g_Cmo܅Q EpYvT-8q KɘAn揾bgFQʅx~Q7R$xki7`èP3nL1œ917BPXB]J+!@x`VhadC<}@Ö{v8!!KSI=9Mwݘ3[~3gA%H,+z:;;%.ZX@py22܎ivfqwON*g|$+I3.4k( SA<(@`XA L%t[ E&B]K,2"xS0䂄a˒:Rݿ|u3[/L -F#!t 8Ĥ(GЀ޼g$a1/;h{FȾYuxl֭>AFbe"tZUa{w^YJ,az%K40< ߕSߋreWV%޺'!Mʀx h1XF!Gi)!' L?|ն5 h<Kُ `a:*]HB * WP6`p<!m#Bym͆ad͠P.n)"ʹHsw68߽$.(d7 D<9˰iQ `&,C,ޒh("H%R$O(N FdxD7 MA(k8 J~~^ sV_~󖚖H6Ե~&˗/&HK,UBQ>KINkdmH׊i)Feq_*]xUʞՏ ]R鱬J$,`Tb=>!Tbӂ\~ ֕3\ w'^]xkewu?uMX8!rXτȼB>}+.+[rš,D|_У-!Y{l 6#B,6 eh4ZWW;Z%A7-i?7禐*ғyT"aһKQgSU%bts=O8 2haJN vm޷9k-hU^,}I]D <'qfT 6]qNsy#ح?~1 4R纅&ֳMlBrF4D=yb1  .^j4&$ Hn4#/M5x("DnB|H-(4ȝX(KIfRCB䯅j0 ' {ܱ6hO.!FGNzl#)@D׏>-3)$WI\k x iŁ7ub[%NDI@aMDF9&V<iYזn㺻:`iNIq[bԆk.%zxGKz-?՛k7_4{~_^3BI-4T<:9?]/9mPBfԑ Q܈Q +R#O@0RkuaP@;<: }^1~KԐ[N7†!5Cwֿ ,**Z&P[C"~BbDxْC*5 j%2uf HxF1ऍ{ҵ8lK AiLIhM&m- ʆ`0#U; %!$D$K DvT=U47zr1TK1z&@ b7`HdTZɡEaX,oPwHTS8ƾI׺y*kf& w,#dg3`3(d*p`~3wSW@_5鵭9IoOP9@Ǽd &l9_#_Y4za*3w4VcF%>iţhʕkq4?yx~IzƍJg~u[UItxRAcnq qL{\/@̜}YӇˈ &)ʼn/@;zSeP .E}ˡ4~WBxTB+inԥ޺N+8p zr9lGe; 1ԯ|W"R2\c`Y+!F,X!\M \ (G[?& _S͔1 2Ɂ1yĸOi$qNhI@:ʰڹY5ډ-eTy$tduLvNV#=t4kT SA|qh:wL}K|1`z'rm]𣵵 YME[芀Y($M^l%}%ԦQ :҆Y@uFĄDM2ɭ(Y˸G6CQ9@^ ^]>|k !CbM"F>)" 1; <6ԙlcLpPg::XԩNO,e$:>>eSA(l:Iդ\?K,n[KY(TFm2 hU;sck5kCulwDpPTߺa@gGRq@ԑ[60@0P J8cgh:ֹS҃:Z(2.>D`C8WӫGlmY4=C*o߭g|:Dۙ(:lN-f >KQMé q1r<{=):Ԉ*rhmh|{ӽ?QUM?u հרsY &-êrr{>%W +M+n-bF W sU"'[+*bfr)fa2`<9.[ IENDB`}DyK _Ref117064775}DyK _Ref161137195}DyK _Ref161137204}DyK _Ref117066165DyK _Ref117066165}DyK _Ref117064775}DyK _Ref117064775}DyK _Ref117064775}DyK _Ref161037664$$If!vh55p5#v#vp#v:V 455p5/  / / / 44 xax$$If!vh55p5#v#vp#v:V 455p5/ / / / 44 xaxf4$$If!vh55p5#v#vp#v:V 55p5/ / / 44 xax$$If!vh55p5#v#vp#v:V 455p5/ / / 44 xaxf4}DyK _Ref161137236$$If!vh55p5#v#vp#v:V 455p5/ / / 44 xaxf4}DyK _Ref161037026$$If!vh55p5#v#vp#v:V 55p5/ / / 44 xax$$If!vh55p5#v#vp#v:V 55p5/ / / 44 xax$$If!vh55p5#v#vp#v:V 55p5/ / / 44 xax}DyK _Ref117064775Dd7 T  0AbwoPd SnKoPd PNG  IHDRc@usRGB pHYs+IDATx^] \E'3aB2 9 JP.q Y8YrD=rt=x$qu]\P\VyWذ<$k&Iѯ;o?vϣr3vݿ_U\R&Hl͉Td2\;HC8E& 8nχPKڣ"e5haHdRp29O- .f /lLqPAI{^(/'٠+hg䘀FLh q!g!.2>r}yƴ0GNhGX0D]A3n9M)_Ic#c$41q\;3|`ر]WC9Qze"0׌ h)1΀,danD*#'F(q1i2*Mw1>ꌍ8"XGTcB+#v=HT8!uE6qU9[3x `Q;[_keɁmC{K'x,z_^|\.f;::9^Iƈ8{A:?Ė+>5xf8"cYK_ n AVv4yt_]?(Q1Oe"&GLkq4Hw,5?f3',3M8K؃[On1}um}wok_˶=^4i^]yj].Xg@ (1ᅷ_xp\}ᖃh G*/rL&I D6 {ѷ~,b+x&G6biDEFɽ'vY}]+uW_~ɜk˞ѓǗl٢#8]J틿G*IohRQ(~B X#s_(!0[_68hZI^"F)f2iL&uB/|\eon5?ݮ2\z6r8Wɖ}M z?_[󼅃3rOܞU++VpBpJ15*5&A&B%4ꯠ@9 t=I3&xD]k2AJ/Sz?0STj'ɿgGN1U>|ÕJ\KzQݥ?y*Zlb-/[HsѨ/8U֭8)"Ɔmo^wueK{;n#*^CHkR*gM5׺ }ioleT&ap`h,8 lCڀ戶c!Y6g.aIXĄƮ2<34jb&<"BaXz6u3p٘*q bq%N%mV;H`-aC;2+w4G x?ىWl}pl͖ )/1bKy}BU}ۣw~H2eHd.BbE}tSQqdzXr67#! 7A"$Cs fxwn2Wf~&+m %: + `"V`tNٿ|n?߾=]y˯>ҡgN2=}%PD%|;U ^d.-g{_Nt y>'}4, = %bKWothːUlZ<%&RcL@gRHH_~~w 97̅i((cweQPK82#Ԛ߻,ί]w꣋6kߺڲD[g7%"e֮]K&H,ؐť rT;ZҨ"Kq+M+^ZW$rRnzZ߂5gD&54Ʀ%>}}K9؆9ؾhL(]#3tLZ(Y g!}uQ\@EqyvJuX,l(7@$ɤh4^EnΈ[or\c|q?QMzo-l⪖IyV"pxd}hw$Xn"M1I)M.p;IG {tDln$euÀ{|g .<s6nL }k;>?kNtqui9B0VB09 ~le]O}0Sc¯Y6v2.g,Cȶ`l<p!rf2cW"(,2;.~+ nBĮuR8]zӳQtC]DoTԆW7?-iE HjP ̵"Z^q:,1?/Qp"o}8y @&h fXAEvwS&5#T KvCt)"3\"UN^l)ðj\[i$(ҏivʱMI.pS9ULUD5Y|  bqF1WbJvP-l!'}'jOt@2Durp ċ– a;7׿7tb.F-Q:rhM%S/7l@+Nm[m&zS8xLt}OMUr چ}`䂩W9 J+ˤJ#_;Uuswwʙяx/z:9tU X|ɫ%+K@3uR lE2K[A%w`Y}.Zs=c3U ߣĕT6)N9amPTc+wv_]5je:7ڼ0F×-L1j^Y*&4FJe.-;f 츆K|Uo.ϼhMvyYϣ4\`|W4\f^<ʴKɣe"V}aBTOǚx @>o{"]K _:5%rgWsNۿEZrd@eGiWQ5\] \{Xeޜ]0ڥ9A.eaEojlNsu$t!æ*GI=ڥr2[6Q416)=KuLCNi5ޓiJ >x^ZJ9{,XzPhE넋y߽]/Rę2#65ƫ3VQViMZV(V4ՎQN$]] $R4@ .nshY@p .eyAXBL\|JciFdNSM\>62=pKJ PuYcis+hR'g>6 Wꇋj'f~PCp)=R_/>߶0SNLR]$]Mlj1hKwu{~~n҂ڷvZ.XZ( \ KS$i.w "(NDX&/  $>~-m,uU-mRLkiV>V1U- HpѾˤo&FC Y $$]iIRh:6]|؝(.erRC- .n9Mw<`Vmwr x-Z4̍@h.C+:ݺ"qqP?% Jij=G@_V `|S4^UjtyZW5kJF̎d+fuF-m,S-Ҕ> LZi 0p ԚE%HhҢ.ɭEKim z[k=O.D{t|eW[ΘhI L-~6myGxQ] $|t=?ƆneKՃ0Uxy|U4|R Rj-<2WsQ'yO4#Ę$9;N&Fۤ%DA)IENDB`}DyK _Ref117066209}DyK _Ref117066209}DyK _Ref161037777$$If!vh5(55x#v(#v#vx:V 445(55x/  / / / 4+4 xaf4$$If!vh5(55x#v(#v#vx:V 45(55x/ / / / 4+4 xaf4$$If!vh5(55x#v(#v#vx:V 45(55x/ / / 4+4 xaf4$$If!vh5(55x#v(#v#vx:V 45(55x/ / / 4+4 xaf4$$If!vh5(55x#v(#v#vx:V 45(55x/ / / 4+4 xaf4$$If!vh5(55x#v(#v#vx:V 45(55x/ / / 4+4 xaf4$$If!vh5(5 5 #v(#v #v :V 45(5 5 / /  / 4lag DņyteZ1$$If!vh5(5 5 #v(#v #v :V 5(5 5 / 4lag DņyteZ1$$If!vh5(5 5 #v(#v #v :V 5(5 5 / 4lag DņyteZ1$$If!vh5(5 5 #v(#v #v :V 5(5 5 / 4lag DņyteZ1$$If!vh5(5 5 #v(#v #v :V 5(5 5 / 4lag DņyteZ1$$If!vh5(5 5 #v(#v #v :V 5(5 5 / 4lag DņyteZ1$$If!vh5(5 5 #v(#v #v :V 5(5 5 / 4lag DņyteZ1$$If!vh5(5 5 #v(#v #v :V 5(5 5 / 4lag DņyteZ1$$If!vh5(5 5 #v(#v #v :V 5(5 5 / 4lag DņyteZ1$$If!vh5(5 5 #v(#v #v :V 5(5 5 / 4lag DņyteZ1}DyK _Ref161204588DyK _Ref161644929}DyK _Ref161039433$$If!vh58545#v8#v4#v:V 58545/ / $$If!vh58545#v8#v4#v:V 58545/ / x$$If!vh58545#v8#v4#v:V 58545/ }DyK _Ref161204588}DyK _Ref161204620DyK _Ref161644958}DyK _Ref117066209Dd0 P T  0AbsT3/nsT3PNG  IHDRj4sRGB pHYs+lIDATx^] \Gy~sK+,cMQ& 2` `812Wp $,JpAl( $ /9rl- չs3o߼9hv{_mw_wDžsB0cⅇ8B,b<` 9E*~4?PxyeK*SP([,*;#ohE)2af ;(<. W8>A7w("%QAkyY(%͈f<sB!pb: E*/ѳMh(TĈ6ke3 |gٸ&˦5svYRΏOV?uһOdMLq&Dɫ?|+/5!`CM C_mˋtT*s^3D4C"WB;fτ POc#"c=1ȾmGv^%|āPȪ@ͿfK4=FX6 Y1Ș86@xN`J^g2#"& bbu&0E.#a(2-&FG1{<4"=F 60]I'*%3O5?fKneѸV6: ܿůѱo|>庻<~*(ڷA:WӉ~)s Ȁ,ryD>rŇ 4 #Vn,uxޟ'UF)[MɊ|9뺉"CD{/z:FLt85?Af3/3M8~[oqu4uֽ|,f@~vYȐ>N}q0?y玭G~mw~6~/|W~}U1ZӨ㹟cZ](`f`Z®?lIdFpˁKShiQzL?b.9ЀDjF 4 mkzYiYReD=c㻏 @7.xCO7}W^|[̝ڗ7oެ.W%_VW;+6@/'>LЩ,6x A- Ms~ƕ2"SOd9V$di*z`=ʶ^m*rEg .^l6Ȟ(u)xl)Y{ޅ׾]W^NjK{Y4t񙣷\ygr")Fy0^HMƛԉJ&/hIn 0h MZq}>s?d]-L.ڏW~,D0t˃\1dS?,/V2 `zTҮ, `ƨ_|Yg]r$G/tK Nu!@` !BHo} ;Nez~v<}|a>k;# ܵ3ಝ$Zp o1} Lr' ^HlMzsx4 "?nQfܘc$9'Crcnh8!!%*W'B0ӁɁx ,W -h<,_ܱ̾/?D؁E]xl>o@Fbc"vZUƽ7o,%wsQ{뼤s &'7$|>q?_x`}O})!Mʀx h1XF#&%lIS$B#B#xO{ɷpxxoVÓ'4^QBbRQjlPt~rY!m#B3M3 oB$p9p{H9XV@[Pޛ7``ߓ(jtM޸<U|V$.ӡE ,Y ߲2"xJ HhO HQ#xcɿܥ8qwHw9rU䢻c JeD`GFYOPTHUǷ\շ~m? }ڷl;d"/_|ڵ$` EY2*7Eq)i| Z1-ExӨ,Keq+җ_jٓFAR,:( XτbvPJOlZ ]/2qoJr}7&]xj}/w5? pBd 9~|ֽMlIQG>G?-l& !]pE Ζ?ǖNJMdL&F`Gd3%|N"}iܟ*oTcQ#,x QUrL!6 ?ͻ,&Zc.ɝ&=6*p~+_'7̐ȇX04'kdʊ0AGj8@[h9&޻Pl%ia++@x$]CSŤQ" n W+d]|sy#ح?~1 48RyKMlE}3#¯6vy^HtӚ'3 As `BJʛs]'Wk l߳~@X #I wbL>`/M'mJ {VC 6,ο~l4'V,\BK䝄m؟@bD ~u8Br?M>QHU὆XXeک8ԿGvbS%NDI@aMDF9fW< iW,#gg7<7xh, Ҝ43פ]J!8wvR]!:!͍%X@R)= #e67 Mۯ:ܴ%i[Ԕ[''¦)X_[CM?nbAVP%04( ڲѠSB#ϖ4-VLd@4{O/-3sT@3᧔5'mܓEyf[POcJBl7i{niP6$ $FB:R9*JP ABJ԰.o%Z@sC8+vŒ ?a p# !HO,- PKDby'5CRɜ75~)9sU8,YF]Y0z[ˎ6VK 6 gZss^[ xngi;<4D>/,v?G[/3>QnrׯBI @;ZWN` GG(>EQJuрhNh*h@Ro@]=|gx/|FOڮPBTB=ý mɁ5^ S]*㋯˥4AU[YC> JZu{7j1.A)ʚ$>`/8`bF<\u0v`r5Q;c\(NWM/^3n":cEO8|L^^~Fi\'5>LnVY:b4$DkFצ1Ѐh _,U 9uxufJ=AJS8ހRq`AچА(@uQuۨT ȔMVrPƺ^XY0Y4 I5 :F i0Q33lۙ-:3lNg !g)ڸlZ-6N?*}-ǷڷxHMIq - Ł@6wӽ QU?ufL:q oXW#W>+?dwgA1lʏQ)K\} %;?`)NU#7JGV;S|`'7s;Թ]Qx̤WQ'?K"Gu31Գ+ӝ>tSۡAgV݆ӆ@D& u&[yP'j缶{> *M:m )л48J '480iT4:8KDfjRYӱ|DQcPz1Q   r2e'^.uZ{;\.nA`ӖCW/(DGN@taBi#RBw]g"=˘.DudŭśMj]5 uL zFO*r/oPO< |/&ZXXШ W(ND|A4:ےa/|}m9F'Ȟ<b6[ud Z>1vB^wf`y'9FTSu]`nQ/˿~[^ _ ̘ݶpyG C=+AHeP$;21q94X{H ah@tJ$ap(3vN,ic,a1 ±eZIqy Dތ"ÚPm&v/hk6s$D'1_&{Kܲ`@Z4)5go\[[XɁ5uZ!n]8|ەJ>E뺟l_t@k R{7E b 6H"PiY/\7 S"a!:R ydZjN^3UڕV0tg*4"#جLH%ںܵZW͸R f CC0kezzYDo;.uWq!ph1"= 23 |Ãʘ,4LxxgͺpLe8[ӻy h ~ILBvXA4Dlj02%R cx? ٚ7fؾ56$틡|ث=QVŬ5;4$! \CY@C:Lf'}CN1.ĹC<0< 6!hQkaLsWhО0)#2 a,m䪙I m߹ahf+R,(a"Zǣ0Z`B $39D2RiH$2 g`X &EwGcb%E ZC 4H'E E&@?hA#D!N@z]aMvlf=+u)=#O]VGp:d^gީWm:whTLR(~@ S#_(!0Z&8hXI^"Fg2jLFB^.w|allPw^t"p٥7)1W~j<8%g-_fт?Y4齗4p^rJs+8jNj&ҁUGFBRNRUR KW:jܢ౶ݑ{ɥ\3!q'ߐ7Ae&?[r/S⚵YDug,Vj>3Au!\rsz}Q',\tlni7\p lk{(?)pFBٹԕݷ&_g'teIR˲ͷztJEKq(+ . e4 Rp"vL$!42ITPߕfn&PIBgXDh9 V"\Nz.=C%V 0=eڪb ,v O3};0cj]z|oރ>36Q0w 2٬yNrBn.vʑ,_y@7|}.v$S֍Dfs]WL\vˮx+N!{3Dp09(BЁd`L&oTNN&Lps V!BsYXj{I"4Nu!`v )n aP[1 7Mv/sO{oʤ̝{-1J". Kـwqy>ye$ ܷp-ޑ4*}8oySs:Sv)y# <>,`_O0 (99(1]3@(]TLzi&nL-]-,KȟX}њ%[`ԡ`dr8+]DSϻ=ɾ~H_a5%1i-y3xWm&مp&G&q8fgkLSzʄ<:`֠rL]L>1e,V?7"ꎦ bb-'H ĢOkň郝h_pv1uϫѡz: ̲"vHeSsg^YFbݢf9a9қc^z&tO 쳊".%&\e-ݢ#LCWUem]LpLJΏ2I " yL5}_AbrKV1 0R%,Fj.'c0XSk4B9s,YB"P,lߐ_ơurESstI8ή4+{a).2WvW yW?]\]9#"W4.5FX.I\L=cX{++bo薻"s3ZvK s1({yr~QҧzW] F.r9sٜw#1`hT*L&pss3{EN0:#^ҫ!u?E.hДwFͮJg) CUZW:ZxKE&TdpiapD00ľMKrq|MOx0@{`6_!%f T&c3 sxŗnl#-κfs)hZ#ûS9R3$Jv`{,EB/9֬D9<_XcDX84 M PdLL/% F.dY|z{Mм4&1 "F F… Vy]QX:C7\PVh]4PL~Pc:enC/GoTԺeܛvEB$E5(@Ȇ X@K\x-q 8+KO>-Gh- 0I4j7cO9"4nf<#v`(VyRRLdWE{ V:}Ϙn.EQݪXHU1F_M]Y5TS.U*pi>c}QSS ~k/ښDC#_^ևQ >\ά}S|^ƇQ èM~S]v).)GYa6Eu?f?'<dhײ(W~GMmSs{w*gi@ʁ]XZDø42."kd&K}7k6T%L|2ޕ.Ea6_X齻U${Zt/=BS*K%hR4g^/[ќƜp/j *RU:w)%<[ek)K]QmABY#..c~gPgBJ&x)}5GF *Sgx,5OP Rx,lbwAc|2jR;K߹C;Ā $@TS8W,&yvsQ&ȧ(ZiO0Yߋ9-Qq qjd8l,Y/h~[#K.:ˣF((*MvxOYKsp]ݪ%و}4bWf.U3_zX.4.-\][ۖրp񷥕MmiӸ$໺>$* p1PK+>JJL` & .E7976AIoU7nyIM5np-ɌK)]Rhߖ6\J5rbvj2V=\Vp;-]XK7|BWߖV[UeltS___ԿP 펯/mi^@Y嶴F- VMole)]p|G"(Nŋ||P@ <"Ҷ.FEh_K{ 7\miSki#]F}| pA|B">T]RoսԇhXڥ6^|؜Ȏ.etR.v>燦\;1M1z/8;R>*@1qTT T<~|%P\Įĸ KH6l(nPJ'3v^,hʔ[> ՝j,m0.e -Q+ʥp9t~m/8\Z+%P1%K*nC@V:y|(yMmit 75C˞-\饌OoKG%z.wa. |-M@0p>iJ @KfpNn ˇKv|uR/qt'ţK8~V#]J}rѳ )oGg45m Έ!+2Nӑht@Xt@t k4q6N.2'今F󖫒‘D*=^{NJB%Sumkd>bIӁja8gGĠ4"a[IENDB`}DyK _Ref161214128}DyK _Ref161137270}DyK _Ref117065824DyK _Ref117065824}DyK _Ref117064775}DyK _Ref161039990}DyK _Ref161137284}DyK _Ref117066165"Dd$ T  0Ab!4!n!4PNG  IHDRbWsRGB pHYs+!eIDATx^] U>1L&1!!+Yv *.ˮQktWZVJؒ], R VԨWذB`<&{sνgv9;]њeYvhޮiX>ъ7 ~a+E"at錙%)2^h9ˮE6g/g&Yb:ZLxC-7̊TdH&͎N\zMG`յYpNU,haBZIT,B0E_´Lfiγa''QiQupoGd6f3lnke[;r5ӦXbQ1q__Yo2 >ũ9 sy oO8F ,RY62WƙMA!E¼䉛?Y1E13i,Y pf3qareeRɩآ? dЋ:=V|-Z#o=#:=/2Z010| "t84)~L?5tR9zh;hcq jQdt>I#LENG"ssbSC>jRsL6;2*DL ʧcUA@)?e7(3)k:βL +f|"udڄ1=gͤ4^b~b|CCBxGs57cNs3lʠGYS#'#X&,"«փX[c+VfCl sk ѭܟ.=񂕯\.fO;KȈ~tpԠRg,M;}hM_2Lk6_xԥ[_zRl|xs_{go{?>yǎ&~mw|n _/pغkJhOGHK5B>XNCKnpٟg #`|x#Ȅ3\1Zl sxv!P;X 8/ӳV6 @ʯ)89L&8oOLLeRGwY`#ZECC/zy3sd?{Ғ?xwKy6-"-Gp<[:"H>X%LUƓC%ps^sL޳aDXF=(AޓL![.ķvBi"kg {&?eȭpF0?&uѸXxYaY:SO4O]'Vps/߲Ջ\1vi7_}%g,Y{ʉR1F 12&O{o l2)+It2P(؁a DC0QYk\ Ai/b_9O7~d~`;rb<'rpHO޵huJ*D^CbAJA)8እPv 8JR1'NFUsY`M=Vc۳wwR~}&qՄץʄg ;n߮{<_&*`-?8z)1>ͳ&f/~bL;s' t}aU +NǍ(SgNi_~#O\܉Fr4{u7;`O?r8\Xt7R` %תXDS!RݖQ!rBAIڕ4] S̰Y2eAYp\*K &_;APު &M |PK~2Sg4BNR]oՅSFYe'" S~̃>rzNt tz,Gp@s Py#MPC~w={zOe~5>K{0Db8 3يT[rooCb [+Y<\ɑJP!e ydV˘#xgR "Ʋp,Ψ?QE gs30AqfE5Z1,[V\.ӄCvJ eL) l_2_b8S`8֎fyP^A]sL'M ԙ^5SÓSXy;}/L۽{ɗvH yZo̷U3V]KrdȼLT w&@fT渋;\/-ZY~bYxC׸՛xuw``G̈_o{>Cߘ|I#ЋaJV! OOt_`i7F> Lmם,N>COd`Jƭxl"e02\"n/Z7bbEb .Y$ϧ0i[XTfvmnǙ32y7+96?.Sp]{@ϕɷ糦 ( G׸Eg >cH1Ay/!޲.!˻0#J~Dv )uù)! >VObR3~eǡKq|D0e茬;!K[\^֋_g #ٿh`ٛ1ښ5k֯_PbXĆWJR3i) #\F-;y/"/T*q*>מOk;ճ [pH(QY:9Mw7P̤x!:Ŧbz("rѡr_ܘoH>1s_HtSߞF'(l1i"5)R7M~J)<=17!&kcX١5ϱa$٢{xb@ L&Nxme'zpY&Kl?UB!Z8[*Y-=ݹOQƷxs*fC$`R-Wk$fqڤvɠ6d ܃1F-+vrDP0 ̴uhy9CBFeӺ%Zrb(nWeN+dA%\!N;gwڅ6 ei̛xL҄胑\S-D?]nNKlՇ ;uu(m@j#C`B:Qާn=58G,>}XlEk;"P4&DFl$9ő!=9׉b(ˆy5&x$WYv˖v,F:glNY_*ixL!v3m3PmyD1&W>0is _ Sbh@|V^f&ɗ63/+ -р3=&9HhPѯkzutS"b-9:aQFQ1_6vkaQT:te.=O_s*xē6DUi~D8TJ:>|F溿FDcCӖxϬ'jnZvĎQD>,kgXOĦܛWSG㱨›7)Wv:<iX~voN>oMhb ;f&JG=$d!l_!=Ӈ )lNG;P9wj빏1oܒټ-/ǩODy!2ykJzl¸s屈U&( =;_s(ܑx#lC|' E4[Dhh+|YK>Nzbڤl |P31,W67-?ob&pƦtE>ȌQ| 8*wX8~U tx#G-j 0)MG0w ? <&Ew#( 0J4Kx<\L9 8 ע8V`mbf )(;g.?Geb@(X~ƞa{+~_*!L&&"BD( E44S2".GI025I'ZD1']^xOC@Ksa5oⷿ]F;ġ* \Y-͛҄EGYp@fw ?&7M&t`M:KvM ["l4A <5ApVx;G"# HG%@ YRq#@4|LI"!2w,>g}@^rWq\ M(;6l??t!ijBio|^0=Gh4[}5a& Q(ڏ=Do[!2۾"Hy ]gW_e80_;DB hU[U& FPi-M,?u̹CɽoZJqa? -YqH7uD%,&J{ ESZ]oJsutgOOTCImnjooVӃ#Tw[0?֙#IU$?q8*ѝ& dmL{#N@';n="&9lM5;zA2n9I yhEqJErQ.&*<`πUF;x>ݠoyKE.x;I^QdBy%S Gum!A"t&9TbqvS/+] 5$cC"#5J)uwȻ踫CRP1o!m{%nZ1A, q|Aknф +A.b P#7P$"m}س0i+Ji"4՜#f8-7RMhV@ς!oe>;֐5^NDSՋb?kv%r| AD XZz.Mhn%qy:xzC4ڰ 4E0TQovz.C Ã]) \# ҫWk(3)<8v 8*b|Sx<=+{aLv>D]ǎwB)D9#<~#ʀPM*H5T=l )RHM;VC/ܩjZѐ5Q~;,%YO&*iBW#ΆNwHD3iB}59DPBvtLǤ JA[se_M~;}miH|5ae1]hbيS@Cq@7#MN t 0~F_EkBDŽ%RBB5ErhhD@ RBA T.LK@}*Ѽ5tȹw )5 fI@ a :N M&4 4Y;RBЀ(!@TA@i"BЄm߽ېziB8t M-m;փnn]<&`NGj `VGޛ"KMЃȚKo 6!ʾ jVmۊfIVxPPPĎ|ݽi}][HRTꖇ X$F45$(M;w͎iBCPHn9r["l:bu1s!ǧY;Jh]٭k|AGk $B)ۅ@48*mwQUF؁,uڣ MvD#{+|帿Π|jզ"4Z5B7r^;˯c107P }S&i]H,Qh&}RʅI"W>okk9Zq+ݠxiBGVKLuSA >$0 @"*! hwh_N W&QBoMX~Yyor&X P JEv"M0O}kw.>;$[b:MP֍]_e8tԍ'%$z^i*'!P7DuCG ^A@/+r@P0gBYAx@"@4ѳUO'"PaDФ/\8>'I WP |GY5ggڐ&zk(Ԅ4Q$JF@&B]T8Bhl3'FW&ǏZEf}x" n@`nMO&؊-,1-r'ڦu +׾ *tHUY^W N$m/uZ=Փztx$:A=C19ۙ5SJA9;%/IENDB`}DyK _Ref161043936}DyK _Ref161204588DyK _Ref161645084}DyK _Ref161204772DyK _Ref161645097}DyK _Ref161043936DyK _Ref161645426}DyK _Ref161043988}DyK _Ref117066572}DyK _Ref161205081$$If!vh5' 5$ 5#v' #v$ #v:V 445' 5$ 5/  / / / 4+4 xaf4$$If!vh5' 5$ 5#v' #v$ #v:V 45' 5$ 5/ / / / 4+4 xaf4$$If!vh5' 5$ 5#v' #v$ #v:V 45' 5$ 5/ / / 4+4 xaf4$$If!vh5' 5$ 5#v' #v$ #v:V 45' 5$ 5/ / / 4+4 xaf4$$If!vh5' 5$ 5#v' #v$ #v:V 45' 5$ 5/ / / 4+4 xaf4$$If!vh5' 5$ 5#v' #v$ #v:V 45' 5$ 5/ / / 4+4 xaf4$$If!vh5' 5$ 5#v' #v$ #v:V 45' 5$ 5/ / / 4+4 xaf4}DyK _Ref161204772DyK _Ref161645115}DyK _Ref161205069DyK _Ref161645485 Dd0 P DT  0Ab эs$GQc .n эs$GQcPNG  IHDR|CʣsRGBPLTE !}306 4k<Gff3fffSb3f3f̙3f"333f33333450(<]33K333f7e.3ff,N%\3q3J-3f3323333f3̙333333f333ff3fffffbDU?/f3ff3f3f3cSr[-pndffffM}fWAh^dp`ff3fff̙ffff3fffff3f̙. .tN4sDoِs \p|0&d⍢ ^Z>v) #k]P9peѝxQJ( /2%+CN?I8+#ih_cf o^ g7CPmEF. (RjD'GΕɖe u8[(CaӋD lrx.Z y(^7&b;~&bT@e dh*8>۴X1b!Wa`%jIaI]iuKXiÛv y5r 6ۭjEOnUG|7Qo%kwmMg[iȜp)'F!>tÆ&DAaf ^ <̼xXEr2Q 7 p)Q%0;,!Ю +lpUXԚ'w@l *nW=)Ԗ4(~J./3WxMp)/#ݮs 3:S tm>O6,Qs|ҾheIMw:3~{{Cj4g٩1&qfH?> sbσ8 90pk\ɏjx+/8|!`0k ~|)pj>jO0bh;N"٩1+~6Ϻ]4TM]1z10wyv|| V˧' (е|fJ3X;B(%Cw×I9忓OKwQ؃?hM_V1JĄc 1l5nË!/LP5Uc7Ya!N|kڶϚ&)lm*Itt7 b߉ :(T ?}R๎%LzGpt w5Tjg)AlXapC7e'&&zsZS3__ 5NgA0T Lqa`ƥ:$(Oh` e4=0 A0QG0X`,dkȨN.M+/kTUNO{00e,Y+d}0 $"I 02V`_$~~F` `m4^`^O,,NRE^4B#^2//Xa $CZcz5O!퍢)$3F%FC8 ӟ#ڳAF@ [XO&#S$8mt-mvx{ b;$.O;ꇼʊ#ڽQvopjD)e$sn Vv)d]#&PJUukpHZ =wUe~|)|g:rIێS bOzv`Ga: Ԡ0~iPa;$l`x ,†CgEAǼBz,"0ǰA}BrZEDA[FVjU>ШĠ $<6:ߜnd393|;|wC10&A#Bv$Q^P>I zWeQfNtLǘď>{R9ٛ}lS~!&fw2G]LcNcF1Ol`MJP4M:yԔd]R2%K2DY S8C پNG*DE'7?;OZ8OѾ{gQ,!Uas( Xl;a'ZOI. '\Iَ[&Yd(JHٓe2UDzKAg``4dY/ 5d' e%R!L ,2q6r@WxЙSN"$g<:D! zEa Ei1,VU4pN|yԑ3 a |NZU'Ԇ^"WUV8Ŗ%YbगM%HLl7<^@/iJ2̋lfet&1%R3'醃st H7F x?#ɨoȰhܡMyi'ND¬DWU8l/1-3473 {~sxզ&Qa4Gr" NRMr&,G'eQd %@2 P^ -M5>|M-rUڙ)c:ic5Gc.b[u{֕Cߔ]Ge+SM]YeCvة*N|\9`:m yVcY-N ljFntTqJW hpbF^\j(y#f 4˘Gc;dv&W]d6lV<XZwO-DP.̦=Yl=%mn@l8[O57_UwSVkb_XН:w)?EL L1#_0ҝl1.+4+7sTIg%|TG:bH?u)9)gWL>n/lsRqޠc[~7w 3&5J!\5Y~/ö̝@N6uˢAt)p;,SOa;VͰaZႵK(]4jWS(H+E *<"i DЌYK7>1+~isˤo9,gKӘN8%qPuRXX_S<óPoV |R ^H-!s9'N?+k0mLʼ\3 hڳ?-~'?-P(% Cj㙮Q]KE Sk'Ұ.Ad']y1Oɓ)RkdݩD$iVͅH\}bF]ynܖs2B~|qTzRk|˅SoWrYRٯPw t3U Vy*KN&aIX%@zA d!؄&D0]) TvLBYc `0u Xtc)XJE2J#M}'0 ӟ:jG'>=}TҺiNU, oHB-@E-zXQNz35Oj X{Fث_4jʀNFIYbfAdT^Ya5߼o'p嵄ezfe?{.Ha k=~<G,i. Rn獲O\WGgW9ʶ+:Y {>T[O;:ycNp 7Bjh"T?"0})XN`WuP`Uw[ SY'P]6Dq ˿1w ,[{Ņ۞ݗ]cfGR77 0DEo%J&NMMy0j6eZ.+ ;gX.2:[M^LIe[9Y/*l!|.sM ѩu33 rޟsQ\%Of.i>%tlKa|/1}䏔4-g ?_~lᣓ,̌LL5j5'@4՟>~}ys|uȍK*t|`Ukb:MIp|v?\(BW"XoX9ynnpO?h] )MD RbSE(S]Dߛb;!`FEO&r4m+7UdXA:unS]gaЈ-Τ`:ݿDzޔ9*ޣdp%'ߐa8z>ް̴ aUvZa㒰8f> )P]4{Zywr7pR3y'P!ײY_.}rczk"2z`v<ǝm?KJM0 5P19l91 \ TM Ll5Udavx5+I<񘤹0( 4V&< LZ?Y],1hv81-" 'KptV2q~$PL0J%Ϳ7)0UFH1X2P]-\+ds-<+}[Ί~Ŕb(foN1*((+ш ^̄=U/HvfZ^(2ɿҳH U U} %1s}~4 QaAzmd&R[ON0l\S6?E)=]O%Lg 7DHW0  jJE]ɷi_n= B?8V*z*GL|_`X6$ ҳ$5m"iZ;::L&Sjj*&sc @\Gi3[G~7ؙ7[v-k杌]}5I~I\>0B^i>@EDʚ"}OSsy*8^ۭyjU\~1'`+Ne$Ȇ#O'0R4WS7Ϸ]iHU}H% -#MHKaɘ Lg-`;? NyLJz0o&M}5}w0 !% 򰣊F/^d̜ӆ6vfoZ퓄駀tɈm?L`;٨LBr/VE p%z}e[ %a驺d;THX؁>T Gi}#]~\q>nnOWMOKץю*lQkf+G*iv!kc mdok5;?RQG0ryN:Og P+>N# 8+}HJbɗDnu)hX悔CQM" Rk~+=dzpU60maAKW7}x 6e&I( 0|J´"Wd B,Us`)L\@;#@(쫃X(%b=Fb= Rxqʫ;DV|4y^zXhPTBbTuU)١L}xcKW{BZ\n] ]'eէۧ8_Z۵M׾Ꟃ۽=RuVk!d[UM.*[`\Q8GKadER#5$:B^cMր qFgbQ?˴d Cm0AS=H!4BBW |j 2 ]^7v*~?{ ^<6@$*LQJ!Te,+[Jʈ!@sPAMtE$hT+kN6yI7}l^'}JhfV'3?oe4^%F@LZzUN㵖&"4&b :kHm^DZcr rLO5J䀆xrW;hH/5JNu(2:wXU!AZc#{p!R+fjtȁ@j-S 7nOp¬tK!H KK^8]G Y8؀׃(R Nq./R=%,fս j)ZNH?\ss<rnRĩoڡJSW5+#2g߸t=ǫV\*^UsߌZċSn)󮒷tf,ȹᷔZqo좴J)ǫIIؚ0dVD4_U3.ZXRf2zDAhP~Oj_햋L^!1njaϪj}PUפfܠ5 K?&HbW᳟f. ޝŭ*3"OG0/I.ӏ7z~ rƅ`zS9cr"(/B*XPe` "%kê$RzUJ;]40%,hb5Y|i ԍ5Ѓ=pF+f9^l=^:Lw ʌ7H*Nc)Ǖ@x⻳5upWvXҕUk U/vR(׵"@Mv#OqRsiHOٟ?7Vk[r_ yRd'` U}Jw ipgʚe`+!@w\A3$́'_7=AwNIN1;^~߯d߬&Sfh oOGiE߈ۮ88|(쩛^>Vzb,b8^h%@fT|ۨz(^c} muo:БkQLYZD){bρ.!՚MQ^ Ke2կ^$Uy\gOx UѬ ُ" ?B@j\2uH'Q@; Y/s휓;tO_J)?fkN\ :J/m0D"WOf{`y2y:37M=Hs^cѓMufŝ+U[/搥 -yd_W!Ț]y9o.}9I˰9A+g㿽1'vCYrwCx BzB*Ե[nՏn8FKU$\Fd/ œ2sn|=#OuY`w[)#YDR&[ $熹.'-}=oI8r=,ehW\0tܗz.L=daOjKO޳C]"-jB}'P=b:V|%kek_(z) dUO-bO(oܞp _4t=ޡo^M'ԞeԞwk, tT[=R1p@׽$ii4ĂRcEF9?"@)GL-a?旪vjn?ӐDCjӺf^KMp**BCjKN?4WS#Uٶߪׇ{O ~@G*`䗖 ^dz (%)t_OU0`΋e־9rf25]@]ᙖ78վ;&*_{Kͭc /p$J_}󽳳?'rOԛJ鋇nV?AlFmP@IR~ծ5o1fܘ4*r"ϨT:rx ×j#>k5$p]`~WGwW"WoNLzd~B֩U%7q1U m˖ǀOF}=zV; .X鹿 w xI:74&KΎhHww_ں!`4p`LwH)B5c @=1c~<+⢦ƺC 2 ~Y0]%G}`|>ꍉT)Riy+Y7N^Qg[tMg胡ôr UT5W{&vZEHk㻛*dcE*:4v@ :56NUE>YU"SD:kJg+omp8ٯoۄJ8Ý.Z: ])\ӣTx>b1:!rF1?Z"^ǩtŌ(.P]Wl.p)]Vq ۙǺzG{> TUu';3JeGB/ߔ&`"II50n–)`P:IzjPTH+5 gWQRzCA|ߔPuu{LO%)ú=IhSk|݀-1+챕̱@$H%U]UQ7r%!7@)*3zx!ͨ" ^;O`r#%Ҹ@_id,+ 'oۺ7EKWzKuY#]aBMB,PB"%S5Ӵ4ӵ"ϨP),9n0aG10l*p*Tmw5q80U#hHS5dPՐKjǁQisu_܇ ͨO㼷WOL8҇ GjA@9p줸밴}b__pcu}v Mw>qcΊxj۠Qhh!F\CЕ9ؘ58ehzRF % J18)R9@LfuڜL%QDew Qv8eсAS CŁP!ᲉQ9!b s$[w?ѭ8ŢyH =-|K2c$qiuzEp5rid!8e  V|ɃDQ?=L"MWNn;:ߛaҥtZZpӛuV8 I(1FZ Z:(9 pThrGo|?WK";i3 g1=Śxs)&LN=s( dD-_k+aZqi=5t"r>:o@*J┿bZ-ϙSFQ]/QUXb-[<{wpdDz7*!а]}f״E$Kӟ POlohgfenԲk7?z)#IENDB`}DyK _Ref191725518>Dd  T   0A  bg=o%CQC=vsn;=o%CQPNG  IHDR#bsRGB V)= _k^'itD:,ketFB?Oe?;&EpZi1Hl=!cRCɒFM'g۴D(uJ![].3)[[ȅI"m=5$^KRd Qx):I.ٽT۳JԮIɌB$d5NC8&x—7}tװHS+);u #RKre6 Jþ%锁x^įIDYJ;Rs~ʹUۜTnU])_OTO|()MI4`< Ѕ)0HB%pTc\*Z._{+mAj݃bˌox}qK[-D!1mo9wֿ?47˖VnmVZ; F7UWfhqRЩi{갚}S_(9,No'JxkoTA.F34b!؇Unj!MrE|ꮱY"@]1$&6h :6/:dK s4MNL5;;@#/R(:8li`:̙«-bGI[*J}AKCd>pfe75^4WV3EEEW!)RtB$ Ͻa4Zͭmbżl]`LbȆ_~[.69it3y6-Wcln2E [ωrJ#wiv 3mNf?V04 1I wTKO4j+w|GJ^9t׼?l޼cwA }˦]x)j}jYykSTCȺ/TDJU:>4E{\`"#4:TN̂IuI=fPhLd` &b8kP2 68H3w W唴$vLN'Ry:)A?鴐gOAOѢ !g|xr"_*C$HEŠ DZ@L;HC2\A箨ϛjx3 (/_& Zf;B8(xv ղl/pЏg0xY{&:+81/iBV圢3.mЁZ BdIc#k\Io^{W XhHhy&O-^Qoi3ҕo>CL3 XEHտ%6_,u(q;>SĝƎ5O 9"מ Wxpc ]0q]o,kM4x-ƅb777u Kp[t?yɟdQ𐙂Ns!l\;O5$xCœqT"r1_Һy7 `=q&zZ^Ty('sU'5gk342UVN²',S+9$b%k IKLh eG"N̆@I|6xkJMpFJ3RIb ؆Dݰ)e:h*/[;ck8[qg<0]F%Tcz RS h|4 H؍it EctGVלHv.@3ڞ/2Ř.êaV`\YTH05- E°DLaZzJf;o5?oyTѡ/.dZ[ f:V?$r8 )%"i{RQndO\b.Y y_ 4{忾x:c]# 9dO+6*M"|2?#>/Ivܽ977 "7Ȼlz(--e `4Fly7[੫~[!Ԣv_MlŵfĐ o4:03fT=@|W[1h6 x6$CP3HahXHwiڜvB154$=H} ݞiXA72N _Ch9j?x.a gN;q/X9;LK[_kk f0,m'}Gҹ}d?=dntU#gH!ᾯ/W5h7t)߫58 [G&^ͷ[We%'_~%U@cόm(`y7[HTBB׭؏Kp[b䐤 W~xYSv+-Rl^dp_uJ׭Vkۏ 4n> ͧ-'{ްh_t#?fzҴ){iӶM;~c*}Ćm.#(4 襝=|d Zz̈́߇ E2RtX~tiof˳?{)>oxg ?[IuZ0p灁+$[)ck&ݒfp)kw^f̘+ĵNѫu׻%r%I21O?m33礻%(۠{Mޯ\΋ΞX0"ddiJnDmZv b]K duG鼩so|m}/k8&ψGogm1v#:<#W I@bn ڑ;0e0s\L@5aNb#ondM‘aJipqQ'$HBswelqcVs6OZv]O엿v1:ޤOCAAADb~rwHim&&-ݏMdl1LMmM鳧MOmܱ˞ޗ 3A؍t ͼ֨z=Ρxяv+qk]mWHO%&%Fs{߾@WkkkKK`HHH_Do'9o$z59\Ou$+nJ{\moV1V?{԰c'{iy}X;9A'aE?_u$?,F 3=Fga$eu`/9wX.Q3Bd"6ML֘~,2Vx51A٬vy;!K4vH ހrÍnNS&1}b{Ntz5 EJNt-,}V9cX!Aׅ`m IKCԻ39Bd‘VGj1۬eg H}( t S6 3ovhg vH++m4F-?Ɂ7f8vxm3'Aә5 :g*EK{C݌2]rG%]`Bi8 i6:(0@z柚7TAy{cR/=vD]X實pǞ/1TĴ8>z~fEs7-NU1$h, TqkGNL*H7gl&gw!}myI."  pH 1=$$L )nnDdC2n+Մ?{"I-g%Jh"/QAC8IU -T vQ~t[o{>=*J% D_#^fɂCU5ߣicS>. eH}mҌQ;|Ye4]1FҦZ꨸cSz(ߪ.~Sn -HL1FĀ6"pEP\(_= XUﭞl,^FuoS"sϻ5%ְVvqtsJcWq%(qP،BV>9SR)#ks%sy=أ!e5Ϝ9g4[l'@Zk7mǎ@AV|+14RN0I|qcwvHn-F(pUe|GJ56t~H0PyI]+u(@ZwkCj:A]ٮV?V2;Nxv,AӧWj*eknuzQ TyI[3u(7HUY>{4ٗ7ˋql\\__Tj;޾F<g{\|W?,!ZHHƋ|9gW8BI^4| _%AI-әpF]H j = ǹ`w nBs1- ty`:qt8 2b IirH= "{,H( ZX!˕ÏN+f&V+i3Aӓ$=SXXؿD}9",;ϟ?_^^~ȑe:-zsƄw]$>Hk|%/-҆~Y͟)gJ1\`8t[[.m7}ᖣGv֐7F,_8Hȑt=6l/;1!&edOI훔eWbjBbzZF~ykvtD!z\b8s짞YY{1viyۓ1JNvh0Zś̜9 5m/* ҦNka3 e7vH /^k$)TԴw?17$$)qKOr ȒLNx ʘDj$"RDbBZzE5E;y4?J| R I+ꫲqi>:/$i=-ft:(H OP7c;Um6g*KA ńgc@J˚:1[w)٣[sMbYLXii?k'pr-ݾd|%/ň΅;`6ceuKg(2=+Q r()"ӧO{:FHՇrEH㉭'~E]n/T>S4Z8,WFΨidץ -u60{ O]9&:^{BР9k`qDEi%uYxرZNGq5c#8uԼa6ᦚї?jKGdAzQ\N;1p/6^Cr#Y;rpxd22cLʌDDnmמoOBÈ|]|`f\fwBR<[GN ~yg؜XI7 2zb\=AT5p0lٲeoAm6>`SD!" gw}wQI4Np r*Ѡ qI)Sg2x *!,rtիWg637kARM_ IC~Uֿ铨=j!C '蝬}4XX^uO7\IxG2QO%(ƹs$DVz*+{H>QT (IHw!4f JwYA4Ei=]d%"KOAՉ!QdF!tZ7j>㓶<"2q 'YF+@Ӽ;hh["@T={D :"z#W2ů:AϿ2d|zLGz>N34^cEc}º_ĻH~VlAEPak<_uiѶſ$"[OՇg*u-΋SS[gJv[^~Ye.KXSP7=j;<)≒IlmM1s 6<6cڢZc8uIu S ^~Ye.zIYU;bC It*7h3>G$Ds$s&{-Γ'ON|f s<4~m0c'jx׌"$" uP-A!a䅲}%ѵq2L̝Q17}rS{)[7 &x+7rG d8B"$#6Ŀi7q-aGyD8hÆEW"aaLr?O:{_sYH`/֓Y~ŏ ?HK-4G l][(ve+MVFt2]C 5֏юsM=og fw9\ ;H`"@dR'|y[o?-wA6H򁘞co +%|BM%H[4s-~H YA^^e;`X1`ZlI5ˎÔ;Ya.3Fop=:-B;rVT[Dt!+HH ;LLnwqFW^y6Gb'K= 'iK](%Jw A >S)nb4 WzmC1(u9Իk!h,,#ZھB}R3`7ŗQ)T^hvz욹vф%W=|9yg/{w:\VMU vR)i *B Pፙ:?-AX$-`M3G ~>;$`A@xviH4Um(⧩ M]6ѣGW^xܬONKMLHH4cJLHH:mNDU^E(xD|$h-i^!{1  -fđxmh,SHfۈwN tBZ8iSBJ$ DJFH h `#](EF!HS!,A*$z11 cByYB=μBӦM0zr@mzP!߭JB Bѕ;1 c6xjD4Ӣ+cm괓s]8Ќ!Ok|}A)Ht\c i%xJ4 {o@ %_8iӮo_;mcn89\3̩ؒ+ N,ftؓL ]twzHUR Fjڜ6N82zSC>NSvڝr@Cؑ$titl*iZ^oĩ'-gfΜZ(i0AM%Kz\HI1'Ӓ <%јd2|SڱHS*Duinit;vM2%D9,h3P;!9l..;lx"95aCaJX݃q}u'+^X+lHF#.C]![llpY6'Do9C<-MSu;, D%i*1Ac|A&~e".$Pl LD(.47~d ?TDtVP`[RTCB 2~KV/??*#OH/N` ]lF*XaPӑ%5~,`QXy3@h^484 .iCf!KaXEsqmR{}u;10ȍ6٠wK3{H!U<tV1|cuv\ő2~ZEEwQJ]ʝ$.N,+l\,Fnå>9/Pg遟?(0D!ǹV<]Ț+P 1.LF!>~ڥs5ы6a%(Z4/5q 9XT$K&rUwǺu'f"Op ؒ@恙,j=F6m=U}~cgp:aJ 'Kgx fyTp݅1KOȄ9|8dץH/3]0N;6V"MMQB#RW,f/ (C,<Ɵߤrt4rj,9,ٸS܂u^dDZS0TnFvvzl15#/]bD*TOClEP?E,fm)MQKE :~wҡ[3(iXe>RG]@u2ʏ2ͦIðk&z"LTO+#᳖$N^_ZꐠvM21!l+7%epBM#<-*QONÅ!Fe$Cf [UPGt0ڇ9gK ’bi &la<#aE[ a@Xui(SRaF[lkq,KUêsX5eu(d{4eRfcߎ/9_+2 ;hs˫l+~?"2㮪`bF6 C ea^: {kd 1׆i\< .~sN#!a:ݠ͞=-[DZU^HP?M^L$!^/BmVZZ#.#{c6h=Vai_8 wuVܶm|>WLԷg,C ͼ@xA DTJuZD !  H$go\v|D] {gdkR[,#QS!ICp!.@2-[;:xbNOˁM~7L~ρYz-y%@RiF^d8(Z$K!sKa% */ TJf0wIENDB`}DyK _Ref191725588TDd}% IT   0A  bSRO0`"RuSnSRO0`"RuPNG  IHDR'q&sRGBSXIDATx^} |TչL&o! (TTr-,Zomm[Vh{k-XzN99J+֣^k( @h$$c2}Z{L&=L2ΰgk߷='Omd ofIіEv3Y Ol2 LZ!*#6ɗݔ(z@ x,thsXe,em>Y^$Pgۗ?IZ1K2ٳX6P$e6ym`[HxP10κhk=^/=3;|tT߶WxtP' mőYy6<LNUl '61׀G=9MRBP}W{QmOu_Y~ws13{ EYV&E2YdX-^Y6,&v`)N3r#@ ||fIlQd67(eg`o1ff B|:F^?sYLL0GYe;tfB{[ &b$M@ 'P@ `x?.!.8zBI(5Ćy)i'A'nk8yr7VZ$S.[S~2&7)~뙲/>iI*ˏWOHLq87 ~lB^g Ń򞨴6{n*s[Ac::>q I2Khn206C7[ Ͼwv=c Uxy'(Or~Ȅg}n'R%<7o?sGk˳g#{=r/}Ԕi0e.>> <*o{nKfv[b^dB[g%D(?G5JM1WX-\m(T~i[^,AꑡxC̠O't\yT|0Jqb O\R.-nWCyGM!a*rd;r5Z.۸ :>ecw6s8?8Awq `ُp ٓKƕz);`cry!eGerG쑻z^0na?,TrrOW3>&{{eD^-t$t](# f>#q*ݖXVVVsYٲB/O x\:+&O}g?|Xmͭ0tr jKUAA) o)㽳z<aL7 CՁO =#ȡ`j=7I+ٿ]x=**y/[g{{ro\uuxB~2>C)/߽46חvfn7ΰ $%ZBO۱=ѳu~wh9g}_~~uO[gSz?Jރ?%-n(yz۵GaDUEWlLL$ۆ)'#3OoPl~rЩ@'(N &aX: $.#+Q/+QzezC-#A|/1 M-D.avfKHϟl?{eMհJD\`*AWCXmj\\%/9]@)IXl4<ˆI\zp䁃Odpg^sϕpNS3gbf8،vOoMȜѲq:✳;؟ĉ/wв^q)to1R9UV aEIϑXŠh@.C[UyOιOQj6JjJk׬ڌNK^s}RͿZ%ZhѦ}'<9oNS}&bblRV$9kim5r_쯺a/XpM`;̑[Ə*K*US)as%fpgB=h@>H>߷`kVw:\ Þ>z%@ KQ-56hɷ7~ۊU^EfOd$uq_)Ma7 ?5 V\h/V0_M$fș0TV+!ETo:XGǩ?H3߼Tu0 ԇL7Cg{3Μo9w:\GJg4]e߸c{;d5Y^m?fu13r^:cα=9]ޔC26wҍY}ªX=n4Ur೮Yo!ވa?1ӿySv;,q=O_Uh_m]ot1VE*\?G1g##1 ٣@MF'P!'M|!)(PJ~J*6NBPʦׯQ`~@!Iu'8GcG$dE:΀=Rl[4|yo{ۧv7dgOok=|lL!I.g$}UܡfoN~E&E=>*~єYe,8d<_57޵=U)R&PD8~onx$I8(]TA1]]> ;9pҼX{/(XΟd}CͶ<,!8eY ߲"[J©lNzK&~7V#݌=X,$WfgW?YъcO.Q생vEjj;Ợy幕IJPb!dV~V۞566zSm>ˆ8ZGL_/WCqcS{H/l/iZ'!2Ȅt*Ԝ*$rȩs<DYu5~M4`3,{h#7RѽYQ-*׭",,o1fI<GADXBوa 9ɻn6+ssMٹy9`DK, n,M5."Q@539Q ,n>긧z>"/!**V9Vh}+b$%`&dV% /'!V"Pw^"oʶ;Hh x`|?| Pװ) 7%RN7@a{3bdI+?gSSQW sh^3SM>b#쉍c8hFhXJ ؂x[*)@JzC?yٳI%_K-~?D{MɿlO1u&1k Z6r?Ol}P),"Zר1_*sPq0nEhs聏DLf(n7&;u#XW X 0T!@ lShhۆp9 x)PT;Ȅbvy'(r{ ``a,aDa\2uPlWw~cΠ `Da\ata))]Z[EQ2FƘwza RK:Ns_$v ofȅ@!bt]}֟\q?-X8xNo&G47WI7;;g9+;YxSao>~bS'dߤoR/ mnhΌ2q[F:;,FK{N|̙1窽5)9Fo[o'$:wetsx9sV!c+2}C,{uW{]¼WAԒV-.4>-*}f\FmIjN-#P7vWBܻl^ jTg}]>#[ټubg+\=\u˅DžF]Bfx7 s+I=X(ܕ ,IgX1CKt46݊`anUFl2sgn$^#zSҿ_Cռ%Kt֖b%V VR-ݏf|Y)n{`io-e;դq7Z[zk v{֤I"Y?!&M*ۑ ]cqoPFHKJ &9^JQi¸9$ڂJƽNP(v{]H f%=Ό {eg8Lr(Ofû-QgB u$a Huƨ0(00P77gP@1 4 Q2]36)7fl0d`Jf3>56\ a  mTvϏ97.GѩD)yqp&M`Of e"4R@`` _΄E]቎Ì)Y6!G8lZ:+~C`c!A`s8  bʠ2˘et46TC5›lY6+m6+>C]ּ ~% R%GJJ&X34hR:z:\]n` ۭ[fÁAft?˞bVxis@x訲lڴҒIE-9 _*˱)@w6: ~%Jxơ!@loyg^_=d3V i}r\3 };g pӸ O>w t҅EÄ|n ^/= gYszF|5 a0C魭kpud9v#eQ'7oKC?6M@%X'+0:w E+b)1~jcv'A*rut}S:G=7ב 5 cf:uSPL4S=^/Y6{ꏉ)x]Ģ G5Ο7;/Q1eց:: $쯵<(LެV\Q%5uf~w2?qR 4jRsY`{rp?wqthF)pqo锧ֱ@m# ?'{^N^KL"nXO+(ȍ۸)p${.\ i*o]ή{UUݞ]=ݽz =4ʌi <}tS?́&*({v75IO.az:%/VHB%WVM#Șc-yY4R2FäHjk&ad! &y9ĞNHz-CnLv l溾{_{ϛU@h*_oL YasudM{S%&3'6UU'$%OIZpOsn ?ùRB0̈Jx".ISƕ)2K)9zBi٩t~I%ŌO\[;_^P;ZqxݳGq۴̥-<:2[v]Wj& mZy&9]9LG=U'0}"}[ǣPKϽox[WV$vT^:ڗΉיO\푄t' W)8-f5o3l,E 8S^Y,q U2B0n DnW|bfD04aLԪf&*!l} 'ۂ oz[Uߤ~FIP A5BcΧoϽcZ\n|,&aMyh:맟{^j=1D1B.W6ڶiMƭ눡{n`IUF!P A5ŝaܾ)EK_TGW.Z)JyK{U">=P{.$Eպ@2e"Ym9jI!'a@2>00M< J?n1t`{݄sXicuu*Ž >:hX?$X/==r r#;N_^r/:D٤)wPeZ^r I?Œ@B &%"%y|7^6Mȓ{A1 v9 gMW"0C:*w/a57;(/K{2ဂkD)Ut hY\\ëUS:946s@ 6P疎UGϞmqDp+(Ot^4D-)YL6< ? Gۼ7EMpu#*|1]x>DRy=3PJ㠌~uuOl:Z[!`quN5/mܗ<)^'8"^pu xO4!BȎكj\})Cو2 z"8`76=Y˝mS"8bDpYjf9?ĊvY2-ZTeJGu(.pw6j;~:0U8B!ܠъPPgZ8DXr=pr0UK&PDĦhyLaS.hRh@xi1nFuJ.%lCMޮ6 ,AFsǎ7`؃>Ӏ_*˜"ϘAHjQd)IxZn{+/XXhͣ uTrӻ9a4xɞ|~ Cva >dC+:E{)"0 Rr2c"!Z@fl cvCR ! !#&T)LZHue)Ij ]$P'="ɁE ; /ƃRV "9pMzK 2 YEH` hqGW|7h&Btq =Zc(e$aWCe^s\2d:N,PY.4s: AEG@52#QGQEd" 6Oi\ɼgL4M2Ӹ&) ɔH<=2)0ueHVuU%H!Rr}!DDQc3(@ ie| xDFXIQC%O,?m_ e:*@ɗ<}"_UP<`) #ZHνZ YIɄcK;`9i уn05"|[hÄ y3zeONb=dJݣu6'+7 *+˦M+-Tْs?VS->΃39%L <\"ԅ{sQ%S 0EPRKbF Pj7D+.7{ pk0c͆ gg|` \'ε80Q9mF+Jrm-OJIb^+Y4L+*u{n_4{ΊF0_S8ƽ@^'Vԁ ";58:sr@d>ˊOER}jChTD%Ijx"Nubcp #^7@K8zO/YxwM4}HڊEl910+&<\e"44\ˢÍ]YiwNG T0R5=yooY+.`nyG_Җݝ9Zl#+/?'?ϑ)hD"i'4:V{2FEJKorH⮸FSv~aLtJWNc߁G6R H~^ ]$l^pGxD&LaSDfruϛ;HrݫP)v)jh~5gÖKe__.|NTS1wŮsYz8QX'[e B3"nNFiq(Mwr0lyLtN:9cr;{G-΃kv+T}g毩gq(sjqqێ%Ee'O,Ɔ 4=0; z뮛u _3P)6gF롫+xLӧ'>sX2Bs-Ͽ&gXջ_oO SІ+Jzܷ3}DӦ]'-\##^Ur?jWKW_BO|]]CKkGQanaa.˪K.w2T/ g2;ZSG_dt;;ԂSG4x5-mY@o{*d S ڹxKlx4_ogNlc;3e֪xSx#@(;vMڰ9v ~/$^p`Be{Ԟ%Zpߧk ٥ލg}|rz&/ö]kFZAo6>[vwjLOhƎuy ;C(- gD[ *gX.v|R8Q_QEwﺊm˟Y]C@a¤;.[[ʓԵ;kgMCfKT 3Xax#VEs/xط <1 nZ2Ōnì0РJ07SL.ZO¦fq*K Ǽ.nڍn[X~c;vna7of$xKtQyyNy)x&N[שmkV͚µ*c rdB*1(jlaaee#`$CS7_~Oaܞkvz_W50`[X6e8yds W,;|LhTT7qb!l`E)g`A@s32Id;z~`XoqrΠJO= θÃP}S+KȽG'p:җ/RxpwG%$aܲp.E9U}\EpƦG?pm/yA.B9%N8½j?$V3D2?0n qdZ eDrw TS˗mG4%//~ܔaDtJ>;E7|! "Ɉ(^Xm=y.wdw4 |N㭍.v3)N< 3Hjaf|,{gKcCa!X}|n(ֳp< }f 3= ;0334Zb6 WЂ]1Z5jig|P47@8B„ ;zb?g PgDā6Q}~G d(iި41g'Z>,;eAB(<!M 9}D:Q-/S$xC"8zb| xK6%V^ D&Ƌu|bzF:<6q$"VHYEiWX,e2XyivEǢ`s&,uZe93?4Cs;L%::DžFu.GaDL a7_`f.jtt6V"Pd6xlLnu/nC? Re3F1E2Z[GQ_6! #ZHνZ BX#` 9@WGOB=w< snWv0B]SZ"F)6h"łQꬮ=hHuDB] Xۋ|u +:x`¼~|MYWB#B9 V @dںg['̇}Y"󩨋o&H =:u!/5r]Gc}Ϙmsף0Ojm3V2Vp"h7̊ױ/#N:v -u^Mr{i =nɟ7I6)҇:]+6qaqgԑf;Mo]xG,:] 0h7ݲؚ%׾I;?#vw*gUUQ,( T(0ajU]"(َ|RΚUA E ߈-/Op|[sjN'Tގ)+X:²%5֤}&uՁ73줺{Mڦm_v7WB:MfKJ'bv6%an ϹpT"ѥ(-7NPH&דHqV,!q(Pyh=FQQa^aa.y"m-{vvn5iՅa!Y3%.VX:/(F:L ђ0fy]MxI|r4J%*cz8E"ZQxAﭏNb^74uY_.W7FJCquRiOl:Z[/380:btgȼnSU FiDxWgO{ Գ$'Qlv[+m0a6pF!KfFDg9In׎$w!HGrOt.cS3<)`nl??cS3<)`NfP 6M/IT:&.U>VcnLx8JhY[cRa(afLdM*\arW^ٚ:C0bqdZ?5&7~ 2NT"Np6y:ʭF)#-TC!g:BGO:!X 8V8sV?HVR20?jF\ڴ0b:z: x 9|[hG^vZ5e;?xQ8"dEͼlڴRD6s? a΃39;Ep@ <\S)CP'yT hEfϼ soAAtONkq"` k;EsVu%MNI+:q& X\qEAଘ:}nD "U9ilS0giPٱ֙@g"!D_V|zPSi=KIy!0M&} (tExU>IS:Т`&O3ݛA*rut}S:D\ + >)!Er1pAއ:p1bk$\ Q@v >ػ+ݟѾ4!`wgδ֟< Ǎu")X4rdsN5#ef)--Á7?wqhpQGVmm8 :^ ]D* [XE(I|nUU .$xݬQfLS߽u#vǟb ɤD򺂂h2SQga|ҟ)!,_C V` hӿwF BC v}_xaϟ{"bk #l)|G*uY-v415ԍ4R~D($ѡzfjE|qj*Srĵ)q@B*Q>O̸G)^oĀݏE<6mb<-A%/X4+կFܑ""y|+;i) d[8+t!\!b^ts.5^pө2H/uX)Zs:xP"R``6xuy[sz">ri/|^ EGjհFA`L>!,+.. m mCHiSK/?]C1P72rri/ Bj-}n)Qsg[>#; [Qg X}|n(I$< ϔ<B3DLFk!^؅uX a&z%♆hR*(=m0d_0)sN6*"a"XBrc"!Z@flKŰuBQh2i!ԕYЦ'q<ʪ5hvLCטȈ܇g"S$)(SxGr<5!WqX<]'{ދQndȐda&ԁQ-hOͤQӔm/A4ɝb``"7]FhSǀCGg"!PIӧ As!(U`qIloܕX Fi@7 IIENDB`}DyK _Ref191726098? DdBB 8 8 T   0A  b  06ws nk 06wPNG  IHDRvvg pHYs  ~ IDATxN[gr2C hBH|9) \4r$ ʾLj+RoHv^`UHJbovlC_|(Y^9z x_Tg?86dV+5wNu!LCf5P zh@CX *}ru@q @'ХtƊ]pBcݠ)En)RBUf1,p8 esF5@ƺUco ~ee e>M}~p `^i8yur j4Hl-dj)rq^L$ߦgLE6r G#7J=O'&&6i THBE2Lwn}!L099Lj Kn-6(93x~v}[YYiy!-ͽHW[/gc5OFG{niX6 R7pfccυ(NgiiP(I Xk0ύp8X^^Ç?H !e;lFN_z7\Ν;[5)2E eM"ݻwp=E"f|IAUŒﭵVd? c aRACY !uDc&>u?L~#Yۅ$c=֔ ]|yycԘ>5 ۧPV] "C4DjT_ߊLɲztGq0H$uTZRGH7;ɛ{OCiXq;؎ѝ RSȶj"[L­Ț0Ji?liikNԯš̬u(. 顣kkk992DU~/rjbab&yi?, maaveP>VW`ҥKd2/8cHmӇy Acf i- Gƒ܈`0vNn~ HF$Cl3RsNu~{ȧ~m!mT\+k{>KMv CFN aP'=HѠ bb7 tiC䧰>2Yle"E EF}ءĆ5މvX zboFgF+bg] XX9F+bMsb\WĚ[)x.c_0b}5=R\ƺ`ω5r]kzl์u; ~)k"Jsv@S<'uE鱕2#֧xNXc+e FOX#V XX9F+bMsb\WĚ[)x.c_0b}5=R\ƺ`ω5r]kzl์u; ~)k"Jsv@S<'uE鱕2#֧xNXc+e FOX#V XX9F+bMCʧYcxҒ3dMa M@dbb"f"vJAn=p8Vz4@"3\n/$kHwZ՝;Hn+++xW;;;?}6==`0V#Hi2pKK_nnn>}^(o_H۴ Hrj)|q}}I7f>5~zAWQͤݩFͷ0L3KKK_r7ʲxf{ߨ[Mw .u'n-`:m=xp<$B^I&J. &۫ŕX,X__J97T'ɼHp8L״^I-X_<`Uݤh*yFtΘ՘^F4QuЃs vtUZۈ|; 蛜CgK4&=\i4Ԃ_ZU+2T雍 YE}hYV bvFc!_Z゙ZX\r-pՆT2v)q|z$EW#[*kiݠOS[+&Qcj}RвkZ}:vsPCK HTAIENDB`Dd   T   0A  b`BqqUu<An4BqqUuPNG  IHDRttT' pHYs  ~IDATxؿOw'?q FLE)%!Ab:`kiHR vѥI\diډ8t/Ty N{y?_($WRH$jN kf9*Kzf[՝6LxFm@;]T\wzvo騧' 7pFܨH00-^fSQl@Y7'e|3n[<ƀ~GMN*;7 1<`5eM~?e`[}ڍ$h3{9mdޜlg?r9gv<:6R/ڰYmdT c6v3I|yylg>~'Rv9_t_L o%@ ;u v_GATA_EiKnK[T{ ܳr^з H if[w,tcA|7$pxP䠣o(. ް݋sӃ="e򹃮)tM' vh0(h0ڡhvh0(h0ڡhvh0(h0ڡhvh0(h0ڡhvh0(h0ڡhvh0(h0ڡhvh0(h0ڡhvh0(h0ڡhvh0(h0ڡhvh0(h0ڡhvh0Uw>G`=<(HT$aA*y:=Aio1AvxGjۀv}EiIJ$oяيMz٨m *ﺤj3[jAQ=l vjs)R5Il^j'|!IENDB`Dd T  0A bNreIfeInNreIfePNG  IHDRddpT pHYs  ~hIDATx/J@aN!0Dа"=EL61~6A7m/|aea0?~`|^EG߇,قrS6h:9bH!1cH!1cH!1cH!1cH!1cH!1cH!1cH!1cH!1cH!1cH!1cH!1cH!1cH!1cH!1cH!1cH!1cH!1cH!1cH!1cH!1cH!12[A2]N؂ݎ٢.؁/uzo?Y~IENDB`}DyK _Ref191726098}DyK _Ref191728658}DyK _Ref191725456}DyK _Ref191794618}DyK _Ref191725518}DyK _Ref191728658}DyK _Ref191800790}DyK _Ref191800801DdG wpT  0Ab9=Twfn9=TwfPNG  IHDResRGB pHYs+vIDATx^] E{ߖ}{ xpL-2a( 80huQq#GgpH<.8Fʦ8 *0a$YޭowWۯow{n.Σ꯺9]5-!-2 X_-&gY:T阃X V\:{fALEPft 3"؇E038K=60􋟧K_{czW:5`ai(j\w ffI,ź&iߌ L13Kllo_-i@6gI'1#(JbKh@>p+R+(oØ[ ,DJɥO3NL<}8揓 `hkYY(͝G<#aM3-Ӝ8qݥrC id%J-+S`0P*EgjSƉ45k!e9 I׀D3D*,}J#,珞Fw͚;UIOa] !HjYB1 - +TKXHײ˴pK/ff:d2iM=[;x)FY/+B_#J!+$Ͳ8*s2}7]9{`ne1ɬaѧ"6m5 hG45ћ;0ܷ1M4w `z=M!DϹiiH/OU3΋|=s7<` Oe<-͈/'>8RHL G;QJTR`;K&G7oF$OxF1). ,L*JN/X~ݟYfTe'ى ֿVԛ RajĶ nUT55vz`oxtcHBt~c ̘,4O}l8kuC$5 "SoLh [ϤY&CU! 삁 O%#C? 1b0;&uյB=(pNKHT`콎8raF;1adD#jh(t t wt<3sȄ sҢQ jaT@cp4=t'.3ipd(uaFcjҧ#M݉kW| A 1OOY* c'R|"I#e26Ǔ9nMY<)v(2'',LU͉QqJ5ᥐBCXd5lRz,&:A-h 3L:=ΥQ,jaJq\Uڛ|{|I:td?a/3O Kg9ah׽|[736lM_/1Zhq/o;eH>NNt_G5#l*T9,ԅ)ŻXDGb,qbY63oOye/Z ӧ˛7oC5:E^y,EݏHsyݲ[b*ۣMKCA'y  ,<[̪Yd/_( 1&;M3K6d 咛0m,8k ,=Gy=h4&!aX)jnu-Z|kϻڳWeawKZ8tc]sgYu I U.5t`#YP3A ]1oLHjZS=n,m񊾥OMK|>yѿ$sO$>xG}<D0JkZ K~3~t>Hؠs.ٲ͎Xغgq"A$IvhތU5 iIG,-=:g1|-L1+:jWuI+˗NG=QP[Yyґ|r:h8&`8ǰ(<9FCosI仟]d1"|+~">@5E'QD!-'c_89?xttKMl%O igdAwx;Uhs3 w0t]Ã?ux2++Io<01rdKOqF &`= )HWS꘼~N--;팹 >E9\qM&K&U,RY1[CeQ0mk GRD\#A+`t2Kge5 Z$BT޺` X>@` &rЇ/KzΧkTQd,PR!m$aG#;Ne|;K= 2Oڋ*4 9C<HGpވ42}:_ ,(kWp.ŕy02^q[\9̎>a@K, |WRc_ư#1U6&dN!z^^`"haa2q _gwzV6(D24Kib(,R=?\n&ş)]=<8zց}Vw"~ldW cwkI}={rc&$qq)X%]d7x*+@44)طz;zᢠ]=n-@ӱ0Hߠi˩ g TtAF"Cf* B"NC ILQ9w!'40嘩ɍ-/^3_L)|. G#jUHw' 'OEG0X`bKEޡ/x6rwI B!B"1 (Kk! Pt^m_ڟE֬:rsf0,'޸`^9s H`6bo"C8-LH99%ZńŞ;:H\mO㫏."tk/"iPA7A7ȗݏܖ%viiHχWӰ(h YSh-=pYbg}žD檒l*7|(iWۢq\^\-dDF,|XMRi&D@!.8煺MǟY{ዱ]v Mȍ 0B,FQ>"Px8h@?[+c9eCcC>F~wmG%ܑ.>JwF`:JrVZYCǭ6mb$驰a"ܼ.qCߟ@1`JCOTn(Ӑ[yT#/~4N*:DKh#̴s,y|iA8}`T6 1;IdED.T8(*0 m̨"CtAcK9=ĭ}r#d6Fo~v=*\uGv"l,qLO*K[p`/> ʝQ).wEJVǁ ƪ>QYNO܎jTպIէ%8$DVzKh+P`P𨀃tZ1'-z}i^MtV~4 ^L+0P;S޶K@38]*¾m4SSr`TοV27M٩y\)(bF*筲rL70\3%һU  ( Xl8rͧi`Ӎ8*y4FmJv{SmH&5Ü)ZPv\-o*ťaZA8@;HSi^A߮pet޺|t;K i*ֵrǬ Utoڙ 8<:ݣR3ѪkJ3Tgʔ*0v;fD.TR(* nFLlZ:{]9 h3rMpmʩdMFӻ@U9@?wŁ<rxкVu>_0Ԇk30 0| R]6\ (p- 5QUHL{_)5*5z]:Qru8g;n^ ] U~EP#(ovy$ UM70ʮs1 3[2GR i&ç(Ω=luHt7Zm5%L\r/ڪFa !|`?k הpLץFGafC7\ 6@5F1ЂQ΁&XT o 2d$TOm" (57\:kÖ~v>q]7Ue9ԯ ",+@ VW8Pw(`ԝ`'p@zQP>F) .pIpjõQԆk)ǍUn5F0WlwWRޅ r^E]9Ѯ=P(绡UY[lZ7rNZӺ ׮ݏQ1G<* ܿ~5G Z?ެ0V* cԣkϟhcZ9Q+$Y/N5j*(4cEyu\hsҔ+rW0e ifCAX&^rI*c Vd2{ $ϦδCZs} loWA9V/,ŀ! aB4c]P>U2):" e\,vi݁!ă]Em&#筴i$ܔ"& JC@2派EߋGA I@9M y%0bהnhlDr a{c9c[T.8%:TԂk3nI:v:MAEzv0* 1-nA59T|`LC!z;`P/utA>F"{qH`Y*+80nmݍ rZE97)ۙwDDR 2No)VTW]Wl[OǶo ]+wZp- of8g(p*er`a7HJ?}WJjtѮ6u" * !ܭA.lle" 4.Z&tsя|%v )hjyZ6/qUDBE+ t=FR1/O[|V)ee2)^]d;m/EdC? XO.. b\HgF.:P՝FK:[p9U|QH"{ĝ[j~uPrp(jJ_e J4EfXEK:P-bc4񾡇KQ0u+xMXo @~k2E^eo5d:_o5t} Ͽ EaQͿ`9U*فr*p=IENDB`}DyK _Ref161214237}DyK ArrayEditor()DyK _Ref182908620}DyK _Ref182908648DyK _Ref182908661}DyK _Ref182908700DyK _Ref182908717}DyK _Ref182908732DyK _Ref182908747}DyK _Ref182908763DyK _Ref182908779}DyK _Ref161644779DyK _Ref161644779}DyK _Ref182908817DyK _Ref182908830}DyK _Ref182908935DyK _Ref182908948}DyK _Ref182908979P$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5H$$Ifj!vh555D#v#v#vD:V 555D/  / / / 4+4 xa$$Ifj!vh555D#v#v#vD:V 555D/ / / / 4+4 xa$$Ifj!vh555D#v#v#vD:V 555D/ / / 4+4 xa$$Ifj!vh555D#v#v#vD:V 555D/ / / 4+4 xaDd#B1 %T [ 0A6b1! ^ xP dJn! ^ xPPNG  IHDR,sRGBPLTE !}307 4k=Gff3fffSa3f3f̙3f"333f33333450(=^33K333f7e.3ff,N%\3q3J-3f3333333f3̙333333f333ff3fffffbDU?0f3ff3f3f3cSr[-`agffffM}fWAh^dp`ff3fff̙ffff3fffff3f̙. |ha_w=@Upl}|>hzo>__/*ЇFtNV8&W㿿 -5G S$xf~V'ʷ~\{|Ǐ= Gg"v><3tnц́%! ؞d ٿjD _>鷇+'gϮf:2뗧X=6wiYGRWX#ټs}>C ؓ-4_.96| i7b:6* 77ǀ!8ŋ~~X΅i >”G0A0Y)OmX)ʊJɼk{.㋸#S0O?i{?zǏ|0iNv0=U;O$_z.{ay%?|;6IpY|_,8}|"WWO~}ɓW Xܩ>5d6** M(W` 5BrfS2;<f ^ 6L,8 ?]}yz+p#lFY1h ;ֱ'PV]:U/7,΃aVuv0hg^=[F'Cս_?},:ޭByV԰>ݸC|\OwßE0/g4ߓ(P/~ϳ " TڟUʓt@Q<P}a>c]+8#+e07I``p޽O|ϟ?}l:<>wmMMcFeP܆uce>-_-2 *) Xz``#`{_8ݫѵL"Hgyحg\y ?AJvRڄՠVAŒۗl"a) Gs8pz8U*|&LCq)e ԚLK߁ٯ^W߼yq7N6)Sa^X){xTt-Qp2e^ 6ewXS0e˷:Wv?7M?~L={OB(W. ,gͯͳc@.3]^Uq[71(wrANg&L@A.' *DI YyOtA&o;"pwDՌ@@ĘN# LJ'ʷ؜;΍ڐW/t5 /d Fۂ_*o;ll0 )|tLkKu`vRcͼOMOg֎: iiFG6qTq050+g6; 84GUI]aRv jL f5nWW{:]YZ[oY7kisjCڠeOm\ݜvkeIHJ2aG%ҾAJ$#t]DalS]bZD?ӽq|О敲֨NRƷv46[,S@mjLջyᓐQ`}=,Ge㙲hز\wkƍOTC.rk/ڎAk/1~u[jWak-ᚙ;}Zng:^r `>&`p; v; >o$nβ0líp04KZ$ <"zҼE=뫴aLoy BPto IM5g+_譨F op=+t{ KnP8"\_WjUylY>U)?gjQ.o~,UbU묺YmV>7'7.AtӬip֘ ӎ“Y@}uhlF e6Xm{~]-LBdX@#QL<={$ۅGN#7 p70r''y7'z|̻8?#` @yɷ'nwkkYrZwi7q:o 7}W̳ow7XDF0N!|Ir@[*`Z<ݹs8pCpptv +6xvUgr$A"Bl@7M9>SHl X7!9tQfpp#=&홂:=&7o {-5!凵xXcvA`<1 vam0]kpv6k̮5ѓJGq||pR]+Jח9~ҵk/w;0P|+eqGm:vDj5Э \\7Ú-:/Wpͮ?0wzC׮C=ٶ 8zkfEBO.=> 39ǀ [s¡1 Xoӿ~P57'(lny\.`sv^'r1; x0GG'nqdtO^w3h[se'D<_ 哐}^ۗ**eڧwk2- [[+n+rv?2 @i~8{p L ?#NkNq|c֎#vf>ohX~q=_vŅ(cy+`3uˋs0kˆ~0]Vz;ߎv\ W(v<:2pY ^;4Cp^+`2^;gUB;^^B?8>EjpxVruX]o"A*}[7,qJ_ޚ#'NEftmN:{W#j&n0y XۜH҉I= ɽa=k>:;w(`><z`kV֓ޭ97ppjֈp]u|r;gU':`_~DD@A)"*!oDhA)ׄ(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~ErL p..bqI3A`2A@&LHנȻfIENDB`V$$If!vh5D 5H#vD #vH:V 45D 5Hf4V$$If!vh5D 5H#vD #vH:V 45D 5Hf4V$$If!vh5D 5H#vD #vH:V 45D 5Hf4V$$If!vh5D 5H#vD #vH:V 45D 5Hf4Dd.:= GTTT \ 0A7bmٮ{$D8IgnAٮ{$D8PNG  IHDR38sRGBPLTEf3333f3 "3uf3fffff3f3f̙3f3333f33333?@?6FV3333333f3f3>P`<`3f3f3333f3L33333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffMNKpnd`sRffff3ffllffyFfff̙ffff3fffff3f̙3333f33̙3ff3xff̙f3}Ι3f̙ޥ3Z̙3f3B3f333ff3fffff̙̙3̙fʢ̙̙3fÿѿ3f3f3333f333ff3y_fff3f3f̙ɿ3f{0 pHYs+IDATx^;v:= 9>n$9DӊzqL$*f(Y “?mwj |Ir r{VH&YgP3'`0sr6 lO3(zs`̬@_̬XN©:fV'ZVuj̥?x?].*9i%3[*Lu0uNݭB(Yq뀷Ϻv/=;̰p|^$^tvq.&8ffuz .f2w=4m3y}т@2C_˲atKb#x~o7Uءvp3@ڬkrA!M7͋)P=3߻K,f:c;,q_19oLSd(eXOꤝyߗ/y$F1BDWi2[`%''Y0xv]Xfq߿j|nj#̌GJafnw43M:~zz<:x/|)3}r+*:_ipԻ#^jG2Cr㹶fUVmN_Pji.n*43?_zc}tjl+"IvlߤV0|tq,>o=>sޯtkr vׯ3uΌ.8Ya2abF̝|S+̐"|HtZrg@|GM$nvFs1ԗKό̴eFh`qrN1p,7Ib"^կ,MTdlE:؀9H8\;2l6j0o023.Vu -f8f&ʪ?2V״O/W2S|hG"RԞs+4NJM"K90J=ԲSp΁UIU3ĕeGv6x ̎YN=")ה30Sf)W7 ̔rfM=sڏgkTwPQyӪ  N8 N烙HṲt;퀙vtj$`&i̴T#aFQz!*O+\n1p*3nj`)3O13@`fS3 A̤V]1p*71a@6)jrgI)ކ3"1&I3xx}Ӵn^X=Z  և&m=bl}mpbAB$ȎQi &3n#x:̹}h9fa|Y@_BIMF79b#=H}?If8>2#M~fJ0 2cHs3G7J>f^ex:̛\S273MQR32LQGɒ\~!|ɍc4 ʌoqQ%;K,C?c4U& 7raLker`jR.j j`g).~f f$EF0ߔQ&3SRac f5Ad7X=iPf" LJ<$Ӌ,3 *5\f :"ov;o*09BliLl W?iOGfbKL{:= 3 MwsWܡU}̔D- LMՈ87?eF`eF~^|8D L3u= f-3mr- V$9&t"#_L xpNlil\($3$cƉcpv&^c!47cemgLC13'M  ˆM~r'M3ΰ*PǮDrE~xS% vfVfff޴hM\}]P,ؙQ;IO3'Ua;`椊1l0Cx'=̜T;;驰3'Ua;`椊1l0Cx'=̜T;66xBOrF=YS\f림@33 l׵smߓF3{=W]Qylrה/`<23 `32h_Lό?@ 6i۱iTȌbd:Qdj8ɦ*w;S,3d$5w;pᏝ4"480ؙb3c6dlFt11 .2%-h  ݙ5iBڕ04'2Sk9/{UM\;Xyf2 fLu0I7 f*V^LYTL]$3+/SL&W,Xyf2 f={!yr}4f7 5~bƼa~f`YhÞC(fcfإn£{J;`}Y0S-3NS;G7/T0޲fEv xC3!wdK3w@(oؙb 3#wonff7\{rw_1L} mMX)p!`E?~obԖ#>f$)޺dUTA{hh!{ ;S2v ꍍ=[{*3BV*eq3PML62g73&geG /bDG1Q ff;32ʍ`'nOh'f$63s͌ʧDec\ g;3/ y-#&"gZۙǶnLLglic+FK 8|R$D.3ͩ4Lt7iNfLs*> 0]5fSi"n0ӜJDqs T}@`&k4g[ bp[%7 :oPaНR$`13ѭ^`z&I.3ի0LrW ^fL*L>0\7fWa"A H`vХ\ C?j@FM_=IENDB`Dd T ] 0A8b(sF6Fn(sF6FPNG  IHDRXo PLTEf3333f333ff3fffff3f3f̙3f3333f3333306<6FV3333333f3f3>P`<`3f3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3vxy`sffffff3ffl}fff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3f̙3f̙̙3f̙3f3333f333ff3fffff̙̙3̙f̙̙̙3f̙3f3f3333f333ff3fffff3f3f̙3fqI]IDATxu 0DaUw_ _56]-lX\)/Yܫ]ktIKmVo@ VdAoZT`PyXL)4]JK'NUz;7cmyZJӶXX)r)4$zRv"e=Դ$6Njȃ 'bvdlVƚEeHN^8|Le]=KheVfT tbO7z鯾o͊~ݡ=_Vgy#gWNr=hsN8"]=2Lߓ2 zkЀL} XB+AIvJ kzD'Zg'VBf%>ȿnDgbu+|e+Ў/VAֽI򝯝os|dxo%yQwwU? Z]4?q_P Ȍ),Ɉ73LN[S2dIcd90Vz,O:º+: -Bi/N;ӓΔH'=Q(c#Q)dUIe\=S{I{]!UùG&^qןZ HKO䈳; Y2x8+*Ĉ>鴓NXql8~8z`]ɿq:R}ɲmfPIʗRId{'w5әV̍w^x}!+995kW'Nu^?fXg[cIxw,ܵ.-B wk`KVzJ+2٬\ԝڠ @ah;_%ueu֨gWҰC+)r\pˉrxW(2lE99gjZ^Ywzq/,'W/0d䞃߸촍tޛo>ovv=qV{EkAvm}W!j_*-;w<ڝw[sO6?U9GXYZc/q \sKW j VΪ\]I@+\k޿;G^wwmX9b uLdY{ 5-ž䬷_s׳-hӅ?XG pĝ]]ܓ2 oz2'~]"-U돊;MSv[a/T4NtYW֎$Q+y2N-(IJ"u*?vԇ<'O|e>yjI<]Wt'D=dwL;Y-8;F7@e>[]yx[|ꙟtKZutab1~ Y`~zw_.SAdϜi=f{۪ԋT)(U5 `ɵAI\:w}J3Gr-e/N.&mewjCmoծD> VSDdvv}CZgg+:l[VȈ:mU]⒄%RܢtʥvrrbyGr/-}mK҉_r_n{9?xd[=*vU*vwzָGU-PWT5_ȧѕV*߰@%[6[>z[MS[ROފϞ=Kd\kk7~_ E!pks0l %jME=v ;o[,DڕȧJPӜt84,k/v}RgJlQ-d`DJž8DR@?d"_]Sۿ{o'.{;^z _7VPu+Ν+)ѯ7Fa9KT<,6]i%v`+rnֽI =#e}}Wm=1n">"ԭ3_ҲTQY0 8?Y;dTRFC&ffɣm̈SشAkwfW׮D> VNP*CEYRY/+ k7+/rD";.[ΠA%۲׎;Nztd_~xi _?:}Ga.y}ኯ'c };o,uq]r\[ܹn3\,/Le9ٽfˠKgTj2^m@iߧU V=]f^e4Ox]6~i_HS E}jZ=(Wɕg-rdWp$:}%_kJ`%)Qg5lAɠrmR]\מ 'NE4ZQ&t-̒Ax"7NtVr (:Q==5}_y`褬QIg'#rSg=:| #;.]RT$eFaR-/w=q{7&I5BK'-PȫShx|ekZUUVߵ:^q0PU zf=_۟̔Cuco7bK@MaVcj౫zk! J,-c֮gW"okJ.%+QDnhWtXXp*}[_I 2|sPA lHaQ;}˻MO 7!WG&2l}`x6_?+N*){QV¤RMȼ;82AAȋdju+/^jVy[R+w ,{ y[ٮF:om5^;],r:P37\[i媠r9)P)/WT \.U"Ȅcw8Wn-ck~}*w~蜷郫es zWf8Wx x{F)o׵Wpg_TOZa-/V+*zkP@f(+MH+.5! ~u&&Zd|;{$q .*yW ʁx_~]۷J+*i9v)ɣ3OHwJrcCh9>Vo~jKn۝&S:˭֒'c^#-Fǒ_\?hѠqpqdUWh}zμLz;.wV Ju}u*L:=wz1@ W݆:U@lmSkM=r8ΞX^<`N*)lri.:eIvPs䩥r+z_pW%˃vJkqb`O˘x6Ύe [ǝo->V89kL[;^u/Zo8T '2^:^e;ak띩ߥؓ-r`qۜc?jz3V0ܰ?r_ 7>r`~[i'&ʜ E[f[u%%?'za"%/M ,Vr=I][d:]BvZ ddq;Je񚗬 |*-H;i(ndٛ~Kb({.|}H'+:zD,cDDf  WzPFe1-X뉓G|ޯz4FCSgKO=?K 9&b@|s?}_;dD 5*K'7$(K nH2yh_y7uTrSmpOs;{{dBFZ-JUS IY],$dZ!oY^sI叿qOdv^a-_ƠEe$;Jc2\'@JeTYs"v%ܮˑl(]kzz{Ƿۮūڴ7稹̦T%yQ<,m*k;ӛi2S!r tbJMpsg5Z;եeuַ.m#j͢yn?$[@u u;HHҒEIO`$Y[?)jΆVȔu&W]Ehxe K,캡b{;5QjQ)$ڞd˸[!c % -f3 '$ByErD鸫2#WDj=nUh_%Jz/LƊm.wy͵4+4[,/_W qSya|9 NXyZk|Ekl{@r' m@!@ J640@@0mh`0 M `(` >@P,@4}@#҆ x[)'x! @qJ@ ! @wG!:Ae@; 'bHaqW-xǟgaU 9t1..j|}ZB<>W!뵧p=~-[$pU_\:=6Qף<$_:nj@nE'(k*XIpm}& PsLlr R_7mrT9=" 4cБ 8AQ!@G%Da~~mcڸ` M'@g+gY{o+[Lf@͈V,@7;ֻ[qhqv@&TZ),mLW&с wKI"FX@h2\12hyѰ0DR4fd@UGd'3@+fH}]E 0%ɠו@;s{K mC`+(~icl2tp unTCnv}k%0Mqِ%9ks$5֔J*>%m{JAG;19FtlB@@-b۝lwN۱c莡a@ ΎhS3ۖE`!28dNfqh6*_xct8 kHcTgU6iAg<:!uy3+ OkYM <@Ia=2/fG"!= SfB:i2S?qc^MlB8̴63.X}я=D  AI*!AQ&+ P/ǁQ%_ P%<+J·@Cs}䡐KYbv$;l U:l&bZy_Z7NzB@AsnvF7Cw;” E@:: h9fMy~-a ІsHYSzXnR':&H`^Y:&M SR2F;qs'@ϝgO`aǚccpH{')cX"tRmg4>iV!TtSqRYxҌ:w.dtR]Gi|mul}Duݾ&i '3-Π閃6e o26d}MZFnZ*;ǞIn&M DtaR f@I 4DT@fҤ.@M$Cc3U5|&wm$$8,5I8lm{J!z ]a4aaqm3z t@P,@4}hCYh C І  @P` O%Q&gt !x@wAD@ x!. @wA0':qk@  ]$LIgJmK1@\4 :.O@ ]2 BK:tׅ !@im}V qSs`O<ܖn\6پtmi=mk Ͽҋ6קmQ*>+YkmO[ay 輕ͶG n6W_]ùl&b{G0h q8B]CPa( 7<56nq_@ AwA0':q7k&g_)λZN@K -K$=ݔԭsq@qT u{ڨSN=9M{o t2A ,F4EJ@'^ګZ[vOOIZ{BX@cv-$ڟ>kzMehC4 ƋxwZ%ںˋrk!PIWJ >Wj3bIch X_֫:!n8kUP,Nxhl V&"#Pj~x5xC"aS6FZܭ'D8DЄwD_ T, yOZgM@5rؽpa 5@`y(Bb] .'@wy1.Iض˳$LŴU&afzyt,D}uGa?<46mkt{8ǷO.Fn-ux1$) @1@ h桱Q@A 4@+z(@M6@s%@ϕ!^2UcCwܔe"g"4\I.V gJT6,TA6P@~X#9- 䲙m t  @Cs 4@`>P@m @2MT'ce> 75]Oj@ΐ#0zg%A!>o%OCEIu 5hbadFWV2=7xQ XOÔ: [o@&\\iPD;L74#! AQ#`&ބ"@w<Q:vNn0LO ~tbZ.^K뗩<=L@MH_7|(_5QY_i0}m'@9 BGljRNn;r  v4@ jhL{I~<0amS<4c\}#LzG8q nR_eOH~}Í}OzgEI@"A@~4hCYh C І  @@ fA@ %@̂ @ J640@@0mh`0 M `(` >@P,@4}hCYh C І  @@ fA1&`[qu@l:@ ! f @c|\&@bLqq0mv|1:u@l:@ !3 8e+h3Uh S AbO} `*` {t S ЦF @cJ652Ğhl `2h5<4hCYh C І  @@ fA@ %@̂ @ J640Ęmscyhl{C 6=BĖ8 `:a [tlCh#}@l б =C@MA%@68N6=BđFz|aH@ 8F! @wE0#:Qg@+ ]&Hc tW #!8@u|aH@ 8F! ꉱ!F 8@}|&@Ls0mtx03:w@h8@ 8G! F 8@}|$ UOE VA@L%@mjd =:]hS#]@ бL%@bO} `*` {t S (V+ @zn,9@ t@@ fA@ %@̂ @ J640@@0mh`0 hGc C2B ̀ PC @@ fA@ %@̂ @ J640@@0mh`0 M `(Xkhx0 +uZb':㦜bOψ+ˏؿoΉti>o |}VJY۞54 4^>w %7!@@s-> !t, FF@̺Hg=!3h`1V}o t@Mσ}4 @ 8ƶ/8 ` dWHh`p0 "@ J640@@M[;͒@ӽ}#.(1@{5@z \94лIߒJ\5?"q!8G!S hSÃ]@ бL%@bOY2 07JNV}F&ķ4㵧0=ȵ]A|. w@G? ~f ::q@ bw @K<"FX@q,7,N:d4tnza @|MYm'dTG| =[uӸ%PBTHB>M=DUBm7fc'L4fu0h+T5 qv%քh}uiBaiܱVzm1``hmg!K+8X2 @YiU0[1ܹlXV3B  _Ex̚u Ò 8baO |d>َEVAoIX8FtxDZ10Ϗ gC g&nj${ZM `#g^ztY2oЗqDZҾm+K=t\WAjyݶyXZAkXSIOnh⫓[}e~d4xF;(P iʎ1BpY淒c|pd9yף_~.;_^Y||@Lgz8 Bue1 {Jckc  ChӽfoNU CL2oA/~kzR52/4VAk1cwfSa"RK]y̙_[o:QMШ[X2B,s) Bu ]z6U oG:uP5s!dzNl?7ux; P<IENDB`Dd44 @@T a 0A<bGrY̊872#nrY̊872PNG  IHDRabKGD pHYs  tIME  73IDAT8˥KA?3"ilkh@݋/JB/J XBdC(Mb51MV6zp;&QJ|y}?T|V\'+(Ctf+v|>vV eFa!=MVDPM4RPj^Ki~ jZ.N f6$,lPTr.\K1;7 Ӑ(qIyJ#jUp~8~op d?lZۦ1Qm}N1O9Њ%&r0σ):&?% ~1y=W« }=W%+{rӺ۝*IENDB`gDd T b 0A=bD#S$nD#S$PNG  IHDRabKGD pHYs B(xtIME +0WIIDAT8˕oSszN{glMqsQ= "xk$^( 6c xiĘ-Jd2M&ufjRnd\G\WK[۝Nj&o|7~ e˲=$rsu ,""'O:+cY*0)خkiyoÄa4Mw p ̒v7PD<~[,0Zhyw{YQs; k%CgiPC$Q*:Z"̗uE H$*cķ `.؎Kz W6'+޵EIѪkX_ĴLrQrǰ]%gJ4Ld-ľ6C_!Қ87;"_tD"_͐-d &r6 b~B7Fgn~B7FPNG  IHDRڭPLTEf3333f333ff3fffff3f3f̙3f3333f3333306<6FV3333333f3f3>P`<`3f3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3vxy`sffffff3ffl}fff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3f̙3f̙̙3f̙3f3333f333ff3fffff̙̙3̙f̙̙̙3f̙3f3f3333f333ff3fffff3f3f̙3fqIYIDATxc0ud*#H [G!R;%;ar,Wuc hc+Jc 8'/|LbIENDB`P$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HV$$If!vh5D 5H#vD #vH:V 45D 5Hf4@Dd= "$$T e 0A@b?P>$a?n?P>$aPNG  IHDRU䙦sRGB pHYs+?IIDATx^KnWqgځ&+ٖ% !Kɬ[̀LF1#CR$Q=_J #; E[>{ޏe+QkoGGWoZUZUk}n 0~K|?εZԙ\7 ת\֗mwk􆶝Pru&4*6\֗=$LcH,Fg/WZӗ@@TԿ>ʒ  ;'C㟃"2gD.Tot]X0%L^AuP R?Lε}`{{7QduG:+GFI>K"`coEX/iay*wP21O8l8u>!QvST{ tJE"n;u|4վ[c%31? rQ"8[BaŒĸ\){$鯬OfM$'aLDa D[ G7dqIZG]"p7E21T8ŏDܪn_C *7Q|EK%Xz N{9[Jf/.$_g :f!vH.!*a B=? f4OU\uݿKih    = I`Vgrݬe / *}YmA@@ H  Fk:l@C A@_54E%}p݂ϛw eb@ZYV'srLpgJ2ǜ.ljoQ>r ΚD"8 sȴN"(SEEJE`t"hǝf[Iz}9 8}tX9:7N_a9wu{1McίTxhəbVJ-91|?Ǯl[7|~Ma9OzXLKo!c3@NWNrnP/dchL, K&B!brf@PxxtPQĴI9c̒9[+yB hm[#zLzE{,pq0q9Kr?(ҔbǨZ7hzVfi_1}#ۭZ /vlK.;@He.:H e2,31ƣZdBeXQP,J%b?~Glۄv s*gG>{HK ZϧsQsU%h6Bs2j1PArc H[lI v|x_tR&; @, y ڎ'a0 XHי\7k$cUT;k^ϝ q  .( 9fD+z_;Ei!+Wy5Ugrݬ9$Nru%u)̌KrwY䢢K|~9$9[/ιc`Zbf'ŀk9BKu9qfb |b3bB`}N)i 8m믞#c@ \5+Gpr [ΊZrbk -9J^ʩ(˱spc ]T oKZT,ҝ+;(_>ﹹJ6\8~-QZu`F ؜[ )\t6&* `cK8 술 \NHi$j@~HϐU[0SYꌩWk {M h1%`g$_3 $9ÝWyqwDoL~d8˸)~I+;~?#m qxi?ZN݊,r1Q:fzgd[[eu D(\>0m.#nΗ[QWioڟK\-j3ebخtGUgrݬ1zbHpH3OB]z)rZ%vfX@@`?wn {:fu S.˧mA@Fvm  w T}nnL)e _\mA@tp/hO`p÷^*}h{IP5~L,(/%:^)Li0'YˏEz3M F"j,@0ñ_b 102('MK= Т1d5/m 9rr(R/m|kM.P!t cp1?#$Xscs!Ć{~ʜ!W{q rx{(5K r7(7<31s MGՒ6MG\zM %/,' Gkd׿Dl_g"I1`xslj ҵ `J *B=oSڎN}tfdU~Ksdl]x܅Hվ 'lJAֱgnb9ѓI~tE c4İHLc-f+t%eLN̒R!\[]d1 ~keC:q+%g#/AeS2a; 2ޞc)WAcҘ1H#,k$SH1@@`:?CXQ˖lls $@7,  6k8Kw<@ǯwbbSL/h_e@@@GH?_O>z}9Gm#nrCaXPyY3lx~N}cd;^).\-6|Z~,SHX aW/?ivү bs_d3덳c8">E o'r9IIΥz ;?(@uj-'/bFUy8I(G uߠ:$Ճ #I19B';}b "=$瀤R zE!V] *& _T0 ZrJcUR>&X#&F*L* Y_?h   N;[6kES[7y\*>gN=^NIpO19||a| vLD(KPR}c W[m&\zѩ޻a7;"`{)-&Gdq>N`E]G%-#I05_fcԕɦ߮úI{}6[8Xd#GKκc=W |9}ug,6\ y5fol|,-J,BȪ%GxhY_tj,^?:f͟oN"k OYv_iSSWM֤%[X5{['+z|#ciV|Z^̿C̏r45jԒ5)Eyb#'OA j7h<*rۮ|yj1WήíA?PdUu<\l"3AS3}"=ׂ5=ϩA~l70& $6V*gYnTc't,Iu0u|{qP֧AԩUnϢ6s tU`BSڎ_{9}ytT(K}COx!p_Oki[-?3|AzAN(r'rc- 38%qS7'fZX ]Q&`yIصwc}dM%?TRL꙯NVO6RK+'Xi*ϵLhVOXx}sbrd*rthMI* }8U˶I9xVO:KWQ/TB@@tB;-X; dþ(OfcE߿]y|X)yƭ<~m彫dt6{0OBPS.˃pٗˠ-?E͋}Ϗ?:ӟ,RA` >ݻkP#m{wD/> vAy]ys<xگ^˿yg9^?cPiGiBz{0 ,K sW~ 62(S/1p\yύ-?ty08$$8O?t9=;0w_o/9% -t=n0hP-z]7i\A=+mzbӇ6svn.._c/ǟxk,"QlR}?#ڋ''xR%G',yN$Q\Dr]'~mD &U}=sL֎+-u6ΑslNə9?5<`eZrBӛ*Zi%'OS'JyN#b24#tp]_-_'Mt%%B3qVp5>82;=9<2GȜ_.'ᓌɉ9"A\yU )l^pIH"9S2:/"xxczd0t"&Us Af!QMo}Cд9}^Lߞwۿcn6wmstxON2xغE:/~Tk期_bӖR) ؖȺho/f]gx`No/P5_/`%g _L'udV`.~b*ɏ }[]s^?ZCi@/9@J!*ZZrdb[tSBHN)vtΔmݺ|:[OV+ 3OyrZϭ?6g.fO~]?;|Tbc?/uP*FGcI?80>无]r -Mꛎ~g2{ICV5*qc[6?;rm@7-ִ)n:UA@5c?[4N`=2C1 c[ NrۉX@@`o} %Py^`|[{1q ~vuvo5r௹/@@@`PY  m~1ޟZrk F%z_<~6wP i19|da|f;$v┊EK'g>lW'@϶KВ dLN U χHNsU0#CIT2ڬCml]G /m>% @`j6Ub|1[̛oG^֫(+!mi9ŏ|9 Ϲ1eƊ.|<L3$%1q|$îrouͩUmMN+_䴆#}DKjϞUIw ëv0I&v 2^%͓1Mi[jƦG=$#K_U)߄ȗ*#/K4UYIsXrsdZ4]=iú}"%KwFm9HyQ1s-`~fpU8g ٖ sXNndSZhK>VB,mLm,ƨ~aT _coS[^$b@,pĶhjsn(J ;7 coxU~?YHёOc\Mwj3_JI4koH,$rΓO?Dɑaw'ߔv-&dJQtvc$g[<ܾ䄩!:O,G>/y>/!>y8!*C,[wNb`?Ui7T[Qp`!KؠrLPnhG5M@@P1ll=  ]kAyJ0 @@k6_޻w`rkvE2E38c 5(/|{l셍 ?|s$TG4Dל+CQ>[ڑ+>1d/Ae(R#+;p!ǶJJRgFhlWdҩS+D#uZBi':gn>>7Cs¼O>I躨1K5GNGWȡ)9U6&{i<'rr5xAO/Pw5ƜG< Bv'(9.c#G? ÿ<,KN)#Vr"9}=]gfkdOwߛw̯ͻ*5G[w }*+BYt^ z*?[fOڵO~:OC_Ob|p\_[_-*Z+o$[{~#sȼsj.0o_őBW*9tX/\ae%ܢKu* ă h:ꟼ0?S< m AYER0jŜr6l/x;{~'ۓ3svlNyE xrpu6S.jNѵf,l)C*[oдb\P֕:U7 }oU_9x{';ǧGx<5gg7?Z:P1U6N1v$3$gW/$%\LtX` [6R9o1g'wO~7oָUS D_TGhU{3x/m◌'Y/8/}0ŗOON'#IƇuR?Cp( `sϚ0|i?tu`R `.#'.9Nb;q1>E YN^33aI- Y$;LXcvGU]$xC2A[w( ZULs>9mWoPKN1IQKN5|o H)t[ۍ|K'|?"}`BL-]^לlLR*opbo+6,rP,}G[ĞJ?fVJSpA,)Bq.(?yW% [;ye|nS yҵx&\A84 KRZ߿lfucK'EE_ѓo)F$'r aRq¬IMF mTn;o f^VҒ3R)MBE]溙{KQ4Ò`<}*l}mx'5llR}2ut>OKv6%'w N:#-1crT!!i'=Գu'?#吧0{]ew/ho ;U`L8Z_Ipw2u`E†V_ RZd'; -52tGdZVgrݬ1zbHpH3O_X\6DND֊ߜd-n?ܬ̺)/'/WĨ" PSr)'bľ&Ju&ҹ9`sQQNA̶ִљѥǗG$$7A95f OLE`H̍Cnj"!m!FRP*FQ-T ~L21I.#0Q<, KN) *ZW3|E.]  hſ6o =-NAڵO~ʶOC_ʗ1交Ryl]$7S?L(k)\N34d܉6'+/i!Ғyt^r0?y r򗨆Pȉڀu}Pp;G0 &bK~NV r taccU\\Q(zN}Q19voϼ+os|P!E/6.\vr*/$,%D>;^2R#js'cz?ÿy\cmoch *c%sIŌ,fKɟ=|t'.g҄1SQ +}t*ޣ?> s|nN.\\s~nydwhC_ړ{.'q9*XrUNsMof!-\b*>/ͧgR%C`~yGc} n兹r7^ūsd{rtfΎ9<4oS݉ʶ%;UfGg>CUs#h0,[ 4+;9>8:69;3oצ^}6ǵlγJiGՉVf(~IopZ~tG@ə/lOĜ=ݸgSwq5$3ȹM{VMsiyqU^=̗/䞕tԍKNfƜNHEQ ?y߽`~!' DɑϹ/] mdIG"nB6|9Y"aiOSt*9ߟvGu Aɑ7z~Zr2|Be)mx:} ePlDLsRQt|LOnGA-wLb`scc~洜Zʴ/'D QLN])!)_Z˄=WU Gk BHB_38j_"XYInNixC /!;IXc?zΘlm-(V;'Ű.T$'+"ؘ}Жa-NEݩ mIQoZ"US#+TD_ӬX ST&,gS'TLۭԊRiO˹:?@4 R SgKVSvJLhDcGF[o`Џàb[grݬ9ZS[ -9<3rv'kà}#n'g\~oά[ZoK#י\7ZILO.pN ϡ6?d7r-ofi<  H@SQ'Z0u&Zpo\־ mA@$۠S*?' ,C 5.lVuV5c<"3Kڂj]wI޼㫛]ꁵA`lF4Ln}˜bE[5Q,~ϭ >;7wy=f_n;^VU#8"scqL|peA/%N̏E %C~b#KSMuvKW|z}f$8b?Dϭ퇳nl|AO?=0WϞ/tR¦s\ؘbzΥu)6ef'1P8;&,_mX82Qܪbwͽ;Ĝa5O<:EfLNa|GZ&L*4qozXQNMm_o#0 S$^&C2r %Mk-kab> -v/Q DkS<\2bnP hhpcBEx.Xl,ǜg_o^{s1n;9:<~''j\2Zo&LUsc0g(~? *-/ΰ.ϙ̡(v:ke"/۟ŋ{˩@.ZΝ%K &%3`jct+ ;j(*Q>$R|g^'72g|1>*`jwvC痜<xlSۜ>ˑ/P%:VuJ$@vљN3RE~_ʁ,q4L\6 שTp!@@e-{- |G|X#aM'vJ;$&;#rE'AVȱ&;?֧?{vdn}z/~{ kHQ"ΗDŌIlk%x_B67̠P:(+֚@˔c{w\N{虛ơy90/O.$ B4l~)&?G I9ǶJ ņ{?4ҏr*!M]'ĞR]Zbo=^ UoyS_ocr"VEd-qZ/WN__.'g|9 QL6\/9aħ8}!B\$$;kUEL>L9g_~RTNH-rLNkyGc} n兹r)^C_i3'1h|lAϠ\[<*ikŨrZKabsy߱y<2˳ss~f..r+wd7 \Nfd/dE/\J9()]BWX/xlUh3uh?W%~cb[6SQи|\ v`nlOٱ9=7歟n|G^0(lfB}Ab) 3?Y럃9dcx.Δ@o gMWkmNl_9x{';ǧGx<5gg7?ZfJA2c'KK(:+^h-\ ;kI&p3I|VҘ~qӟ۷9;{q}ϬMZ?7VV)} /m9зO*:X I$_RYcvqUrezɐIhsG\F(-VHm>y c.͗C])D1y:;b[[p}7RlVܜ(],A+ʼn\?O@Hb1S:#F9`/sW۽&g?7ϮQm|b7 :1 @ T!3J`=2Jaݵg{=u ʃ@/@ Tέ&[ [{gM3nVךּ.}/-j 0@VMlvHw _P^~pPxiJp*#LL4q>'5?_ˏE%gԿ"Frl_(0 ?/oХopp&s.//0%ApsnSqs,X|c]\~lKgn!}`fWf+dQS_ʫȯR7+=)xO͖)=ZcS?u.98׾.*Gu7NǼn'!| f;zGAK19bZQo?peN؅rb3= N[ɑrbpxҶ6v.猱O+J^JCW+9?A&99!qKr9$:?%Bw d!1KT';}IENDB`V$$If!vh5D 5H#vD #vH:V 45D 5Hf4V$$If!vh5D 5H#vD #vH:V 45D 5Hf4V$$If!vh5D 5H#vD #vH:V 45D 5Hf4V$$If!vh5D 5H#vD #vH:V 45D 5Hf4Dd' T f 0AAbPeWA,n$eWAPNG  IHDRZsRGBPLTE3f3333f333ff3fffff3f3f̙3f3333f33333???33f3333333f3f33ff3f3f3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffMMKpndffffffff3fffffff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3f̙3f̙̙3f̙3f3333f333ff3fffff̙̙3̙f̙̙̙3f3f3f3333f333ff3fffff3f4f3f*vW pHYs+IDATx^kv{?9M3$&ۙ2!0%z&I%3[f߀]]g. T|/`MyO`rw,~Zb(dd$2 W~]DW $׶xoօ~T3HA/) =r>'K/z"̥WHuOǩk(0>N1X` 8cO?˺~wBg{' *lw0߷e-^LP`—{d]Jzżc2a䕡`p[[?e6 %3s՞ ntJ> w/{f.}G7ybq_K~?ZɁ3L~Tmiqɾrn0g gg @h=$'t ZLx6'-EO[N?~PxUv3Wg{*ϚSڠ.|rFz%g[Rᣁt!zp煴`Dy[,Am**w҆v-Zd̎Ġ-}|}:o/Do Lgswp7~|a_5`[> W71k|8| ܐzg@Q aZ|9__0V*9|Og(bzgWgwxg cαAT  `zf Wt҆(B|5O@@A`euWsuldfzP,&CP>Uw||֔<9U!_s,50/# eԕ+0xW.CqBh=b D*% *I)(a.R0xAzpqQ)Y%% =hK) `7xw*)aP CVSex|ao ,Oho~g B9 H[*m&ʘy`AzzY P}e㣗cݰYQI̼ᷫ*J_A|ŠG[eov l[䗃)zxΐ~E1hRU=<2a]`{216~2XA`Pٍ3+\AQXvDj`D.;(a~zP S{ڲgVP 5 ?u\e:1E..@b~y4Z u7`@?+D|}k9D`Tpliԃ,A !` ЃK&l1]=Vc?l|tο1PQcp\[?t?` X7)ۿ,[V7[*(a/"*@1hK[r<\{H+/A1.*lmQ7, /tN(aPt5Eq]Jԁdɶґ % Vz)Hb ZS,6qzy$BA|9g##=KxA/¶bkfޔ~ZG:xoݽ|Z*ᔥ7NKM&}AG"i+R*GçVvEѶR佔j t?`bZ ^}rc ra% fR@BeH6;n!{e"حTP€2mjE gŅ+(aЭ~8a{&,{8Bz@?v]Z vR Uvd(0`(HA-Ɵ殄ITP€- Iŋ.@B@'q,nV"? z` I\DQePN0փu C ^=z`14$/\A V=uw#,RvA% Ͻ9.Jg/\A V=`=XփQ υ{XTؗi4IMlXb{J"?|=0 ΀@ۼ[@0KoZLf:. \oڡA|I!;/K.aOlk?#zR W(^MeNg% ETҪg '[B>H;ub*4rJb 4!R?h1Y?`+ Jl6->v҃vz8C?;mPh`ۣLȱ'U M/ v;p'BF ,Az9 ;`o&+"SHd鰃 Q4~ Y6{6HRPoF1@tؚ|| ƀ#.|q){ack^\c9 P[QPmlbBWZlpi!<$xch[([:ܕDçS7TO_Ճ3vQnàA\ᰃ[٢?«" fXB\򰃛%; E .zBU-,? l YC (=h7QJ/\weS1e7}.S2Jb^y ,kP l\Dh JO1 2 >҃ A^M;U̎@p(%\[ߊAoΫ[11*Ad݊֊p++Ō݊Ġ1VdHtŕ"tWa'[KJ˘F"tWa. ӕ(6.exŠ=̎Tm?·H9^Et` LtF,Ǡ?vE;+ W H6qh7.~A=`ˀwϜS|zXZ~p*p =ٹ-AE/G"mI1qQ$Q 8 >`>:zPzn e:m>e㳫IA`ަ!z4'k A`g2 EnVKڌ^dxO*rTe@AU3f\$1`(0,l{avvA{fd聭?`I0Šk\kNkCbs6뼊'e|I/ŷb@AyBͽڢ?Q pމ2Qyˠa\73/w݆Ae,nW8,W-j]+|5c0EEoa8VI*f7-UIG5ƀe'UHIc/;@J~I4RoN1d;Ơ_vR5$1i $ߎ1藝TMc %vAj)Ic e'UHIc/;@J~I4RoN1d;Ơ_vR5$1i $ߎ1藝TMc %vAj)Ic e'UHIe ݧ_Sj*c0EG/08E\>طd0I" 3Y`2oRIENDB`P$$If!vh5D 5@ #vD #v@ :V 5D 5@ P$$If!vh5D 5@ #vD #v@ :V 5D 5@ P$$If!vh5D 5@ #vD #v@ :V 5D 5@ P$$If!vh5D 5@ #vD #v@ :V 5D 5@ P$$If!vh5D 5#vD #v:V 5D 5P$$If!vh5D 5#vD #v:V 5D 5P$$If!vh5D 5#vD #v:V 5D 5P$$If!vh5D 5#vD #v:V 5D 5u%Dd#  T g 0ABb$9'2r$G'n$9'2rPNG  IHDRSEЬsRGB pHYs+$5IDATx^]ͯeQg<_XJȋ`YYDXDYDbH,B=<Ɗ 6B(D EHH"eAv`y>gz}N>xϭ߯NwUw7La`b ,&W jW߻~&@d)R6%Q^)ys^ew/ӿ|Dd)ޕqs۳fܮvm7۹ v~^owc?~>|rGumb%?|D~*C'RёW6W/N׳jws ٜ=_\Ty1a\l^Ef3߬f|٭ֻͪ f6s-Wr)˄ 0\oլ~Uoβt5gs;ĭ;̈́Eg=00n$^[}{y~;Mc+?nlUS/ n_Pj]11('KdӽznsWɼղKׯ^z^T']os~KTzԿ扖h0$8o+ʠ\?e_y ߽ٞ[UiIM(yÞVfnwoĞ5S_&A$NQ PN<5a5O~տg{{2 ie8$j?ءDGUa7?z W?wy/f*~7J=`DjUH QH$e]*wsPWԷ:T_ݯ|`uھU!O(R6H` Zն9wvoܩՑT3=g_YV@ d࣏Vww;pޮy9_-fXࡲm;_?)RIN5*C'Ro|'x_~U;"Rda(T/~;7|JUk{]ޟ=g_GN>G{1f訤;YD??XܼD>&N9oP/8a~7s?:ZKH 2<{GX4;kKo!_pe}zWx*Ͼa>D5_X"v_Xd"/uClo8rQ="yCV#_j~D?i^ow*SIr#jض/G$z"3X, ?ߩНwfvG)~6-i&q!&2.#m+[.p9@DXFq U?FoO.h)Fd .dd`G^ <cNt8~z|wUϻZ`v9~~DBw~G?C7n/>dibXD!.l6lGF]t]ÓFn|q~RjW=hDyzΗ>qbP:J\N 8FMԕYBD|jgC ]îoS& ?=eh($BF^/z-SEne/Z)ܰTSCXD?sy؜o]D.@pyNZ@GG1dOzb@"0{g"61a@(|n9",}%¤.M*Cbe<ɓu_O1Sc'v7M-hCDe/͒zHWxtokvCrWf 5j D R:R~w+I}T }%^Qǀ&+$F' 鉛FeB))TSw*fT7Z$U_dq6C#ˏ]-":}x%\dz̄ܳۚSwuCְMljm/jBCXFcq#GނK: b@"SzQ- z{Vvǫ28t,p"E``P=7 X[IX{ D¾fsy )`3t-D|Ԋ.HW>yxC M0 atG^ PۯdetQ+5, A>{p ,|֬()(ij {<|ЀIX&!$\=z/a;YL^0Õ/`J { #eA,3uY7U,ձ,>Ƣ=pUqݗ+_ue>v`w 9?.m 2R4?- [#|?DEWiBlZ =E!!+Qxן #Iϼ_+i]\P*cC{CM28E-,pt>0 ?; ]l.ag =6& H#e@v)G" p oaqv"G)A K]9Ed=HcFڦv^~3;^~&h6.uT-[ ۡ)' OVޤObZewiզ kуٸAdu3(O|z;Ii>V0C$rt!'olz*Pe5]`[6ޣVm ÊAV79ɨ1.p xQM%G(>ۢ[#ϩ8-Ma Gi6OmMG_$zȯg,0@g@ѹIa8ސTvǫ28,p"E%J)cAS=Moo${l]xACG |QpfqcnްAbPTSlWZF.@w$4,ic c k&Kx#YPFr͛RB ZZ櫃#.[,n)z>Ї>6ԩcG u])5%hS+6vcGVՇ}ro1{!Slvt<߆^k3< Ğ[4ꏊ \~t+?Y;y $ݏ1JO!q]Nz$L@grQ+ ̀D~# z@ ]=+Uz@L8,wDjk D[[SׅK ON~?IAן#I/GickWc>jfWwY6'S=O*T;ptWdA No\w'GŀD~`D413-6BG}DBԸӭ:]md>+鍰`Mq>Qg|5Hx݀n94x}%)}]maSuv@d Ջ7{n5 BDU-t.=`Oa[Wuu@I@%DV~懢HA-@Ť~RlRg:&y~G00J$G9lb0Бב@i. ɀc;^d)rWOm] :cBba{ ' ?o;Fo 4%ED%"799\z[7l#qCf)LȏAC}>W/"o-! (Zj8CtJfBWjsڞA\=]ޛ JR֬𕟉 86 H~;8L$𑳃͖~Gy'B@fN<K9߂묐$hodɜ_I@v$S,2 w 1I2 wWepN=M8,wt-m2$q~5 P?9 ޽yoLq;_ruX zۙxÞorS׾ݧ~nɁ afbRዧڇq-R{00]m\~Jo[yQc+ujSq߷%ã37ƕO`wP Љ`u*9<+PxE@/t8g{oN6@ :;2'S:"Kb @XDc@aE}^V hW(M榝&QpyDS BG@ڄˏ6F1e)%wm9.֧wGF9 jɧzjz/\~ TӍJsa@(<:b0Y+ #;^d)zDb#V#kQ}$roU n(fin</3|\ӏAs -=Hz퉲#J+G#TitPxrZwsB;?QNo,FQ" x'Gu.:N rϢ|X9Ǣ# uIe5"~ t:{$ЫY #_zmR D"_,@B?\=&mk-O"" jK]D;g~y>{^b]2­].y ʯwF>~;Gx߱i. 2 _ࠈI@v^va rWoxUN(]=]mvw8X4 [Ajf[;IAxG4sS=NvW |犺AoaBg:M֧seK! ykc_ 2\;!Tϓ`헿גh%z k"u,hk6ƶ~?JmW7c9.ŀD~m:CBtìLx9(i&|/p;wGJ*[GHC"? T%6ƪS0@f@"LUgAZֽ܅^sS{7$'t$842դv$Sm핋 }Npr@y|NR@ y\+6x}[s /Qޕ|j?D 2 _Y@V^VzE0oew*C'R]=eVQi"M1nm@5o-a/W&v]D%(굨:."RUn$ 7-qb7-v8;zI@[t"m `{\yRgsH!hCf C ,I-&7B щ}F-2P)D"?m$Mҭekw-x #{M"?~4 -l2+ zϒ25!cH{T܆gH1flW GlVvcus 8Iޗ1sy#]$4;f dJ4[ fLT.lQJD?mM#rF<)_7iVLj*|s?;ͳK$zw'|~p;Z9eisnڄma Pj(/2edG)Dzns+ȷ_N{z!CyzRPH`t1#z|wt"B?F؅|m|2x Y|o "tz9 oy?-鈓͐}, p> -fyx&Od函kH1 [, ˀ+wl2a Ȁۣ;^ z,p"Eճ%cܵ :Js <ņT2,r~Sꉰ-CDfЅ/>r•_~CΝp|r^,Cm[?1; on*eg<A\0>@˕)mߌn@NEysqs۳fܮvm7Ɔv~^owc?~>|rGY(wҖD╎G2mgW/._<|G.=rՋ'W..<TZw-CH'0: !$'j?],7r=_mvno6F-gݍ[?b#?"陈,yOecW m6x:o(FX;r=*7g'6j~;$ܬug=Jț5Q6Eu b0%kv7:y L䲡&z&ߪ^Mg?7?Vsz7kjtN5J32<*UUO_|b߹vK/=U0(e*z?HÛkڃɀBtjJKׯ]펏Lz<ϾwGph E5䷭կy Fp]S`&Կb<}V z1wFҽuM_!=s%# VR?.Eq|-~k5;uثUث}~C`O[P21w竪~{zO9۳7K/XZa?Ta_%𪶯{xlo^;Rvb6H7<ғ0}zk߾}` M%o-g_sy#l_?ƿǎxn?}*}нO,ٛ,p"EWuNjY|vy,6_)jه׺0JcO^6XHH w(rņ8нx㣏Vww;թޮy9_-Un6.?]iF Ad #.G&ʌ_`qp hB作@~s'Ru{8 \/j{o,>(X||]EqSJgyLo<ȷǔBW.G⤇^wn[ա:ɫjo/"W/|S.V7"?9YPJf@vJMxKđIENDB`P$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5@ #vD #v@ :V 5D 5@ P$$If!vh5D 5@ #vD #v@ :V 5D 5@ P$$If!vh5D 5@ #vD #v@ :V 5D 5@ P$$If!vh5D 5@ #vD #v@ :V 5D 5@ P$$If!vh5D 5@ #vD #v@ :V 5D 5@ P$$If!vh5D 5@ #vD #v@ :V 5D 5@ P$$If!vh5D 5@ #vD #v@ :V 5D 5@ P$$If!vh5D 5@ #vD #v@ :V 5D 5@ !Dd W %vT h 0ACby2ev!1U$SnM2ev!1PNG  IHDRz*K !sRGBPLTE3f3333f333ff3fffff3f3f̙3f3333f3333333333f3333333f3f33ff3f3f3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3qodffffffff3fffffff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3f̙3f̙̙3f̙3f3333f333ff3fffff̙̙3̙f̙̙̙3f̙3f3f3333f333ff3fffff3f3f̙3f-r pHYs+IDATXGXA %?a-h:I$xu?S~ BJeo-؊~ʐʎ`$p^q.Lx3|}_9ל[xUF AD<{uPoJj,ŻFYIENDB`P$$If!vh5D 5#vD #v:V 5D 5P$$If!vh5D 5#vD #v:V 5D 5P$$If!vh5D 5#vD #v:V 5D 5V$$If!vh5D 5#vD #v:V 45D 5f4 Dd7 LT i 0ADb '}b5XW Yn '}b5XWPNG  IHDRUsRGBPLTE3f3333f333ff3fffff3f3f̙3f3333f333333332@q3333333f3f33ff@Q3f3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3VVV_g^yffff3fffnjff3fff̙ffff3fffff3f̙3333f33̙3fe>o[ff̙f3}Ɇ3f̙她3f̙3f3333f333ff3fffff̙̙3y̙̙̙3f3f3f3333f333~f3fffff Z3~ʙٷ3fC*t pHYs+^IDATx^;v: tڋYGREN3tTvd*q;$HaIAI0ilYEU`eKPO 6sC}RVϒ~w89c]2Lԑ0B5RA+GiȻu$I$DнZh^7YFN5h>辣ŸZ?8hx pwAie 32Xg.кx=Ԏ PrF\FF#o1t'agF}(2ݎm#@ݐf7&[kzCiT3ZvL;#ټq(|mhp;g1&= :ٖi&%nNk5W܆D }CPJϤGt U-X XxIT)m'(u}(BF)ˊ1> j&g¾dwѲ֚:JW8z%P:d1!,n6Tn风iɚŵ}U:߾?/g)+%|9X"X{CHo|y,_M㠍ΕHUS㠁rŬ?Z.5u4 ⢋4͢FkcP̻ sY 1v<sm`,լE[c}B4L|6mA>`Eb]t ڄB0h١sD+6*KEDFMB[3:stDf)4,Y%ߊ5֒EsUhtѭ ZoCv&ySoC׼ZBp4RT Y#:RK-0;.z%vm;]ߗ4`ZK+.`XٯWXYdI"[ب:JE "5c ]']uUZ|OS4[.RO1uQ-rU$|EIStfXVul٧.KY2G칋4qD* z:w{/1GY~N',v&wѯyCS/kkG)n"5ţ)2Srj&g?mhhb\2Ek:3r+4U'`>Ո{6u"-_@W:Kt?R}:C-Z媪78Z7T Yۤ:30+ݍ?jf\A;fEPHK lJ=4}x7]\81dj`qǠqj~Lq<#Ҭuth"l;ŷ/rcI9ht=lX9ӵ݃6FKM6ڱݝf {87}Ӟc<,d$63g1'uNn'ZEz2LK:ߜ8{~teUw72Sn8-vk٠HX8np N4wdR Mw 6z\ +.`X/؉l11 YczM11։FɲIENDB`P$$If!vh5D 5#vD #v:V 5D 5P$$If!vh5D 5#vD #v:V 5D 5P$$If!vh5D 5#vD #v:V 5D 5V$$If!vh5D 5#vD #v:V 45D 5f4Dd e&T j 0AEb&)Lz8difn&)Lz8diPNG  IHDRKiE.sRGBPLTE3f3333f333ff3fffff3f3f̙3f3333f3333333333f3333333f3f33ff3f3f3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3XXXffffffff3fffffff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3f̙3f̙̮3f̙3f3333f333ff3fffff̙̙3XҥŬ̙3fٵʹ3f3f3333f333ff3fffff.^鯆3f3fb pHYs+bIDAThCK09%q=7+1י y,B,+|No7zC=vjˎclq,BVŬ rPŐ<ւBEոBЈYdA~y߰xsqҬZvN@g9`iViӜYic1m~zbygwc27cl\== WZ)5;ńT֩pEX^ò1r8۵OD toz [Y,Nan''NHKDZIU=q\;=/v0 i_nqɊ/E9ܿX-,6F|Rϕ!kXGB_qzB̫__WWKuezwÚg|F$=)0Ա‚Ha߽K^.2WezU/'^kD9K Uk[-'S' I{KqCO?ҝ*ҫ~IENDB`P$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HDd  :T k 0AFbF<3&nnF<3&PNG  IHDR?&l~sRGBPLTE3f3333f333ff3fffff3f3f̙3f3333f3333333333f3333333f3f33ff3f3f3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3vvvffffffff3fffffff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3f̙3f̙̙3f̙3f3333f333ff3fffff̙̙3̙f̙̙̙3f̙3f3f3333f333sf3fffff3f3f̙3fjC pHYs+RIDAThC PW~*B;AB۹hau3_NFh{"h.,@~N3#4RTbr.6?SCC Տ|(~ʧ+W&u]OӇ4 Hͯ>ǔu?PڗG95B?Hm+>SL =ӏ~1X7G@_L /&fy ^=>:g@1~u(~aހV]IENDB`Dd! *T l 0AG b  u&%tn u&%PNG  IHDR@%sRGBPLTE3f3333f333ff3fffff3f3f̙3f3333f3333333333f3333333f3f33ff3f1j3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3srmffffffff3fffffff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3f̙3f̙̙3f̙3f3333f333ff3fffff̙̙3̙f̙̙̙3f̙3f3f3333f333ff3fffff3f3f̙3f&C pHYs+gIDAThCQ `Y<:enӇ65K Lf_ Ccc '7L`` Q.z7A4?Ad8jm&(s?î]~vZp-@:@H6NJrƊp7X^d,V=%=/} G4#S8k`B <Id:+I\:^$ NKO qViJ&z:#}T`b8"a=u8zL}ʡN_>A'PtmmjϷp;Z m/+9bIENDB`P$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5H Dd :T m 0AH!bYןt1dCtb5{n-ןt1dCtbPNG  IHDRbI`sRGBPLTE3f3333f333ff3fffff3f3f̙3f3333f3333333333f3333333f3f33ff3f3f3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3srlffffffff3fffffff3fff̙ffff3fffff3f̙3333f33̙3ff3~uff̙f3y̙3f̙̙3f̙3f3333f333ff3fffff̙̙3̙f̙̙3f3f3f3333f333ff3fffff3f3f̙3f/6 pHYs+IDATx^K0 9%qE^ϫHί2SQ򑤯4 k-C)T6e ˒$*6W*%p*㑙 S(f#/`-L] Q!R0 TCa,@KT#cT Ml,GTU>cЂ.3mTA$U^`[,#nti(΁h.`+3J!qjn(,G N;# q29p[ ;P ,*Ί;>tDOF܇bD-7Nh3cZ6wd+wU (r.4_KTnr CRQ-34E*ޝ@7̀p8I$ *DPe> )-cK0|V;T9REe>Ń^ʟ*߿G:ڦQ6D۳l%MSLm~s_GeEeb KvAàjĉ?k|@ bZI>2o^^^?BX pQ+˻sA&:].eʺb^P+TAIn:+TDN:e݃Ji=JR(7-3i^^%Qwv%$kzlrFP H0!eǃAifă"Q-@Bn Y-&.3Σo>GM%PȁL3M+*ʐ̏ " tOڧcԝh^O8ƊǑ:a,T[ G|LV9a(?H@\hD7 w[%So+<\4d5)ʴʤ6뜷=en-E%o|6ak"TTֽfޟ_ylG=wyc]#XҼ{TqEfvtih 6sH}Ȟ!*X`=(KQ*Xd \FSIgh.PiĆGC%^48S` "f+lce4 8ĺNLס}0lXU> p6VT[6l{6- ɋu(ifgOQ[VwH؟+{y}[74@Ld>+&cIAuFwIKEf',PurXĔ+Cfv#B1E0M gerb2*&ɃxdLHWAbOԷI$IENDB`Dd; :T n 0AI"b~dibn~dibPNG  IHDRccV*NP3aAh2wT xv <)TBPG4m%@yBT(T)JpHc舊V*f8z ܑV`OuC{.}DQ+]rK%aRC9I07 ״5Q3Gc4G Lnr8(rw~u0>DeA'ZuGyy϶/L'ف7mȢR%vAǧAm#ƻ]B*bdw"h|?c*E,| ΀ \I^qFaI+YTR6+űC TqMyE lT)ϬT+Q*J)Q#3iԊ%p ܿ2 "9ܿa#T*oʞh&ݾWVv=zώKV t;P'{P!oY o6g&{rn¨OAa(Lsu;϶5Uf[VWG<~u?RA#Dw|PVZuZQVZ VZIi^QVZ i%]m׫+&QۦT,vkTJ V8DYY +T*^cYb)"ab*dY_ }ae($("@|8X3nX{ ¢Wrv&y%#(,Rramߖ֍A/ 0^p(̕c2_,G^Yl^ej8(nϊML#J=aa02:'Z)x<*'O?q\9< &}$L+ɬxgTY?+=IENDB`P$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5H<DdG T o 0AJ#bXF++r(tpnhXF++r(tPNG  IHDRtS5qsRGBPLTE3f3333f333ff3fffff3f3f̙3f3333f33333333??p3333333f3f33ff3f3f3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3fffgg~~ffff3fffffff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3f3f̙̙3f̙3f3333f333ff3fffff̙̙3̙f̙̙̙3f̙3f3f3333f333ff3fffff3f3f̙3fY pHYs+IDATx^y0 3هuu,Y&'/99?cin=oԵqM*r mh'Ymsg]u4J;H]ݗMaXd:ᚬq:ʲmiq S6u$=t࠺Z0Vl7>!{Ka +ht$N+F/*s]#(VXY$bDbTc/Y D]Xt (m9lPS*eYSmv'=Ov"/l6& y&LKį5$Lm~ V@*Xݍ鸟clcyN|Ft?_u s)[{530M)eBq;RJ=_6sCJuyʏQ-+c u^$<&XhDxfxj t&ҺrD`!ON;r|/J^S+F !늅2tUeJQHL =ժeu?Ge" 9ms]sϹx} ~NuII%$#)X)Y>2qIR+~Ԯ<+g]SYdK,N@>2b"2V;~h\UdLy [H1X2VJY.a1]κY鷹 Ƥ<Gy#1n8\ ʃ'ᝆ{?#{Vs dd>s~ޕf|KO7=snn9,d`X|z=۽Y7JSXa"H>u-uIENPBkR5YrU JzPBVM Y1[gMsɣɮ喏ՖTmleՒau=fb nɺÒs=&Ϻ%5 Vz}N:9v܌uX4,{9ShIENDB`ADd )T p 0AK$b2nla16u3nm2nla16PNG  IHDR6\4.sRGBPLTE3f3333f333ff3fffff3f3f̙3f3333f33333333@@q3333333f3f33ff3f3f3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3VVVgg~~ffff3fffffff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3f3f̙̙3f̙3f3333f333ff3fffff̙̙3̙f̙̙̙3f̙3f3f3333f333ff3fffff3f3f̙3fs& pHYs+ IDATx^]( 6MO_:3B<0Fn6EO\_z5Q:@N3F?&j_I 8LυPmo{ceh 0X 7itIv:$ȏzjcn@Gu:ܠ3 ^ewspr +$3R@  B@K\R T ؜vVʥ_Cy勗 q24 'd]t4e'T=c$7eg1W$ib4fQ.ԍq9@K>_$GZү/]$}:aCT=PK-\+J: ńlQ@MQ 8`?csL]9г=şf@rG3MwŨRFy6BuP-@nw CY@2Ph~2( s.@:}2s[0hh_w]|/3D@DBݿ3MPePPb/J1 6PXiGbL&RTS苦D1>z gTQGOCk5Tx`xw5@ĞJD,uPI$grDfTЬLЦ*PI,@Dɏ8K"/IMs)*%P\W 8V`t(m&+ߋq=V$ CogKn~u!*XdEPTVp#PXlvpv>33(m?e mӫĨܻ$›"Cs#H9u }x#.Z풩ų) U%!aP8H"TPgIxU$R#mMԪ$S]%Jwxt^"YB@GxvDx9GL%!Ҋ ̰$1QQcTi *%n7ƨ1tg0UJffJKLW)q*-3]Ykktg0UJKf]_@_tm.NfI.oPk3K#_k@/hu@ߠ#=.XWKw}$17M R+܏Ҁ)O=Xי_WgƎz+x/̽U[žnզb .qZK>#20lƏpŸifQ4 %_G(v)P)|n ل{Q4Ib!iSKOFMl(h(f6}@Gz4]LE,샪Q"ґQ<<2YEQ!{ydb/X|5؝{^)j ëx/Cb"R`]f7XzNe1e膃=~ $wc4BgT;rB&h E@{[$(mc*&PPir2obţʋbl8H{N{<Ɔzn:goٜ6g=ٱKcvXE}t/# Wbnze.5C{i-7`f֫kvqQt#r^9Dzl1mQK5JC!!D eP9*[kfFWH"{DJdRP18Oy]@C(2b4ޤ{|-u1uwY6  \V:3z6(e`|ha_w=@Upl}|>hzo>__/*ЇFtNV8&W㿿 -5G S$xf~V'ʷ~\{|Ǐ= Gg"v><3tnц́%! ؞d ٿjD _>鷇+'gϮf:2뗧X=6wiYGRWX#ټs}>C ؓ-4_.96| i7b:6* 77ǀ!8ŋ~~X΅i >”G0A0Y)OmX)ʊJɼk{.㋸#S0O?i{?zǏ|0iNv0=U;O$_z.{ay%?|;6IpY|_,8}|"WWO~}ɓW Xܩ>5d6** M(W` 5BrfS2;<f ^ 6L,8 ?]}yz+p#lFY1h ;ֱ'PV]:U/7,΃aVuv0hg^=[F'Cս_?},:ޭByV԰>ݸC|\OwßE0/g4ߓ(P/~ϳ " TڟUʓt@Q<P}a>c]+8#+e07I``p޽O|ϟ?}l:<>wmMMcFeP܆uce>-_-2 *) Xz``#`{_8ݫѵL"Hgyحg\y ?AJvRڄՠVAŒۗl"a) Gs8pz8U*|&LCq)e ԚLK߁ٯ^W߼yq7N6)Sa^X){xTt-Qp2e^ 6ewXS0e˷:Wv?7M?~L={OB(W. ,gͯͳc@.3]^Uq[71(wrANg&L@A.' *DI YyOtA&o;"pwDՌ@@ĘN# LJ'ʷ؜;΍ڐW/t5 /d Fۂ_*o;ll0 )|tLkKu`vRcͼOMOg֎: iiFG6qTq050+g6; 84GUI]aRv jL f5nWW{:]YZ[oY7kisjCڠeOm\ݜvkeIHJ2aG%ҾAJ$#t]DalS]bZD?ӽq|О敲֨NRƷv46[,S@mjLջyᓐQ`}=,Ge㙲hز\wkƍOTC.rk/ڎAk/1~u[jWak-ᚙ;}Zng:^r `>&`p; v; >o$nβ0líp04KZ$ <"zҼE=뫴aLoy BPto IM5g+_譨F op=+t{ KnP8"\_WjUylY>U)?gjQ.o~,UbU묺YmV>7'7.AtӬip֘ ӎ“Y@}uhlF e6Xm{~]-LBdX@#QL<={$ۅGN#7 p70r''y7'z|̻8?#` @yɷ'nwkkYrZwi7q:o 7}W̳ow7XDF0N!|Ir@[*`Z<ݹs8pCpptv +6xvUgr$A"Bl@7M9>SHl X7!9tQfpp#=&홂:=&7o {-5!凵xXcvA`<1 vam0]kpv6k̮5ѓJGq||pR]+Jח9~ҵk/w;0P|+eqGm:vDj5Э \\7Ú-:/Wpͮ?0wzC׮C=ٶ 8zkfEBO.=> 39ǀ [s¡1 Xoӿ~P57'(lny\.`sv^'r1; x0GG'nqdtO^w3h[se'D<_ 哐}^ۗ**eڧwk2- [[+n+rv?2 @i~8{p L ?#NkNq|c֎#vf>ohX~q=_vŅ(cy+`3uˋs0kˆ~0]Vz;ߎv\ W(v<:2pY ^;4Cp^+`2^;gUB;^^B?8>EjpxVruX]o"A*}[7,qJ_ޚ#'NEftmN:{W#j&n0y XۜH҉I= ɽa=k>:;w(`><z`kV֓ޭ97ppjֈp]u|r;gU':`_~DD@A)"*!oDhA)ׄ(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~ErL p..bqI3A`2A@&LHנȻfIENDB`V$$If!vh5D 5H#vD #vH:V 45D 5Hf4V$$If!vh5D 5H#vD #vH:V 45D 5Hf4V$$If!vh5D 5H#vD #vH:V 45D 5Hf4V$$If!vh5D 5H#vD #vH:V 45D 5Hf4Dd.:= GTTT r 0AM&bmٮ{$D8InAٮ{$D8PNG  IHDR38sRGBPLTEf3333f3 "3uf3fffff3f3f̙3f3333f33333?@?6FV3333333f3f3>P`<`3f3f3333f3L33333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffMNKpnd`sRffff3ffllffyFfff̙ffff3fffff3f̙3333f33̙3ff3xff̙f3}Ι3f̙ޥ3Z̙3f3B3f333ff3fffff̙̙3̙fʢ̙̙3fÿѿ3f3f3333f333ff3y_fff3f3f̙ɿ3f{0 pHYs+IDATx^;v:= 9>n$9DӊzqL$*f(Y “?mwj |Ir r{VH&YgP3'`0sr6 lO3(zs`̬@_̬XN©:fV'ZVuj̥?x?].*9i%3[*Lu0uNݭB(Yq뀷Ϻv/=;̰p|^$^tvq.&8ffuz .f2w=4m3y}т@2C_˲atKb#x~o7Uءvp3@ڬkrA!M7͋)P=3߻K,f:c;,q_19oLSd(eXOꤝyߗ/y$F1BDWi2[`%''Y0xv]Xfq߿j|nj#̌GJafnw43M:~zz<:x/|)3}r+*:_ipԻ#^jG2Cr㹶fUVmN_Pji.n*43?_zc}tjl+"IvlߤV0|tq,>o=>sޯtkr vׯ3uΌ.8Ya2abF̝|S+̐"|HtZrg@|GM$nvFs1ԗKό̴eFh`qrN1p,7Ib"^կ,MTdlE:؀9H8\;2l6j0o023.Vu -f8f&ʪ?2V״O/W2S|hG"RԞs+4NJM"K90J=ԲSp΁UIU3ĕeGv6x ̎YN=")ה30Sf)W7 ̔rfM=sڏgkTwPQyӪ  N8 N烙HṲt;퀙vtj$`&i̴T#aFQz!*O+\n1p*3nj`)3O13@`fS3 A̤V]1p*71a@6)jrgI)ކ3"1&I3xx}Ӵn^X=Z  և&m=bl}mpbAB$ȎQi &3n#x:̹}h9fa|Y@_BIMF79b#=H}?If8>2#M~fJ0 2cHs3G7J>f^ex:̛\S273MQR32LQGɒ\~!|ɍc4 ʌoqQ%;K,C?c4U& 7raLker`jR.j j`g).~f f$EF0ߔQ&3SRac f5Ad7X=iPf" LJ<$Ӌ,3 *5\f :"ov;o*09BliLl W?iOGfbKL{:= 3 MwsWܡU}̔D- LMՈ87?eF`eF~^|8D L3u= f-3mr- V$9&t"#_L xpNlil\($3$cƉcpv&^c!47cemgLC13'M  ˆM~r'M3ΰ*PǮDrE~xS% vfVfff޴hM\}]P,ؙQ;IO3'Ua;`椊1l0Cx'=̜T;;驰3'Ua;`椊1l0Cx'=̜T;66xBOrF=YS\f림@33 l׵smߓF3{=W]Qylrה/`<23 `32h_Lό?@ 6i۱iTȌbd:Qdj8ɦ*w;S,3d$5w;pᏝ4"480ؙb3c6dlFt11 .2%-h  ݙ5iBڕ04'2Sk9/{UM\;Xyf2 fLu0I7 f*V^LYTL]$3+/SL&W,Xyf2 f={!yr}4f7 5~bƼa~f`YhÞC(fcfإn£{J;`}Y0S-3NS;G7/T0޲fEv xC3!wdK3w@(oؙb 3#wonff7\{rw_1L} mMX)p!`E?~obԖ#>f$)޺dUTA{hh!{ ;S2v ꍍ=[{*3BV*eq3PML62g73&geG /bDG1Q ff;32ʍ`'nOh'f$63s͌ʧDec\ g;3/ y-#&"gZۙǶnLLglic+FK 8|R$D.3ͩ4Lt7iNfLs*> 0]5fSi"n0ӜJDqs T}@`&k4g[ bp[%7 :oPaНR$`13ѭ^`z&I.3ի0LrW ^fL*L>0\7fWa"A H`vХ\ C?j@FM_=IENDB`Dd T s 0AN'b(sF6F n(sF6FPNG  IHDRXo PLTEf3333f333ff3fffff3f3f̙3f3333f3333306<6FV3333333f3f3>P`<`3f3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3vxy`sffffff3ffl}fff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3f̙3f̙̙3f̙3f3333f333ff3fffff̙̙3̙f̙̙̙3f̙3f3f3333f333ff3fffff3f3f̙3fqI]IDATxu 0DaUw_ _56]-lX\)/Yܫ]ktIKmVo@ VdAoZT`PyXL)4]JK'NUz;7cmyZJӶXX)r)4$zRv"e=Դ$6Njȃ 'bvdlVƚEeHN^8|Le]=KheVfT tbO7z鯾o͊~ݡ=_Vgy#gWNr=hsN8"]=2Lߓ2 zkЀL} XB+AIvJ kzD'Zg'VBf%>ȿnDgbu+|e+Ў/VAֽI򝯝os|dxo%yQwwU? Z]4?q_P Ȍ),Ɉ73LN[S2dIcd90Vz,O:º+: -Bi/N;ӓΔH'=Q(c#Q)dUIe\=S{I{]!UùG&^qןZ HKO䈳; Y2x8+*Ĉ>鴓NXql8~8z`]ɿq:R}ɲmfPIʗRId{'w5әV̍w^x}!+995kW'Nu^?fXg[cIxw,ܵ.-B wk`KVzJ+2٬\ԝڠ @ah;_%ueu֨gWҰC+)r\pˉrxW(2lE99gjZ^Ywzq/,'W/0d䞃߸촍tޛo>ovv=qV{EkAvm}W!j_*-;w<ڝw[sO6?U9GXYZc/q \sKW j VΪ\]I@+\k޿;G^wwmX9b uLdY{ 5-ž䬷_s׳-hӅ?XG pĝ]]ܓ2 oz2'~]"-U돊;MSv[a/T4NtYW֎$Q+y2N-(IJ"u*?vԇ<'O|e>yjI<]Wt'D=dwL;Y-8;F7@e>[]yx[|ꙟtKZutab1~ Y`~zw_.SAdϜi=f{۪ԋT)(U5 `ɵAI\:w}J3Gr-e/N.&mewjCmoծD> VSDdvv}CZgg+:l[VȈ:mU]⒄%RܢtʥvrrbyGr/-}mK҉_r_n{9?xd[=*vU*vwzָGU-PWT5_ȧѕV*߰@%[6[>z[MS[ROފϞ=Kd\kk7~_ E!pks0l %jME=v ;o[,DڕȧJPӜt84,k/v}RgJlQ-d`DJž8DR@?d"_]Sۿ{o'.{;^z _7VPu+Ν+)ѯ7Fa9KT<,6]i%v`+rnֽI =#e}}Wm=1n">"ԭ3_ҲTQY0 8?Y;dTRFC&ffɣm̈SشAkwfW׮D> VNP*CEYRY/+ k7+/rD";.[ΠA%۲׎;Nztd_~xi _?:}Ga.y}ኯ'c };o,uq]r\[ܹn3\,/Le9ٽfˠKgTj2^m@iߧU V=]f^e4Ox]6~i_HS E}jZ=(Wɕg-rdWp$:}%_kJ`%)Qg5lAɠrmR]\מ 'NE4ZQ&t-̒Ax"7NtVr (:Q==5}_y`褬QIg'#rSg=:| #;.]RT$eFaR-/w=q{7&I5BK'-PȫShx|ekZUUVߵ:^q0PU zf=_۟̔Cuco7bK@MaVcj౫zk! J,-c֮gW"okJ.%+QDnhWtXXp*}[_I 2|sPA lHaQ;}˻MO 7!WG&2l}`x6_?+N*){QV¤RMȼ;82AAȋdju+/^jVy[R+w ,{ y[ٮF:om5^;],r:P37\[i媠r9)P)/WT \.U"Ȅcw8Wn-ck~}*w~蜷郫es zWf8Wx x{F)o׵Wpg_TOZa-/V+*zkP@f(+MH+.5! ~u&&Zd|;{$q .*yW ʁx_~]۷J+*i9v)ɣ3OHwJrcCh9>Vo~jKn۝&S:˭֒'c^#-Fǒ_\?hѠqpqdUWh}zμLz;.wV Ju}u*L:=wz1@ W݆:U@lmSkM=r8ΞX^<`N*)lri.:eIvPs䩥r+z_pW%˃vJkqb`O˘x6Ύe [ǝo->V89kL[;^u/Zo8T '2^:^e;ak띩ߥؓ-r`qۜc?jz3V0ܰ?r_ 7>r`~[i'&ʜ E[f[u%%?'za"%/M ,Vr=I][d:]BvZ ddq;Je񚗬 |*-H;i(ndٛ~Kb({.|}H'+:zD,cDDf  WzPFe1-X뉓G|ޯz4FCSgKO=?K 9&b@|s?}_;dD 5*K'7$(K nH2yh_y7uTrSmpOs;{{dBFZ-JUS IY],$dZ!oY^sI叿qOdv^a-_ƠEe$;Jc2\'@JeTYs"v%ܮˑl(]kzz{Ƿۮūڴ7稹̦T%yQ<,m*k;ӛi2S!r tbJMpsg5Z;եeuַ.m#j͢yn?$[@u u;HHҒEIO`$Y[?)jΆVȔu&W]Ehxe K,캡b{;5QjQ)$ڞd˸[!c % -f3 '$ByErD鸫2#WDj=nUh_%Jz/LƊm.wy͵4+4[,/_W qSya|9 NXyZk|Ekl{@r' m@!@ J640@@0mh`0 M `(` >@P,@4}@#҆ x[)'x! @qJ@ ! @wG!:Ae@; 'bHaqW-xǟgaU 9t1..j|}ZB<>W!뵧p=~-[$pU_\:=6Qף<$_:nj@nE'(k*XIpm}& PsLlr R_7mrT9=" 4cБ 8AQ!@G%Da~~mcڸ` M'@g+gY{o+[Lf@͈V,@7;ֻ[qhqv@&TZ),mLW&с wKI"FX@h2\12hyѰ0DR4fd@UGd'3@+fH}]E 0%ɠו@;s{K mC`+(~icl2tp unTCnv}k%0Mqِ%9ks$5֔J*>%m{JAG;19FtlB@@-b۝lwN۱c莡a@ ΎhS3ۖE`!28dNfqh6*_xct8 kHcTgU6iAg<:!uy3+ OkYM <@Ia=2/fG"!= SfB:i2S?qc^MlB8̴63.X}я=D  AI*!AQ&+ P/ǁQ%_ P%<+J·@Cs}䡐KYbv$;l U:l&bZy_Z7NzB@AsnvF7Cw;” E@:: h9fMy~-a ІsHYSzXnR':&H`^Y:&M SR2F;qs'@ϝgO`aǚccpH{')cX"tRmg4>iV!TtSqRYxҌ:w.dtR]Gi|mul}Duݾ&i '3-Π閃6e o26d}MZFnZ*;ǞIn&M DtaR f@I 4DT@fҤ.@M$Cc3U5|&wm$$8,5I8lm{J!z ]a4aaqm3z t@P,@4}hCYh C І  @P` O%Q&gt !x@wAD@ x!. @wA0':qk@  ]$LIgJmK1@\4 :.O@ ]2 BK:tׅ !@im}V qSs`O<ܖn\6پtmi=mk Ͽҋ6קmQ*>+YkmO[ay 輕ͶG n6W_]ùl&b{G0h q8B]CPa( 7<56nq_@ AwA0':q7k&g_)λZN@K -K$=ݔԭsq@qT u{ڨSN=9M{o t2A ,F4EJ@'^ګZ[vOOIZ{BX@cv-$ڟ>kzMehC4 ƋxwZ%ںˋrk!PIWJ >Wj3bIch X_֫:!n8kUP,Nxhl V&"#Pj~x5xC"aS6FZܭ'D8DЄwD_ T, yOZgM@5rؽpa 5@`y(Bb] .'@wy1.Iض˳$LŴU&afzyt,D}uGa?<46mkt{8ǷO.Fn-ux1$) @1@ h桱Q@A 4@+z(@M6@s%@ϕ!^2UcCwܔe"g"4\I.V gJT6,TA6P@~X#9- 䲙m t  @Cs 4@`>P@m @2MT'ce> 75]Oj@ΐ#0zg%A!>o%OCEIu 5hbadFWV2=7xQ XOÔ: [o@&\\iPD;L74#! AQ#`&ބ"@w<Q:vNn0LO ~tbZ.^K뗩<=L@MH_7|(_5QY_i0}m'@9 BGljRNn;r  v4@ jhL{I~<0amS<4c\}#LzG8q nR_eOH~}Í}OzgEI@"A@~4hCYh C І  @@ fA@ %@̂ @ J640@@0mh`0 M `(` >@P,@4}hCYh C І  @@ fA1&`[qu@l:@ ! f @c|\&@bLqq0mv|1:u@l:@ !3 8e+h3Uh S AbO} `*` {t S ЦF @cJ652Ğhl `2h5<4hCYh C І  @@ fA@ %@̂ @ J640Ęmscyhl{C 6=BĖ8 `:a [tlCh#}@l б =C@MA%@68N6=BđFz|aH@ 8F! @wE0#:Qg@+ ]&Hc tW #!8@u|aH@ 8F! ꉱ!F 8@}|&@Ls0mtx03:w@h8@ 8G! F 8@}|$ UOE VA@L%@mjd =:]hS#]@ бL%@bO} `*` {t S (V+ @zn,9@ t@@ fA@ %@̂ @ J640@@0mh`0 hGc C2B ̀ PC @@ fA@ %@̂ @ J640@@0mh`0 M `(Xkhx0 +uZb':㦜bOψ+ˏؿoΉti>o |}VJY۞54 4^>w %7!@@s-> !t, FF@̺Hg=!3h`1V}o t@Mσ}4 @ 8ƶ/8 ` dWHh`p0 "@ J640@@M[;͒@ӽ}#.(1@{5@z \94лIߒJ\5?"q!8G!S hSÃ]@ бL%@bOY2 07JNV}F&ķ4㵧0=ȵ]A|. w@G? ~f ::q@ bw @K<"FX@q,7,N:d4tnza @|MYm'dTG| =[uӸ%PBTHB>M=DUBm7fc'L4fu0h+T5 qv%քh}uiBaiܱVzm1``hmg!K+8X2 @YiU0[1ܹlXV3B  _Ex̚u Ò 8baO |d>َEVAoIX8FtxDZ10Ϗ gC g&nj${ZM `#g^ztY2oЗqDZҾm+K=t\WAjyݶyXZAkXSIOnh⫓[}e~d4xF;(P iʎ1BpY淒c|pd9yף_~.;_^Y||@Lgz8 Bue1 {Jckc  ChӽfoNU CL2oA/~kzR52/4VAk1cwfSa"RK]y̙_[o:QMШ[X2B,s) Bu ]z6U oG:uP5s!dzNl?7ux; P<IENDB`Dd44 @@T w 0AR+bGrY̊872#inrY̊872PNG  IHDRabKGD pHYs  tIME  73IDAT8˥KA?3"ilkh@݋/JB/J XBdC(Mb51MV6zp;&QJ|y}?T|V\'+(Ctf+v|>vV eFa!=MVDPM4RPj^Ki~ jZ.N f6$,lPTr.\K1;7 Ӑ(qIyJ#jUp~8~op d?lZۦ1Qm}N1O9Њ%&r0σ):&?% ~1y=W« }=W%+{rӺ۝*IENDB`gDd T x 0AS,bD#S$X"nD#S$PNG  IHDRabKGD pHYs B(xtIME +0WIIDAT8˕oSszN{glMqsQ= "xk$^( 6c xiĘ-Jd2M&ufjRnd\G\WK[۝Nj&o|7~ e˲=$rsu ,""'O:+cY*0)خkiyoÄa4Mw p ̒v7PD<~[,0Zhyw{YQs; k%CgiPC$Q*:Z"̗uE H$*cķ `.؎Kz W6'+޵EIѪkX_ĴLrQrǰ]%gJ4Ld-ľ6C_!Қ87;"_tD"_͐-d &r6 P`<`3f3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3vxy`sffffff3ffl}fff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3f̙3f̙̙3f̙3f3333f333ff3fffff̙̙3̙f̙̙̙3f̙3f3f3333f333ff3fffff3f3f̙3fqIYIDATxc0ud*#H [G!R;%;ar,Wuc hc+Jc 8'/|LbIENDB`P$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HV$$If!vh5D 5H#vD #vH:V 45D 5Hf4@Dd= "$$T { 0AV/b?P>$a?./n?P>$aPNG  IHDRU䙦sRGB pHYs+?IIDATx^KnWqgځ&+ٖ% !Kɬ[̀LF1#CR$Q=_J #; E[>{ޏe+QkoGGWoZUZUk}n 0~K|?εZԙ\7 ת\֗mwk􆶝Pru&4*6\֗=$LcH,Fg/WZӗ@@TԿ>ʒ  ;'C㟃"2gD.Tot]X0%L^AuP R?Lε}`{{7QduG:+GFI>K"`coEX/iay*wP21O8l8u>!QvST{ tJE"n;u|4վ[c%31? rQ"8[BaŒĸ\){$鯬OfM$'aLDa D[ G7dqIZG]"p7E21T8ŏDܪn_C *7Q|EK%Xz N{9[Jf/.$_g :f!vH.!*a B=? f4OU\uݿKih    = I`Vgrݬe / *}YmA@@ H  Fk:l@C A@_54E%}p݂ϛw eb@ZYV'srLpgJ2ǜ.ljoQ>r ΚD"8 sȴN"(SEEJE`t"hǝf[Iz}9 8}tX9:7N_a9wu{1McίTxhəbVJ-91|?Ǯl[7|~Ma9OzXLKo!c3@NWNrnP/dchL, K&B!brf@PxxtPQĴI9c̒9[+yB hm[#zLzE{,pq0q9Kr?(ҔbǨZ7hzVfi_1}#ۭZ /vlK.;@He.:H e2,31ƣZdBeXQP,J%b?~Glۄv s*gG>{HK ZϧsQsU%h6Bs2j1PArc H[lI v|x_tR&; @, y ڎ'a0 XHי\7k$cUT;k^ϝ q  .( 9fD+z_;Ei!+Wy5Ugrݬ9$Nru%u)̌KrwY䢢K|~9$9[/ιc`Zbf'ŀk9BKu9qfb |b3bB`}N)i 8m믞#c@ \5+Gpr [ΊZrbk -9J^ʩ(˱spc ]T oKZT,ҝ+;(_>ﹹJ6\8~-QZu`F ؜[ )\t6&* `cK8 술 \NHi$j@~HϐU[0SYꌩWk {M h1%`g$_3 $9ÝWyqwDoL~d8˸)~I+;~?#m qxi?ZN݊,r1Q:fzgd[[eu D(\>0m.#nΗ[QWioڟK\-j3ebخtGUgrݬ1zbHpH3OB]z)rZ%vfX@@`?wn {:fu S.˧mA@Fvm  w T}nnL)e _\mA@tp/hO`p÷^*}h{IP5~L,(/%:^)Li0'YˏEz3M F"j,@0ñ_b 102('MK= Т1d5/m 9rr(R/m|kM.P!t cp1?#$Xscs!Ć{~ʜ!W{q rx{(5K r7(7<31s MGՒ6MG\zM %/,' Gkd׿Dl_g"I1`xslj ҵ `J *B=oSڎN}tfdU~Ksdl]x܅Hվ 'lJAֱgnb9ѓI~tE c4İHLc-f+t%eLN̒R!\[]d1 ~keC:q+%g#/AeS2a; 2ޞc)WAcҘ1H#,k$SH1@@`:?CXQ˖lls $@7,  6k8Kw<@ǯwbbSL/h_e@@@GH?_O>z}9Gm#nrCaXPyY3lx~N}cd;^).\-6|Z~,SHX aW/?ivү bs_d3덳c8">E o'r9IIΥz ;?(@uj-'/bFUy8I(G uߠ:$Ճ #I19B';}b "=$瀤R zE!V] *& _T0 ZrJcUR>&X#&F*L* Y_?h   N;[6kES[7y\*>gN=^NIpO19||a| vLD(KPR}c W[m&\zѩ޻a7;"`{)-&Gdq>N`E]G%-#I05_fcԕɦ߮úI{}6[8Xd#GKκc=W |9}ug,6\ y5fol|,-J,BȪ%GxhY_tj,^?:f͟oN"k OYv_iSSWM֤%[X5{['+z|#ciV|Z^̿C̏r45jԒ5)Eyb#'OA j7h<*rۮ|yj1WήíA?PdUu<\l"3AS3}"=ׂ5=ϩA~l70& $6V*gYnTc't,Iu0u|{qP֧AԩUnϢ6s tU`BSڎ_{9}ytT(K}COx!p_Oki[-?3|AzAN(r'rc- 38%qS7'fZX ]Q&`yIصwc}dM%?TRL꙯NVO6RK+'Xi*ϵLhVOXx}sbrd*rthMI* }8U˶I9xVO:KWQ/TB@@tB;-X; dþ(OfcE߿]y|X)yƭ<~m彫dt6{0OBPS.˃pٗˠ-?E͋}Ϗ?:ӟ,RA` >ݻkP#m{wD/> vAy]ys<xگ^˿yg9^?cPiGiBz{0 ,K sW~ 62(S/1p\yύ-?ty08$$8O?t9=;0w_o/9% -t=n0hP-z]7i\A=+mzbӇ6svn.._c/ǟxk,"QlR}?#ڋ''xR%G',yN$Q\Dr]'~mD &U}=sL֎+-u6ΑslNə9?5<`eZrBӛ*Zi%'OS'JyN#b24#tp]_-_'Mt%%B3qVp5>82;=9<2GȜ_.'ᓌɉ9"A\yU )l^pIH"9S2:/"xxczd0t"&Us Af!QMo}Cд9}^Lߞwۿcn6wmstxON2xغE:/~Tk期_bӖR) ؖȺho/f]gx`No/P5_/`%g _L'udV`.~b*ɏ }[]s^?ZCi@/9@J!*ZZrdb[tSBHN)vtΔmݺ|:[OV+ 3OyrZϭ?6g.fO~]?;|Tbc?/uP*FGcI?80>无]r -Mꛎ~g2{ICV5*qc[6?;rm@7-ִ)n:UA@5c?[4N`=2C1 c[ NrۉX@@`o} %Py^`|[{1q ~vuvo5r௹/@@@`PY  m~1ޟZrk F%z_<~6wP i19|da|f;$v┊EK'g>lW'@϶KВ dLN U χHNsU0#CIT2ڬCml]G /m>% @`j6Ub|1[̛oG^֫(+!mi9ŏ|9 Ϲ1eƊ.|<L3$%1q|$îrouͩUmMN+_䴆#}DKjϞUIw ëv0I&v 2^%͓1Mi[jƦG=$#K_U)߄ȗ*#/K4UYIsXrsdZ4]=iú}"%KwFm9HyQ1s-`~fpU8g ٖ sXNndSZhK>VB,mLm,ƨ~aT _coS[^$b@,pĶhjsn(J ;7 coxU~?YHёOc\Mwj3_JI4koH,$rΓO?Dɑaw'ߔv-&dJQtvc$g[<ܾ䄩!:O,G>/y>/!>y8!*C,[wNb`?Ui7T[Qp`!KؠrLPnhG5M@@P1ll=  ]kAyJ0 @@k6_޻w`rkvE2E38c 5(/|{l셍 ?|s$TG4Dל+CQ>[ڑ+>1d/Ae(R#+;p!ǶJJRgFhlWdҩS+D#uZBi':gn>>7Cs¼O>I躨1K5GNGWȡ)9U6&{i<'rr5xAO/Pw5ƜG< Bv'(9.c#G? ÿ<,KN)#Vr"9}=]gfkdOwߛw̯ͻ*5G[w }*+BYt^ z*?[fOڵO~:OC_Ob|p\_[_-*Z+o$[{~#sȼsj.0o_őBW*9tX/\ae%ܢKu* ă h:ꟼ0?S< m AYER0jŜr6l/x;{~'ۓ3svlNyE xrpu6S.jNѵf,l)C*[oдb\P֕:U7 }oU_9x{';ǧGx<5gg7?Z:P1U6N1v$3$gW/$%\LtX` [6R9o1g'wO~7oָUS D_TGhU{3x/m◌'Y/8/}0ŗOON'#IƇuR?Cp( `sϚ0|i?tu`R `.#'.9Nb;q1>E YN^33aI- Y$;LXcvGU]$xC2A[w( ZULs>9mWoPKN1IQKN5|o H)t[ۍ|K'|?"}`BL-]^לlLR*opbo+6,rP,}G[ĞJ?fVJSpA,)Bq.(?yW% [;ye|nS yҵx&\A84 KRZ߿lfucK'EE_ѓo)F$'r aRq¬IMF mTn;o f^VҒ3R)MBE]溙{KQ4Ò`<}*l}mx'5llR}2ut>OKv6%'w N:#-1crT!!i'=Գu'?#吧0{]ew/ho ;U`L8Z_Ipw2u`E†V_ RZd'; -52tGdZVgrݬ1zbHpH3O_X\6DND֊ߜd-n?ܬ̺)/'/WĨ" PSr)'bľ&Ju&ҹ9`sQQNA̶ִљѥǗG$$7A95f OLE`H̍Cnj"!m!FRP*FQ-T ~L21I.#0Q<, KN) *ZW3|E.]  hſ6o =-NAڵO~ʶOC_ʗ1交Ryl]$7S?L(k)\N34d܉6'+/i!Ғyt^r0?y r򗨆Pȉڀu}Pp;G0 &bK~NV r taccU\\Q(zN}Q19voϼ+os|P!E/6.\vr*/$,%D>;^2R#js'cz?ÿy\cmoch *c%sIŌ,fKɟ=|t'.g҄1SQ +}t*ޣ?> s|nN.\\s~nydwhC_ړ{.'q9*XrUNsMof!-\b*>/ͧgR%C`~yGc} n兹r7^ūsd{rtfΎ9<4oS݉ʶ%;UfGg>CUs#h0,[ 4+;9>8:69;3oצ^}6ǵlγJiGՉVf(~IopZ~tG@ə/lOĜ=ݸgSwq5$3ȹM{VMsiyqU^=̗/䞕tԍKNfƜNHEQ ?y߽`~!' DɑϹ/] mdIG"nB6|9Y"aiOSt*9ߟvGu Aɑ7z~Zr2|Be)mx:} ePlDLsRQt|LOnGA-wLb`scc~洜Zʴ/'D QLN])!)_Z˄=WU Gk BHB_38j_"XYInNixC /!;IXc?zΘlm-(V;'Ű.T$'+"ؘ}Жa-NEݩ mIQoZ"US#+TD_ӬX ST&,gS'TLۭԊRiO˹:?@4 R SgKVSvJLhDcGF[o`Џàb[grݬ9ZS[ -9<3rv'kà}#n'g\~oά[ZoK#י\7ZILO.pN ϡ6?d7r-ofi<  H@SQ'Z0u&Zpo\־ mA@$۠S*?' ,C 5.lVuV5c<"3Kڂj]wI޼㫛]ꁵA`lF4Ln}˜bE[5Q,~ϭ >;7wy=f_n;^VU#8"scqL|peA/%N̏E %C~b#KSMuvKW|z}f$8b?Dϭ퇳nl|AO?=0WϞ/tR¦s\ؘbzΥu)6ef'1P8;&,_mX82Qܪbwͽ;Ĝa5O<:EfLNa|GZ&L*4qozXQNMm_o#0 S$^&C2r %Mk-kab> -v/Q DkS<\2bnP hhpcBEx.Xl,ǜg_o^{s1n;9:<~''j\2Zo&LUsc0g(~? *-/ΰ.ϙ̡(v:ke"/۟ŋ{˩@.ZΝ%K &%3`jct+ ;j(*Q>$R|g^'72g|1>*`jwvC痜<xlSۜ>ˑ/P%:VuJ$@vљN3RE~_ʁ,q4L\6 שTp!@@e-{- |G|X#aM'vJ;$&;#rE'AVȱ&;?֧?{vdn}z/~{ kHQ"ΗDŌIlk%x_B67̠P:(+֚@˔c{w\N{虛ơy90/O.$ B4l~)&?G I9ǶJ ņ{?4ҏr*!M]'ĞR]Zbo=^ UoyS_ocr"VEd-qZ/WN__.'g|9 QL6\/9aħ8}!B\$$;kUEL>L9g_~RTNH-rLNkyGc} n兹r)^C_i3'1h|lAϠ\[<*ikŨrZKabsy߱y<2˳ss~f..r+wd7 \Nfd/dE/\J9()]BWX/xlUh3uh?W%~cb[6SQи|\ v`nlOٱ9=7歟n|G^0(lfB}Ab) 3?Y럃9dcx.Δ@o gMWkmNl_9x{';ǧGx<5gg7?ZfJA2c'KK(:+^h-\ ;kI&p3I|VҘ~qӟ۷9;{q}ϬMZ?7VV)} /m9зO*:X I$_RYcvqUrezɐIhsG\F(-VHm>y c.͗C])D1y:;b[[p}7RlVܜ(],A+ʼn\?O@Hb1S:#F9`/sW۽&g?7ϮQm|b7 :1 @ T!3J`=2Jaݵg{=u ʃ@/@ Tέ&[ [{gM3nVךּ.}/-j 0@VMlvHw _P^~pPxiJp*#LL4q>'5?_ˏE%gԿ"Frl_(0 ?/oХopp&s.//0%ApsnSqs,X|c]\~lKgn!}`fWf+dQS_ʫȯR7+=)xO͖)=ZcS?u.98׾.*Gu7NǼn'!| f;zGAK19bZQo?peN؅rb3= N[ɑrbpxҶ6v.猱O+J^JCW+9?A&99!qKr9$:?%Bw d!1KT';}IENDB`V$$If!vh5D 5H#vD #vH:V 45D 5Hf4V$$If!vh5D 5H#vD #vH:V 45D 5Hf4V$$If!vh5D 5H#vD #vH:V 45D 5Hf4V$$If!vh5D 5H#vD #vH:V 45D 5Hf4Dd' T | 0AW0bPeWA,qn$eWAPNG  IHDRZsRGBPLTE3f3333f333ff3fffff3f3f̙3f3333f33333???33f3333333f3f33ff3f3f3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffMMKpndffffffff3fffffff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3f̙3f̙̙3f̙3f3333f333ff3fffff̙̙3̙f̙̙̙3f3f3f3333f333ff3fffff3f4f3f*vW pHYs+IDATx^kv{?9M3$&ۙ2!0%z&I%3[f߀]]g. T|/`MyO`rw,~Zb(dd$2 W~]DW $׶xoօ~T3HA/) =r>'K/z"̥WHuOǩk(0>N1X` 8cO?˺~wBg{' *lw0߷e-^LP`—{d]Jzżc2a䕡`p[[?e6 %3s՞ ntJ> w/{f.}G7ybq_K~?ZɁ3L~Tmiqɾrn0g gg @h=$'t ZLx6'-EO[N?~PxUv3Wg{*ϚSڠ.|rFz%g[Rᣁt!zp煴`Dy[,Am**w҆v-Zd̎Ġ-}|}:o/Do Lgswp7~|a_5`[> W71k|8| ܐzg@Q aZ|9__0V*9|Og(bzgWgwxg cαAT  `zf Wt҆(B|5O@@A`euWsuldfzP,&CP>Uw||֔<9U!_s,50/# eԕ+0xW.CqBh=b D*% *I)(a.R0xAzpqQ)Y%% =hK) `7xw*)aP CVSex|ao ,Oho~g B9 H[*m&ʘy`AzzY P}e㣗cݰYQI̼ᷫ*J_A|ŠG[eov l[䗃)zxΐ~E1hRU=<2a]`{216~2XA`Pٍ3+\AQXvDj`D.;(a~zP S{ڲgVP 5 ?u\e:1E..@b~y4Z u7`@?+D|}k9D`Tpliԃ,A !` ЃK&l1]=Vc?l|tο1PQcp\[?t?` X7)ۿ,[V7[*(a/"*@1hK[r<\{H+/A1.*lmQ7, /tN(aPt5Eq]Jԁdɶґ % Vz)Hb ZS,6qzy$BA|9g##=KxA/¶bkfޔ~ZG:xoݽ|Z*ᔥ7NKM&}AG"i+R*GçVvEѶR佔j t?`bZ ^}rc ra% fR@BeH6;n!{e"حTP€2mjE gŅ+(aЭ~8a{&,{8Bz@?v]Z vR Uvd(0`(HA-Ɵ殄ITP€- Iŋ.@B@'q,nV"? z` I\DQePN0փu C ^=z`14$/\A V=uw#,RvA% Ͻ9.Jg/\A V=`=XփQ υ{XTؗi4IMlXb{J"?|=0 ΀@ۼ[@0KoZLf:. \oڡA|I!;/K.aOlk?#zR W(^MeNg% ETҪg '[B>H;ub*4rJb 4!R?h1Y?`+ Jl6->v҃vz8C?;mPh`ۣLȱ'U M/ v;p'BF ,Az9 ;`o&+"SHd鰃 Q4~ Y6{6HRPoF1@tؚ|| ƀ#.|q){ack^\c9 P[QPmlbBWZlpi!<$xch[([:ܕDçS7TO_Ճ3vQnàA\ᰃ[٢?«" fXB\򰃛%; E .zBU-,? l YC (=h7QJ/\weS1e7}.S2Jb^y ,kP l\Dh JO1 2 >҃ A^M;U̎@p(%\[ߊAoΫ[11*Ad݊֊p++Ō݊Ġ1VdHtŕ"tWa'[KJ˘F"tWa. ӕ(6.exŠ=̎Tm?·H9^Et` LtF,Ǡ?vE;+ W H6qh7.~A=`ˀwϜS|zXZ~p*p =ٹ-AE/G"mI1qQ$Q 8 >`>:zPzn e:m>e㳫IA`ަ!z4'k A`g2 EnVKڌ^dxO*rTe@AU3f\$1`(0,l{avvA{fd聭?`I0Šk\kNkCbs6뼊'e|I/ŷb@AyBͽڢ?Q pމ2Qyˠa\73/w݆Ae,nW8,W-j]+|5c0EEoa8VI*f7-UIG5ƀe'UHIc/;@J~I4RoN1d;Ơ_vR5$1i $ߎ1藝TMc %vAj)Ic e'UHIc/;@J~I4RoN1d;Ơ_vR5$1i $ߎ1藝TMc %vAj)Ic e'UHIe ݧ_Sj*c0EG/08E\>طd0I" 3Y`2oRIENDB`P$$If!vh5D 5@ #vD #v@ :V 5D 5@ P$$If!vh5D 5@ #vD #v@ :V 5D 5@ P$$If!vh5D 5@ #vD #v@ :V 5D 5@ P$$If!vh5D 5@ #vD #v@ :V 5D 5@ P$$If!vh5D 5#vD #v:V 5D 5P$$If!vh5D 5#vD #v:V 5D 5P$$If!vh5D 5#vD #v:V 5D 5P$$If!vh5D 5#vD #v:V 5D 5u%Dd#  T } 0AX1b$9'2r$n$9'2rPNG  IHDRSEЬsRGB pHYs+$5IDATx^]ͯeQg<_XJȋ`YYDXDYDbH,B=<Ɗ 6B(D EHH"eAv`y>gz}N>xϭ߯NwUw7La`b ,&W jW߻~&@d)R6%Q^)ys^ew/ӿ|Dd)ޕqs۳fܮvm7۹ v~^owc?~>|rGumb%?|D~*C'RёW6W/N׳jws ٜ=_\Ty1a\l^Ef3߬f|٭ֻͪ f6s-Wr)˄ 0\oլ~Uoβt5gs;ĭ;̈́Eg=00n$^[}{y~;Mc+?nlUS/ n_Pj]11('KdӽznsWɼղKׯ^z^T']os~KTzԿ扖h0$8o+ʠ\?e_y ߽ٞ[UiIM(yÞVfnwoĞ5S_&A$NQ PN<5a5O~տg{{2 ie8$j?ءDGUa7?z W?wy/f*~7J=`DjUH QH$e]*wsPWԷ:T_ݯ|`uھU!O(R6H` Zն9wvoܩՑT3=g_YV@ d࣏Vww;pޮy9_-fXࡲm;_?)RIN5*C'Ro|'x_~U;"Rda(T/~;7|JUk{]ޟ=g_GN>G{1f訤;YD??XܼD>&N9oP/8a~7s?:ZKH 2<{GX4;kKo!_pe}zWx*Ͼa>D5_X"v_Xd"/uClo8rQ="yCV#_j~D?i^ow*SIr#jض/G$z"3X, ?ߩНwfvG)~6-i&q!&2.#m+[.p9@DXFq U?FoO.h)Fd .dd`G^ <cNt8~z|wUϻZ`v9~~DBw~G?C7n/>dibXD!.l6lGF]t]ÓFn|q~RjW=hDyzΗ>qbP:J\N 8FMԕYBD|jgC ]îoS& ?=eh($BF^/z-SEne/Z)ܰTSCXD?sy؜o]D.@pyNZ@GG1dOzb@"0{g"61a@(|n9",}%¤.M*Cbe<ɓu_O1Sc'v7M-hCDe/͒zHWxtokvCrWf 5j D R:R~w+I}T }%^Qǀ&+$F' 鉛FeB))TSw*fT7Z$U_dq6C#ˏ]-":}x%\dz̄ܳۚSwuCְMljm/jBCXFcq#GނK: b@"SzQ- z{Vvǫ28t,p"E``P=7 X[IX{ D¾fsy )`3t-D|Ԋ.HW>yxC M0 atG^ PۯdetQ+5, A>{p ,|֬()(ij {<|ЀIX&!$\=z/a;YL^0Õ/`J { #eA,3uY7U,ձ,>Ƣ=pUqݗ+_ue>v`w 9?.m 2R4?- [#|?DEWiBlZ =E!!+Qxן #Iϼ_+i]\P*cC{CM28E-,pt>0 ?; ]l.ag =6& H#e@v)G" p oaqv"G)A K]9Ed=HcFڦv^~3;^~&h6.uT-[ ۡ)' OVޤObZewiզ kуٸAdu3(O|z;Ii>V0C$rt!'olz*Pe5]`[6ޣVm ÊAV79ɨ1.p xQM%G(>ۢ[#ϩ8-Ma Gi6OmMG_$zȯg,0@g@ѹIa8ސTvǫ28,p"E%J)cAS=Moo${l]xACG |QpfqcnްAbPTSlWZF.@w$4,ic c k&Kx#YPFr͛RB ZZ櫃#.[,n)z>Ї>6ԩcG u])5%hS+6vcGVՇ}ro1{!Slvt<߆^k3< Ğ[4ꏊ \~t+?Y;y $ݏ1JO!q]Nz$L@grQ+ ̀D~# z@ ]=+Uz@L8,wDjk D[[SׅK ON~?IAן#I/GickWc>jfWwY6'S=O*T;ptWdA No\w'GŀD~`D413-6BG}DBԸӭ:]md>+鍰`Mq>Qg|5Hx݀n94x}%)}]maSuv@d Ջ7{n5 BDU-t.=`Oa[Wuu@I@%DV~懢HA-@Ť~RlRg:&y~G00J$G9lb0Бב@i. ɀc;^d)rWOm] :cBba{ ' ?o;Fo 4%ED%"799\z[7l#qCf)LȏAC}>W/"o-! (Zj8CtJfBWjsڞA\=]ޛ JR֬𕟉 86 H~;8L$𑳃͖~Gy'B@fN<K9߂묐$hodɜ_I@v$S,2 w 1I2 wWepN=M8,wt-m2$q~5 P?9 ޽yoLq;_ruX zۙxÞorS׾ݧ~nɁ afbRዧڇq-R{00]m\~Jo[yQc+ujSq߷%ã37ƕO`wP Љ`u*9<+PxE@/t8g{oN6@ :;2'S:"Kb @XDc@aE}^V hW(M榝&QpyDS BG@ڄˏ6F1e)%wm9.֧wGF9 jɧzjz/\~ TӍJsa@(<:b0Y+ #;^d)zDb#V#kQ}$roU n(fin</3|\ӏAs -=Hz퉲#J+G#TitPxrZwsB;?QNo,FQ" x'Gu.:N rϢ|X9Ǣ# uIe5"~ t:{$ЫY #_zmR D"_,@B?\=&mk-O"" jK]D;g~y>{^b]2­].y ʯwF>~;Gx߱i. 2 _ࠈI@v^va rWoxUN(]=]mvw8X4 [Ajf[;IAxG4sS=NvW |犺AoaBg:M֧seK! ykc_ 2\;!Tϓ`헿גh%z k"u,hk6ƶ~?JmW7c9.ŀD~m:CBtìLx9(i&|/p;wGJ*[GHC"? T%6ƪS0@f@"LUgAZֽ܅^sS{7$'t$842դv$Sm핋 }Npr@y|NR@ y\+6x}[s /Qޕ|j?D 2 _Y@V^VzE0oew*C'R]=eVQi"M1nm@5o-a/W&v]D%(굨:."RUn$ 7-qb7-v8;zI@[t"m `{\yRgsH!hCf C ,I-&7B щ}F-2P)D"?m$Mҭekw-x #{M"?~4 -l2+ zϒ25!cH{T܆gH1flW GlVvcus 8Iޗ1sy#]$4;f dJ4[ fLT.lQJD?mM#rF<)_7iVLj*|s?;ͳK$zw'|~p;Z9eisnڄma Pj(/2edG)Dzns+ȷ_N{z!CyzRPH`t1#z|wt"B?F؅|m|2x Y|o "tz9 oy?-鈓͐}, p> -fyx&Od函kH1 [, ˀ+wl2a Ȁۣ;^ z,p"Eճ%cܵ :Js <ņT2,r~Sꉰ-CDfЅ/>r•_~CΝp|r^,Cm[?1; on*eg<A\0>@˕)mߌn@NEysqs۳fܮvm7Ɔv~^owc?~>|rGY(wҖD╎G2mgW/._<|G.=rՋ'W..<TZw-CH'0: !$'j?],7r=_mvno6F-gݍ[?b#?"陈,yOecW m6x:o(FX;r=*7g'6j~;$ܬug=Jț5Q6Eu b0%kv7:y L䲡&z&ߪ^Mg?7?Vsz7kjtN5J32<*UUO_|b߹vK/=U0(e*z?HÛkڃɀBtjJKׯ]펏Lz<ϾwGph E5䷭կy Fp]S`&Կb<}V z1wFҽuM_!=s%# VR?.Eq|-~k5;uثUث}~C`O[P21w竪~{zO9۳7K/XZa?Ta_%𪶯{xlo^;Rvb6H7<ғ0}zk߾}` M%o-g_sy#l_?ƿǎxn?}*}нO,ٛ,p"EWuNjY|vy,6_)jه׺0JcO^6XHH w(rņ8нx㣏Vww;թޮy9_-Un6.?]iF Ad #.G&ʌ_`qp hB作@~s'Ru{8 \/j{o,>(X||]EqSJgyLo<ȷǔBW.G⤇^wn[ա:ɫjo/"W/|S.V7"?9YPJf@vJMxKđIENDB`P$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5@ #vD #v@ :V 5D 5@ P$$If!vh5D 5@ #vD #v@ :V 5D 5@ P$$If!vh5D 5@ #vD #v@ :V 5D 5@ P$$If!vh5D 5@ #vD #v@ :V 5D 5@ P$$If!vh5D 5@ #vD #v@ :V 5D 5@ P$$If!vh5D 5@ #vD #v@ :V 5D 5@ P$$If!vh5D 5@ #vD #v@ :V 5D 5@ P$$If!vh5D 5@ #vD #v@ :V 5D 5@ !Dd W %vT ~ 0AY2by2ev!1U|nM2ev!1PNG  IHDRz*K !sRGBPLTE3f3333f333ff3fffff3f3f̙3f3333f3333333333f3333333f3f33ff3f3f3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3qodffffffff3fffffff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3f̙3f̙̙3f̙3f3333f333ff3fffff̙̙3̙f̙̙̙3f̙3f3f3333f333ff3fffff3f3f̙3f-r pHYs+IDATXGXA %?a-h:I$xu?S~ BJeo-؊~ʐʎ`$p^q.Lx3|}_9ל[xUF AD<{uPoJj,ŻFYIENDB`P$$If!vh5D 5#vD #v:V 5D 5P$$If!vh5D 5#vD #v:V 5D 5P$$If!vh5D 5#vD #v:V 5D 5V$$If!vh5D 5#vD #v:V 45D 5f4 Dd7 LT  0AZ3b '}b5XW n '}b5XWPNG  IHDRUsRGBPLTE3f3333f333ff3fffff3f3f̙3f3333f333333332@q3333333f3f33ff@Q3f3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3VVV_g^yffff3fffnjff3fff̙ffff3fffff3f̙3333f33̙3fe>o[ff̙f3}Ɇ3f̙她3f̙3f3333f333ff3fffff̙̙3y̙̙̙3f3f3f3333f333~f3fffff Z3~ʙٷ3fC*t pHYs+^IDATx^;v: tڋYGREN3tTvd*q;$HaIAI0ilYEU`eKPO 6sC}RVϒ~w89c]2Lԑ0B5RA+GiȻu$I$DнZh^7YFN5h>辣ŸZ?8hx pwAie 32Xg.кx=Ԏ PrF\FF#o1t'agF}(2ݎm#@ݐf7&[kzCiT3ZvL;#ټq(|mhp;g1&= :ٖi&%nNk5W܆D }CPJϤGt U-X XxIT)m'(u}(BF)ˊ1> j&g¾dwѲ֚:JW8z%P:d1!,n6Tn风iɚŵ}U:߾?/g)+%|9X"X{CHo|y,_M㠍ΕHUS㠁rŬ?Z.5u4 ⢋4͢FkcP̻ sY 1v<sm`,լE[c}B4L|6mA>`Eb]t ڄB0h١sD+6*KEDFMB[3:stDf)4,Y%ߊ5֒EsUhtѭ ZoCv&ySoC׼ZBp4RT Y#:RK-0;.z%vm;]ߗ4`ZK+.`XٯWXYdI"[ب:JE "5c ]']uUZ|OS4[.RO1uQ-rU$|EIStfXVul٧.KY2G칋4qD* z:w{/1GY~N',v&wѯyCS/kkG)n"5ţ)2Srj&g?mhhb\2Ek:3r+4U'`>Ո{6u"-_@W:Kt?R}:C-Z媪78Z7T Yۤ:30+ݍ?jf\A;fEPHK lJ=4}x7]\81dj`qǠqj~Lq<#Ҭuth"l;ŷ/rcI9ht=lX9ӵ݃6FKM6ڱݝf {87}Ӟc<,d$63g1'uNn'ZEz2LK:ߜ8{~teUw72Sn8-vk٠HX8np N4wdR Mw 6z\ +.`X/؉l11 YczM11։FɲIENDB`P$$If!vh5D 5#vD #v:V 5D 5P$$If!vh5D 5#vD #v:V 5D 5P$$If!vh5D 5#vD #v:V 5D 5V$$If!vh5D 5#vD #v:V 45D 5f4Dd e&T  0A[4b&)Lz8din&)Lz8diPNG  IHDRKiE.sRGBPLTE3f3333f333ff3fffff3f3f̙3f3333f3333333333f3333333f3f33ff3f3f3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3XXXffffffff3fffffff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3f̙3f̙̮3f̙3f3333f333ff3fffff̙̙3XҥŬ̙3fٵʹ3f3f3333f333ff3fffff.^鯆3f3fb pHYs+bIDAThCK09%q=7+1י y,B,+|No7zC=vjˎclq,BVŬ rPŐ<ւBEոBЈYdA~y߰xsqҬZvN@g9`iViӜYic1m~zbygwc27cl\== WZ)5;ńT֩pEX^ò1r8۵OD toz [Y,Nan''NHKDZIU=q\;=/v0 i_nqɊ/E9ܿX-,6F|Rϕ!kXGB_qzB̫__WWKuezwÚg|F$=)0Ա‚Ha߽K^.2WezU/'^kD9K Uk[-'S' I{KqCO?ҝ*ҫ~IENDB`P$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HDd  :T  0A\5bF<3&nF<3&PNG  IHDR?&l~sRGBPLTE3f3333f333ff3fffff3f3f̙3f3333f3333333333f3333333f3f33ff3f3f3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3vvvffffffff3fffffff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3f̙3f̙̙3f̙3f3333f333ff3fffff̙̙3̙f̙̙̙3f̙3f3f3333f333sf3fffff3f3f̙3fjC pHYs+RIDAThC PW~*B;AB۹hau3_NFh{"h.,@~N3#4RTbr.6?SCC Տ|(~ʧ+W&u]OӇ4 Hͯ>ǔu?PڗG95B?Hm+>SL =ӏ~1X7G@_L /&fy ^=>:g@1~u(~aހV]IENDB`Dd! *T  0A]6b  u&%wn u&%PNG  IHDR@%sRGBPLTE3f3333f333ff3fffff3f3f̙3f3333f3333333333f3333333f3f33ff3f1j3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3srmffffffff3fffffff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3f̙3f̙̙3f̙3f3333f333ff3fffff̙̙3̙f̙̙̙3f̙3f3f3333f333ff3fffff3f3f̙3f&C pHYs+gIDAThCQ `Y<:enӇ65K Lf_ Ccc '7L`` Q.z7A4?Ad8jm&(s?î]~vZp-@:@H6NJrƊp7X^d,V=%=/} G4#S8k`B <Id:+I\:^$ NKO qViJ&z:#}T`b8"a=u8zL}ʡN_>A'PtmmjϷp;Z m/+9bIENDB`P$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5H Dd :T  0A^7bYןt1dCtb5rn-ןt1dCtbPNG  IHDRbI`sRGBPLTE3f3333f333ff3fffff3f3f̙3f3333f3333333333f3333333f3f33ff3f3f3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3srlffffffff3fffffff3fff̙ffff3fffff3f̙3333f33̙3ff3~uff̙f3y̙3f̙̙3f̙3f3333f333ff3fffff̙̙3̙f̙̙3f3f3f3333f333ff3fffff3f3f̙3f/6 pHYs+IDATx^K0 9%qE^ϫHί2SQ򑤯4 k-C)T6e ˒$*6W*%p*㑙 S(f#/`-L] Q!R0 TCa,@KT#cT Ml,GTU>cЂ.3mTA$U^`[,#nti(΁h.`+3J!qjn(,G N;# q29p[ ;P ,*Ί;>tDOF܇bD-7Nh3cZ6wd+wU (r.4_KTnr CRQ-34E*ޝ@7̀p8I$ *DPe> )-cK0|V;T9REe>Ń^ʟ*߿G:ڦQ6D۳l%MSLm~s_GeEeb KvAàjĉ?k|@ bZI>2o^^^?BX pQ+˻sA&:].eʺb^P+TAIn:+TDN:e݃Ji=JR(7-3i^^%Qwv%$kzlrFP H0!eǃAifă"Q-@Bn Y-&.3Σo>GM%PȁL3M+*ʐ̏ " tOڧcԝh^O8ƊǑ:a,T[ G|LV9a(?H@\hD7 w[%So+<\4d5)ʴʤ6뜷=en-E%o|6ak"TTֽfޟ_ylG=wyc]#XҼ{TqEfvtih 6sH}Ȟ!*X`=(KQ*Xd \FSIgh.PiĆGC%^48S` "f+lce4 8ĺNLס}0lXU> p6VT[6l{6- ɋu(ifgOQ[VwH؟+{y}[74@Ld>+&cIAuFwIKEf',PurXĔ+Cfv#B1E0M gerb2*&ɃxdLHWAbOԷI$IENDB`Dd; :T  0A_8b~dibsn~dibPNG  IHDRccV*NP3aAh2wT xv <)TBPG4m%@yBT(T)JpHc舊V*f8z ܑV`OuC{.}DQ+]rK%aRC9I07 ״5Q3Gc4G Lnr8(rw~u0>DeA'ZuGyy϶/L'ف7mȢR%vAǧAm#ƻ]B*bdw"h|?c*E,| ΀ \I^qFaI+YTR6+űC TqMyE lT)ϬT+Q*J)Q#3iԊ%p ܿ2 "9ܿa#T*oʞh&ݾWVv=zώKV t;P'{P!oY o6g&{rn¨OAa(Lsu;϶5Uf[VWG<~u?RA#Dw|PVZuZQVZ VZIi^QVZ i%]m׫+&QۦT,vkTJ V8DYY +T*^cYb)"ab*dY_ }ae($("@|8X3nX{ ¢Wrv&y%#(,Rramߖ֍A/ 0^p(̕c2_,G^Yl^ej8(nϊML#J=aa02:'Z)x<*'O?q\9< &}$L+ɬxgTY?+=IENDB`P$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5H<DdG T  0A`9bXF++r(tpOnhXF++r(tPNG  IHDRtS5qsRGBPLTE3f3333f333ff3fffff3f3f̙3f3333f33333333??p3333333f3f33ff3f3f3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3fffgg~~ffff3fffffff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3f3f̙̙3f̙3f3333f333ff3fffff̙̙3̙f̙̙̙3f̙3f3f3333f333ff3fffff3f3f̙3fY pHYs+IDATx^y0 3هuu,Y&'/99?cin=oԵqM*r mh'Ymsg]u4J;H]ݗMaXd:ᚬq:ʲmiq S6u$=t࠺Z0Vl7>!{Ka +ht$N+F/*s]#(VXY$bDbTc/Y D]Xt (m9lPS*eYSmv'=Ov"/l6& y&LKį5$Lm~ V@*Xݍ鸟clcyN|Ft?_u s)[{530M)eBq;RJ=_6sCJuyʏQ-+c u^$<&XhDxfxj t&ҺrD`!ON;r|/J^S+F !늅2tUeJQHL =ժeu?Ge" 9ms]sϹx} ~NuII%$#)X)Y>2qIR+~Ԯ<+g]SYdK,N@>2b"2V;~h\UdLy [H1X2VJY.a1]κY鷹 Ƥ<Gy#1n8\ ʃ'ᝆ{?#{Vs dd>s~ޕf|KO7=snn9,d`X|z=۽Y7JSXa"H>u-uIENPBkR5YrU JzPBVM Y1[gMsɣɮ喏ՖTmleՒau=fb nɺÒs=&Ϻ%5 Vz}N:9v܌uX4,{9ShIENDB`ADd )T  0Aa:b2nla16unm2nla16PNG  IHDR6\4.sRGBPLTE3f3333f333ff3fffff3f3f̙3f3333f33333333@@q3333333f3f33ff3f3f3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3VVVgg~~ffff3fffffff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3f3f̙̙3f̙3f3333f333ff3fffff̙̙3̙f̙̙̙3f̙3f3f3333f333ff3fffff3f3f̙3fs& pHYs+ IDATx^]( 6MO_:3B<0Fn6EO\_z5Q:@N3F?&j_I 8LυPmo{ceh 0X 7itIv:$ȏzjcn@Gu:ܠ3 ^ewspr +$3R@  B@K\R T ؜vVʥ_Cy勗 q24 'd]t4e'T=c$7eg1W$ib4fQ.ԍq9@K>_$GZү/]$}:aCT=PK-\+J: ńlQ@MQ 8`?csL]9г=şf@rG3MwŨRFy6BuP-@nw CY@2Ph~2( s.@:}2s[0hh_w]|/3D@DBݿ3MPePPb/J1 6PXiGbL&RTS苦D1>z gTQGOCk5Tx`xw5@ĞJD,uPI$grDfTЬLЦ*PI,@Dɏ8K"/IMs)*%P\W 8V`t(m&+ߋq=V$ CogKn~u!*XdEPTVp#PXlvpv>33(m?e mӫĨܻ$›"Cs#H9u }x#.Z풩ų) U%!aP8H"TPgIxU$R#mMԪ$S]%Jwxt^"YB@GxvDx9GL%!Ҋ ̰$1QQcTi *%n7ƨ1tg0UJffJKLW)q*-3]Ykktg0UJKf]_@_tm.NfI.oPk3K#_k@/hu@ߠ#=.XWKw}$17M R+܏Ҁ)O=Xי_WgƎz+x/̽U[žnզb .qZK>#20lƏpŸifQ4 %_G(v)P)|n ل{Q4Ib!iSKOFMl(h(f6}@Gz4]LE,샪Q"ґQ<<2YEQ!{ydb/X|5؝{^)j ëx/Cb"R`]f7XzNe1e膃=~ $wc4BgT;rB&h E@{[$(mc*&PPir2obţʋbl8H{N{<Ɔzn:goٜ6g=ٱKcvXE}t/# Wbnze.5C{i-7`f֫kvqQt#r^9Dzl1mQK5JC!!D eP9*[kfFWH"{DJdRP18Oy]@C(2b4ޤ{|-u1uwY6  \V:3z6(e`:?Ok R~Wb{k^9X3:V% 7*I TÇ`j+ _?{ټiol_FДI}\$HSIk幙_M^UW{P^ٝҪ?++SJOJmͩ"jBI;.!p@c)݃{> XڀZU;BQXp9`ɾ k{s?Ӂ֎j#ſA=tp>%v׿3|O~< X |;|yx΃ˇht3A,%;yb\n/S7-`@`αzkmX>ONu!F.ʒ|+Wτ^oB:US=4wsI\\^;hY~Kac |~jƶ!ݼ9px=P蹟u>Y eafɩJ˴?Z06Hmɬ;d5Qquugz^C$)\V}VpF[R`ZǜތJjz>~֙3ƨ.T^ dS-:ZG d~3M߃exl3^Wu?O (@]uZuprlW8S 䢶yW/.,7q]/*jE`_Ӄbbi(+.,x2z_݉H8jy M/Oؘ~ \ KwW{B*99iXz>Ǔ"mp"u'S|P,v+_&Ð"Uz-p9s(nD$PW_ s?#{o8P+I`A5̏!y6![ߟOqQXx%׎Ĵ0D;knӺ!A@2hh;Sz @ E.%;9 K 'vM53>sx.gޠN(/H~N!Ux GhU$KkNf',M'QT9X*O*J߱KPUY&T]_E=>хr篗sI]S}mWUH(\s񲇲i<Ӑ-̩ @êWMxUQ^5՜|Um*|_&P@ڪ\'4,|j}ժ:w437J!;ʹgSf}PkOzǓ"W4+Uo[W^qrceWϾZIN (v@i}=ȕz"ɶS6 7Q8?y2Hsㄾ Ϡ 1@1 ^ H l/“{0$ Rv>]| EudK)ˋUW+u.b\AIg 2ʭ"~ 8P(jwxyn}g,[v(iKNR= ZHs u, rv7$Y(pIP:jٛs &%\8أP?4p.{6=e+ZkMƹx{j.'Snvi6"icu ނ@@9?z4~IpyESUdNxT@KȖER,K*ђt֑$XBǬ,zt|@慄y9ʰN(,I^:lh|"ÙHҦ{>P@m&G2tKIh²8K]?̈[K|]>窨֏ ZM9 f @¹s=s VdsTUj1}K4zgM䡬:ƲTQ8 몮w5a9ە*8+wΩlMہjjgdj5^lùП\LΩWķۮs>rZΙu;XJ&AnYа ;;V3jqeHxJ5U ҮsuT&.'%Ϫ7h25`s-1^ͳ\mpk~IRa x^pP7SsT=ϾSU-C eV~g#ĺr#ꑏze$Ojb+ɘ= 4@]*rI"h>DrjM۹zjhn9UӕFU#djWC"O)#qdd@=ib=ӔOO l{4_LF KdtDe9 *N buZsOr9;KG>3\MDŷz3Gw woq,h JF!~)!˱5 tS[n 4vٓ,^WW?/d#%L;H*ȧu)7*7@NΛmH \]OV3^%ZXX >iI,Eg+U֩T=dW 8^2R+o:wEȱwS^k.[.k2I`zcߩ8?m_|+s[_/ `хNs߽]I@gma]1xOsoM7J=)n~W_ >y4;S6a᪩@*s?BU&ُK渡&kP rD*iYOOYO3@Ib_- wTw<]F ԟw^w_Y4^;;\ލiݫi-tbxR8M(u*/s`2\˕Q#>oqF}-<_cg;^B˘j聹? xbo_$a?R+n?P>$aPNG  IHDRU䙦sRGB pHYs+?IIDATx^KnWqgځ&+ٖ% !Kɬ[̀LF1#CR$Q=_J #; E[>{ޏe+QkoGGWoZUZUk}n 0~K|?εZԙ\7 ת\֗mwk􆶝Pru&4*6\֗=$LcH,Fg/WZӗ@@TԿ>ʒ  ;'C㟃"2gD.Tot]X0%L^AuP R?Lε}`{{7QduG:+GFI>K"`coEX/iay*wP21O8l8u>!QvST{ tJE"n;u|4վ[c%31? rQ"8[BaŒĸ\){$鯬OfM$'aLDa D[ G7dqIZG]"p7E21T8ŏDܪn_C *7Q|EK%Xz N{9[Jf/.$_g :f!vH.!*a B=? f4OU\uݿKih    = I`Vgrݬe / *}YmA@@ H  Fk:l@C A@_54E%}p݂ϛw eb@ZYV'srLpgJ2ǜ.ljoQ>r ΚD"8 sȴN"(SEEJE`t"hǝf[Iz}9 8}tX9:7N_a9wu{1McίTxhəbVJ-91|?Ǯl[7|~Ma9OzXLKo!c3@NWNrnP/dchL, K&B!brf@PxxtPQĴI9c̒9[+yB hm[#zLzE{,pq0q9Kr?(ҔbǨZ7hzVfi_1}#ۭZ /vlK.;@He.:H e2,31ƣZdBeXQP,J%b?~Glۄv s*gG>{HK ZϧsQsU%h6Bs2j1PArc H[lI v|x_tR&; @, y ڎ'a0 XHי\7k$cUT;k^ϝ q  .( 9fD+z_;Ei!+Wy5Ugrݬ9$Nru%u)̌KrwY䢢K|~9$9[/ιc`Zbf'ŀk9BKu9qfb |b3bB`}N)i 8m믞#c@ \5+Gpr [ΊZrbk -9J^ʩ(˱spc ]T oKZT,ҝ+;(_>ﹹJ6\8~-QZu`F ؜[ )\t6&* `cK8 술 \NHi$j@~HϐU[0SYꌩWk {M h1%`g$_3 $9ÝWyqwDoL~d8˸)~I+;~?#m qxi?ZN݊,r1Q:fzgd[[eu D(\>0m.#nΗ[QWioڟK\-j3ebخtGUgrݬ1zbHpH3OB]z)rZ%vfX@@`?wn {:fu S.˧mA@Fvm  w T}nnL)e _\mA@tp/hO`p÷^*}h{IP5~L,(/%:^)Li0'YˏEz3M F"j,@0ñ_b 102('MK= Т1d5/m 9rr(R/m|kM.P!t cp1?#$Xscs!Ć{~ʜ!W{q rx{(5K r7(7<31s MGՒ6MG\zM %/,' Gkd׿Dl_g"I1`xslj ҵ `J *B=oSڎN}tfdU~Ksdl]x܅Hվ 'lJAֱgnb9ѓI~tE c4İHLc-f+t%eLN̒R!\[]d1 ~keC:q+%g#/AeS2a; 2ޞc)WAcҘ1H#,k$SH1@@`:?CXQ˖lls $@7,  6k8Kw<@ǯwbbSL/h_e@@@GH?_O>z}9Gm#nrCaXPyY3lx~N}cd;^).\-6|Z~,SHX aW/?ivү bs_d3덳c8">E o'r9IIΥz ;?(@uj-'/bFUy8I(G uߠ:$Ճ #I19B';}b "=$瀤R zE!V] *& _T0 ZrJcUR>&X#&F*L* Y_?h   N;[6kES[7y\*>gN=^NIpO19||a| vLD(KPR}c W[m&\zѩ޻a7;"`{)-&Gdq>N`E]G%-#I05_fcԕɦ߮úI{}6[8Xd#GKκc=W |9}ug,6\ y5fol|,-J,BȪ%GxhY_tj,^?:f͟oN"k OYv_iSSWM֤%[X5{['+z|#ciV|Z^̿C̏r45jԒ5)Eyb#'OA j7h<*rۮ|yj1WήíA?PdUu<\l"3AS3}"=ׂ5=ϩA~l70& $6V*gYnTc't,Iu0u|{qP֧AԩUnϢ6s tU`BSڎ_{9}ytT(K}COx!p_Oki[-?3|AzAN(r'rc- 38%qS7'fZX ]Q&`yIصwc}dM%?TRL꙯NVO6RK+'Xi*ϵLhVOXx}sbrd*rthMI* }8U˶I9xVO:KWQ/TB@@tB;-X; dþ(OfcE߿]y|X)yƭ<~m彫dt6{0OBPS.˃pٗˠ-?E͋}Ϗ?:ӟ,RA` >ݻkP#m{wD/> vAy]ys<xگ^˿yg9^?cPiGiBz{0 ,K sW~ 62(S/1p\yύ-?ty08$$8O?t9=;0w_o/9% -t=n0hP-z]7i\A=+mzbӇ6svn.._c/ǟxk,"QlR}?#ڋ''xR%G',yN$Q\Dr]'~mD &U}=sL֎+-u6ΑslNə9?5<`eZrBӛ*Zi%'OS'JyN#b24#tp]_-_'Mt%%B3qVp5>82;=9<2GȜ_.'ᓌɉ9"A\yU )l^pIH"9S2:/"xxczd0t"&Us Af!QMo}Cд9}^Lߞwۿcn6wmstxON2xغE:/~Tk期_bӖR) ؖȺho/f]gx`No/P5_/`%g _L'udV`.~b*ɏ }[]s^?ZCi@/9@J!*ZZrdb[tSBHN)vtΔmݺ|:[OV+ 3OyrZϭ?6g.fO~]?;|Tbc?/uP*FGcI?80>无]r -Mꛎ~g2{ICV5*qc[6?;rm@7-ִ)n:UA@5c?[4N`=2C1 c[ NrۉX@@`o} %Py^`|[{1q ~vuvo5r௹/@@@`PY  m~1ޟZrk F%z_<~6wP i19|da|f;$v┊EK'g>lW'@϶KВ dLN U χHNsU0#CIT2ڬCml]G /m>% @`j6Ub|1[̛oG^֫(+!mi9ŏ|9 Ϲ1eƊ.|<L3$%1q|$îrouͩUmMN+_䴆#}DKjϞUIw ëv0I&v 2^%͓1Mi[jƦG=$#K_U)߄ȗ*#/K4UYIsXrsdZ4]=iú}"%KwFm9HyQ1s-`~fpU8g ٖ sXNndSZhK>VB,mLm,ƨ~aT _coS[^$b@,pĶhjsn(J ;7 coxU~?YHёOc\Mwj3_JI4koH,$rΓO?Dɑaw'ߔv-&dJQtvc$g[<ܾ䄩!:O,G>/y>/!>y8!*C,[wNb`?Ui7T[Qp`!KؠrLPnhG5M@@P1ll=  ]kAyJ0 @@k6_޻w`rkvE2E38c 5(/|{l셍 ?|s$TG4Dל+CQ>[ڑ+>1d/Ae(R#+;p!ǶJJRgFhlWdҩS+D#uZBi':gn>>7Cs¼O>I躨1K5GNGWȡ)9U6&{i<'rr5xAO/Pw5ƜG< Bv'(9.c#G? ÿ<,KN)#Vr"9}=]gfkdOwߛw̯ͻ*5G[w }*+BYt^ z*?[fOڵO~:OC_Ob|p\_[_-*Z+o$[{~#sȼsj.0o_őBW*9tX/\ae%ܢKu* ă h:ꟼ0?S< m AYER0jŜr6l/x;{~'ۓ3svlNyE xrpu6S.jNѵf,l)C*[oдb\P֕:U7 }oU_9x{';ǧGx<5gg7?Z:P1U6N1v$3$gW/$%\LtX` [6R9o1g'wO~7oָUS D_TGhU{3x/m◌'Y/8/}0ŗOON'#IƇuR?Cp( `sϚ0|i?tu`R `.#'.9Nb;q1>E YN^33aI- Y$;LXcvGU]$xC2A[w( ZULs>9mWoPKN1IQKN5|o H)t[ۍ|K'|?"}`BL-]^לlLR*opbo+6,rP,}G[ĞJ?fVJSpA,)Bq.(?yW% [;ye|nS yҵx&\A84 KRZ߿lfucK'EE_ѓo)F$'r aRq¬IMF mTn;o f^VҒ3R)MBE]溙{KQ4Ò`<}*l}mx'5llR}2ut>OKv6%'w N:#-1crT!!i'=Գu'?#吧0{]ew/ho ;U`L8Z_Ipw2u`E†V_ RZd'; -52tGdZVgrݬ1zbHpH3O_X\6DND֊ߜd-n?ܬ̺)/'/WĨ" PSr)'bľ&Ju&ҹ9`sQQNA̶ִљѥǗG$$7A95f OLE`H̍Cnj"!m!FRP*FQ-T ~L21I.#0Q<, KN) *ZW3|E.]  hſ6o =-NAڵO~ʶOC_ʗ1交Ryl]$7S?L(k)\N34d܉6'+/i!Ғyt^r0?y r򗨆Pȉڀu}Pp;G0 &bK~NV r taccU\\Q(zN}Q19voϼ+os|P!E/6.\vr*/$,%D>;^2R#js'cz?ÿy\cmoch *c%sIŌ,fKɟ=|t'.g҄1SQ +}t*ޣ?> s|nN.\\s~nydwhC_ړ{.'q9*XrUNsMof!-\b*>/ͧgR%C`~yGc} n兹r7^ūsd{rtfΎ9<4oS݉ʶ%;UfGg>CUs#h0,[ 4+;9>8:69;3oצ^}6ǵlγJiGՉVf(~IopZ~tG@ə/lOĜ=ݸgSwq5$3ȹM{VMsiyqU^=̗/䞕tԍKNfƜNHEQ ?y߽`~!' DɑϹ/] mdIG"nB6|9Y"aiOSt*9ߟvGu Aɑ7z~Zr2|Be)mx:} ePlDLsRQt|LOnGA-wLb`scc~洜Zʴ/'D QLN])!)_Z˄=WU Gk BHB_38j_"XYInNixC /!;IXc?zΘlm-(V;'Ű.T$'+"ؘ}Жa-NEݩ mIQoZ"US#+TD_ӬX ST&,gS'TLۭԊRiO˹:?@4 R SgKVSvJLhDcGF[o`Џàb[grݬ9ZS[ -9<3rv'kà}#n'g\~oά[ZoK#י\7ZILO.pN ϡ6?d7r-ofi<  H@SQ'Z0u&Zpo\־ mA@$۠S*?' ,C 5.lVuV5c<"3Kڂj]wI޼㫛]ꁵA`lF4Ln}˜bE[5Q,~ϭ >;7wy=f_n;^VU#8"scqL|peA/%N̏E %C~b#KSMuvKW|z}f$8b?Dϭ퇳nl|AO?=0WϞ/tR¦s\ؘbzΥu)6ef'1P8;&,_mX82Qܪbwͽ;Ĝa5O<:EfLNa|GZ&L*4qozXQNMm_o#0 S$^&C2r %Mk-kab> -v/Q DkS<\2bnP hhpcBEx.Xl,ǜg_o^{s1n;9:<~''j\2Zo&LUsc0g(~? *-/ΰ.ϙ̡(v:ke"/۟ŋ{˩@.ZΝ%K &%3`jct+ ;j(*Q>$R|g^'72g|1>*`jwvC痜<xlSۜ>ˑ/P%:VuJ$@vљN3RE~_ʁ,q4L\6 שTp!@@e-{- |G|X#aM'vJ;$&;#rE'AVȱ&;?֧?{vdn}z/~{ kHQ"ΗDŌIlk%x_B67̠P:(+֚@˔c{w\N{虛ơy90/O.$ B4l~)&?G I9ǶJ ņ{?4ҏr*!M]'ĞR]Zbo=^ UoyS_ocr"VEd-qZ/WN__.'g|9 QL6\/9aħ8}!B\$$;kUEL>L9g_~RTNH-rLNkyGc} n兹r)^C_i3'1h|lAϠ\[<*ikŨrZKabsy߱y<2˳ss~f..r+wd7 \Nfd/dE/\J9()]BWX/xlUh3uh?W%~cb[6SQи|\ v`nlOٱ9=7歟n|G^0(lfB}Ab) 3?Y럃9dcx.Δ@o gMWkmNl_9x{';ǧGx<5gg7?ZfJA2c'KK(:+^h-\ ;kI&p3I|VҘ~qӟ۷9;{q}ϬMZ?7VV)} /m9зO*:X I$_RYcvqUrezɐIhsG\F(-VHm>y c.͗C])D1y:;b[[p}7RlVܜ(],A+ʼn\?O@Hb1S:#F9`/sW۽&g?7ϮQm|b7 :1 @ T!3J`=2Jaݵg{=u ʃ@/@ Tέ&[ [{gM3nVךּ.}/-j 0@VMlvHw _P^~pPxiJp*#LL4q>'5?_ˏE%gԿ"Frl_(0 ?/oХopp&s.//0%ApsnSqs,X|c]\~lKgn!}`fWf+dQS_ʫȯR7+=)xO͖)=ZcS?u.98׾.*Gu7NǼn'!| f;zGAK19bZQo?peN؅rb3= N[ɑrbpxҶ6v.猱O+J^JCW+9?A&99!qKr9$:?%Bw d!1KT';}IENDB`DyK _Ref182909681}DyK _Ref182909697DyK _Ref182909697}DyK _Ref182909761DyK _Ref182909779DyK AnimatedGIFEditor()DyK _Ref182909796}DyK _Ref182909831DyK _Ref182909831}DyK _Ref182909865DyK _Ref182909865}DyK _Ref182909946DyK _Ref182909946}DyK _Ref182909966DyK _Ref182909966}DyK _Ref182909994DyK _Ref182909994}DyK _Ref182977879DyK _Ref182977879}DyK _Ref191464188DyK _Ref191464244}DyK _Ref182977905P$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HDd  :T  0Ad=bF<3&xnF<3&PNG  IHDR?&l~sRGBPLTE3f3333f333ff3fffff3f3f̙3f3333f3333333333f3333333f3f33ff3f3f3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3vvvffffffff3fffffff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3f̙3f̙̙3f̙3f3333f333ff3fffff̙̙3̙f̙̙̙3f̙3f3f3333f333sf3fffff3f3f̙3fjC pHYs+RIDAThC PW~*B;AB۹hau3_NFh{"h.,@~N3#4RTbr.6?SCC Տ|(~ʧ+W&u]OӇ4 Hͯ>ǔu?PڗG95B?Hm+>SL =ӏ~1X7G@_L /&fy ^=>:g@1~u(~aހV]IENDB`Dd! *T  0Ae>b  u&%}n u&%PNG  IHDR@%sRGBPLTE3f3333f333ff3fffff3f3f̙3f3333f3333333333f3333333f3f33ff3f1j3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3srmffffffff3fffffff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3f̙3f̙̙3f̙3f3333f333ff3fffff̙̙3̙f̙̙̙3f̙3f3f3333f333ff3fffff3f3f̙3f&C pHYs+gIDAThCQ `Y<:enӇ65K Lf_ Ccc '7L`` Q.z7A4?Ad8jm&(s?î]~vZp-@:@H6NJrƊp7X^d,V=%=/} G4#S8k`B <Id:+I\:^$ NKO qViJ&z:#}T`b8"a=u8zL}ʡN_>A'PtmmjϷp;Z m/+9bIENDB`DyK _Ref182977905}DyK _Ref182977941DyK _Ref182977941}DyK _Ref161136597}DyK _Ref161204817DyK _Ref161645188_Dd F JT  0A?b7! Hn7! PNG  IHDRsRGBPLTE3f3333f333ff3fffff3f3f̙3f3333f3333333333f3333333f3f33ff3f1j3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3qodffffffff3fffffff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3f̙3f̙̙3f̙3f3333f333ff3fffff̙̙3̙f̙̙̙3f̙3f3f3333f333ff3fffff3f3f̙3fh pHYs+IDATHKU 0 PrdΑqPB|;!\q\bGTi_"$diWxq Tl9)ؖxNj%5BeW ~FSeuݯ/&TY!}kA= cU?_{x_xmOBhO=vпf?>Seuݯ/&TY!}kA= cU?_{x_xmOBhO=vпf?>Seuݯ/&TY!}kA= cU?_{x_xmOBhO=vпf?>Seuݯ/&TY!}kA= cU?_{x_xmOBhO=vпf?>Seuݯ/&TY!}kA= cU?_{x_xmOBhO=vпf?>Seuݯ/&TY!}䶺ΰZ^hZ88=*e^USvM}IyxH%1_88+h>?WokHk+K2 GWteV2W\+]xfuĭqFYKFEc$Hǩ)$07ѭ5kgH ʒhB3a);\:,zd/Ci7a8i#M$8%APWX NJ!ү-f.x70gp"rB'=G~Jhn=QTu`w=8 y6wmN"[vc;]o, 3-4xJwZu4j2@Õa'|~r> ?]Lo2;J(ApI /N삻3*jmi?m&Yͪjj b*QM0x]iג݋ w [c fn  (z}ج-<>Nhs7v8>Cx r,2X[ &DI$J 5LF|ƥܛgѭ^-_lOYP@P@ṴoZ{IdrGfXύ_OHK{Iaa>6i>9#?,?/Q'݇${eߥ =`̰oGvٖm~(Ò=2|m}rGfXύ_OHK{Iaa>6i>9#?,?/Q'݇${eߥ =`̰oGvٖm~(Ò=2|m}rGfXύ_OHK{Iaa>6i>9#?,?/Q'݇${eߥ =`̰oGvٖm~(Ò=2|m}rGfXύ_OHK{IaE1EEQ? we$}!P@P@P@P@P@P@P@P@P@Dd:d|  Ddb :dB  S ABR= @"C GF @"CJFIF``LEAD Technologies Inc. V1.01    $.' "+"(6(+/1343&8<82<.231  1!!11111111111111111111111111111111111111111111111111  }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzw!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz\& ?,( ( uXn# 2+kg(kLԤImO}%^=!.f[ǿ9ڟK{8?4_p}S{? o"gojg-Q}mO}%={C]>ͩϽGsKٵ?(qiv6>E=!.f[ǿ9ڟK{8?4_p}S{? o"gojg-Q}mO}%={C]>ͩϽGsKٵ?(qiv6>E=!.f[ǿ9ڟK{8?4_p}S{? o"gojg-Q}mO}%={C]>ͩϽGsKٵ?(qiv $VI?NXk/%kG[AA꾨{_EYZX:*bOJy]"s H5մ.%kJ2Z6*/#"F=OI!񽝽ƍi[>wATE IG`#c&;I{ VYHm&<* ,Z_0 SCtЉڊ[c[98,o|hm=[ɳon7bq۴ y`IiC6UWӮUg <(Kd ?i6d7Sy UU1DB *HxY~RwdܡSVkOmߑ5Λ$pk/fT-J5VV7ՄM+6{d\&ecmou(,էI-EǑ y`8Ul=qRQEmFK{!O:e[ VI:,‡8 ~`q_Kݍ"`5싛i.'c$1$I3@@P@P@P@P@P@guK<\2K*r!8$u^sIP;ۨ#w GG8\,?j_wvCb9t&g[A, dhى9K{"C_E-7ssBŐU!X /LK-|7mgoGguu-RBBna$5/_>IVl&my+~p87T=%]KPAgG9RG PO#`L)b}c~\twO-aڐ2,zqI; nfu u5dhDYT(FF&|O<._XnG;-} 37 \e>V֞|gc}IdZ@@]Yv&(ṉ%"[k,Gb޵?CFY`ӴRYeHGHPAr(15ݔ<٣e8їb=ON0N6w6bK "h."2],$.{ n$!H( ( ( ( ( (IcI#c,`ץ Õjs8 v[mgc,QF68ִU ϒWԲ5ū}ߑ "€ ( (+zds.x$[d/_6Bnv|JѡPKΣmdVsM*E Χ$UrX ܚx: ]Q$iᛋyKbkhXLuM&PP'h<< }.;=3NzܺRCnkkE_ݳFW+|آ4hMmwt{u"kdQߋ3?o? ;t}Jo{yIuT{~/H>|]RAvGߋ0??GԨ_}Q>G=?*=a$go>.Qo? ;t}Jo{yIuT{~/H>|]RAvGߋ0??GԨ_}Q>G=?*=a$go>.Qo? ;t}Jo{yIuT{~/H>|]RAvGߋ0??GԨ_}Q>G=_LIK#,J5˶ĀdNKkM.'ziG<YT?EOQdG<YyQ4E@T?EOQdG<YyQ4E@x7UӼ#nc ؚKiac_(i<Psy$Ru˞2v_j[]~CpZaFۆbaԨJ?oK|S&'OB䉭OmQH(a]!dtEuj*tU5{[R+O]v ӵk8ٜڗ2~]Pw 1iFQ_On{w?xӺ}t#zuϬQuTW#zu}=Op7QW >GރTW#zu}=Op7QW >GރTW#zu}=Op7QW >GރTW#zu}=Op7QW >GރTW#zu}=Op7QW >GރTW#zu}=Op7QW >GރTW#zu}=Op7QW >GރTW#zu}=Op7QW >GރTW#zu}=Op7QW >GރTW#zu}=Op7QW >GރTW#zu}=Op7QW >GރTW~ sòTWW\2u( b-*kn"β,( ( 9b<;_thQj+Ǻ8b P3`d-85?ZK_jrGrk9eQ vo`RTi5 w ?GqR_'i! !#[jcNi#Ga/n#$ g; d7C&=2 ( ( ( ( ( (+lP@P@PCg2.]^EXfTdT>XT'Gq; 6Lӭ,cm"HaMŶdp@z~-Z[h7 r% oD}v(KO 7 KWldoY< #.#\`b 9.lໂ[M|) /ܣgX ( ( ( ( (9º@P@P@yZ?^xKKGDDR(G$n 3s@!+Bаm2_*7|rQ'ji vkxtŵi5ƲA0vew f(WlW;}+R-^UҮD^]"F Krᶪ 5{nԧH~h"^nBDR9g̙*w͗( ( ( ( ( (A@P@P@gX<{]7KQI VDO74MxK64yK|omiV/:}jj5T.$BV%I>YI#γCM*K~t47Ҭ1ƌī%*d ( ( ( ( ( (+lP@P@P3 ϝf[۟36o?w4. WSۻ6Y%;$[ef+N*@ mA] t"MYe_r:]8C؂c}Xu)fOo kW݌PP@P@P@P@P@P??WR ( (343ص֥muuxńV7Qv3$w/ԣMdڤ˽eHъG },ĨRmWW_ik>4SH 7, `䌁I>(sk{Y M܍"6PJyk<P@P@P@P@P@P@sa]KKg ( (>P~:Lt:=+C=*$Ig]apI}eXgl|1Kku6ɸm$4%Ǎ{P.}Me# w!2eNTA@_5uIH|; dke Eg2GʼzPh7C?᣼a@Mht?7; vh7C?᣼a@Mht?7; vh7C?᣼a@Mht?7; vh7C?᣼a@Mht?7; vh7C?᣼a@Mht?7; vh7C?᣼a@Mht?7k/M:.4EV IODd:    l 2 C (A1tui_7_4C"RL\|:KN:3FL\|:KN:JFIF``LEAD Technologies Inc. V1.01    $.' "+"(6(+/1343&8<82<.231  1!!11111111111111111111111111111111111111111111111111  }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzw!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz.& ?,( ( ( ( ( ( ( ( ( ( ( ([45k-. 6ZS$`A `ֵZxT Z񦔦{X& A<ilntoEN'E9t? zO6L w>fL#q*dVV'fL#q*dVV'ፒvr[A%!P/KjmF ƥe-D#H@c5"^;6ܪ`|Ɩ->eon>兣aeL%h¿&ψ֤,7H[Omhq4~YwyByV!H/wvZy Q@M52)w;+60IZ€ ͚I"[Ug.Aé3c8Qi"oukv V&ui%qnېNHԧRx>ѵ{j# zKskxmx1C哜XjOxbEllb&-/!,f's w:9c<˴;yTd6K ꖳYj,3ek)č]kGS(&v_ٕwcx$֤0 4VLwjţF8$#53[n]giPR[Ɍ.r}n=+U(C[ܖ--a5M!/t{qm2wq \duٌy\++jN"OjZO a>dQ6z w#Q{_TGFM;É/!`A7W"2rLh @G]nY)KK / 0)/+f7 1##ip:C ( IjL&XAJѳs?nxo/omb刡Fb\I%Dѣ)Ti!7FR0Z@ FNKO$bl`6<|r8u{xQ.Gdq #(_'ΑX[`>?V.fQ{;'0hmHSǖs=8w73j4Zy"X,F##L>d'ip/z,Zubh#GB.2ޟk+ kO>kıӾ$ݎ2O *\1Er7G1mVb}j4Wz,_A}<F"t>ELʌ,P@P=CSYf>\0glw"RQes9.BL=A~✩3MbfXP@P@P@P@P@P@PgbO쵈.bv[7q,{EvTӡ?är0ݘ>o¢}C|hPϸ2хGRBu#!5j^xX4m-FU c`RvT!+jɥ{}n//4ےH&h|Fvab|eL)R;M4ɴ˛?*%yrVqnV`mP@:z Fʑ$n q? _V1n,^f `ߵ#Ł317/Յ87[0u-I>w6e%XL52G%G-PH} L T? ?ܛV'PJx۫ m]so Ym03*t\@"g;e~=I^u}'K-}m/3c~ ̊ Seuݯ/&TY!}el&dݳ+ LG9={M9>ͩϽGsKٵ?(qiv6>E=!.f[ǿ9ڟK{8?4_p}S{? o"gojg-Q}mO}%={C]>ͩϽGsKٵ?(qiv6>E=!.f[ǿ9ڟK{8?4_p}S{? o"gojg-Q}mO}%={C]>ͩϽGsKٵ?(qiv6>E=!.f[ǿ9ڟK{8?4_p}S{? o"gok+K2 GWteV2WYT <&t/)#1ȏ GMRD:vz9TL3ybTpXx*]>hR//˷sp'$*qI #|aAԦKnY|sspX zg{[,o:+i38) H zl4ygu]#Fks$9VyPʗ8?!](~0mn bKʄ T+C2֟s k"k>%ɝ6I^3=i lMuu:+s&f$u <$w=e~>GR;N 4ėSY;# H(X?)vђFs^ī$*o;~W87}t6/4 =BhᶲC _̌dWP[~ $.0GIVl&my+~p87T=%]KPAgG9RG PO#`L)b}c~\twO-aڐ2,zqI; nfu u5dhDYT(FF&|O<._XnG;-} 37 \e>V֞|gc}IdZ@bk> :v#jeb8uF=rݷAK[Y e_4Hc,NIS]"fM~5+KlUPW- 0 ZŮ_gb~o"kyOiPKUnU99w7s{?aVÚg''inv2qg5ƅP@P@P@P@P@e&kVu~/lOYP@P@ṴoZ{IdrGfXύ_OHK{Iaa>6i>9#?,?/Q'݇${eߥ =`̰oGvٖm~(Ò=2|m}rGfXύ_OHK{Iaa>6i>9#?,?/Q'݇${eߥ =`̰oGvٖm~(Ò=2|m}rGfXύ_OHK{Iaa>6i>9#?,?/Q'݇${eߥ =`̰oGvٖm~(Ò=2|m}rGfXύ_OHK{IaE1EEQ? we$}!P@P@P@P@P@P@P@P@P@}DyK _Ref161204879}DyK _Ref161645238}DyK _Ref161204905}DyK _Ref161204905}DyK _Ref161204917}DyK _Ref161645264}D}DyK _Ref161204879DyK _Ref161645238}DyK _Ref161204879DyK _Ref161645264Ddbi :UB  S AER=$f0 3 F$f0 3 JFIF``LEAD Technologies Inc. V1.01    $.' "+"(6(+/1343&8<82<.231  1!!11111111111111111111111111111111111111111111111111  }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzw!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz!& ?W[to+_SjH3W:EO%JgVuʤ u \ۇI@A^[7גyVֱ4Ҿ ڊ c=POwqi2\Ix G#=hT *v 3QrHw$ ޓͤ\f<1 w\W9kzNdjvWN<ϲ$3gi8hH ( ( ( ( ( (5i[ͤK cvOqj7IlB]0i#w l#Դ}_HқP5Un"#0B:72h 4M&C֧XȗR}H'pٕ$o{{Ŗjb[9t州eA$yjvJ,YV @d\M]6uH9KLM[(- HmV)uxnOM^&kyflsH8bۉ8g>Z~*3kV:Koe6ͪYnJ/`{y5g6%/u9ma0 QF3\Y 3ycŰT70:ON?{4'v&R&lX[q',x yiO$o+U;-gQЬ+V9ғ2!Pv;RMۻtxZk" o.lSnpR9݄r1k B7<'s{=q^X"am>1gPgVa ,€ ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( }DyK _Ref161136679}DyK _Ref161136691?Dd 90 H # AGb è"#GqX~ un è"#GqX~PNG  IHDR&FsRGBPLTE !}306 4k>Gff3fffSa3f3f̙3f"333f33333450(<]33K333f7e.3ff,N0i3q3J-3f3333333f3̙333333f333ff3fffffbDU?/f3ff3f3f3cSr[-pndffffM}fWAh^dp`ff3fff̙ffff3fffff3f̙. vv~{ٶ`z[# ],G_|Rbk0yɿonn~FVh 1w6[rkSDLk$!^SLo&ٛO,6Q) '4*ͦ,{"%!fas:{)my} Sx$j}:f.DlŁ{ɋTݜUk']gL63&L RY0廀ٳdv}`bB=y `U\VUܫPB@]19>[U% ZXdpl&RpH_gˋ''NTwV>8P5 YMrqtI"B&5q* PW+02%4e5'Dz#}79Z^ ,KɶRՀd3'yrBCL?AL!L( ]e|flyqg+I^вp%٠"Xnv5R+(A|bbI,t]\P!lX@!A&9wfz{g{fqh8Sݜǐś]wX< X̱Va01ĥ-ZV.oqm7'A I/hy% t '.tXxD+ݝ2:RDRLR,-d nTvֺUTQ6D*PvVq{gXrp [aã %%ήBJzNa].Oyh: lg![JLyQ`v̓(W4qE\12/vEd`|.6g1eHrJg#FD<9N!7\wpBL)EO\F}4|YǡKRAt#QF'.>nq1Ym4h3\B]'j%Q`NeT\qvj΃/+3̛~a1`d:^P UѶ^lَ^mI57 έ@G2IPEdYsjV?/c|zw$B`0+2-yHmX S\ xawt^uw l{`d:&Ķ d9 no\yKW(+;`ffh(cNw%Ne74*;xHc{}h |ޖ{́ag,d,8ݞorYD5sΡ>>_>HDbr_vKٛ.cC۷؃vfey@1DG8hN^tI泅hɟl~qe30Nre.1ot$ ) ]@ 8OƜ(hM=1)m92XFT64~}2y閻 K6.䇻d_N1!%@+raO'Sxٺ_n\suvYs+}g\qիVJVpsK^a%Ȭ'*4i{:f=pE_uh*ht[k< }n?"%iItbK(W{PJkNQ@J%μ`2M7%)E"Ur*{1 EyhCS8l^` W-G|0fshqҭE˅LH9J7L 3i1icنER _t=M ] i #&r.&c^h2y- ZE=?Y#% J孜_;" \`AGHlh͂?LS7h"bm|IaQ@ta8ܒ+*j D9w*1qMр[Hʒ[6#.{3c`Ckb !,XqK9 N#eWwZtyËzҩݻwSz6\C|&|]՟2Eޒ.(zp|XNI{d<ɮ@+<'->b7w|:}gR؜s[ҏ}.-dE]/&RҖ3O#! gĄ 1́slkwȆwKq?{o/ {1i,؄c'rp;9O%]I+AޥK,ïZ8{ܹif0Fsac8m9]}k{ &NY !?yJ[+Z%+=]b5w)nsS}N(.@np;Aj4m D*1]r8J"{{[`O0&6j6 ."&H$KQ /A Kʄ7H ~~~-x麋,+55+VXnޒ%"hyvY/62@#E^?V/)O!}yT*+,2 JjkOwF~s cL97(ABz,O b'[R%ޜcSO}6ܭH˄ĪJ&#FŽe97Q 7;UHY색9ČDV<ŖNK5,@fǓdWW:,q#] Ilq+z/ 5Q^XMtSop @5MgH+ِi+Xѹݼ;RP`!pD#DZ ωV80BnȰsl%|X<5I&&val\4SO!9y^'+a>_3{m~e0ϳCs rOuH-XVy8bAh k4Z-T3犓]FwcN=w8V?L@1CBahzIy So7>,։M (zm`NHwӜzL~.!  10.3_țCQy} }| 0dL.b<@@ZM!VJ#Oe>XgEt;b0Qn7HR4;x8cP6GL4ċ&1F4{/ Fsa }}$H}UΩ+Q!Rc79F fy+~h_?V0ZْZ[ ' `aht|i~t5r \owTёx'az4)!0"6nXXE w-b/{o>NWa֝kڴfyd".&k, %~@~Ɂv+.g7̭.ꃕvvցG`&K"ORRZǔjv8/POڷnە4Ŗg3qf)8Ƌ w^_ڢ&\1[7wĄX0#K4&&%K* '&0B8=1R눙#0A%PСP9Ҽc.} i BRfd'Ĭ{98d`\).y~61[t,jbmTLe{@b^B8X/a&,# '!۪Nº~ ^M[)ӯ`Rq3PRW.~siSTh]MbUgY |D c' ]zM5PUX:gOK^P 6ً;Yd])Ih= ^tfO)][٫sh@ *Yq4Pqd9k 4Ĵ5%lf hkOajG6գQ]T)YܩS.f5@jκҭDk` 5 Q]L^KV%:,T3.4@ qy/6˂K:NW-+;u=QeC?JV2:,eiZ5Pܬ- d=312tj@5d/C4Mޱz MXwZl؉ɺ[D-@h@*Aкkݺ%k 7ZрQ k 3lfsiS A]r\XcJ]oVp 4HEH1lH\ՍI"dTlV.<4)tqBL0u"LKKqyy |%ȵRUr Yr{r:3c3j3?bÿ}Z mԝ\lD 9U/Ur{>bXq }KmDa^I`ZhsBM"vEt5X,d\@V]9ƭ ҭ?.IXi8mwzQ2ro)do:V_qԗlxVAMVn5A$r/j/]ʨeKcRM̓+jj򟕢UzKW5ȭB$%j$jYtW> zR]ee<奨"f=>z/Z.y=JZ! ;&TԻKV5y{=FbaK{QIHFr&hl49I&xMwj X~=N1TQJ\V1#"nh//OZfOqԌ#.tDRoMڨJ`!5]G 3Q5Vh:r3P#ea8՗iا5SjD>$8 U; 6ً;YxC bpf6XuqfUQ hccV3o/ hW}ΰ4fX:рȠ6 : K"sRGBPLTE3f3333f3?Gff3fffRi3f3f̙3f3333f3333333333f3333333f3f33ff3f1j3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3qodffffffff3fffffff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3f̙3f̙̙3f̙3f3333f333ff3fffff̙̙3̙f̙̙̙3f̙3f3f3333f333ff3fffff3f3f̙3f! pHYs+IDATx^Yv(EK&+sP$tuNe ]!} ݪkp?8 !ywC^G@<yU\4yUښ{'ny[T_{cM({yqA<ߟ|,k["mlseIa]/W{/O7Y嵄|^~okY|k; Jշ;S]֣zkWʯB9gyPk~Ѽc-qN*ޭs/|K~#4֜Sg5#Zݚ_?w9CޕR- ϟ?Лm5m_=<2vil]! ƐԻ8>~kJ7/9 =!ѠnO?Q&ۯ4?guyMJVgo֣ʩIo4y(gC2c-T}#4Yz.TNZ[~FT}!3wrs7YVS` eiNoX=遺onT !ݨ2B>3P;ȻQe6|fnwwl@ F򙁺&_j'@k~Ϙsa5΅=_ח_Ӡ67>xz_z.-0838u߰ J|ߤykFT}Ѽ]BRJM_;l<}jJ݉޲s_E6?O50䧢t(5x6dƋˍ.S,cә||:T>}+mKM%%>ϒz_̜p Z4;KOXw1یE7/%sxnvx ^?ARAgB^K1oS1 C+-sҌZ9m!f/i 4c|A>VN[ 1rB>'_9i| I3WuMbaR'JIk~!ouR- y[르Y/Wh}N-]:UM yȫyȫyȫyȫyȫyȫy9r=\9y@f |A͹ސWu%ϫWPEWPEWPEWPEWPEW!=;L12KKY[?qǿ_\m#L_k$CfO~Ew`)ylc/go|C%!?myȯ=aDhY -<0Ǘ1J|wym6Y(O*b4(~Gv,SĴi>]Nvekk>.=Ux]ŢվOیX@ W+mFe, _62/ yQ ȗj{ͨp&΅MojA>jc|<{C AljcogA[j{HxB0< ps"ϫ2ܑɷ`y6ٹQؽg&i*<3L gl-;bxrVIW']Xd& 3p޽@m; Fc< mXR4?cNfl, _ '|HYSWxTnM~_"rC^.'!yU\4yU\4yU\4yU\4yU\4yU\4yU6Vn=&c/gf%[(iU@o[%cboƆ<FS%{=1+tȫWPEWPEWPEWPEWPEWPEWPE!zښ Z[mN IJB>:%w,6{̦odҨOWJ_]em ]򪦆OyM :}㠪#e/cLl<4xe:tn{j~bcGQ q_UVy(/f]fxOؐY!]!MO|zR{ K@^E>S9?)LL T'vfK&vxۯl[%MtEڐ_Zol2m/a5k"HIjgV:MmR-X@^А*.*.*.*.*.*.*. +lښOVI<+v6WӅM泒#4<YlS#JMjy[ W!yU\4yU\4yU\4yU\4yUN|}ݾ8 V/VIENDB`}DyK _Ref161718374P$$If!vh5D 5< #vD #v< :V 5D 5< P$$If!vh5D 5< #vD #v< :V 5D 5< P$$If!vh5D 5< #vD #v< :V 5D 5< P$$If!vh5D 5< #vD #v< :V 5D 5< }DyK _Ref161205317Dd7 RT  0AHbW]wv6ywݽ½J),.Hx &WKpIBi4yχ ^@?t|ԉA Dt])驚/_W@Q?;q_]>]~op$<ץ__. ػ|3O[(:j ^PmgZ*\榪^JdKNV:^-Tl$tIL3M%KdRUH\%̕7nD/]ČK)5psХގpҨuEX#p$rS XT"KuU|{ \Bt.ʕat.i*.i?4(5Xӥ9{Cw-3e*)]Vx@tY-S]»w5PuO{d ,f࿣򗁗삛[?1(e:1:4t1y:4t1y:4t1y!?Hk.ӡ~I-3P.hfwNjM1 Vf=&Ƀ+%mtlZIoJ%9jYBKl~dtNV :ZFeK{9kP%3.D~hZa ]Z !N$hWyX]r(kN$~4zBt9(kg~>QhdzLthV%!颼W-lʇK5*LBy2 "M^]d"K4yqt~.!I{ɄO?R3/~BK8 { +ν]'ȗ{|8tq _.ܛhZŽtQbm\?sPQ͐+__etU;xϐ+@WLlhv|fEv:jzW I$ɧEnzE/gх't ` 9cs W#2.03X,tY* E:@e;xJ_W%T,SB[9u,!\0jD :xcJ36c1jE,ɛes3bR?mPkȩAr!/I%;#ʥ ̭.٢Ë.raE$sCtY,s]⻘GUG.ktQׂx1^,v`b@hb@hb@hFaFF5}ek6.gr,Mї_1NxifO]̢Xې# 9ڻM{2#Q=葾Ŭ{!0ފV2=$NetLuY+2IENDB`P$$If!vh5D 5#vD #v:V 5D 5P$$If!vh5D 5#vD #v:V 5D 5P$$If!vh5D 5#vD #v:V 5D 5P$$If!vh5D 5#vD #v:V 5D 5L Dd7 LT  0AIbH 10;nxH 10PNG  IHDR sRGBPLTEqod pHYs+IDATx^]0tS+Q!AM*=n% >~ox~hK):'+hz`_Oo2zhYX/dU9LK@*ue~4(o*'h(\h sQp>yFd2qO&@[bLoD⦠wN~F>pkYi_wUjP ߤ2!{S6Ր_y!Qٳ,e txfGN)Zc|2ЙrMdژΙyaq$yټ K7J:CKԁ' z%*8 "O**aGsF%=?j5z)۵IvkUs* _yJ2gό+t4>L=3W+lE!ڐCVt0]!O i;[pUcM[Ξ>t]"6zPgOmLu@KǍuS.Z&嘗Ktk^%mA$T" ^%h(&j.Kq'H񺶳:?:{mg2\+wv=,].3Ձm5鱟l J젵,w,;&յ[2B%m8IENDB`P$$If!vh5D 5l #vD #vl :V 5D 5l P$$If!vh5D 5l #vD #vl :V 5D 5l P$$If!vh5D 5l #vD #vl :V 5D 5l P$$If!vh5D 5l #vD #vl :V 5D 5l }DyK _Ref161205346 Dd Y T  0AJb YwsAVa% Fn YwsAVa%PNG  IHDRArsRGBPLTEqod pHYs+]IDATx^]킣 nOIIŽ;ٶa2A P #0q|8 Ka=0xLM_wt4axmGD~ (ZaCl%R`a%cgGib`%N@c a ^;RAӑD c` 0AP}+X,) @PtȆ!؛&FB$1jñD;,Gڠ_y k#"9|rs1M&w߼3oJ'~f6S4>0>:8V;8٧ K^FT!Q<>hvt9+ȸB0\7e- H+S)f[{Ie hi6صf~`EU!i-a3JZKHdII?C|҈qjU.-9IvJ)@9 OT70ĻPS0ݥ C@gBJ|'<`RK~zM lKn /IlN P¹v]*O8g'}16BSlDpxd *.S @{(~H d:|aO r`ڔ``0nrM pYe@ B@. C? $2qt@e* H/v0} I Bu'2Y{9|z*#0YD)P7,y7l| ]hp2uBxf!HLp 8F8?욲KFj)w-_9[qSl ҬH\aþT$&}xxНUpN fslsp Ca|H }(  ay5b bot)d $[ydLv0lQzV/ ,Ofod<$6X1Ru -6l0]Ca9 z+` ?fkK$.ꗂE-ldk4(hCQ +u^kHQ]ի1ZF0A}'Dq6o$}K)pdijVjuADm80 iYj h|WLM[6 }( ?h,,L/K ;lw',]ߪF,Y~\Ɛ׹}e-W6N*6q%n1ϠE!u Mgk\_W0DD/&!dW14"~`2``"vڠ` ? 7"dl O 0wgTth8àݘ+Kʼn L ; ~gnXg`_]/y%liGU˃릌j ֨ \Z~`ؠ}~e]NS8S)pR,6@ hCI DB"!t"""""""E&&&&&&&fO `"`"`"`VJ7R@IENDB`P$$If!vh5D 5 #vD #v :V 5D 5 P$$If!vh5D 5 #vD #v :V 5D 5 P$$If!vh5D 5 #vD #v :V 5D 5 P$$If!vh5D 5 #vD #v :V 5D 5 (Dd#)' E4T  0AKb'6c3fc'Rn'6c3fcPNG  IHDRZ{ԲsBIT&CsRGB pHYs+'4IDATx^!xa a0000VCeC0a[VcI+ڵylvGO;ZǞ~s;_njb7'<A5B/?7A` 0b7i Q Q` c&9sm EԵjNX޿lr =:@0r6?|͛ú@To\9@v u S<@"9#ۖmq>IGG 9 AzdF DzШ'M:+d_J{Xt_?>ť Ac= $3J`9"ռ#޴pp8[4hbBN,$w6OG7 c9<Y'u e vJ!فq艃n4 '90cNkJhXJ Eh=V RQ/+X ڗe@.14ʻjojiv.%B@8RR B.#tN eHk'~( "U>}$01`QNk z >$E2(oTBi=xA71FrPZ!^ -AGGr'1"!Q A~IP1@Q q48\ @"zZ v %9:XJ B @B; CIXTF PAi=xA71FrPZ!^7p cz#9 -@i @zC PAhtA[` ۍodYLٱJMnOS+Xy 'oBCAB?yI[P [e|T[-:Cg<]G&@p yc2~qrMKv6{r%S;/c9q 6dQXou<vI;pO:#!">hoB~K՞^|V"%t*}$yS9Փ3lx' ::M0˿o#.v-biO#ϲQ|wZzv53Td6锰Cb&):egAl鹃NC9WZVolxqQw퀾JofYd#V/%XMGuKY7V-$%]:av~-u-=آ7;q5;NW&:%", #-|CȞT?UlbNU,Fpe N+`B$`k "r>d-WjV$yɁ2n r#@S|[h"(@9pg̒.e-觕Y;(@/@9xQX1nF|=iE8 @Fܹh5`ĝ@A/X @Fܹh5`ĝ@A/X @Fܹh5`ĝ@A/X @Fܹh5`ĝ@A/X @Fܹh5`ĝ@A/X @Fܹh5`ĝ@헟29XVb!M&fȗ'eoFuf0Gi7׿.fmBpfyTJqÆ֤vkrI%f5g]O\d1 K S7΢: Al" _;>;_Mg3.泳fgl$~r :U̟ﳁԏu峒!@H7rsWRpiH7IJzMjB 6}f;p^|ǧ(ކTPg!Tކ4kRb}A` @ȟ >B 0@Q Or!B@8!T#%6RNJ[ݗ-,|8(߼! o\9A8@X @Fh%`@8A8+cۖmq>IGG 9 AzdF!A#)ݝՉQO X tVNɾוfj Ts>H}}K=^{НHfZ;rD%yGiuqeiĄRY6!Il%\nN^%sx!Oec @2~Cҳ} <#)bh(Nr08rUac94QzDˣ^sWd@J/%J]bhjwqԠ>2#]J$Uqpa)p 9\zE?G4/V*ʐN)QD}I`c0P"ȝ|Ip1(->dPި J#z @o c(䠴C A(ZΏ<u;ȏ OcEB @:ȓb0@iHq.` D L $94hA()KruZ  Fv4] A]'Oy' @4z @o c(䠴C AohJ#9(/FrZ8@J1 A4+]邶O}Ȳ.h#cVٕ~5tܬ3VxeNބv ~󒶠E]T[txh$aM$dKZ刵d(yqÛNq=;]?g:TI7z;j5xxg=-mierk" vA0Ʉ@L)/q}lF##<0K؃w^ rp~ҽpViRn) R'ۏ[tg^/RCzhqC&M;* (}  5@ v  @gA SL;a 3G )A@`xᙣFȔ ӎAX 0<Q#dJri ,`x2%9ȴc Or0Bͻ΀1%@r4(&Wٌls>1Iy|\NUgi7:l=c]d/8- x9\gO-mU?Srؽ#uRG>nMfrޯ fœWjD,k%(Mo2&$F)CT+_^nNQDZj<9 xMA浭vo?~r[[նPKp\0WՂ׊q n%~5`t"S,K T@W ar@Pqm3ͪ-0E&mMzOܕ\ 04 hqy ^Sڇ5>'A"ЂM_<&_i1O ~xoJ+Zؘv~|_HǼ.&o_A汉069xwG"p/xfyuFiHG@Qp1y\Fvx9p/cF~/Vmju|~~)>zEMHա}Ĝ76ZYW-fvuDq4W`0@r6^vhL y zvGf>bM,uqo=jD.hٲ.k5eEΊjiyn Cm6[vkG9!>6A{xY% uFύK|6 !-^dNZ+xm[uLn-(tӎ*mHF"L"3 !$h"پG_m@ xRAPA`8xpQOO#D Հ@ "@j@ @ 4)!pzW꾔h'F`\X>\@yMa '~FNr0F@ ,A` #`4 @Y˷o߶.hxI*=:j8ȑ WHڵ-#@ 3 $INzR4MrJ7UK]O:+ASS\*4؃@2ڡ#/Y;M G.K&&ϲ Nrg}(tpp:*Ãx}/[PkXfHraM8HF@}p ?tϱ&Pch-%Z⟻'R})QV t-CS`R" A//L $# N!Kȑ,+9B~y}qPQvpN爲 _LC @vOPA l'Fe P,cz#9 -@i @Bt~A;؁@~ A}s/(B2HriGEr]OCskȕ g`Z AhA BIXZ d0* 1%9:y;Ae`cz#9 -@i @zC PAi=xA71FrPZ!^7p XJNxFtAk?j.ήxf4.p&;/O(J]HEߢP#Obx]Մj2$3@?TȎ;l6ŵC2-UNj[9EܵV+ݛkjngO[`5Mʲ]-etX@w2BaqԵt`~ܔmno sg; _$Ma%#-r\Z|=m@gg5p)xz r/IKaKD낎W:9|YLV6ܠse4,[sځ,=Dp>Ob+5I+rvMK닖UCCxu94b"@wx>tX1(@/-Vʟr N3]>y݃zyW @] %HկKh"9HE~@x T HOrP| I @B4R" ? P<A]@*T$'9( HEr$@ w!@R(.D@ A*߅h"9HE~@x T HOrP| I @B4R" ? P<헟ZV岼1d@`6ZbY~-_vyϣW6OX<%8aC_kq59ݚ_.'뇇s.ޘJe}%֩ wgQcHK 6hsgůPbM&mn33|6[czD?oOu{ǺY^ pZ$pr@X&[ڪ&.>$<5{=VG"|LƿH_xO*']i @Y@zK"Qe(L&˯I&RۇJ!DkW@4//Y ܾ񝢈`%P_ryr,( қ#'^ k[k~䶶6myšaNWٯC6Jm}jtzDЧYy^kh=05`BUV% ~NxvdDӫ#Qa&NpCH6PP."4 A Ȭcu۞z8-ݝZ;$\TX;4/ftNB_eyqcNn8C!/_+TnVݟ^S  X ZpK /1e7ӎi?͎IRV.?m^_SO׾v (A@%g/|_"AAx~ZM̚ެkttGgœGvP^}A(I%¯,5%za6ng4W/U[`LÛ8qb+)4A`h$b@?\ qk|NExM3?8/|[wvc0`7ߔW*1dy]M޾2ecalrD,^"/#Ӑ hcxЈHBr#@Ћh$!`wrJaNvIENDB`V$$If!vh5D 5< #vD #v< :V 45D 5< f4V$$If!vh5D 5< #vD #v< :V 45D 5< f4V$$If!vh5D 5< #vD #v< :V 45D 5< f4V$$If!vh5D 5< #vD #v< :V 45D 5< f4}DyK _Ref161205358Dd'  T  0ALbSEc"v4/8}n'Ec"v4PNG  IHDR,sBIT&CsRGB pHYs+IDATx^흭8{u4K`O؃6`[vl%lN[8p6 6&lNYZ˲lK;'n$W%"bX|9,-s/0*PH@_,c *bqGa 0#(ьHJlh0 3":͌(9d׉2V?on @`6yiJ}5$J!xU"։J0~@ __P|(@)JtvnLR-]jX6/I(jus?=}kۭ}tUGvZ0!FL Q"#%n3*K0v+Iv^ߺN˪G=[v(@%2miMq-0, fNyDUPvL䍒@@겊=>}6>foa /!$A vMNVJ [ "@U1;2ւ28lDP"8Vt*Z䉞~*F. %Gb֛4떮"R];<ℍVE -%r҉`oeyżHj^v&A r2rINn\ө޳wmsYD)&;e,wqU[4Z,"NΚ@%J_ӓ>O!ROC y(Q+y@  P0s6^~Sp`p ɔvw,5N cUC nY'IqI@A`&P7!4(`fB%IqI@A`&|߼"m4IM!].D>1(2O ƙ7! l&T b]|q@2&Bx(Q!Ad@% H DŇ!\3dsyOm(k_~Z4d14m?صMU(џ7S=n6/SQNa:qTr{MteACK4%vZ9Px_DJY)ѳG%Nk}^ mp-,p-, , , ,<Dr@35 naQ0s*΃@J\Ξ fSI+;ƾ '<@)~*ׄ a&0%rKU]ծU'eWdE_087H.}ծ.˛v.FR_-@JE-T#$׀]A[((BZBܘ뫓[ dw\ &nm>ZШ7\yWDyS( iQUޝKA"hD yݧv)ӤYo7( X4PbHhf[_Ul\[u|[uƵٸ]Z[uƵٸUl\[uƵٸUl\[uƵٸUl\[u59iEPJ4} @PcJD'M,P" 0=h`  D @%Z^M  0O!Jdd !:l2Y }72復~NQ{:S憜'AoɣhURiD T"XTYI:eeǻP2d QC2*by}%\Mvm\˾^i2dOoV||zz|8<==Ic?ùkSZ4<[,LzG3&jRkDD싒4"<)4MZUX'(NS&%ګs6Dƽ:gAlܫs6Dƽ:gAlܫs6Dƽ:gAlܫs6Dƽ:gAlܫs6Dƽ:gAlܫs6Dƽ:g!bF;ƑwM]r~ H .TdW#^aNpPT"e !i(QJ4,_Z4P" %@@KJD@`X(Ѱ|i@4( K%/C(e a Du@@CsVM#!+29[(Wd˴0d\CA4٨D D3csjYА=!Jʻ<97~B_T('PI꜍;qٸ9꜍;qٸ9꜍;qٸ9꜍;qٸ9꜍;qٸ9꜍;qhj׉wVr'A@ PȝJ{%@J">@ w(Q~@%*! DG!P(r'A@ PȝJ{%@J">@ wlx&w#o~$}<޹$sAFFQNVsEpq Dw^dM%: 8u" 0=h`  D >LO%>XO6w&|(X $F]|_}bSdL- ˹^4 dc5dF(JTdXq @2 BH(Qa)dF%,` " dx'z1 k2k68'm_`@ #Z%b( b*%Z@FJQtl[԰l^P"s?=}ٷ[Tx`lCuYmg*jJnJLeɚbVVku坖U3o!7jBd*gxngr@~5v(9A`@%FI[9rL@wֈ-Ds PQj۱_Y㍡DGQ2B = JdArɐ\@\ h: P2ȍ"KLKuUDjWkAI;6Y E`l%r~ȕ 7GzyV\ v]]7\+?P [Q*x+G[k:{-mp D,άk$yH -D:A 9+H7=" = :'P%!(@c/^@ eG)Bxs=6#`u~  ŠH@?(Q?~Ԇb@bP @?jC1D1( ЏdyjHۜ#M;qF!Pr('P&.YV B'J@0l FGE@ 2V#9@ J*@d(Qd4@QL% l\)- T@* D?C (Q7v-:Ƚ-::LC@qjDȾn[+>Ahggա#Vi'FM.)UnB`TJT;;Ip N"fEFܘEhNS&wjiCS &u"\7iXCqvִƬ_Zj*X,XX DmIݱ yZV=d5PiHwgq |0[lq$M@u4A )i)QRh0@ZD͉ DDJ4} Nn@`|oyD/Ƿ3B0w!ȝIENDB`}DyK _Ref161205371Dd.5" eT  0AMR=5}AASF5}AASJFIF``LEAD Technologies Inc. V1.01    $.' "+"(6(+/1343&8<82<.231  1!!11111111111111111111111111111111111111111111111111  }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzw!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzK ?W.UM<;iOkVFv#~ B`)]VVo[.n"Aby]IM@ǥvéD? E{iE>vQJ/bO7Qϝry=ҋ|أ_m~ox?;o(x{߱G'(9<iE>vQJ/bO7Qϝry=ҋ|أ_m~ox?;o(x{߱G'(9<i>vQN/BO7qϝry=Ӌ|У_m~ox?;o(x{ߡG'8 9<i>vQN/BO7qϝry=Ӌ|У_m~ox?;o(x{ߡG'8 9<Qϥr.Qϥr.x?K_(]iE>QȻ=ҋ}-Уwx{ZߡG"J/BE_k~( 9wQϥr.x?K_(]iE>QȻ=ҋ}-Уwx{ZߡG"= mi1Ep=`=`=`=`=`=`=`=`=`=`=`=`=`=`=`(a+֗$(Yp/"}V$/IQ_D+֗$(Yp/"}V$/IQ_D*֗d(Y/dOA ğ??l/K_¯'iO" DI?Z_f$a>*֗d(Y/dOA ğ??l/K_¯'iO" DI?Z_f$a>*֗d(Y/dOA ğ??l/K_¯'iO" DI?Z_f$a>*֗d(Y/dOB¯'O" DI?z_f,a>*ޗ$(Y/dOA ğ??l/_¯'O" DI?z_f,a>*ޗ$(Y/dOA ğ??l/_¯'O" DI?z_f,a>*ޗ$(Y/dOA ğ??l/_¯'O" DI?z_f,a>l~ŜyvKDqQXVUS~)֞[Z$gԫske? fT2"^.V ^+qO_/ ?̾D~񅘑bѝ%mΗ gRO=hff-%^voѕ5-?xz_;=e?d #*]z{D# zҖ/%58akb*<¬\'V(X>M:}]kϖaJ;|Ϩ !/f8KA,wO3Y&?{"#3ceY} ce/9gV~?_a[D>&88}9e7hI/#m1i)/G桹]5L#2S҆_2&REWe/8~B|^M?լs8:ţ l<9=}uNbܴf7܃_ƄІu+7wy'15L-e{ pY{>[55>#[hm2?1;˞v#wRq5"i_{SqI;tRŝ:ܐmǣ-uÅQ(d(G}ゟ]sWSOd'ƽ!iwOC>ȝp\4˱_ cڏ٢,$uo1qQ\EMȗ]ϟ Ըo~CO!0ky]hnE4~C;0kt% \-hV:i`S$!.ֹ\ҒnХ*mc>h_"YqB3캇U1\VH#$#d}p?KV|J._)+*_?)]O#־ ȩ7}(?Օ^ ꐠ,#6dYGjZS?'0Ѩ*?B}sp [,yr,ҹ ̑0}Nq? a;7 D.-7 ?|bAUreI,kKUwOTYGux}O&mSXgKǕp? {svVg5DԒPsrNS~? ]XƬR}ߙ7*yOD.`'vLJ -eYYr?nWBth ac&_dhci dq}j󿽛6poAij[}yGrwzlO8_o?SR▹k3Tb#qIYl՟OԝJ Ͷ!tQɶ(A ^E}[NI~g>߱]|{—װFׄ-mԦh`600 zW>!I8-Fy(BqZWx@/\'F<O(_3UVgI?ʼ=N?w^]Ty0>יU=a$qNe#rz5xx[줵`DN+î6L| 2U7CyzW29_Rurh^bLr#?S\U3;Du|J6_)+*_?)]O#־ ȧ7|(?՗^7|Q^j3X (_%ݟ;EoR4svZFw#X{)>G ߃"MFXْ4'-pGcZS(6Ln6Z%rk=رKhFʭ!EXӔcL~U؟W oʵBdko{_ZePUw9{ ̼ [O#ay<}R1/mp ($^ӣα(LQA׃sʜzr<}\MJt;7Kޯ>m}Srcg[ociV_B+Iiʖ95H{oGFz^gW^StӪ_j؟WoHUn^}y)N< 9RMYl/?_5˻=9Y F.$l*]*Tun37GW_yxW4vW.X6W`C_'ibkwVKEaaVw7ZкF$d(F>/S{~?ѿD>o>+u xM ڱ$ևb)nPtr)mH(͐b Q{XV77eo#Կտ5}v~[鷖wrIq ,3yn"ZiAn&Zj0ww4< #@`8C8a?ʼʨ3יUMft6 8ybyܞSOf? <*C:k+Ԣ|e%Z!rM!sFn%[^&oECν:L(ԇz^(-ݯG?kҧ-bB[u=6ƹdrj9J=3ԺG>]{z"'f8e toF-x"9e3s򲾥 >snG5Y_(ڇ褯ܩ|yu?/Z-"V^]9zvB9utI gzUS:Pf?,O?zkOuf̿E#Z>aa+q1®2O^UNɢ*`TR]Zi~FC۬Ӭ0#]I1DEN/Hvo\X/ \:-z9eHOԃ9 7ZRxSU~rQX\_mfϗ-dv۠JPV/a%f>ޗ/?*]CZa%a2ͩ idR&dq}k60Wz[(+DզqqX?2^ڗ/V5j.kb2LnR7`gmg)J.霳Ďd` w:\-hќף9jcdRS]a'Jؔݻn˝lo\g?9nWdi?%fmXYyXrU6FW"3 wđ&rYt¬T4tkH%yVX*M^my!N*nӒO͐Y_k#[F·v]Xo0'Y2?,~uΞV5HTWOЩxOZOpJ4?\ح u~M_ KD֭u7ؖ` 6OU(|JtCD8.*jQUӋo\֕-8Ot??R _ȿxO*rQu0+ԃK4eW ^6+( ؎:VgCcS̨&:  jyUĜuHj'pH+? G[c>]0H񫢓}]4JP1i{ D^#6V^#zICν*l#Ԁz[= D`揩F @? 6{4M\l6Ñiò(WgŻ8ɲ:扲U?CzW/g}KA?=k۱\ȴbO5b?}>%sj-rҙ,_=ksҎ~#{_YywB?Wb/;#*_?%C^)'}dO]XODxE~_R=ga_b/*a#J;OZ?h?" (xEOcʅuy]osV_s__/_cWR5dpSwÂvn٦\Isu㝭8et4?O ?g5c֢I8GDЀW4=&W4pCՋV"z\WX4_Gbו//S k_U3SB ߱m?ד#>-wk7F?݋E%}[K3˩Y|$zoxG|1 EVl6-\_3R{v389o}/m^}OĿo?jZ[>WيnʕVp83$Xe{k}}c" Ӝ~5":72jʧgr_/ C]nXzӷ/g~ubecuf˼v}SO+;߇O_hUw&!($e9vz9(R?E;.|ּڙzܹ>C>޴[s6_ƣ5?a!a$ {Hh"A%(:\n9ޭ8EF$}~ W*KV3l 3x~N?{׫CiZ|c_^yy-Iw]եmc 7[iwyw?b9o"\ķH%Y,g]]Y\䐭'8׫fpQG~[knI;=nfrX/Ȯ=ar[}j5J~NšoHoْ7p>P1Oּf%bfktW/}o WSު<9؏a}/sJO@SkA/Ckz hQ݁x. @0O\F!VKKXO;ek<~[WSVݼcqPr][{u^O ?8 U>o֏s6%-E@S9;16k;~v]72~IR|wtUP}KA?uTGYe}O:<ݱ?w><ܲ#yr8xxՊtEEdT?|]5j=+עZ'C^6Pױ@͢zٵ$a^?O^6zo޽*LhrS^HL&{K\gAJ=XWX2V4LA^_ů._0?jա_Rurh_EcnfiatF|WYS?͏S>k%Pv/yo/.e_Su˿/W>6(a#!1Ҿp9r?tt}V}ѫOMxL6.NRǿ5fDyxSI4̫$xQ)(E39(.e+BgdW&.sy mfY cgꡎ9(S+Nm5GC˻T;@2klyG+ >vx_ۘoܿ &mna_r0Y/^[Zx^V>vrTd}]QI;UL֍94ӧ JFC?ﭣt[X'0 # #?O'sI8;9S[=O/!iw6]!9ϯ&x綎 X)ūTBZei>'o<5fn ۷Ϯ|3?uͭ#?SIlZgmH˶ <F9NTd&uӚdf^.ԮtBs]x\*j׶Ô]j_i}WW%_QcQմnc"j䎙'^v+ <,&\eͱSVmf(eaנy!Mc"hsOa#.u|9}[%}:pag3Z&m*g$sE:n6`*c:TM+sq@[R}O&&%GLH' u+:ySWg?&ics :?4c}?x=FnYGWDyYdz~GUvg}?pT9N1< xQJnoyUP]TMjHQFM-{tLIP׭Dĭyzٵ$at?O]FF=:(ŹQKCӤI TJGH Uzqz&5LxLQV_k^d5c?#+C¾ ^Zksy6P#^&/+O7F?݋E%}[K3˩Y|$zoxG>1_90GԞ+Kު; G;4_ ^8LJZ`r֓![?h>9_/j_R> k#NM{yֿƽ>#ymh`}4oAl/!#]O^/5sE%mgѭ_3<0_Sֿ=B$w~*J̎_A_'z/͝</+=SΫ`?mz&m>{~X3>7wp4yzGqkF{BJ|c帧?_=V #@ih 6:54yfzs\5fաsڸf:NiUby5JsGY5Mt֤kդ%S^#6T׫Dgƽ*l֚1n~zTщ|9n?k=*HǸw5R${Tɞ"#ڹVvsXIZJCҋЍʪh j£*#ayש- r>:?4{X'65x83lOj=濍QbI_wRL_/[E9iG^?rj.Fqy*BCTF~WoI🇴B+?Mhna$ #4K29+6_#Xci"W6ܑӑPi1 ɿW7G!T2ٲ0e>spGJ(Ed\e-"}B B`B~u s>-ڼ~//?ſQO`J:8<IOh>$%O"iY3Y~rru~o¿ o if/ކ(mˆ1k8Qd3(EF;#y{%w7R 駌N*1z|xzs|Z´__/'{~gCZ>ۛ{X ByMrԩ*W,M=,]$+6<ݗ=oC5+Bq/YZZioc6}-1޸*b5GvRF"Yao=J3p^7k?X'mU^F_7xkD\`m>KMsN:2幅Z+[uMVծY _B09Еz|?W-2k/=~~"D{.3c-;|`*'ZSVg.+3֝w-~HҬO<( Z? f}FNpuFkqTGFk¸b8.JR1[3˨Skx̪規>KRERLk֤f$S^"d}`kM3]gMף=뺛=HȸS]jǣL qS&Jr!XIӤ]VgE}+bՈڼWT4_H1^sש)5G•/\'F9ھӝ6WcG _O2z=濍QbI_wRL_/[E9iG^?rwN`AZ>Usҍjʜy?,>՞M#aw\֙j7^edgllÿt$ˋQ)ŻN{]d΋ 7JIU*ciA[|#c?>wgL%ԭcSxdVRd ׫VqVm._|:Rn7Ikj[9Hԕe5Os_zSgjVNEA;/ڕ/tǓe?J99/\ת>#/|@BL)#+lδ*J)-c7$蹗n34oiSŤ9,$f}ӌT7o坵 $2~cPTj6>5+Ji|U?WM<ȑS|W26O;d*: OmFO˹NNQks\<U mڜكSZƃMhx+p:VX,,+stЯ7ḳwf=׈u/eYap7dW3 :\~3 ?/+zOY6.VI1Uv}̰ԣV|??_Y࿚_z#4v? K#ԮZhURN7?sZMݵf..' 0R{_"pWԿs\Q^\5k)5OO¸ ֵn:v96cҜbyJr+h*%=(󪢹Ʒ8$FN$^"ITץH zfd\+ 歷{M$eN8繮CЦ>%Br%dN-+ 3Ң8Erg|^l+ͪ#a^eRԋT+hq?GL 1X;[h\\ʐnI#TPI$1/S'SLOl--Y|kO7F?݋E%}[K3˩Y|$zoxG_*]g3k)%;F^1vG@Ζ/ާ_|_ݖ tЅti~g6+xEOW}3Ǖp? }T|qOg?WsCoEm!ES}0_mԿ7 Ȫ3:#σ?Kt_zkiWh|?]?&Se'#:WЙD _QTu<=wyW|hC>?kOh9+F|K=6< #@m6hIjp8fKS9qTf ~4)4*HN+dEIMm>+VG 5Fm"U5!=IF "w#*]pgtv9o޻iwSFdoZv;鏈 Lli=LW5FwE j#jj/XQ?#,K~~=#@+~ ʿ<+x彦~MByl#Qї1,C~G\:2ҙ mnG"da<j{j-rҙT,_=ksҎ~#{_YYwCfVHcbS&Ҿu;ڶm}%;XX8cgb*I>]Ily_b_Č {?+_Op?}9ͻB8Wc_eׯ{j-rҙ,_=ksҎ~#{_YywC?A8GQBAq_8zugj?ui]dv5 پ(wq"6Ub_ia^TH$A# 5ٜ4x&F_mS{>ʟr ҕZqNOuΥ((6Ƚ{os>ZѾˏ\|x}ho]O>簏 ۴UUe`MwF1Z5JSi7?j#؏k?y1,NNI;pf}|wJ8/."eRVp;_[ J z.mڗ.wS>܉}ϧ~ K$ 4Y&䐛$ &QGD6lѷ,6hۜci#lѷ#r'$Đj' BHZCZqM%]D4Pƀ#q#9^?X>0xĞ&aƺ4*s鹆 Xi:T/]~ޟ;"N`l *>I}k8.S;r>1O\8] <ΈgrУUngJJ2<'^GOs/_xgwޘm-H,YV' U*Ԕ`f5g+&z|P}KA?q\GM\G,~y#lW~M>V!89Xsi+*ND zRj9"dGg#EƇ?a/ VoC~b{?{I^1a@׬Ǖp? {/r1OĎ??Xr⚏Vf)|?d{KӾ\5# ]L bF ?4xg #=r?k7S=fW_q{/ɉz:O 6tթ$W?L3k+_OxCHdv.&[XI3EȈd!g4X&rȅg,ZE1ºM]q&p dk%E2YSuTߍn:"9:bLm$ъI+)344WCHYthxdK_wZrgVgWԿs\?=} yط4'z_gejH/_͛zGj-rҙ,_=ksҎ~#{_YywCK/7Fu64e98ۑ{Eٞ<?o_9ZsXU< xo>\b1܌{yNs xG:/-.T1\Ӈ</k´O *??%4e[]l+~Fgw]k_ږ7Vk(\|'h\Wԃp_?Ur}U7;+1o.vZhh` ۊ{*^?U2z_?U,u-}x8+91ᰞWFO8FkxUQV8}ܮ3qU^K߇ѴKm9nǐ\ sgXT3J*%X<>k#'n@~FI"&O_jXglv$,بLh|xShOr09᎞;s?CZk}g>x< 5~" sͅ9njʢ1W[KMtjM*NX6s}.,Zz|V-:LjNH,S :?4ъͣؔQuZ0-Dqɣ2mՋvDHZG<y0hPk(\(5rd7*L:fEg^z֪FV#xr:bL e&n\+i!R+5/Cث3+_O|J|*='Y=vOj??͝s_(ڇ褯ܩ|yu?/Z-"V^]9zD( ( ( ( ( ( ( #@/g,ֲhŲfhŖ#&i0bhIHZHDmTi(d8WDEd(5Ed6C[!ZlZAɭS6]h6 h x(l,jL1 a!ݍ" 4Cܚ~GWԿs\O~V{4:mGI^n#`UG5`v5oJʗJgS~H)_?J:e×pB ( ( ( ( ( ( :?4)C;'Jdɒh͓FlF"d0$dRF,ozfТDQ[5T4@D fP+E75C֓6j5 K1Yuߺ_N ʾ?z>c#;nwcG\3+QKmCؿRWTS<ŗG|NoQ׏k?/._lnTԣҤL`hnavk"Ep#J>0[;_Ңyo(dkq$HdC''a?0Nkl 3As,MmL>Q"Te0V]۟h޻֋_r]lߴ۷nx4Y{Jl5o7>79F]spv[k iW[ VkyNW@ {]˒EG}-$fַL%D%GT 8f]rm2X qFg ,5V%Vs.P:`Zu=KO͹d6ܫPQu![sE2 ( ( ( ( :?4J*:%ZlMCD6J*\Lrv3hi5V3hniE5BPEhF5i"&LUh^jBK*nh˸fsCC*=/GRdz`s/\'F>GWsGm*au|J6_)+*_?)]O#־ ȧ7|(?՗^7fѵ(ٴVH5 Vk%*#&7~X' ;s* }^ K[ˋ"|;d9) ჸy kyeMՓ>\q) bLhWs8rhBX7rkΧ5"F\"CflQ*+Lϑ|O:vS z4ZSm,VUT4ı2bPvy`TMnoP߻4jѐ>eKnl2[uW 3ۈZWiwzMvC,+Q[<رQIoU CZ€ ( ( ( (+_Ox=jlCcMԬHEcIbv!&$5hV ՠ\jRDl*-!EU@RHpZ W-1ԛ*bC CoC+" o4ǫ}?`a域xjGuh#O7F?݋E%}[K3˩Y|$zoxG[jqiI 9!˱ d9R=j'Sb%p.D\|֭/c.K2JXbMXwe_j'Ur dPiZ,@@+uk5|ym'(A O? G+Fy<YgZV̸%Md29 B9Xm+W?ŽV,d9LoH6ړV"7s&H C O~cql&1 $QT?MX b+Bs7h-ZE ;d{Г OvU#<ޕγ%ı/{v(nN&7oZXZ}2bF&9=zҳ@C}Egvy3 [xLh8' vB)j)l/–/qnѯ翵 # :?4㢷 B)PiXA,!)BQbD+ L,A`+;ia10=)aE(r ) )¥ Ŧ_c֫E}KA?|Z깇!gB8?KX*mY|J6_)+*_?)]O#־ ȧ7|(?՗^:7jnz kbFG:L[ +Q䍗[} '^?α{uu!@y]rg,_+e&03f"X#T"Se2EꡰU}k9[VJ A՟h?I5jI#S-.#ق8ǽGo?4`Է.o?4]Rh vK,ږEX;1dnhlE'v=4]pȅb$m-?#WS'=b04rTÞ=b04rTÞ=3F$1FW?CN̥g6Oѥv=4]yG`lE'v="y[ ihSӰoUٓ5;r/Əg>9ŧaiTÞ=RuA$rT`ہk6ve&é mCؿRWTS<ŗG|NoQ׏k?/._vOgUEgmd+nvgZsXCrAs doZy9 9Ҳf_yЬ#\)QI}vRe yϨ͟ZX>֞,gj2FPgn+'^ 2Y> Enڠgk̅b_!IbyRFFv,,Ӷ~jI+ Ƈ_΂{T:Dƴ+hvM[򣛫!F:ssӌBhZz\,Cs*ȿ)gj$)ivSiTbP?(@wË3Oi꿯UsXt22hmi]J-G _nT]_W΅a#ϡ:Ƞ #@}P@P@^ _[Cj#e/{JdZޥeǕﺷۻn<ْ,=7:=&uOQ3vIcT\ zޓFjq!v,w$i 9.aA'$݄O'tHtص)u>; dwMr'nx>YcE?B-جB03$OO dq]5iR'Q6q|Y.~pce1(VN7'ntP ܛgѭY!=dY_(ڇ褯ܩ|yu?/Z-"V^]9zuKدlm4[u{2ڥ|W=e??E_# i$@:9,!.,=p(sI _A_-#KU1\rZ8SJXF w2G \_6]BPֶe??E_# |OOx4&: {0pc'ZGHusep ̸.6 hծk=2+"3\;;hn7|OGhr J1lI_-#KUr0=gR[)? N *_Rurh? ( (km_3?~ß,oL#sH!6Te8GR0sR0x9渓 PCf[ "*[\<~ . ]q jmR}^u4򸷶nlRH6HEtپi4) l2,@g Y$U?z?Λ5BѪiq(bA*m ]ҩ:ն"ԭlKK[wV?!eu¢Ƈa fWⴶ UP4"1v6M_3֬_w؞,('ZG, C$mum$8u;H`l.I.Xmh MZ=eQ o7+1F×.aw=2CXn  yQ0_}ϝ~θ=~ebenWq?sQ/3K%hK%h ;f?7yovݽgosҹߛRᶅ̳濍QbI_wRL_/[E9iG^?r}Yb`)a}kS~}W=GQ(mBnC*̠6>ePߘ pA6 \bm ]!he?:Fs[{ѿ1|`aobҭ:8*8* dKKhђ(PF8P0H }7?Ÿ8Xi<n9aӬbL Iܒj,}7?Ÿ8Xi|pFy?ҥzzC` tpg!-p3ӎ5+?l>4bI{Թ\,Ag671yDPv1SХ`kѿ1\aoB?OjNW X 0n^HmIrI;sѿ1\arA{O' ^a@/\'F9*C0 (:A69~G9"_U{6xM1.o*UHnrhw]110ܹ%]?S .]]y ̪ n&<p3r t5LII5;[sujCpe1npc$3aU36SP0ER\NLt[&DvIcc_7e4om|ChzvI=F+άD]R>\$/7|Z}ߐCbzȳ'7vZunO"RJI@[""1<4ڽ]j~c})ZDoU/g,@ Xz4+ӄw5'RA+K =.}fo ?%Za''Xq6 ,mlv%8hȒ/[$͓n _0XGG<6+k 29UĖ<,tt_fKr ebFHB$nj`9Mש3YrKeuKmoRӧ[qnmB,HKbg;Ej7!E֣OM‹ y_w('7 ,>M‹ y_w('7 ,>M‹ y_w('7 ,>M‹ y_w('7 ,>M‹ y_w('7 ,>_‹ !7PIT1O\Ҵr#K!i$cLpdH }Aygiqqebi@ pwT! \I4Y`_=:xy?P Ovv[k.kc1܍ ӤB`I@_9qFub lE sk2]y*%R`p 3K[[*Py iadl`#85{k,WOu9Kul !yw돑G85 ,I> (+)xĊ=Ҫ H;&V}7];fvA'5w|_?V}7F[XcVФtb8zVRرPPP@ gq ۓ/5 p AP܃$zm ao-ۜ\g9.n9# 1dO,:om9ǿ$Nd9!C%8L~Bl#hV(b%oVspڀ#WjdJL G>08n Cy08st`.?7׎XKY $U#7 {t2 fV# HB}=8 ],6_/mɊd l|׎9Q`qt\~n=oq# סS9 o"E1'{lg`\x{VF ((F1fORfE9์HHWhIB*9 Zyg 泽LNh22KLcx w2m|!YjBR([vG{t2l$*цKy|pl.&]]XRJ2eUf<~Q(nxt+Bit'K\J.p)g?abT/uƟgu4B*בo1{䓀&VDzɴ-NPGg`a1p T0=F #%Z%ab whE/+^{3w%1|޹ocIơGl-Ɔ<\tCb#lp,m-nèkZMF8k1=f˘ xH,8Y2A FHjnؙv74m]}i~(\?QtQR@GXcNN(-ddy rМr(kU=XB]K"H ]EY\Dm7[i-O1sr9ǯ4],,X - sEd.A'Ny,֨  dy4]_hG<1E3@b #q 99拠k$gd)v @FA 'sd`rƐ_?_1G7 e{*!>_?_1G7 e{*!>_?_1G7 e{*!>_?_1G7 e{*!>_?_1G7 e{*!>'h1Q34/y~)~ʟ?}Oo(TC}<?FbeO9}Oo(TC}<?FbeO9}Oo(TC}<?FbeO9}Oo(TC}<?FbeO9}Oo(TC}<?FbeO9}Oo(TE>I^v-mf0Vڬ0YNp:U!ї s|>7F?݋E%}[K3ΩY|$zoxGoB A^kv՛#\ހ95 OZewgeop8Yi^e!q!\```h.ON}[C1sJ#ݝ2جH7saW77bs)kԙ,|wh9?3-,gDo?_&Cc/_ 9mWW5kOt<2~)wJK(z-#Fot I;K1QSXW@,ۇ6N~ɣD]dduPS 0* P@*k?4mX"{I^/:hh{tIWpdH;r2 kxSPO2Da#q誣gO4|+ J_&5P ( (7Ҁ*% -k%)>Yz7ހ oKGyMn-_T#±wʛ6cfG{ky0ojzs},nYd(s8Vp2Fqx,k$ׇWk_88C|0Mwc H )mn %ySM K(S@)j]j}=tˤKP\ t@X\>+[{yW[./nl$[<bj~ 9^90݌oawys,aH,Ge2~IQ hUԥ#K ۙ J/iJ>NA ?[Mwc,E~jA&*e8V FF@2<=z^Nm&ז[a/1$OMPAy`hF7nW6qw| q6څpY<ʮWf žO ^YI k7!Zx‰f\Xl:UO@z7; 4mOՓOyzQbI_gRLY|$zoxG/QڠdQ {hw >?8m7$d8PʣE]<"3Mé2+x C\Щ= &3dPj28Yd z62~A~q#gAY-ޑ7Ρaㇺhg`(dBQrdb 3R.Gbs 夓*He|`ESES[[,SPL~p pVU=kSWCw*L3 INdQ0B zTVz]̏<Vq=׭ QpD?V= ӯ䈥lV@P@P?od.?1wEe n3YP"R^ C=es[!AE砢`d?Qpi6k4^u=ݘg 4\,bM mX#N1-"x'()nG̪{QpFmKAϨɼqnV +q(; \,[EH{뙁kA(gp2$;۷# ao\0KuM.O/ F0. " on-B;uolѪU ,PȄ*q%xgK;5!ˎ'dYH*e,JTd`O iuustdKGUB6P)ܹY lԭ+RUgRUcvJxܒ\,Xt7Cq3Vxa EH<7`GNU.tn"$QPȫ#؜ |BTI;FH ̧ }p=eo^j\,brE]"95CxTªY%Pv/yo/ ŗG|NoQ׏k?/._uVYSqHW!Rp]B24_y>Ɵ?4i*I>WƟ? O4}LJ_/&Ug? O4##@F?/&Ug5EDUE@UFڱmYV*ZnچgxPaM !_jRp]#-WIUgi*I>WƟ?4i*п _MXcOWx{'bh_x{ʃп _MXcOP1r4 $cbh_x{ʾQ@DTETTUT`(՚%ai ( ( (:@nim:y\外6f3ZƵH)4fA4_x?_p/i?G*3U"14}b?=?_p/i?G*3U"14}b?=?_p/i?G*3U"14}b?=?_p/i?G*3U"14}b?=?_p/i?G*3U"14}b?=?_p/i?G*3U#I>WƟ? O4#I>WƟc/?G*3Tx{'bh_x{ʃп _MXcOP1i*F<=B14}b?=?ALJ_/&Ug? O4#I>WƟc/?G*3Tx{'bh_x{ʾJb 8!a#*`8QVGj-rҙT,_8yrg( Is'NV_'h?Oꟶ^?OmS{(v\y?=Oa>s=?`eTfw?OmS{(vw?O3e'h?`]4{jClT{jCkFmS{(vw?OmS{(v\y?=OaOy?G=; ˟'G=;.缟ڧ0PlT{jCkFmS{(vy?=Oa_\y?=Oa>s=?`eTf?OmS{(vw?O3e'h?`]TfeTf]4{jCkT{jC}{}Q3e˟'G=;.缟ڧ0PlT{jC}{}Q3e˟'G=;.缟ڧ0PlT{jC}{}Q3e˟'G=;.缟ڧ0PlT{jC}{}Q3e˟'G=;.缟ڧ0PlT{jCkT{jC}{}=Oa_\y?=Oa>s=?`eTf?OmS{(v\y?=Oa>s=?`eTf9v,}Mg)9nZ^$$If!vh5D 5H#vD #vH:Vl t65D 5Hyt-^$$If!vh5D 5H#vD #vH:Vl t65D 5Hyt-^$$If!vh5D 5H#vD #vH:Vl t65D 5Hyt-^$$If!vh5D 5H#vD #vH:Vl t65D 5Hyt-}DyK _Ref161482203}DyK _Ref161482293}DyK _Ref161482311GDdCM      A C FA@.EnableRGBAColorEditor1C")RF6GUǮvR]B({m5%X,m<9qc[ ?*/BY46ᖅ:Zw`fx2{c={^ 3XVhpec ,<r趾 m5mРc̞&Ԗ\RQs__XiH$8-#/Zk*@r1R@X ׾] .]{+-:mudgئbJ @8<9c.Oq;Og{#Q:9 H#UfO8yGbZ9c.t;SvX 5Fx7\:WV}пmu0p@G,{3:.z΂B|Eݤ@1,czb#9K-%[NKv97񇉗 W WgK0R|P5Uk/sKpRT56jUdr#iK"髯Whf!-^ S9R@^5h։,͐MV/ui.4(t {={װYOݶ'aʠ#;8E-w7S]$gɵ峴%37zׅc焬*־Ϙsz*4j߻]˨n?sz3Ϗbُ̧.Mro5s:Έx~?S#iƫhm]_񇉣鬟Uqre_39W_2;T}56jv#8ڏ)ũWOug~DqeI~(x>_mhP$$If!vh5D 5< #vD #v< :V 5D 5< P$$If!vh5D 5< #vD #v< :V 5D 5< P$$If!vh5D 5< #vD #v< :V 5D 5< P$$If!vh5D 5< #vD #v< :V 5D 5< }DyK _Ref161205386 Dd  T  0ANbs &QfT%O ZAnG &QfT%PNG  IHDR7rsRGBPLTEqoduuuvwwwxxxyyyzzzzz{{{ᬨ~ pHYs+IDATx^] s M[]viclcGrŲxzNww?~=ʹ/?۾9}8h:dVY됴eMYn#;O˙ҮnE7,Ki˜&Hmʖ_eA :4\"NWoi#i4bc1f3iPN L7-qiꁾX8t4+x 44hCm#q(x&򦸙&4CU.q6*6eou]r(h+4hIB*kQQ \Wkvn;J-xJ9Y7= MyZ-j4_Kek4PxR^u ;ɉBD*'zlV6X琄FbsHNe5jZ)k-OQ#NYk}oevZ6vu Wņ fYN\h"0{8lomX6a̦7.4ѽ8s:3`SRĴ7vK@:]uӆH-@!+\hp0'd|hWa|XkȦ`!ذnUCqY]PFVZ@QDYfZ@QT)M(F)Z9 40 BK.btFfFBEg,*6UR݄8h,Hl&>܄\7l}f/ÀV+{:x†k#`mk#8ecSкFJ6'X[!9 4dljcwݹLO,Cx]'95@5ZfGt* ƆPa_NVڥ?DҚKA{b[U;w f3  BY Gw8X}] W$LJS oÇ!!}]0I269J9+Vz'ZW:$|/N*햲*Y:EYCkbÆVG)ЖHD7FFͷČ?,:xmA nBNmH8hOD=._8iРd>!)GX+@.ZzVmmM"m䁑`>}QS]4;.t=v,v{Vkg=ݳg q uL?IENDB`P$$If!vh5D 5|#vD #v|:V 5D 5|P$$If!vh5D 5|#vD #v|:V 5D 5|P$$If!vh5D 5|#vD #v|:V 5D 5|P$$If!vh5D 5|#vD #v|:V 5D 5|}DyK _Ref161205409Dd(A 3| T   0A Ob ,6v5:Mn,6v5PNG  IHDRsRGBPLTE!Uy0_1j7dFrMaTxT{Y{ejqodquuuvwwwxxxyyyzzzzzz{{{|}}~~փӅՈ؍ٔݔٚܛŸҠӢŤӨʨԪ䬨έ֮ձѳֻڽپB3 pHYs+eIDATx^ EWݼXDPTHB\ FQF q="&F]D7+A!"(gP8T,¨ a\)b ) H,Bi!BڹOKJ#;Z"#0\(*.$U4/B$̞I;6bj/}G )5fpU*67 N! X3Ũ0@_nFx+5@qvՕw}oe0bx4;ֻ\0=wymG,S(2;WQUjͬ7?1,cX|O|ۑ.gDV`̝\Dר5-|:2RQ\SD}<,sם}}/U à<$PI>?а?<:طwa# lM# XB9E|)X +qm:: K/ #H*I;gԿw3)DPh2.TBb-,.|xIdWܦ͛ooZZ9d'0v1j08h\0-/c4rG#a/h N w'9Ӄt  haڃ--}>7':>49Qϒ4n"NouNYP{^{e FPB{I03jT|];ħҧ/y/|ۢwAGh?~={.߱}zϊEc"EQ$][~3n!/ņ=o3nݶm۳_0v¥ ׿׿8q"6T1ÎIcF*}-Ɣv1KUHrSÈG=ԅ)Đa$Ux(/f.?׿${2)Xa7< #u הq\C O>ёF>(f.42;U<|I#p3>cNи7p+bWΕ4 y8nJ(fH$$ 1L3 U <䎫gt./F*RG]+52 a7̼7e3&w;H/xX2 U//-S$O|pؠ0TIsXRwSjBߨ09* F) /ETq20Ţ3I0g0Ŋ1@a` z+}xe~tMƹb9V'}\gtwSuDj+H #OgT:1뿋UD]E_ŕvYdgVxg ,{|n3WWWV ,cB01X}FL#( 7\wآaj5ixU^XM=oKuj[z /V:A0›aIje})bE|:S?EXI8yt UM#)10.8Y"0kQ3!ˤ#]aT1pfϰjZ'qс,:7 zXFc ߰Hv)5Dϓ>#۩ɶCv*#xF rvHzߔ ^8Oz.xr؋jOgV;hvH jq(  (9++%Sl3goyi8GA#${\$~2<28hKb?bZ罜ߎB~SA"ai] ‘0na^Ygg 2v8 i=#1=C5>!L5-G?) 0xm/s<g<c@ ,\ z}DoG ߦvIRj  9kFV92 eΚaְ CYf5!?PVC,Qq=glրaE}㎧gx*,e #v=eg K=H]ORf0RjS0\$ \G ɶx= ca0֌8 J7#W3pS Yc6@^Q0U5rrk`0E,}c;$H8yF`TG֭ \ z1aa|\_p-D!Kri&gzz0y=a;(& w @->ճ(U)\GP7.i,*BaR?8) &2g`Ӱ}8O JuMS( 6:uwE@>@iGmE C+Ag TP`:_ J<2}=┴%xoVI2~D 0k; !2g~׀Y\j Qjэy-[$/ "w1F3~0dh445 ١v=/͝aT,qt>\{j!{Y,0zd0 =21Jk9{#ugƒawaH=J GQUHeGX91?(DeF4У[ GQUgd=@=#zTfWfT 14IkF-oc0=Ry}UNl6b"DI'ɺAչ@R"ITms ݊Ţ Q̸4&Iƀ&!Μ8|WڪFG%! zJ)")_ӵ6E$6 nc[PHwTMC5) ldA~AzV Vl(*棴Ez{t29; A @raS F"4Pl>KO#By-(R¢eHCwL/ƽyЬ?b jg/޴*Yn0e=""R@R]~QeѵbZѺjatE\0`Xcs pI~PKkklF!a"C%6 q' S~ CYf5!?PV%4P04ncL =KIENDB`P$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5H Ddb T ! 0A!Pb MCQvtu 3cn MCQvtuPNG  IHDRоsRGBPLTEqoduuuvwwwxxxyyyzzzzz{{{ᬨ~ pHYs+;IDATx^iC ^ pl wݻ?1^үCo_~_JTIN {%*Lec2='=5a-3a^>8d_ar *{Y?nr1RT)0Tk vV0jڌOiN`iƘbBBM~BR؁Rmg8f5 k4/bg )Vf F(kc B?ư4ڂf|L X66.*AC14 :7Yg~+Z~&*NN1UYgMᮟz2ϳcr?X=6T𡰫 n]3a]4h}Feӷl`.\rRcrawkTdN*| gtP˕lBg u*;\ &tPYCɕʪ*E%a:mnٰ zh[[dXx@5gݭ=d8cOD%=}7k%9B\X3PL+ZA'`Ko((;(WLi$vA.v(4Oa ZkGda)ʼne:vuc)JboJP36RÜMr2% |a[` 5c4nƌZL6ݓvq$b]%a_^3MĘPq+%qݒ9ڈ6+PlF en+3sJ-Y؊uHX+5:P?pئ@.kLBbUsV5'LU!3VMž^̘7Q(9MASx( (W啤։V_Ij[%)lʃ@JKڃ/kP*Inta]YJfT%=5Ǯ$,N5>}2oJRA xKTá;nj[I JRixEBkP[+I<^"Ԯ(&l^QTF/c*ۢkyFeɘo4z#Z5Lh5C:58ScUOF(qN<>4fBS9OV<"  gG$lwj!Ό`kѼ"q^X_Ƀ@LX:҉Xgrf,N{"źm)/†,]53a  @|X!Abvxf,FQE7ZE2I4)sE+Wu~( y_fKCG0g-XƨhMlYs{""Yߙ^`́v􉴴u`7ރ&֚ΩvP2XSlw^b x#Agu<y^1a;C!t [W(0h{{$$OIENDB`P$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5H}DyK _Ref161205433h$Dd(! 3FT " 0A"Qb#IjwI#on#IjwIPNG  IHDRIsRGBPLTE;==>>?XY\lerU _ !Uy+0_7d=?????@@ @@@@ @@@@@FrMaTxT{Y{_?__`` ````@````ejqodqz|}}~~ @@``@`փӅՈ،ٔݔٚܛŸ``ҠӢŤӨʨԪ䬨έ֮ձѳ׶ֻڽپnېh pHYs+ IDATx^]{]E}ՆXe\umf5v5dI1JR(4+JVREZj5Cְy`44&]1ZH y?y?939̽6sg~393+/ f((J0<"O0VŠ;,3S `hq%o0Up6"GJ`8q:%iJ(&X.`j0Q<4E/X5i=0@Ջ9䋸ckLs!}Z00dXj&>@/ "qұ$@ qUXbHCMoTLxTk3!c\.e c#2Alsf 0PD:O1j PTR TG)ݨ n#XND"ޙ>n'jk%qՂӦ BL)~=q Xb*xg͠A|L lC6SxdHHt l9Ul9F! #@K溥G:l3"#0p4 e01?E`h!b}F{Pf3R3Xvf#(HnHL9ŹGiJ/5pgY"H=H^2-fH m)۴(H+ `d Դ,K0J.|%5- D2 #eZD3G2"`d;B`d[Ds/'}fX>9[XͰ+hFz`8h3J0% hyYs |s8Z+Z7"WFϒJ}1#ʈ`6qʣr%E.̓_z6Myl/,S#0m0qHV`s5t8T g= z@ >7gy-͙NНFƞTu_40Ȱ$c1`j uI;qwMp1>O`b h2=sN:l5L#34 95i;~U19z8R3&M_LJ%0 `pyYgr'`h07Ls|ipaTQ(r֙}%R!q :?v s''ݰ$6H{43HOLH T9zz r":zr m Z-Ƚ i$;wa MK,cq8(0?!FGb$jC cAb PVV_ cTA{FS` /jÏ0:74tu*\N-:51؂A /EaYV̤}XZHyKC`XH<&Qe%EaZ/oAGid#^,x/Oc} ]s4-/!_3|[ڞC~>E|K03%D<eË.Ϩã.@hn!wy,^$#FoP˶.ᑮvpUJ%%IQzl8Yx(ݟZ.< S\Fq`&\U{F| ~\;x|H 6M֟um|ľF[9لFhK~p7N5Õfc*D Fvٻw+O]14'0^1cǕÙfboKͽછsvVm2h-2xP\U/O#=|`Qm:vyŁN3gOx ~too.`l6VhlH0\VKz886~Q]F~ 05y5qCpV;hn05S=#gs40ޚMbMm?- W}OՌ `9~|?9+.?"p3Dh@l^ ZF7;o}KqߞwEa%^%X$9sV9}MDܕfq`&GbˆM#m۷o߶vg.#9lJ\&_g}vk#bxNY'CCK.}FrÏ<O>̳= /P 9jF?$//U#0rN@j ͠D: iƙ  }FX*)}`XtG`hNm4u2GM7ԘJ GY{F>C^p4rίvUiha"e3". 7y3k__S^08<@E`$(3vzw^Ɉr"J.5C#$t/98MUx.D8.h TXl䘹n2uw%`{PaUb X`ߢ 2+7<ж"$XU. g$v3g~#vYj8BB}"$XiƱwL"$fg$BzƢv FHg7Èm!F3zqv4-:74Uln qrHhQߠ(|J 5k$BY3[hz/7){sa R `֌_bŻxJqsBz/'"aCz#㒶[ry?:LAN.}nJZxy+; (L8z3$Όp_|cV,_.ˢ=}gbBʦ| D;kFxcN:荻vTivkd`jתG$s߽sm0Mג|ĜѠmU xZ,u]"kߠ  sK4tpMJMFڨ,u8vAp**]Jb ) Bs~نUH423qŢ.38]f  ?Jp^W}*Z_R`tqwj;j5^.P`-)Z9/.ehځu+}wL];FZ^vs`8iz%e7=zȯ5CA)LC|GdÕϰM"FR8 ?R9]wstcq`Qu~7gxP1j(sfAb wABtȯ80it7㢯};~~S>A.)E84cI!GG4C%jFZ15y5ͣw; fgl[3\֦L^&D, W}Ou=#;AP\ഉ Ö?wUX>4zEL3˿{N  +;1 YSz8n%^%Xn5C׈7*ܤED,Uo􍎉i6R(w~ 43j4 *n}?$p@hxF,qH3(N ds9#02 eR_?+ "YW`dh(\ZD(-e {̺s4CC@5`5N9kG`dG6GCT3$8A3^<P|Cx0^a3"h9lA/Bޏa4ϐ8% ~c?&2 uU <ǾU|U{^|=Ł4 B#R:t`bb D~*lun#[u}[uVfu 2#NIF & xx`3 w)^0vg *޲l[@8Cj9d4%)1PQ/5 磿\8%B4w7d0h"YH4<0t@]UUCL> 2Ν3+Hp* ((ͰC0]r*j PO:b`0OLK"k]3HCT3p>ծJup: M3`P!ƅƃ\`#8p)W>#9T-Fss<7!`|\ U3E,| R3_![efս:< 4UQ`࡟TeYP Y$X tpDD˅Tx"@Vb X#n4֔pn<c`QiFf&.Xui(50n]v7`>5RHUBf&.XujGz>Ajt} DViH:Zf&ZY,Z?-81HZ60ppFf޽ >\{ި! \wۡ*2xǦPsI4Pp- 5^&g XނVjZ <1 (ӄ&5gBMZ `YR$[Kz TtE5kPv9Rj L쟄}c`޸kNviF&v D2P;C4+ \ 1k4tpu[UF,idf"E]m08yH7hGo׿M۴ddbQ׍cP6U* .ll*]f bQ 6܃єk pFSlEehҥn~/4ZËM-)Z9O|w~/~uHLj4}CK0y "Mϰ#,p. K0yN;w |ۇ8vnȶ^N>99]T1K0<# xT4}&hYMrcqI(/3h^QBXv,d8KS WI "3/!.:Qс1aCqHJ2Lӣt\4 > F41Gn:kp0L/Z3:JئƖ`$QZvu:ψu9V,*_0<څkU _%QJ0J0&ٱf(K j7h 1d>zL K\qj{Al MALX TVr!bR'^J.͕}ek/-?@tA:rբ7$KȭRP GH`F /}XEIENDB`}DyK _Ref161205433P$$If!vh5D 5< #vD #v< :V 5D 5< P$$If!vh5D 5< #vD #v< :V 5D 5< P$$If!vh5D 5< #vD #v< :V 5D 5< P$$If!vh5D 5< #vD #v< :V 5D 5< }DyK _Ref161205460 Dd#@ 6 T # 0A#Rb. q2# )n q2#PNG  IHDRY4sRGBPLTE.;;==>>CKCDEUqod"? pHYs+IDATx^흋z&nMvv3ܑ0#_8vc9 Hǿooޔw6 &*Y-d?U\MuMz_ 2drD/-(@9^i^zԐX{UhDS!Vvm>!dr{d/(R&[0jlAvc1]Pmtd/ 8BvSQJؐu嚵I.$b Ŏw"r70Ei>1V'}#R7sMF=p=Yۆ3O"rA`n{Fɒ[M]Aݚc{:~F=zJ26dkM}ei6їigt,r#k8l Kv!D6ժF}lJ} ΐ hV-Ȃ-͑: Zd'kWrX6Lv`dn[!KDVI,l~VAVu)Y%_ ZNjvq,Y,+ Ȃ-u3媩!N'%UKQIŪ)H ܜcZ|v1W55anwx]{u A\4EXUKx]bh5}k@VrgrvJKއ Q ;=s4/o|V\A=]#AB~`Q2LXm[d8h& kAMG]!{."' ?HyДz0 ;/V4fW3!َ$|dːT,E6)H٤-,7pnx:S%h}qC.Y7]nj*%5[DJ~='K=(qϖ7$o]b5;jɞ8f*#eY$Z'ˌh̏S.J6,G#R  u*VӇլk6,٘,9xPoPmֽE 4}6gǕs *-ٹJ?%wфFw<|֙[4dY-=,jв ͂-Ь28 qծL;7PZ jU>Ȃ-,jв;+rW 5-SYWa E@ˮfq2ԓ(YD1~]4Aس#[:EacSEJ7أYb!G{k0KW0iɾ~ɟ_i :/Z78N,qY,ޖ;3S18ۃ޼;sVל  [+ KQu@VAjyjJa7@ }@I.@h ;Jd[FQr| "4=Ȏkcs/f`dnl Y _j5YY"eY-ZvY"eY-Zvok6li.6yq/Ⅿ;j Lv).s'S)Ntoo fҞy ޒoJ"@6e%čW'X :Bk֬dy)!>[5/J:,=Bpy3 |1 SY_ٜ,SNqսf)*%t42XzfwS:<ٜ!n,!٦Tw';x"/ ddAVM吣Mຑ]a 7M[IENDB`}DyK _Ref161205478Dd*-F$ T $ 0A$SR=Q V#F|FQ V#FJFIF``LEAD Technologies Inc. V1.01    $.' "+"(6(+/1343&8<82<.231  1!!11111111111111111111111111111111111111111111111111  }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzw!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz_ ?W.UM<;iOkVFv#~ B`)]VVo[.n"Aby]IM@ǥvéD? E{iE>vQJ/bO7Qϝry=ҋ|أ_m~ox?;o(x{߱G'(9<iE>vQJ/bO7Qϝry=ҋ|أ_m~ox?;o(x{߱G'8 9<i>vQN/BO7qϝry=Ӌ|У_m~ox?;o(x{ߡG'8 9<i>vQN/BO7qϝry=Ӌ|У_m~ox?;o(x{u8 9w'_k~_k~( 9wQϥr.x?K_(]iE>QȻ=ҋ}-Уwx{ZߡG"J/BE_k~( 9wQϥr.x?K_(]Zͭ<(Ǚ,Np>PI'C\BWocjTjUۡCAqƫOhK$mI!}.&©eDWt$W'5_jF-0\D*dz>35]I7ͪw:0f'ڦ2/ ywUw\7Rò)osLFC襣QAzkZ3ǡOg~[IHvwy#2ʣRjT-e+ Zjyޔ8+lx3C.,4U%8̪*~c.^&W9+{w:qXZT}ԥ~-r{X.l*02a <+?QI_ r V )G} S66װjw"Lg8o~^ 952øJPwqW~=75XJIIZ }kOot9'6%єׂpqg#WVRTs*ԝ2=Aj,j,j,j,j,j,j,j,j,j,j,j,j,,,,,,,,,,,,,,,,,bbbbbbbbbbbbbxcm.C+j^Rw]/U5M! "@G`>My7':ZY;UDQى2+k]^Hm!ͺУebG]9{RWgtf8Xղ66j8ݮjD>!2/5dѠ+- ^/c|SstUMu/ebenwm| gӥ񖔚BJ-b@ZV._xΛOkpm{to ᚚ ֿfū4~iAtRnW֧~:[X?(hVpȍ#^P\:-wuSRium9/,OˮfIʼn8“=x㣖=6}YSF?K[{pO%k,N)Y[ݽux>57ޣyjnn|Uo 8,G^qiN4Z~*jUsѕ~x~'Oe,_OV$/IQ_"}V$/IQ_D+֗$(Yp/"}V$/IQ_D*֗d(Y/dOA ğ??l/K_¯'iO" DI?Z_f$a>*֗d(Y/dOA ğ??l/K_¯'iO" DI?Z_f$a>*֗d(Y/dOA ğ??l/K_¯'iO" DI?Z_f$a>*֗d(Y/dOB¯'O" DI?z_f,a>*ޗ$(Y/dOA ğ??l/_¯'O" DI?z_f,a>*ޗ$(Y/dOA ğ??l/_¯'O" DI?z_f,a>*ޗ$(Y/dOA ğ??l/_¯'O" DY{sVE.Ǻd}Ea[?VINsZymjNEB[R $'ɛ}S_xX4rxf'SxcGSC}?|'H_S2YbEFt:\)K{kFy<ez-mFV ¶Ե+dxx'lw '2BqkJXi p[?i7&z9??ه<{[=0pӰoGfvmWhsÞ=N}sǸi_ϳx;4{9aa?Əg>9??ه<{[=0pӰoGfvmWhsÞ=N}sǹe]V+6F$vzTiz 2 +d`1<֞}9??ه<{[=0pӰoGfvmWhsÞ=N}sǸY;Kvf8Jt1ǹfDm!קK9b3\Z@rOByl?#=hfo#H'Wa"Hq(Q,T)(<{ZkZY` /251*B /g?x/i_ϳx;4{9aa?Əg>9tW֓H# U NJ J/fXPP?:7@'O@tPj-rҙ,_=ksҎ~#{_YywC5k}=Z7`X[qݫc3zkaB.:{~qNT?/뱝 $-svL+ }H;z(Nv-/}_OmW:s "[e>Hc^WB"-߱ՆII꼣( ( ( ({IUpOVU>7Q_cR]K4KfkuE\ $a0Qv:j艩k7VB}[G77 uWlnr*2@ (yucm}qɶY7I u4_Wͼ][uRa(Fw*r89# ][U4 x0-Psr1@P@P@gԦ?șrn5t= Cdg-T-NJ0͓*L3(|([Mo\Fg{on &ٲ=2~,Gυ8 (3\T?]P]ĶnmܤK"0H?gE)T}Tn0mv#ۋ8Iw#7ce$:Mz1Q0EB<3@kO^`#?H>S}^c?b̷wO?<+ݻ~}jp>ŋ}7uS}^`#?H>S}^b[K$zE0 ѣ d2 NrQdJ"?:M^YbEFΚm&U_(ڇ褯ܩ|yu?/Z-"V^]9z~?Zi|_wOckW٫څo.Fs)L6̒m$t+:<^OGk]Z\'mu׮]t( xwVuo}&`+wa0SּQ}t"ӧec(EO1Yeb%:yĹSRO^tN{vWgg^iP@P@P@P=*'+*|(|/gVL# B_HmʰVp#pO^G2a߃5Nx s>Emq`Ӈ aRFy{vfJ2Lү#Εa%4ۙ&[{RxB[nO+0.'4ygEoE^C$՜k|Rl`ϬZ]Om2jW,-FJʽP@P@gԦ?șrntٵ_ VKapKئVT {Z̡u)K6kK;JhZ#k7ٗ.vQP@}?*JOtaDof E~b9z3O@v{B5ӉҫKEhc?_'N;on~\n,x:B{YT.u/ }֑vdwP(klgoM7Wίȡ>EsW,YTDkV&j-rҙ,_=ksҎ~#{_YywC<߲yt[7n1qvx4mϯwO{}Y*%w8%=_ [G}\ᾇo88\ʓ5enca/4k_g/֣~! )=G}Oz0{?a/4hϩ_Zu,%_M?Q?>}j=G4gWGCSH{&a__ iuS_޿>XKAM#?+֣~! )=G}Oz0{?a/4hϩ_Zu,%_M?Q?>}j=Y}-Ĺ؞MP:Yʔ\.,Zk}} HysGf%ψ$Ȏmi3C#`Xn ?:5Ž}|dT0YOCf PU#8#z΢]Q{?a/4j+Q?>}j=G4gWGCSH{&a__ iuS_޿>XKAM#?+֣~! )=G}Oz0{?a/4hϩ_Zu,%_M?Q?>}j=G4gWGCSH{&a_-\am :$ S.EcW *1rk~݋eQ5:ZNӕ_> SpPDŽxnrUH^psoTp:kXKAM#b{?a/4hϩ_Zu,%_M?Q[Gu]fۭXc-Ɇ8EsT45G5x:C%OfW4+5W7>q*m-׌u梣$%.kWSҮku X \$hENi+6vI閖9- HU`?yu%'.T#Ś7F?݋E%}[K3˩Y|$zoxGg{!?j׃K#{ [I7#L;j+ʿg\Aߩw<e5sgI̋Áz8&yVOz=שIrw*Mgk\Auy#[ǧbR[ HT˺'-ok-oWÊNOK~FKY+A]-F0V&wǗ8\p:9dՓ߳o?J.w^^~DcOA* vapW'>w^Mw_$!ҧiߍ ޥ77yY "NU v-5O˲J2{O>1)dڬۈ8>ܯmNw2 ( ^י3 ]UGymUc.wY,IXzQO_qIڣ^_iZIOWak>w4I"k,6& m_AZ.iKUyz%9Z9=?o duD[,pI5UK /1|^އҦc0\)}{)#VΡX{Spv5Oz3ZۼO}N?Jyfӗ,[rM)n`5z}"3~_;x"|g7qC>|/_,Ϭ6fa/ 3?ErA3?ErA3?ErCeq3CmPTJ3@E0I?hw̡9ܡ=HMdz.抗rAgj-rҙ,_=ksҎ~#{_YywC5k}='^ <=sךlUGU~OIۯz̪r*?9P2&婛4hujHWMw)9!xN3U<|$RL\EԖNm~Zk FWx"Kid"*mQԖG[ߕ~?We<fGw)jqbLeH X9,NFIyG{?wR+UxvMgNndWh2:sRo75IYI>mLm,-|A],ʖ[.Č!AU3޵ԭ~?GԩdG)yZ}"+{䔲*S6tI d{ԭ~?Rݚ4/jVSzOïjqos%;xHNjVS˟4/jVSF?zO"Jݗa*}¨пQQ[>OU???+v_ԩa BG'Gn0>?Th_(ԭ~?RݖNéO}$Y Ec[R$ܺxhS2m*d ?ǧ"b4eձ<`~\v&U8~k8Y? *|oŽzš=3qϭVmAR3{=hR\-93z.5M+Y< Y-&Io q7Ԓi:6YOma$kUf,sI|l4eu ~eNJ˥MBa{7QcuaqG"CV@O7o2^a6p_L+Nf>/%:޹lb[Hm'|2JO)¨пQVڕ/>?Th_(ԭ~?R݇* ~Eڕ/TQޣRe}Jv4/jVSF?zO"Jݗa*}¨пQQ[>OU???+v_ԩd |6yc=ܒHDDΤ`죟V1]&\0Mӌִ %-F}i.uE_FLj\G ;dn'I{4Is?y>/ hK?b[Zmlo*Yb: gG[RZsJ=X{y;T/44ׂiZYb.,qAжKgh$bԼͧ\KcYiZ Z%6baU ,*7p 05-WSLw^, 8灭fH ی#T qu"4WPA_IQ+%H:P=g[/ m+M[H7%CB-n 7u(-χgձçۣ\2t`!On7[+`(؀t5S ww{}=̲ќ hm (#eH9 I8f_@1HDr!AN1昶W.ۅmt{sl¦)(J? |o #67P>kxe8s lz(5&L>qǃivzғ\m6mKk'ma"rr.x_|U,mK˩+.Y^P#M;D~a9 Pk<4|귖j|{|*\̨3+Ƨ ?X_e}u \"Ʃ!;g bl<6%0yMc#d]$D%PPg[’4麽6FGyվRaxw4r!$`ddr (#RIaj~U?GbKoX3aN2=)JrE-*'+>eRӴ %ws3aj.g-fp rgEA[dE#dZ]څyQ[W~l X;vY(x]j e޲&Y4-R8dY7 炯5?wyWz}>лROJؠ ( ( A_G/ SS'W,<7\p[Cro<$Bl[9i3(|(ɩ6oeI$ZZCA<1"]k%Pv/yo/.e_Su˿/W܇`ѫ^ /GMմ[R?)tX9_Q 4R[R@A9Z`cS]lF.)61H F\&WWܡ I}Q/xAR7u6%y{]FO%[; XVm\j̫ VN0r0sEIvqip^ZɝA G@-5Gx ʬHRGP V})=H!@-'AV?QS~FW_m~t1rc)ܢ%X. uc$FgY\ѤK+G^hM+Img!?:H۞Z W&D";IDYpR@vhi8)|u.wii8/=ճN|NA9c<aOUkHP5^LȪp.bEӒ=^_Wz}kMHy{tovW VCZTW3}4[mIP+] J]~S]i:&u{mn:ZYJ ,|0'wۀ45}jQ_:Lh-dyBLyFpWVʾ@5գ0S%ו|t9P@P@P~ oJkW)k ; xz{H%>3unkW#?CE @Q֑v׿e$>Iٕ*p%(J(3[?**ޣPONյ (ɑ5Xp$iUR_`Y)k!BT$888+ưVܽ\@P@P@P@5oJʗJgS~H)__J:e×C_0կGt k? VP#,xeo >ZjZ7cdV`c*⮟RR o~SX~27lv {vvUx?t^èدۭ]}N?07 Ac@)t-`uiui6RK‰ny#\SCe9U>n<+>vs6S-ui$wQ\* mB2r2b_ts&iCp Y%Uj_v !rrn%մuHtu H |V2^~eL䏕 |BL:gnx1#cSCkii5& yjĨqH8 xNwmհd_Ӄ'5n tu.|(UX)ua@GqΓJt?0YEEO>jh_h[dEڒ ( ( (?_wF5D+ԣqKZ&=w-il򤈩oNϤpj&tq+eFSN䗫54xE4h`uF|x=z7x^q+MTM>]=.xE/ƆM> On&)ѐI&ݑz< =e&Zpؕ&v Q՛)Nh<7#ςElRl}!6y! \5 KfW"{VRM:v󸜌`gWҵ i#٦+0wp2G!WM) fkwn4۸-ũd26}69fpyW   #M]>Y yQ˂dCo?/M61z[ -َ{Y7 \ n~#:RS5a])y˿ \ 701mdu>b34vPk5,c@k}wr2s@ ( (>k%Pv/yo/.e_Su˿/W܇`ѫ^ /a|\ jfXRvP̩0rO-ۅ;{8ԫ=~I[]f&ox^e}a4(-wU8Rx9Hkz\kKl{qRU!]~=N#-JtKo]iQkpwU,>~E;O]i~hѾ{V(0TR`G> {nR;ˋCU[_;B,'苋[ZEi]Rؐ} >`¾&C7Yj_wo}+|W#x"%}CKVojh_h[dEڒ ( ( (?_wF5D+ׅ^զwf"ӒH`(^*l`9 q]s>Pկos$ڭwIrV7|pTw?3=9k:flt)mfIoޫɸ˫\8wox{MԠY,~{"UGB džHt+ yn%#HݱN$s[FI$Dk(eu"hP2 jh_h[dEڒ ( ( (?_wF5D+ԣsy"WIސOK<(D mW *fPQJ\yM< b!_H E&WDOnL#6c[i !$c郜`|iǪ0re 9''?p׊5bov ( (>k%Pv/yo/.e_Su˿/W܇`ѫ^ /s_4˝SN &Z}H X2CsҴZiwvnLq<PAϮG^'rԦՋDIRK}Lu6 g'TvYF:^LWPwwr[I1-3fHm^9YF(P HxRȾ\PӉY#]ygtFuu&6Y'ж.fmz%qWxTBag}R-kijor6!̦316s-$ ]bTx3&o5p Sp t'huKWL֟gqIsK+#`}Ddrp<@,ybOnh<1`!Ή⇆C' rr˱cխC#Z)=zOk*ҋ:qzYEyU>7uCF KA&L>](( ( (3xjS]}LȂMLGYM4kKxe{ka-ٕU363v?\&ei)m3NWLV"BaypK.d( q]E `Td 3WF'~uMv>\R{qLvú9e7K!"!{}pAkV5!@P@P@|J6_)+*_?)]O#־ ȧ7|(?՗^;k|ohepˌWF\{WV ^N=\a {_%ry/?'s|EQ|aG_'bw?_E~?a {_%ry/?'s|EQ|aG_'bw?_E~?a {_%ry/?'s|EQ|aG_'bw?_E~?a {_%ry/?'s|EQ|a![0u+?܋/Ǫ́LLr 6񺿬ÿ#G[fm 2@JRJZ?ƩXm +$fYXnmu5lG ]k~?B&/?'s|EQ|c ^N/Ó1yA;/"kO0=9<"(K0 ^N/Ó1yA;/"kO0=9<"(K0 ^N/Ó1yA;/"kO0=9ߑClI#`qJNN蝯wT4]UdV0Dd}>db9*E\*nz -AA@P@P@P@go{X.eHbxJD FwNB7rF:V57$]Zn-R3BB+^Gm=.ܦ$8#?>Cⴅ78K)~J-.̠ ( ( ( ( ( ( mCؿRWTS<ŗG|NoQ׏k?/._v@ϦN+DT'B@~^(i7rik$M nklF8nzoqSiW8aNJ+KÒ0=71[;-6rI*5.Nij|IͶu[KtZ]mmno!&D:\y-D%/fvxڤFW.?yY-?v&x߶jmo$>}tM5fBy,Gܮyo?xhe$T\eefj~էkJܽ[].V9%"cO)}_?@}_W/gh4yK<Rƀ)}_?@}_W>Vu=hѱhՏRBdfbpHǿ:eg<24]Gs]d{\ec1AQ䚳[YkٽW]\%s+}<׶jwײ%o$b!3 V9 #Sc)h]3i&ݾmmV&ߵveo yLAWml|olw U*Sw-}y4m<'YkrNhWӹmOƈG.P͈&XG҂iWu%NMwՎTvzO 'NX]b0X$(@ݒ WUuM깼mB%hnK4yK<Rƀ)}_?@}_W/gh4yK<Rƀ)}_?@}1țX'=D ( ( (7F?݋E%}[K3˩Y|$zoxGo7/> ( ( ( ( d#t* QP ( ( ( ( d~/@P@P@|J6_)+*_?)]O#־ ȧ7|(?՗^;yy= jpT${֊NS;A؎?Y,Je/'y4Q)n^io(Y$ ^`H.I =*ji5ZA.bsi1@-ᔱT NH\-ԟ~3ofweue2\$y;v è)Woo$3G9^VP2&B06>q2 ( ( (濍QbI_wRL_/[E9iG^?r|Em-+[d4 B㩭)5ž芉4E\GڧmǫkCDsK_dVqw^_Kaqe 2׭MWT3m[o͸ƥ5OF34SlrUEw cBuk+خu4IgyxP`m \dTӰ ;4լg[;KAq-ѐ<>Ur60;B 3YY8UźV£(@ ?ŋj>mDIgM,Ow0s& 9 08`^uvUn]$( ( ( (濍QbI_wRL_/[E9iG^?r|荻k H'jp9)94I]6=[sV~_z2=|Y-o(<VtHH FA=*gNPՎ3R+2€ ( ( ( d#t* QP^!5 (ͯ5VXwSg,ŬK*;2ovaqrSh$_ּS4մm6r_ZY([ CydY˓ ɂk$ o@K)[ahvO>Yͪǜ1O]6R͊'.'pT.0;黼iof%gcToߖƀFK7Ijh;켞 nC0*7i [f?5ۺuhacp<,ĚśhV87S3!€ ( 'Y)Ĉ$ ! ( ( mCؿRWTS<ŗG|NoQ׏k?/._v}1_8z&wU?oִTgW5m*gN2⊟Ï rz ^Ў{t;\kq fym &>ѳJl!ռEkc :s}$;[! Ϙ~v@U'/o]Z ZM;+m2@< X jm嵔ku[Eo.] rBN𞧬^Zkio4 @6eriH Xn|CHa@P@P QPʀ2h_@P@v$0ġ#5 `ڀ* IY"iBH"Hban4`Ȋq«(`GJwE?ail|}?3wwgb',}ݿumC4jȲXhJ!2Am q(BX9qwP<3mqŷtf$vQ+#A AE؉E\iZ>c3.ƒ"baE*@P@I?!M$A'ߋi }P@P@Pj-rҙ,_=ksҎ~#{_YywC"m#4),w14NP~j').s&Yl5"ԇU_ʿ#ٿYioy=FF6 ZIZ*0wMILwq$n9mNHgrK- lWj `! ^hp*/} L}~f1n1g)݈q"Asak0$[{NG$gtq-y{-a_*Ve DuSV֏Ms?}?}΃E5}n2f[Ku:#$kEsRi~"7]Ky"Y%Ph/agܹ(0F|mpEww*!X`}ҋG? >A+/"G? >(0A+/"G? >(0A+/"G? >(0P&V鶒91κ#B-m]de<]c/7Z}V?̟h_qrȹĎd),v8tTIJ Rẕ>l"ۚ5c ;%#ceU[#8vJ2΅8>td9V @8#dhx*d,V*ÎA%P@P@P@P@P@P@P@|J6_)+*_?)]O#־ ȧ7|(?՗^;yy= [AWZSשY?_=?Q٫P<~ S}?`Kh}Qbk3WO#u-C˸3Kqf GM/.Ry.Mb -m/-ƒ%Ȏ$ џYvhZjxkyXުc{l (۴UTmzEP@-FR]ŴHӜ~zp^9Ni&57hH#Yd>eK0 ( ( ( ( ( ( (濍QbI_wRL_/[E9iG^?r|j1}Q22H8JId?K.co/.B/ a%ζ{McOo?9©}Bm?]: iGt,<=Y)Y2N^Bz({}vmE @/.ǿAw?_]ko?8/`o~qt^=? {}]yx.6]vmE eLI"^(v-dzW\qQI/#'MoȍDzE*Gտ̿dDHegڍ9ht4'ʀhլ7ڄ5d3]S&jRj$6>E/go}= UA;neRJ| 6m֏gomO}%={C]>ͩϽGsKٵ?(qiv6>E=!.f[ǿ9ڟK{8?4_p}S{? o"gojg-Q}mO}%={C]>ͩϽGsKٵ?(qiv6>E=!.f[ǿ9ڟK{8?4_p}S{? o"gojg-Q}eQw<6ßMQOD O+?wsy IJ >SQRW8ԻrB ( ( mCؿRWTS<ŗG|NoQ׏k?/._v}1_8z# ( ( ( (A?G 6E!,̊#} W,:3(|(xOig>&$co6Qbh\:J ClE֯g=կ/]D9hTnÆ&l}PkK#4" =УFѣ"|#npPby|?$Ome}y:$[t$]rʘ*݁5FPuoW!_Jd r8öxؠ ( ( ( lOkM==/6.V2m hC>8sӧnv- :;2@Kgl_wEzN ( (>k%Pv/yo/.e_Su˿/WkDARR֨ҒFyGXP@P@P@5oJʗJgS~H)_?J:e×pB ( ( ( ( ( ( ( ( ( ( ( ( (7F?݋E%}[K3˩Y|$zoxGu_8z!@P@P@P@P@P@P@P@P@P@P@P@P@Pj-rҙ,_=ksҎ~#{_YYwC=  ( ( ( ( ( ( ( ( ( ( ( ( (濍QbI_wRL_/[E9iG^?rWP@P@P@P@P@P@P@P@P@P@P@P@P@_(ڇ褯ܩ|yu?/Z-"V^]9zD( ( ( ( ( ( ( ( ( ( ( ( ( mCؿRWTS<ŗF~*x_Gkf,&ʫ,.:岶r0{k@?(`C~/O_6 `m'`SSOQO?O? WaG?>?/oI_`m'`SSO??)/?|O E`m'`SSOQO?O? P(?֧m@ ?+lZ~?ͷ$QO?O? P(?֧m@ ?+lZ~?ͷ$ ?}j_6 ?)'?|O E`m'`SSOQO?O? WaG?>?/oI_`m'" ?}j_6G?>?/oI_`m'`SSO??)/?|O (?֧m@ ?+lZ~?ͷ$ ?}j_6 ?)'?|O (?֧m@ ?+lZ~?ͷ$ ?}j_6 ?)'?|O (?֧m@ ?+lZ~?ͷ$ ?}j_6 ?)'?|O (?֧m@ ?+lZ~?ͷ$ ?}j_6 ?)'?|O (?֧m@ ?(`SS_QO?O? WaG?>?/oI_`m'`SSOQO?O? WaG?>?/oI_`yB(%ƭQ}v^a=N>rV^$$If!vh5D 5< #vD #v< :Vl t65D 5< yt0^$$If!vh5D 5< #vD #v< :Vl t65D 5< yt0^$$If!vh5D 5< #vD #v< :Vl t65D 5< yt0^$$If!vh5P$$If!vh5D 5< #vD #v< :V 5D 5< P$$If!vh5D 5< #vD #v< :V 5D 5< P$$If!vh5D 5< #vD #v< :V 5D 5< P$$If!vh5D 5< #vD #v< :V 5D 5< }DyK _Ref161552507U,DdU)H o/)T % 0A%Tb+`Ffhy6+&5n+`Ffhy6PNG  IHDRpsksRGBPLTE !~307 4k;Gff3fTb3f3f̙3f"333f33333??=(=^33K333f7e.3ff,N%\3q3J-3f3333333f3̙333333f333ff3fffbDU?0f3ff3f3f3cSjY3pndMaffM}fWAh^dx`ff3fff̙ffff3fffff3f̙. ~_puujT\vC,nȧ?*WW~Ra ߎ~}_/_w$.q;n>, w!|?o<ocsEޜL~s4U yc4 jCxӗd{-%zi7ޔDGG%_/|?Np j*?foԯOp8ߧQwƁS ]gtj1{ȭW.t(ZEI퇮4QDۛ>SOG=6̶&2 ݟ4 Ӟl3;jƁ$J`y("C\'S}bk*:T&һMJE =7Q~d+"z@zH Vy\b_/:Hys*vz툼yly ٪cm7׏ݯ,WjEg1*bx{;oo_}݇gҵ.DӴU<^w6CNL,FNsq=eN1rr`_|&Bz\`a9,D!~U`Pem{z-U@ a 3'!f\Օ6z!O=pp|E¤[ǜ|eTZ* Vkg15TUF} =$)Ul^Ab6lae9@Уy=ٙ &۸W !l#$; iI>*_О訴qYUԮ2qXjӳ%Cg \2 47@XEQeMVY5Dl.LiCN @:|T U;'+*UW%a<"e S@90sVW~68aי ؄F >j9X q 6v8K7J2ٲ5~\]Qz97UB1YpC\d-5w>3 G0AԝZ+ZBt_7W=q\$J" ن@B8nh]M#ݪNE@SŐp` +_ǥ[$ڈ9y;R@Z?1qJW@Z?1qJW@Z?1qJW@Z?1qJW@Z?1qJW@Z?1qJW@Z?q]]f>Ə /6_3=k|penqn@£8&:.vq*O/c6VT'Y"n2S=ɧwFRe0Se tivwl<8<@\nq'}:ط{g i]e@>qM/uڣqxvr.7HɧUa͸R#" sOdhqj ~ zi\e N90a 3 f<@) ̜BN.i.,Dk.`:[sj<$Zk/bNO@YXvcz2jF%K(fn2=݈av 4jM w7DU\9" &0a 3 f<@) xYx>@ڵ[V ~va|UB29Il[AУz"a[  rf?^zKMBG/5n* 9DS1^hṡʚ׶)E+Eћ,A@v K>}Ba 3 f<@) xS@9 7!8 &G @i%@LH+dR$ *@ewˀ3h9UI9нn 4$NX 'e@\"ݘf2a%@D́0a 3 f<@) xS@90s!"LaCD́0a 3'!la(rH|et>[ zPXy7@5[I f(e?a.NeޅҴ'bKʉ'.W]0+ې 8l6AHgoVf>ӆ*eʚ2`l+pp*+~>1/!G)2ՆfbQ5 V+kZV!a&.+}b27S߬a>o\eJ<5 &й((S@90s!"LaCH-%؜rI񳑦3rA>{!aHӜ?s%3m Qv?ʭt LV2u.%. V 6+?.PH( /tcNShdcN s m=l,dN;)s+sZJ #j],b E&ZoVl^@0삣nN\IQG ۉʦCҁrU~0tN@FҗV dpSewf{*b ;݃FUfZR)  ]z)UjtХR6J  ]z)UjtХ)"JU*tiR #!\)4])ߓ3ƼR-M˭"$. M!fX5*]6Lm[F]!@(`ٸtb}"1^6OPG{[yx.kb ΂bI \|)jgbI \|)jgbI \|)jgbI \|ixxooNkae@D́03!7HC Ym+ '7 @ba`xzMq$@4G~0C6E!MaTٻMN@a 3"=/'V{&lZ,ְkUr ]\,װku@_m]F]sڭY 7y&BގEFíAva.i-=c@bKFM `.2,1ua2GYYh.oa-.8w8Ik5W&dܓZ"dAĸ|TqUڱ_R5%ӕx  Wt 5wFDjl3@X3$xy3fs6N2oC@+ΥNT`!@(g|i1@|<R^7[!Zpfyoot3<('N9 3r^|[ d@Ov~)')$1@r2sdO "La01wNeI%̮ݚ@D́0yȦpT]~xt ϱ{w#s_@[`%-|rh& DWǧ]VUkғ3y'0@B)B80| 8 I[b`/ƤS۶UI T\6gxkH^$ԼdUF\bCu8JM7 $$Y?`9zH*+WgP6Ue6(Y3ȍCL=;0Fw%aLn׺7)jԵQed6qФ c#4@|dRyoi|s f_[G Mjr[BG r=gKD@֝ܵDra 3r)@w0yAUK9 4zN@Fwh5NsuV v ܚ vqٛ|u^Zmb SE߲i$%DہU|MWM5:VWh5[XU0"W)Q:M+Q7᯾ 3;4q){KS,Zp5ceABZ=@ M @V6{UlHb+@j[9}3YƈcFPu>YдITs&8gh.z#3߷T1!=8G8L?vG ι>Sפ CF_?")yn9J;@7Wѝ\E\WJH*+jiTbZp2VҺ(@(BUtDY3#Giu2obBqRl>0 f<@) ̜rNwH9@c@;h() >;m8SpG7cRwȤk↿)::YI^gzї|h3a5PB,<@5RzHH08FmC\ΪAe^rZKYch2 /)ρzh^2Ѧ):=C "LaCD́\^CI)rbs==@piorizځI/Nw_*'9Sȥ l]s=dZн HS@90s!"LaC7(HL6^._Ƞk ?:˿9H4ؚ۩!nHMGI>E)wLb}1=' JhT<1rOJ/HzBc'@fv>pE$"'"FW66lhXzN| sIq'qhUE$c'#;ŧCD32$R sR~>G1:hŠrڜP$m$C S4wf?cve^t؋Bb#916!ީ*͑'svQI`&A@nL$nsP9\%y{l^bWo`w*h?bXm\*fbɂ6? D|nmm *׺[݃&+=}\4~?/r|&ic:]Nw! s %z׶R{$.]Y\v"J5@0s!"LaC.y;64vɲix5(@EO>:CXr+BI*JQ;?!H/b @Rbb<%!STSѸhfEJCW d<CŎytѪg S@90s!d*@%Мjʅ\ $zqhV;h9 v ]U=" ^+8@%ٜj lڐWYo WwY0h f<@) xS@9" lO_{EL$,~l)p|5l͒cCinV}>ufonfغp^w' ~+Y {Om~}/ ̊i!3I+)70-Z{`1GI$,&k'TYn1HX P.2OA]|.OJʑE'e~|D@l`hr6(0Ϩ r@į@\5YyXv҄20⌰V 1lUx]#/D\e_ ^6sFbKKb3⢖*N,&>WʲxʸRjH:EU-`F4_(b<*,ZwδtzhUxv֝-UqqU^|[4qe<(ln@&TBZғYe~Q 7[@dx0r f<@) x3lbV&_s=LQgd= ͽUl^^,P~ځ8W:B~v{H3BVeZR)tV 6zBmyZzV@\ʅٓ>]~@0jB [;TKչHd [;TKչ ./GHAGn;Fnr@5NuY#Z`(>D*L!ayO! dy.ߤL:I;AJ9tqQc9k8P\>/ny͒ k'utzA8ZGg<$p񲪔$SUEmypMp{ &ɞ>ٌ%;&XE3 .a|ڥRR _Idqꛁ }/sa@) xS@9B<E\hB2LvnP{<: zPWv@*դCLI<^(@>wɅh˵\dt_=`t,2 <(A*% {Y \*, m3 |ʍv6k)n)2znPe!@&YS݆iap@) xS@9B=d aT @U0vj ,*Na7S0%iN+#(){ *&x;pm<&@gQ]/hhG3A<%w6$s{V<@{?UU P6D|ZOܨ?J+Io1g*?y废E ;@^L~BH @ ;Ƃϝ@{XȜB  >w@bNx]bxL)o@TD P kl=$3,`EkZ!Є![ŰIb.VK* m<UU>>=fHQ wY89 |ci=d`" HsGG=*v@:#+b<=*v@:#+b<=*v@:#+b<=*v# #)pԧ~xoo?Y9QَU@޾e;rIbD~=-ꤴz7b:F#Hi%cȏG ?U.q ]reR{C)5[SUMb _ap?5.gTr/_0}}QX9|kG/\>Mb _ap?5.gTr/_0}}QX9|kG/\>Mb _ap?5.gTr/_0}}QX9|kG/\>Mb _ap?5.gTr/_0}}QX9|kG/\>Mb 9O-SI Z@P@Fn5Wh ʬHRGP VP5f=DjFP@P@P@z4h)<R,ʏyUd"6]^i팂/0n EQMٓQ[h[L~n,>(kOjxɶ%'/Rz{ uStGdV u+.i]ڷB=kC0" $Fe0Ka[r]֟̚-msi1HRE0 XxQdцmJ+;Gۘ ` ^ aⶂMFy6Nd1kU(]AdgFt$ZܿeRX&LYy n@`uVq a@P@P@P@,A@XfDF-܊ϏVpyeeǙy"<JV;m&(WjSv!v?L3 ( ( (3o}?hP@ֳ͝O,3BrF(O~WaϯҀ'&G H€ ( ( (/Zȋug}h,͏z/Ut ct=;ZfEVdn"~ 3Qtuf > c.=Fɫ k ( ( (3o}?hP@P@$)#I=봲p@OH+Zj?֠+Zj?֠+Zj?֠+Zj?֠+Zj?֠+Zj?֠+Zj?֠+Zj?֠+Zj?ōYF#rT,#c˕c]<1MXw.]E@.~cѠq?Q1˸thIU$ SEʱXc|F.~cѠq?Q1˸th_ 4?/?]yw.<F]E@.~cѠq?Q1˸th_ 4?/?]yw.<F]E@.~cѠq?Q1˸th_ 4?/?]yw.<F]E@.~cѠq?Q1˸th_ 4?/?]yw.<F]E@.~cѠq?Q1˸thH`'އnP@P@P@P@HFB1Jvbʓyho|, }~4r sqy:9\ll@''\Y]P]M8VDy_꫗.G5.pſ h#:.y$'`c A"涓#UQU[w +TaC-T"Fǀ|a`܍p= g^q,W726:#}WW/\XѨiOB@n2~u"&8ߝ.r^8WDT0?PxQ{QȂW2FXdȂqy:9\>1,RRHyƈF]6XTb|.b9\>r Ųh>t#]IZ[a$'ϻ4r ڭL1"DQy1G" ][QRēje+Vc KAuO+ ^)lg\S@f%n34lR8&8 P"'K(Qmn wypZ&^Qؙ¨a~lKHi">5ZՕ5Ɍ8[F|ÀFI7y84Y`򡜽R.$U@O6.\9HEѵ{M`qc~Ă`DSC(HC`p MX jC/X?VؖX_PP2u=Ғ.IR/>Von5$kd+eJ)|xrJ=b^\| 2ܹ5:^mZQ1@(M'Yz\ElXPF;W9DcjͰn ϡ"2W-Ojm;wpC$΢p-Z'i#tCjӾU8K$wHKNz&Ŧ۪N{P( 7)jC?ж }0 (~&*>ldы@,q @ }VR?4QJ (/ 1$wB`b \eT*P)\ qt)z)ePq;U"P|ڊ_+F99.o syd*X>l{XyLqM6p5DKLgLKeiKyXĝv5wl??koc>A,NtQqzIzIJX"kI6T1`H<(ɾ}ktٱT(~p'Z(M4fW9e'qIbA@dxQg\[a*͏C0~h ai>kZ9e u 䍿*ל@@s:{hC?-ӮB<[ad-RSga)!\J~.KYo%ymө>?:f6Fgpᱟzp*|7vs'$3+c+~mЫ!N~?Q{P{5!R[>Ħzh kE.d3˟(ӼAxFe ;H=r#]׊ -zAV1l"Qv&X)-nkupn!sϋ4ZH{j'F(( ( r³iݠ͓z7E؃͓z7E ˂Cv?~t]yFdv$#؏`6/fԌ/$js!mT؈|szYoJ?祟]yދ7\vU,TةcF.wK?ug`2F'{4hA'oΝ؃͓z7E]Aڅ' (l~t]*Q/Qvgq.w'o΋6Oߝ`5'ҸĠ dNBG`lѿ:.j ’⋰!u{"b> Ē(vz._6OѢgvfb=cH1Ky齀G? >g?p@(}o?Euo+'sU?:itǞ o?}~P? >g?p@(}o?}~P? >g?p@(}o?}~P? >g?p@(}o?}~P? >g?p@(}o?}~PKɾE7)ϥHX})`=4]'ad}.lE'v=4]yG`lE'v=4]yG`lE'v=4]yG`lE'v=4]yG`lE'v=4]yG`lE'v=4]yG`lE'v=4]yG`lE'v=4]yG`lE'v=4]voqH ~n0lY.fX ,@`$mOL `GF>xTHU I;F]>v3gge=ĭ$~`ER0IAڋg$͏}3¯]:/Q.sM}2܂%s`' ]Ò=:6j]#An[;"S8lG<${IkǨ`Vbx48 9 99#ر:/Q.:/Q.:/Q.:/Q.:/Q.:/Q.:/Q.:/Q.:/Q.:/Q.:/Q.:/Q.:/Q.:/Q.:/Q.:/Q.:/Q.:/Q.:/Q.:/Q.:/Q.:/Q.:/Q.:/Q.:/Q.:/Q.:/Q.:/Q.:/Q.:/Q.:/Q.{[AkNG xX('tQU?qIIؚ +^]:#5,69$9ŮI/oom`/O>Ͽ>\rzj#Եmr=NKK[l7E(@nfN#;~mY|;󝛿~8 ,xMYtV'ni ('dڟ_<55O,lؗ[-q#dCwPha,˭-펉) ֵ7q /:YV268u !rkun,\Z|;J4fTBZPgm\]#JJҲbXC;b`7|Wg@Hl-Xvى#"xш$3 w@@P@P@P@P@P@P@P@w!/ J @ (!cq W6&2!OT!OkZrSL'{+u|WmM營-.>VnxyBWmM營-.>VnxyBWmM營-.>VnxyBWmM營-.>VnxyBWmM營-.>VnxyBWmM營-.>VnxyBWmM營-.>VnxyBWmM營-.>VnxyBWmM營-.>VnxyBWmM營-.>VnxyBWmM營-.>VnxyBWmM營-.>VnxyBWmM營-.>VnxyBWmM營-.>VnxyBWmM營-.>VnxyBWmM營-.>VnxyBWmM營-.>VnxyBWmM營-. n&8F$/KDCiݏ_1XSYr?EqW-YwJ"._ܵQe+,z U甑EG˸oHWšr?EqW-YwJ"._ܵQe+,r?EpZ(_E]?ҿk˸W-YwJ"._ܵQe+,r?EpZ(_E]?ҿk˸W-YwJ"._ܵQe+,r?EpZ(_E]?ҿk˸W-YwJ"._ܵQe+,r?EpZ(_E]?ҿk˸W-YwJ"._ܵQe 8LDbRAH ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( mo .IsZ)[$4?MW" հ0."w 4r :Oƻdkk2ʟeR$l1Ar cO tim!2&IXVcyC>Xr\; Um+[OS+McI"qj Ex.Tb/0R#,dxs\$>!0.?U+E!0O(~9^}DyK _Ref161645067DyK _Ref161645067P$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5H'#Dd4 z T  0AiVb"E*ZGW`E["lnS"E*ZGW`EPNG  IHDR.fzsBIT&CsRGB pHYs+!IDATx^]/|Ȓcz. S_X|, {f Yci6XV?VKdI.k+[rmX֟KP^}hbt]㿬#>qj Ex.Tb/0R#,dxs\$>!0.?U+E!0O(~9^7FH7*xťQOPB`D~J*ұ͈Jzd$ *NB m6SLd X|'7.Gz1/i>+ AʌR>uw?f~m#A*l[É"a7$onyٿ;~B>&b>%TЗXT;%. ;*y-+3ߎ 0 Sl*yd ϶ Tұ}Ldr\'}#SեNބ|ϖ>?edO{x-į=ޙU[^ek>,;V}`Ws\{lmoyE;ꁊe#&.:ݠ r)Rnx9oW+A.9 7*]7M/NPEo/U!qu&VvP)@? =P>tݟc~`4q h +HgyH0Z}ؓH-O!E]\5Q2j*f˓alؠa`oz*a^&Eѩx-8 vWl'iiWLj  e M]'Xr@ R?~藱ӔsБHD`0H_a8Y9Ɓ_ IWPq1㤁3BHY$c+7sɹp W0 o.)s`\ *ES$ *.\4 @TH΅#@T\ixsA`!rҋ#ܭT;j7H']KdW)\¯KAm< Ҝ"gUyU  *PiS޾tB yZ|7 gQl  {Eyt0CN7="{FtXŠX:ze|{)mQhTq~ϗ>OzE'=GqlAId!S;y? =hc)#6h͡,>M- IE*!0 P A^qi6{EK"C_A'@A qЩKBʯh$EmŗZ'  *Ea */N"@3 M1>YUQtɪf(: (E?¹5@OSc:4BRE؆lDIa !F n[~1,b+"S8ҹ(X)-H{`G WbR+'Nd˔lԳI1Hvb|# .3O_=5]/4d4xhmF[+E!Кqbwy^1/+(S%?@?iO SnsvM{d?hM䠲 skaPܬ2!hW( vxZ !ޭ^QDx8,'>Y]ܿf*xM,#$Qq,c!ݥ>S~X|b?[#_0v"L~2Ox} `a X~@_v%]@:xtoQ⻑[яdw@ox܇}CJB]x ^zW*.RAxPOhW1!\xA##.@&-Pk,bStk2kcStk;]~\?ϏAw?ۛK*6Կ$4бʹ1qi&.#*Qk$ԋ+ |XOjV{|I\C6@N3(f=W~B,uȪb}Q܍ҢCXиW$* yEmzz6~7lw#ݗA c=Z'd۶LŶc-=WD/_ѝ *&gŜ8>ʸwr-c <  ]^̃in ."y;7m&{_œ>Z?)St>x?o,(M-K|%)D#0jW4qB "A BxS9?j!wNk #M PĿVNW1keIzDP!Myybl}"*f[ f$a(ci7BNDjlI N<@h;*72,P8\>OVfYL!0e|@?A ~৉!*(t"'̸C\8d^y$Ko$w>Vovʖ1 e{-|ܽbDF,'*9kTUZ\!Of@nuW` )q.b~%QCck{ix^ywP;FU<W|6#'e-P'GOd4=[AץcfJ XI>}s㾼W&%I}4-t~sHЬ%s!GZ |L tl3MWQ ?SqÌ@ch ظKc&cLte,fcpӱq}"@TͣNFWlӑC`!3d77~Tv4p[bAPXı;~ .IWC.^xxq`TTC](sjEIt,OlGFx  _]5G`.+|A95/nưvɭ+bI>6gƖe;(=|(SY ! `ld=NM@2/X%&LR S"w' OzBmg1&LaJ >>̡Ay}hd.Jzy}H9QZ{C!$ FCke _Ћ,LB}4K"ŷ_F6KPT˅Q"[%= u<2:D+/SFv@p/n'>g XSP3dQ5zŒmt ڼ00uw\"H(w 1V=}TWA턡@R[/?/%LA* ^!+s 2p#;!^ahYEA7]dcG_3>"I3HOKNU{#YXchQSXGČV\^b҇əZ2FHEfEx\G'8[^?Gm=".̀捠lQEk>* NHc:*Z2:@\".2R|kWh5`bZֵ'"=woDǘ%Y{y nA.nڴ{\ulBOQCli^}D-afav/ldw%X\ VSb;eoP^%VAQ\L"_Ci+q)JLe-%_~qY־>:) ?%~c8qaphA`{󜟰 ` !Ą m /->;d1t1HXFɃ h՗ڴq)V@Li6%+wc;=kny/gL\C":N 6纪\/ q! .-qr-}}dg t TF'F^X~gkԒmTg#2[~-u _ai*dÛgk3s?Lݫ݋=dQ{U26v V=q!M3`wP`i<8?lhδqz SQ@q>Y̔**N x8F~AALm IF\?\?/m!)gF'JB`!T$ !p6PlB'ئ' B<G  *$5CQ<6!DŞf(>f.B4Lv :zހ:%UcNR22r b@'zTL$rlS &8u*9F]/P O@swYzUFfHÍ۲lᅾi gly7kOK7kH*Н+-J͵fEWZ/d#J.7ʼnaqyQ|ly/ʘ4Vaa~C6$[e4IOXʓ[QTK ' A6ny'ivRǩ>!\,ˀ"{'Q(4[O8MW[VNQ mS/!,̻'-LZalxz$SDޙ+:)!.;xq`vMiyA)q`6TyLҠƪ6r\ 4}Hv JJPl/Ӻ->|#՚LBIW؉m>!IQuMn!4ˌMS-2ڮl :)O}vӚ݋젩+} Ng{s7SІf(QQI ?ST 5!RUR]LH)bu@"T8)&H\%iHaP^d)YN*5>wW9uVU9 gj@S+"+,. FxOmVvLa3R.l}:p#WhKK5jmh *֫5{El:07[n>|p,Uٺ G.$8͸I?Kjݪ@>p1Rʀ*Oҟ|ՄfQwMT muB3SɆ Vi~ XUZ)ۼ21{f@8=HZjܣtGYdܭLQM(,#'XN 07\Xs:Nm+rofej㶸پ jp ϥjiӡ/28*N`1)t+R܋ag,>'βӢZG_E*%-*(43AIBrZJk|3mV[>:2}kԺr2JW^{Κ6Ŗ+i+:l~rقO?Pj6,YOgV ' XAl3Z p:M2G+cN;Xnz,q\ßr{KaC!`#7T @"??5rd)IENDB`}DyK _Ref190748021DyK _Ref162338878}DyK _Ref162338927DyK _Ref162338939}DyK _Ref161204772DyK _Ref1620833967DdbY = T  0AjWbkcRknckcRPNG  IHDRzVsRGBPLTE !}306 4k<Gff3fffSb3f3f̙3f"333f33333450(<]33K333f7e.3ff,N/h3q3J-3f3333333f3̙333333f333ff3fffffbDU?/f3ff3f3f3cSr[-pndffffM}fWAh^dp`ff3fff̙ffff3fffff3f̙. ͝_grX#Z)Yv%b88?tN76shLvVTHE՚9Jae !{X{UX>+R`S(Qbֆ nOTx<u@+YV͸lvevzSz*ʣt>=VlŬ;Hf6 qxh>ZE]$H1aso={6"`WjA֪.FsUxr [lt1noTkOSSܗPdVlQkCemH?PVK,jۈe`-,pYvP`!p@HY%ޤv 45z/c%3 P套)vPm`%eʖ8jEGSe4 - ÀDQ1V Ol Y!y4~8duqWʹp߄oy-(믬洯ZSY=IQQ>-9ճF_7}uP~K܂]ޕ J8$1觞_8}HaDeA}V͵e۔^ Y6mSz}>se6 O/uRI֯:+Mn\ AΔuê:eb;Ϫz7c,戟Jn,=%U6f'J`^buى7n+ƒmsJ¡]g74l~xhh?2+%35J…]Unue7V7o%W B~AYnd[ǭfh`6jv3NmK[6\?^`u'Fz7s`AϲG@VFA̘)T+kE#J'jaQI'9_ݍlv7O'yVg=ƅZݮ'X\,OeM_fVF!i]*7^}7MfeeYMv 6UJlElH[4 #[U+u\wA٠J D,Ee= /uE*Uv?MCs3νV֞~eb{´q-lqƠlsqhPI!-TojL7*{f,Sd]ҁYsvo=|pTux[^kXgm|hۢ- ׇ$N( 9vt7`(808IENDB`}DyK _Ref161833094P$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5H`Dd(j" (#'#'B  S AkXR=`d65T`F`d65TJFIF``LEAD Technologies Inc. V1.01    $.' "+"(6(+/1343&8<82<.231  1!!11111111111111111111111111111111111111111111111111  }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzw!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzM ?,( ( (+Z:"6і`_JGؙ;!f[={Iojg-Q}mO}%={C]>ͩϽGsKٵ?(qiv6>E=!.f[ǿ9ڟK{8?4_p}S{? o"gojg-Q}mO}%={C]>ͩϽGsKٵ?(qiv6>E=!.f[ǿ9ڟK{8?4_p}S{? o"gojg-Q}mO}%={C]>ͩϽGsKٵ?(qiv6>E=!.f[ǿ9ڟK{8?4_p}S{? o"gojg-Q}mO}%={C]>ͩϽGsKٵ?(qiv6>E=!.f[ǿ9ڟK{8?4_p}S{? o"gojg-Q}mO}%={C]j+Ă8c9 ݹ*?GOf=P<17UU/hE4R10\2؟CYա*KQjC( j}?;wlSB9?^Goi6s7u)17))NO&Լk‰ybDga|[(pX 2xk}bUie;5i$.k啇O #2gk^]p\ֱMc6QUT#*W1 v%Hg?]M༂{XPO%9; ӕf'%WMKF,/$l < mZ|E)rGQWߦAե5wtΆC_0կG|9IZ^#Ԅ:_AX#ȷC0'HmZGv4hάI湅E,m.B ^ֵKG{wwmj=怽B#TI]ʤ'OjںjWEe$ xгy\xQl4G{<4D`˨4ԉ>Am̀߈5J? j:u0j7%Oȟh @G7 5ocN#<0H7e )RK1|@+[İ3kasϝ(.g ~7;F$V4,[;u^dQBvԱِ3u]_:fֱ/;_,q쎎*7UV$HzwgmqɩiB)]y>c\#{KwդAOKC=[{B2YS* `k>7.V-rZtmhKfP7-X[hd RdH'EGlt8nݧ[^}{oD7 Xva( ( ( ( (2E-"w[N8 L}3ZA_5-~I.Z{mF}x w)ߟ8Zc dd9;Xf< NU4+:B jv "+o[ve$s8@-5ZAi{}$299Q~1,rX$؊7 m,[qRĨQMqW 9υ4mV}lw$kH&iw8;mv=Ki-%REbvI6Xr\e@ek:\Rwa0v~y#uj\ڔ]2 \&ݛ!3sOaN}7OЍ<<;~?Z)|_uOb_h}ҴW_;2ax<~FׁR\Isuh#O>)D t`P@JHrAH4M9tto :vɑ$fYIchv*KoO 8vR l|TAmw6IDIdq!v%$` Pv^lg[hgg΂6`UdT8F++AXf#/&;&t7<9Io1w܈%0JH' M(r>n IdtVyz=̒Vݕ ` GwLn#OF',K# e.u b.]XOi5{䲔F(_F2!ݽ\ZI"]$&_$yVFHlG`ϗP~~c 5Xq>CU$va9A -)mHݙ':מ _3xCIMIPqضb!@TP0q ( ( ( ( ( XmB=&>դ:zԉo9s52ǬAo K zrNGLuAYlwh;$O\qr4{DsO g?p@(}o?}~P? >g?p@(}o?}~P? >g?p@(}o?}~P? >g?p@(}o?}~P? >g?p@(}o?}~ 1XfBHF׊]\SN;͓z?hyG`lE'v=4]Yv#EX}(N=4]@?G<${ѬnytraXE$om0<<${?Y߅ 99#دZzfs}egO4pQA,pN=(pb>@?G<${zh]^neH`yq)@bj ep` k6^˄nOzr2s˸rG:/Q.rLO 6nLϱvچ-0 y8@'<${c s˸rGc s˸rGc s˸rGc s˸rGc s˸rGc s˸rGc s˸rGc s˸rGc s˸rGc s˸rGc s˸rGc s˸rGc s˸rGc s˸rGc s˸rGc s˸rGc s˸rGc s˸rGc s˸rGc s˸rGc s˸rGc s˸rGc s˸rGc s˸rGGSm )#~8Rn*MYW!P@P@xIo@hT߰ǧekZn)5V2w3WPYiZsPܲ@#$+Y)OKFHRye{!?jgQg㲵yy<NN׃?fd&mYlt\8K&!y,{V&@2#%@؏AvSjS;KM-$"9B$] h4Kik[$x-Gc33!U.I{h\r ( ( ( ( ( >|%T'#c@ ( (јdCXdª2je[\qU:ɿQF¬EIڬMDe/w4="Xڿ?i/j ףL?"6z=i/j ףL?"6z=i/j ףL?"6z=i/j ףL?"6z=i/j ףL?"6z=i/j ףL?"6z=i/j ףL?"6z=i/j ףL?"6z=i/j ףL?"6z=i/j ףL?"6z=i/j ףL?"6z=i/j ףL?"6z=i/j ףL?"6z=i/j ףL?"6z=i/j ףL?"6z=i/j ףL?"6z=i/j ףL?"6z=i/j ףL?"6z=izۮlb&-vg=y9` Wй\f@P@Pf=YƲ^M+(玸#_dTvZPc&,_<,d#Qef3}ڴgjp]|,yi.n\Ͼ_0Flv e'߲s#y7~vgcL0Zɦۛtm&),r\ɸt)i6_([ %9'VlrBH퓏S@P@P@P@P@P@P@P@P@}?*JOtG\Ɓ@NGj \\f@P@P?]M༂{XPO%9; ӕf'%WMKF,/$l < mZ|E)rGQWߦAե5wtΆC_0կG|8]_>*|@u */[kYeG#+?j9X]Cuc$|)6˫Q+xaydBZ5#ʑpn>mAx:U添Ht+k`n@<7 dGKT%(1*Hwp7SDZEHPx3m&]@ ڀ;RYѬuKU 5]C@$g( ( ( ( ( ( ( ( sRPuB{:4 ( (2.[b[;t?\u<]:g5j.mJ.ZO.Vnѐɉ''|F>FΞJ\twrFy/:yM9{%c{oofiyFK1h9!$n$o >NKN°E+nJ*Dl6RFWi4ˈ粂DxRH <2ȊB'¨ \lm:?*$[j(FO'b ( ( ( ( ( ( ( (3\T?]P莹 ( ( drgnAXr)N.M&ȿOk/"y}Qe$>ȿDd_yrT{YI"/={\U_Aȃ=?._*k/ AE/Gr "{ H9}Qe$>ȿDd_yrT{YI"/={\U_Aȃ=?._*k/ AE/Gr "{ H9}Qe$>ȿDd_yrT{YI"/={\U_Aȃ=?._*k/ AE/Gr "{ H9}Qe$>ȿDd_yrT{YI"/={\U_Aȃ=?._*k/ AE/Gr "{ H9}Qe$>ȿDd_yrT{YI"/=F$G/;W̝3HM'RMXԞ,( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( doHWšhr?EqW-YwJ"._ܵQe+,z U甑EG˸oHWšr?EqW-YwJ"._ܵQe+,r?EpZ(_E]?ҿk˸W-YwJ"._ܵQe+,r?EpZ(_E]?ҿk˸W-YwJ"._ܵQe+,r?EpZ(_E]?ҿk˸W-YwJ"._ܵQe+,r?EpZ(_E]?ҿk˸W-YwJ"._ܵQe+,r?EpZ(_E]tbl8B6;1'QE}!P@P@D{3ʁW%yn\qu_ 3y@˟/.eo .︿=97 ^k 2y3y@˟/.eo .︿=97 ^k 2y3y@˟/.eo .︿=97 ^k 2y3y@˟/.eo .︿=97 ^k 2y3y@˟/.eo .︿=97 ^k 2y3y@˟/.eo .︿=97 ^k 2y3y@˟/.eo .︿=97 ^k 2y3y@˟/.eo .︿=97 ^k 2y3y@˟/.eo .︿=97 ^k 2ycM4rDS%mFpOf'4;& Za@P@P.ks I(g˯u+n&|MCMH4 X8[ҕʘTS 0"C]h]KnA!FyPC/ސe0xk&#i-kB=@gXnBAAae'V7Wvc?@n˹Rn%PnV3$jhtfNByS,&3#x :6C~WBtJK;б5+GL#c9Z|BѴ +$\'4B%R i ሄrYڭݾwKnf ePBA }hZhQvumAirfe79QyxJm5+Bf Alf6,R3yD+a@}Ǜ p8U𽶡6wv!X0C)%neS08g`n\Crf@I$s,]Gʠ(o iDK}j7 ~r -6hM?iO__^Cn]~q)UUq H,};pXMk$l!3(IOfoNzlmo=J5;YJЭ<pܓ@˯iwtv~|֩wut_aۋ0F@.Oiwn-ۈa"H$*ʤ ;Fy}+v)2<UA m I&.jz5yautS,| 7u9P|FTP]߃m 6Ե(9c8;7&Gm̠BMo^ɾ%HCGAx8VL`?3U7yo5b}{I;7d}(r̅"@db,Ė>{P@P@P@P@P@Pf?( =sP@P@STW{UHdi wm>b+Z??I5LgI4sCnCI'Cٺ $G4?Y0f0_9gI4sCnCI'Cٺ $G4?Y0f0_9gI4sCnCI'Cٺ $G4?Y0f0_9gI4sCnCI'Cٺ $G4?Y0f0_9gI4sCnCI'Cٺ $G4?Y0f0_9gI4sCnCI'Cٺ $G4?Y0f0_9gI4sCnCI'Cٺ $G4?Y0f0_9gI4sCnCI'Cٺ $G4?Y0f0_9gI4sCnCI'Cٺ $G4?Y0f0_9gk=FuOFf '<-:;+ÂRRWe7 ( (94(w9=>+)F4][hSnjO"|=Gox/]QDuz#.xhAК{:߹|V~G=WWğۼ> />jxۏf659~Љkm|tB Qgf|ʷ!#oU{-'DєkMV',ۄ`I@(մ{9=)5G-aTg ͆m€zm[#pHEf$)$84%P@P@P@P@P@P@P@P@߰/DuhP@>,.MTq<-hinsSJ'`Ӓ(ݖe|ɒKsn <pnHRh`#Uaiw1.lB7oF!޹gw%Q)&)FʮJ.qdQai)J1ɓǸs]\dV_C UMv}e黚OJP`)r|Fc*y{(;srC_0ծ _}',m76zh85{5:&Y1$I'zd PhLn΄¿+4VaȪeG'JK?mnY|>|nր.[A VGHB( 8I@P@P@P@P@P@P@P@Pf?( =sPiOۭe6ٽJzdSZ_[ku-fLK#Y\'amAY*D>UjJcw`\ +;}Id|YI\qbT0Nwg@ (|id?J֕֗%5vDjdV:ZNdq֕:dӭ E \Z3.$ad΋5xد%"-l0\H$۰OD/GpPSHAr][摖X.cߝg=b"z'W=`OD/GpP_h=|+}C'ϗEϸ{(vDOȯ4{Ye>_Ək>??"g=;"z'W=`OD/GpP_h=|+}C'ϗEϸ{(vDOȯ4{Ye>_Ək>??"g=;"z'W=`OD/GpP_h=|+}C'ϗEϸ{(vDOȯ4{Ye>_Ək>??"g=;"z'W=`OD/GpP_h=|+}C'ϗEϸ{(vDOȯ4{Ye>_Ək>??"g=;=;Lʑ(Nn<=ϰ(4AB1h\f@P@P/fu#G9;cy~;o~n*=3ZL:tzgG%ec9R**Y]J>{܇`ѫ_;K#Ҟ x6¾"!Gq<Nnnfqߟrɻ=Iد Zc^I U[i|<ڍ$ E`_k%උYnX٥r\ Č֤!1JBA @+%մ.d YG$ Bd2o=s(ypRˠ <'tu?/XA܏&gi+f; }s]"}\HPВ?-|ӻ<`b5( ( ( ( ( ( ( (35Ͽa_'EIC_ ( (  BH?^խ*ӣ.jn̉3V!Ӵ 5ݬ&qrIkJتU%tL)BDl1`D*8)<z ʖ"j_&<Ճj_&y7`ڳkAX?ehsV?yY-Ճj_&y7`ڳkAX?ehsV?yY-Ճj_&y7`ڳkAX?ehsV?yY-Ճj_&y7`ڳkAX?ehsV?yY-Ճj_&y7`ڳkAX?ehsV?yY-Ճj_&y7`ڳkAX?ehsV?yY-Ճj_&y7`ڳkAX?ehsV?yY-Ճj_&y7`ڳkAX?ehsV?yY-Ճj_&y7`ڳkAX?ehsV?yY-Պ7Y%JL]@u RzW ݢJ5 ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (DcxcddHo`/EeDU,ݗ%⨿`/E>e/(r+gX/$I&78FOT_AX?/KQ "_*}T_v_@eDU,ݗ%⨿`/E>e/X?/KQ "_*}T_v_@eDU,ݗ%⨿`/E>e/X?/KQ "_*}T_v_@eDU,ݗ%⨿`/E>e/X?/KQ "_*}T_v_@eDU,ݗ%⨿`/E>e/X?/KQ "_*}T_v_@eDU,ݗ%⨿`/EtqG%F>i]BMP@P@># 29eHsjbQ88AWn$QUD3<v!9iYj}ͽ֍8fWh[$a9Sx>3iZ+{gtI㈤ޓͤ\f<1 w\W90[`9;(^Em 7@(|5'^c"M]ƷHcܻ0ܐ>顫ox~ K{2+kDwIv6' J,^5"+[HyR;?x$AXdz4:=K̽k2,uWq;3#֋e":9.'ts&)Y]9,&j׿]-w*D!%I<=>OjeihϟsyӚ,1zr0}+ FTC ʒ88$Q`'5M?Vi[U4,$gq)Z[ ( ( ( ( ( ( ( ( .onȮ䁶+a8Jk@3n?w7!l,#컁!ەs*x+sQ\4܄-IE/;}CԣcZp7HVYYAtI(p(>TeM\\,oAq _0XKӵ-k[{9!iLf&0n%#o JH1kbU\ "2 "<%mGKr}Bk_1-s$=2gހ[&xjY\Yx i%FܓGo B!ݿ hnf~յ .Iei_|\„xaM1;7|`uƟ^, $dJRfRۭѹ=F{2ʳH,@u!Q!'+\D^'KUC\ųzmC v,W-p*i>լ5wɭ+e} 8bEA]F8侷gz$e +xBfI@̇ c 0 ( ( ( ( ( ( ( (9wXMZXjYI%6x2202Z<Ӵ_ٽ=`T@D1gj2J(ݺM.٭6%_.f>JL%i[8fu,7WsLcIq.4dn ^vxBR-RwPʒeT` *pj^nP@P@P@P@P@P@P@P@P@P@P@BV/s41/ڣ˵C ;d)9ja>tbYwwg9|il&"crװvENLʫO#90(mr$,ffVwi]%ؑwHc@vx#AԼ󼅎/]%wXc $.$$5`kRP@P@P@P@P@P@P@P@P@P@P@HԼGb.ln䶸`Dq m+0 ]XJT~}&GQmPmDKM,--,gn9a]LkRkWZ9$Qp!m+]#P86ߝ lICX]Y\iGrQV0d(рxfUeS@ oMd]^@LWgl>$A|\-&uB&}8Z]O$fH?u"sp7v€ ( ( ( ( ( ( ( ( (3Szk^-[i7m[Y#/N[j~( 6g_Fy7ÂD,B4>S\am@IxI2(25H£b$[{MNKm.{_*"oJ&G*"{.kS=3_@.P^Hy@&1 MҀ. kqnpg0DB̌YH4&K ѫ"TnUb zJG}ҐP@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P}DyK _Ref161566341 Dd 30 [ # AZ?bֵwExy)ꍋ@b( nZֵwExy)ꍋ@PNG  IHDRP,sRGBPLTE3f3333f3@3ff3fffUf3f3f̙3f3333f33333EC=33f3333333f3f33ff3fJs3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3pncMaR}ffff3fff^cff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3xֈ3f̙ܩ3f̙3f3333f333ff3fffff̙̙3̙f̙̙̙3f3f3f3333f333ff3fffff3f3f̙3f* pHYs+IDATx^M~6ƵΪgIr,WHWuJ| >H3"$=ocD= Q^(0&!\`0&b׎ a{x cF ߿#8{8;` ðoG'=W|TrTSf)d,e`\Z: "0M\>W*ZUnغɈ`0,`e k[9uuXA0d_l5c)ߵ, ?3ۈ0y]'6bž~FDo?Qn 8xYQgx=<,{߿@Y, p@2D盡&뫷-m,{~NGLd26B>| w}/@%#+S/{(O_`~ra-C`٫ :fEpc;L9HdKǢ2a.6N893*ā{59p4(%#s|aΨ18ߙqogDXegL> Of >xs.d c]N_`CӮ3Q`Gy>S=puB!Թk^DR`b)~=(*`1ݴ0:JQDė1|R`}DyK _Ref161566341.Dd(" 3T  0AlYb>fBQb/ nZ>fBQPNG  IHDRP,sRGBPLTE3f3333f3@3ff3fffUf3f3f̙3f3333f33333EC=33f3333333f3f33ff3fJs3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3pncMaR}ffff3fff^cff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3xֈ3f̙ܩ3f̙3f3333f333ff3fffff̙̙3̙f̙̙̙3f3f3f3333f333ff3fffff3f3f̙3f* pHYs+IDATx^M~6ƵΪgIr,WHWuJ| >H3"$=ocD= Q^(0&!\`0&b׎ a{x cF ߿#8{8;` ðoG'=W|TrTSf)d,e`\Z: "0M\>W*ZUnغɈ`0,`e k[9uuXA0d_l5c)ߵ, ?3ۈ0y]'6bž~FDo?Qn 8xYQgx=<,{߿@Y, p@2D盡&뫷-m,{~NGLd26B>| w}/@%#+S/{(O_`~ra-C`٫ :fEpc;L9HdKǢ2a.6N893*ā{59p4(%#s|aΨ18ߙqogDXegL> Of >xs.d c]N_`CӮ3Q`Gy>S=puB!Թk^DR`b)~=(*`1ݴ0:JQDė1|R`1] ,``rR wQr0=>GF-:$=)SC9uX (E9Q07@UucTh$i[]eԢCpƁWC878lh:ട#i, !c4da :d0 ڎ#i8&Gn~uUsK|jZ P0`5Sj fj5CMZ~ÀL`Io0 5i _3&-akV0Ԥ7 |jZ P0`5Sj fj5CMZ~ÀLKdJ~=(*vDZPQÔڠo0 5i _3&-akV0Ԥ7;X"ɰLa}jRs̠ è&nKAxTQN2EƞE9V}m cצ7\'<ݥQL2\%^Bb݌$raݱ@B˜hXQRgK0 IeTN~:nd|NӒ臘޳ ($`P6K4nTM2I߳=zm֊ÉS&ݷh=0/ d2L&Ik$%%r?wptEGל%~%@x+e p) Ih@!0NK:QK,`( i^~4([;Y1(\S@2t >g8h}*`h).`tU0h60h{}+׷5:$0_gT6֛|nף0Kɣy .`Xo.ED.gH7`` S0ߴќg|XX,ck2h0:DӪZv iUq-7,r :Pl3>gtH,ydBu2lB0CTgș0ջ˽oySo 9HEx0('^ƇgJ2S$k?\VHOX`p`PM SU}́(VːP )CWAa }Ԃe*`tɦS 0ttj0dө$㌈B6ֶrD,# /ZTj+-?IK=pE-EU, 5ہwSj;KnS8jjg*0lpT-B*1ƱW^rg:aCB,F3}~llFJ2f8K8S4L`˥N0L;u-pEsp[8*0ZȭϨXYB!`Ld-ֳSBT 8#)qoh{8`3mc޻c?cloj:\a^4KlWp\sely8\rO[,hѺD6[qFFm?cW\T0WKa5䲈;̃`aDڹMym˖:eZƀȭUuת@9 ݅A=Pˀe :~Z`L=LUC\ Usl.U;( "H0L7VZx .R}W Y{`s 0 0!.cs9a}cd'ǘ0en cKucS=eXKپSp /3ߋks%t9>9h$S=roZ}=ZF ہeщZEj eUˈ ?|gXLV9;/ SrX![2a-aՖm~З/юFJ4xצ\J7(ޣ]&z80J`o.tG5^zb'us+(!k7<9"XFJn`:wSWI7X0at`F8Ψ2Luڰ XwetU0h0:DӪ2ğH FVoo۾׷7zVÖa/_i_(wxwV\8ñW]7`D Lt) H.)0ѥ2c"&X`LDR`1] ,0&R`KeD Lt) H.1 N**XFӓB(t40_kIENDB`}DyK _Ref161567129Ddl8 _ ooT  0AmZb3WH~D n3WHPNG  IHDR"1sBIT&CsRGB pHYs+TIDATx^/|ۧ:u2۸Wq9uWY$unZ{q[u]DM\߹\ o!$?^?o ×$' fi@-@ T(@@H3@ H34 i> PӧnOh@B4#9淋 7XR?2MI4T(0f%iz y 6:5v[IqX3Zm[P]K3rZe_$F,! M'Z Q{?6<چv_N{~?Шcr`cOh Q;4<چFG= uA* pH3ճԠ >A=8 {@4޵Of/:=S:=UTv*5 9h8|iFGo4CL3}U?_US:~.%Ie.,\*œzXZTE;Xv:5zy u\'#X7wI-ۑdO3ENt֯hІsT}FsǽN6Rٜgc`ɁIˬ-]U9קQ+A lWfKEo!ܟ2,9 ,\Vx ,+2䎼iFW6HZc*yg俶kiq5t^j)%35ddٶɁ; -K,VTf-#1Or$NZ(F-'y#XbT[tzn[ZTZxC>쭏*12L ^Hҗ%<B߷0JN+&J f&l>ou`:zNyiZ)qW|WZ;3K:+ !i7ljEu4|Z:ώ`ҝtU*P^+ ݝz\/o%Š m&H.o=;QOx]Hi$Z5{ḒNElf$yXK)B}?<#YƵM/OLej:mEcey ib#%5t)3$a;&WZs='ƣRHn;dIjEKҹLɹ% ÔRbT7{&9-:Mu.KV_duVsxZ)TQf}Ǭgƃ{d$ekyc$[X%#EyXq. %čZ$5=SRXM L3g:Oݜ1ۉcimK\_ieBѩ:΂BfɩgC,WX/e%mH?Sr^0UK\W.n'~<\qInoV.V_}{ dzfrR-k˞%N`}@43:<U yI t-y&P՚ݏL CS80;|gyK#8ѓx$ޚK,&`e:>:s<|wd*,h>lZ<)I3kTTr!Cm {+̢a<< tP{@H3Ǫ  f  i& ů]fU@ǎх}ʈ-M#?tNm6 @ҌjukhJ$GcH2w'-Kv:M@ﳅe@j(fT˻A6t~13r=~K)d<'Z+dYV"K1[@^v3vm8?.ܞCIb @EӌRKn]<&hZ=y\}U;^[6V*R$,&h5(91!,P: P@?άKA@`I@hփf BAhi@ChC0f@(fM3Kao@C8/i>> G VA$+QS3oA`@ fvgϖ@# Af@ fvgϖ@#hfG."'`_I3I3@}@݌I3|tAwWvOܿcF  \v ؽifǀ@؋4_|Hįk ^ fBS૗ =%0k;rwaX@VL8Tvo%,KvU!(-̈́mky&<7?{ fs>&99– 羙qn:V{fQ@zJ3a?Pc9vw 0p/ﯯ_׭xV^9Oɺ##LmO7y[a9@JJ3ш#{GfRc=';\a<^<#ȷٌ!('ȈxpSׁFr롩fϷlpx$w^*O6i&fA@nrL?w @il@%!@ ȷgE r'o7f<aa@\"T.F[מm>a2r@4˨x.Ʀ*n^^6 p%#`єY ]g\,@4ޛ19f)mG4Lz ޽ ^%䙳]]켗c,~,@4.~t&Yf^{3V't̞e3Nm/ =NX*zyJ:2J @V4ux [*2z,k[xX9dЍd_ky hљ% #5љ5 @e !i7;-{3u{=@ }YsٙwL  LiT:dTS3ksLY @`Y`s }@BL4 @ T(@@H3@ H34 i> PiB\F @* TK  @ qi@4C@P4S!.M#f  f*ĥi@ }@BL4 @ T(@@H3@ H34 i> PiB\F @* TK  @ qi@4C@P4S!.M#f  f*ĥi@ }@BL4 @ T(@@H3@ H34 Tٶ A$ku/?Otu-$Y@ i&!l!8hE @*i)@JfLC)@c>" PTgK 4C'@P4S!.M#f  Td>IENDB`V$$If!vh5D 5H#vD #vH:V 45D 5Hf4V$$If!vh5D 5H#vD #vH:V 45D 5Hf4V$$If!vh5D 5H#vD #vH:V 45D 5Hf4V$$If!vh5D 5H#vD #vH:V 45D 5Hf4DdZ  T  0An[bpB@3p4w$L\ nDB@3p4w$PNG  IHDRm2sRGB pHYs+ IDATx^;-;ٌ)00nc Fpb0r"$+}Uu(mo.?.۵O/q_G~;?>:?Ok R~Wb{k^9X3:V% 7*I TÇ`j+ _?{ټiol_FДI}\$HSIk幙_M^UW{P^ٝҪ?++SJOJmͩ"jBI;.!p@c)݃{> XڀZU;BQXp9`ɾ k{s?Ӂ֎j#ſA=tp>%v׿3|O~< X |;|yx΃ˇht3A,%;yb\n/S7-`@`αzkmX>ONu!F.ʒ|+Wτ^oB:US=4wsI\\^;hY~Kac |~jƶ!ݼ9px=P蹟u>Y eafɩJ˴?Z06Hmɬ;d5Qquugz^C$)\V}VpF[R`ZǜތJjz>~֙3ƨ.T^ dS-:ZG d~3M߃exl3^Wu?O (@]uZuprlW8S 䢶yW/.,7q]/*jE`_Ӄbbi(+.,x2z_݉H8jy M/Oؘ~ \ KwW{B*99iXz>Ǔ"mp"u'S|P,v+_&Ð"Uz-p9s(nD$PW_ s?#{o8P+I`A5̏!y6![ߟOqQXx%׎Ĵ0D;knӺ!A@2hh;Sz @ E.%;9 K 'vM53>sx.gޠN(/H~N!Ux GhU$KkNf',M'QT9X*O*J߱KPUY&T]_E=>хr篗sI]S}mWUH(\s񲇲i<Ӑ-̩ @êWMxUQ^5՜|Um*|_&P@ڪ\'4,|j}ժ:w437J!;ʹgSf}PkOzǓ"W4+Uo[W^qrceWϾZIN (v@i}=ȕz"ɶS6 7Q8?y2Hsㄾ Ϡ 1@1 ^ H l/“{0$ Rv>]| EudK)ˋUW+u.b\AIg 2ʭ"~ 8P(jwxyn}g,[v(iKNR= ZHs u, rv7$Y(pIP:jٛs &%\8أP?4p.{6=e+ZkMƹx{j.'Snvi6"icu ނ@@9?z4~IpyESUdNxT@KȖER,K*ђt֑$XBǬ,zt|@慄y9ʰN(,I^:lh|"ÙHҦ{>P@m&G2tKIh²8K]?̈[K|]>窨֏ ZM9 f @¹s=s VdsTUj1}K4zgM䡬:ƲTQ8 몮w5a9ە*8+wΩlMہjjgdj5^lùП\LΩWķۮs>rZΙu;XJ&AnYа ;;V3jqeHxJ5U ҮsuT&.'%Ϫ7h25`s-1^ͳ\mpk~IRa x^pP7SsT=ϾSU-C eV~g#ĺr#ꑏze$Ojb+ɘ= 4@]*rI"h>DrjM۹zjhn9UӕFU#djWC"O)#qdd@=ib=ӔOO l{4_LF KdtDe9 *N buZsOr9;KG>3\MDŷz3Gw woq,h JF!~)!˱5 tS[n 4vٓ,^WW?/d#%L;H*ȧu)7*7@NΛmH \]OV3^%ZXX >iI,Eg+U֩T=dW 8^2R+o:wEȱwS^k.[.k2I`zcߩ8?m_|+s[_/ `хNs߽]I@gma]1xOsoM7J=)n~W_ >y4;S6a᪩@*s?BU&ُK渡&kP rD*iYOOYO3@Ib_- wTw<]F ԟw^w_Y4^;;\ލiݫi-tbxR8M(u*/s`2\˕Q#>oqF}-<_cg;^B˘j聹? xbo_\|O Pd3F_-49Vl}\iB[*E@ˋ4!ER}w!&7o)2 - *M!G6g\>8\qv&W! ,,*D1FݽʕP#>H4'Cm, gu'VW%}%p"p RUB+K# ypa@~@ R…i @g HUA'!,TH++o`~a1gvVYSb+x'"BI*=a mAϹF+3Odv˾n9uk.8ɦwyn>0q^sT(}"pC<)L{;ùsc,7=ΕY*MO{t|_0@/,/vNo]Sxy\D3UU=ԆfxuSiuڱw%K;umK!Ryʹw uzsEjhSP3UtP^އ6JM4H}cfLV/|xv_䁣j!_0=ίazKFn!RA|YvYS+$ҽ*y*3sqKo35ijϠsZjkߺ}.:{/[Ǵ[6LW,72f;N7dj_z/%E޸ ^|) ⳧1ID<캛X脾sa߯gkΕOTۛ)n >ѓsрSp\8I>-bh{++i.|~3e.g0[(+ӑ&,Ă@5 ;u7\Udń[(=G4j)/!p'}~T❜9 c(_zyγ:t"S%mf B%E̼mjzCTqK8kcF;Oq419h=ԆbVMFPXiPE$E C9j?A./lqKqg\7J^ Y{EWpO̖T}[u::o@@"Em=+wuμ(դ)o錄@ki8?"S@sHNluG?)_awFmޓ[fO[ѻ#7 Ա!w@</AwITN`ْcp]F~$ʎ+SJTzbDD9Xy&ɞ;UV(q~z52ʮ?9RکyYL6%'|9tvz j];UӋjZW3KnApNcI !{">tZAnU"P8]C_?R+> .#D+z.~_8Z6*`e72d/,[6M50^P٩\80>Q$]Gv=H&RPmis~,9!~9} rX[6FnMob1g"%ƥ 9}O\TMiy<(*5\>8^-7Yۅx ț}*'jŜimo~aABJ@G `<.$Dn(@ T.\H  P7TQ@.\@n<\<wVRH7 `1g;U{L"USu@a⼒.jҟͪ+@K `4۩'PT]8@ R_BXGJW{bN@M'zeUTnqRn**3צhNڟ3ysNY>_u/XՁ-h=+߅T]~}`Ný2=H>:yVUf` FýJ)TU@?`? Zֺ~Hh%DCA R3Z %jPqT?V@k Ds7nm*#*A rq%l^*&[)p+@ F |qastFc1v* @0qn hFH4DA@ R &9qsVzO }1g S03x=&`1gi];K+@/bήy}@ @:^4O"Uw>xaEG"5gGsAm}p<@`>GAU Rr* #bhT܅ʂ@@sZE %luT p{'PjD.uRXf2rC2H%Ŝ@))@=@9@ @T@"> hFH4DA@ R &j{P9xnatFdz;NM)!{zk>]~ *Rv#}֌weOo[ P3e+*_>{  )Ea̿UT)1n&^ /BSXLvDTuaGd9nx<,1zX6_ӦhHi3#Нi4߆÷w/ g sgW[[' h,y$Jt*zϡۣrA+*R>TǹI]B3?(;`YLՆY@ 4TADp8^Cu3rΓ" R5ec\g17繧h|!3P+t=h> 4T4Pdzwݛ[;34L9#WCKⳤIs!@ib}MLTI]ovNu49dfq@i{f@@nؙn0 P1*n5̃D5BEA R;Z !jPQ'T?V@k@Z*TI"O Ŝ?~hMWQMGuTp{7PrD..Z/_zbSn6&"RףU_\ "Uu  ౘ쬐@10q(@ #TFPH pG  @2B2H=;JH;sf 9+" e-WtAEVbݏf@ ߥHїuʈ+_2)R!5t_?-HaN}Huœh-{e!RY!%@ Beש^X Þ>n@)Oh"%ux|~z5iPšKw8@hH=R׌˗_l{of ne9+>R|RMSUD4~l[wfŽz9@ EqdG|et#@k3iUAO@V[Qu}$CVߗ\|0SᇮO6liN]^peb=3sK,0.7>+g?\%˛HF|РuRwBjwSi$W2T2$-p2|[B1F7E>eaSu)88"b sgW[[ 쏞Z;8w| 54Xqc,?"mipOњT&H tj{m,)y@1hyƏ[Opn8"]JqW@1wcx_4=NsX=\0Z2R#t=}"чL.3)띲 )17>F&+ghfSiV9`/HTpH 7qu Mf4yFmx20J70֚sV:afǺ0`oNDA?' oXZڌ w U;sV/_E* vA=hA|qfj}p*"$h V>x@-0q^ f PD(9D(@(TQr P T-Q@QŜ(/7z~4J DE 3ed J |q%Tj~$`1gmQ@A8/@!3J(H"UC"Ug PD 8dv欇3Jhz2izpA Pڊ+Parp^T}_C,k_@t5d𪾈HaN+}vP > JIH'JgԖaK_ʟS>}ƞ}qη_h<]~*QvHt4n<_B}̗GRu{\OML28~Űd"zJhL(=-ʤyv?\#n޽۞>MmE~YZ_I'6'KQ"ōUo;Ͼ?ڧ9Uy8jW_I'7?۸HenJx)ܾkS~RQI)1-Œ)r<tůA,gE-.vߗD4Y9^@dH>tO #y'X1Gi˛ %D^k:v}QO˗˛)3ݎU T}9 )ܯ}";5OÛ#_A)}.ݹP@RQU(/i8W7A[)Z4կeˢFJEL[2ܸedž滏F{=sը`J.Rq샼ۢ&}QgPoWT,0ۡǬU1;Wzt!#dttz+sf rWvU| 4m3IcK"kȈJSF]I,&_'> ޘxEd!p}O$vr{+V1˛jϩFbwwA-GlwB%];iv*?#WSUX/mFA&Let!#Úު=PdU8ĞMlk$H9sQVN.L\VI};4oU-nc1~ĕZK4(>{R*A܌gЩ\0ޞpro2W)NANx>H\!>TLB6fV16zG]6R7j]ϻXd\: 4'@?\ oɭ[ dC 24vkxkS1DReUsNX-g.3Q߆(bT}iY/":Ƭ>-ffbY|=hTA"( RĎdeIMIŴ[Ve [GW%|cAon|ٿo]|5bl0.|S1c}? k_7JN`{azdQ|rZߧVKt+k%I ?'msK>R+x}yfQdmlt?c}nG٦wsY<6ڻ F3nsYv> xM8Sarz0 gyc^{ݺ,j_ow"&}o|6nS.W_skc@!ۇ?}hYd 2NÇ56d*$T6.$9_lHYPEIkY"W x[L~m&,x-t lGC=tΧ%} Ic_j)/9${h^| mmՓ!ahVQ%aMcYkڋN@=&<p0a Ej#_۫U̞՗_o{V1K i 65F"U_,`GwT=9{I@VoR6D,۱j̸T^${]&w`JG=esu&618hJ %Nt/|+hYjvYQTk^=XՊw}||wjt9AA'P=W(q Y| eV(\Ӊ;9\LId\I-Nk8Cڧ_q_[˕|iuLQC s?48h/׽ZPAT EދR% tOn㎪qcoT-XEd=#ZV<,އ J>Ǥ\A-P :6 @j5zs/:_ÙDȗzݮlLﺩRyYvs$#Nj2^1gum+hIx3geKkFa@U AHDIƻ' Cp !!vjjRK߉17P B L<ϔ|:|P#Й st @AtA@g(7N=B :G ;Dt&|P#Й st @AtA@g(7N=B :G ;Dt&|"8#.}_LFa&)/&)ݴ_ `79;;ۋdŧb?ՉMf>Ht!)$S@ 5 8Ӆ@PLqb 5#,L@A2Yc^=\FP|Ӻ}W uaPPk hrE@A]γH=8`QS/ R2Oqf 3.~1]t!PB0l6D;;V<ݢ E/xr-eK(A R84 h\@i C@(AOZ.tk89C<'5 9I9ju3K7S<]DAAtԷ R9dp8 >kK@g'ES@`nB6@<̀@Aҳ' @z(HzvPrHO{Rӳ˩{Rswf/Q(p;tԷ " 1$^ß՞rG4b?9lɛ0!Pe(H 7$o؇@ U.s@P cU&T9mlabP4ȗ .[T(Neh|v\f ZDm!w/hm nُ Gj=?RSGGqN>˦~1 ywzԄ R@}ŤW^(H Gl˰QʆA(H%T6L @A ,eb(OZ.r!>'qY,IkyxҲ [ u9K՞ [AP@o9jxICPnnK5YՈ#FI(@AJ2FP+(t!ahD(@AJ2FP+(t!ahD(@AJ2FP+(t!ahD(@AJ2FP+(t!ahD(@AJ2FP+(t!ahD( ol}1  ̍Ui;7u;jOO~L:`Dh F)[:@At@lPE !Dh F)[ m/-э [Dv;9:8pkƗew0 K=hvfĹeu'\;S{,;,h(Hu~|m8R,;Ui[;_/dk9UV19b?rP\b'TZV6gԇAɃv6E,  Ƚ:h3WkM@PPjl/NJ夦 vF+@bG-UBʐSN(Q(ȇb}Ʈnħ6UL,h S8>[8un\X:3_\LLD!*.sc֣"DJD5K}>yXogsgňə`2`6&ݣ]bmj'r *&u5VK]Tv(HeC%ZC͖ -OA^PzśB [\ɖg^ cʓ5Pju1T^r57: r vt|@Zp2L)8ARPJ@`(H"T*L@A pI.kIlsGYF,s1e`Zs'w< 2=yFY~L:`Dh F)[:@At@lPE !Dhl?98:hIƦ ̎Z-ѽjP EԴm 4_{]~.#Dd{UT)fa8%!ޝհùM눶!ԯ u͏PXgkY;S^=_O=*RsAA*nڻ6qzgݫ"2\ٮHum):r: i-_X5s67p-[TLL<ݯ]7l|N;s(>>ݿ|{|b5$*AgȌ J AP)C 3(Hf(1ZvA_{-qs: mfhz)?(љZA1 0~h lBM('@z(HzvPrHO`~_3#{U\!3u\f3 "%>$d>ohf+>^  ?QAB@_(3O?Fx} FN*)0IENDB`P$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5H^&Dd4H  T  0Aq^b%]G>'e$%z n%]G>'e$PNG  IHDR],sBIT&CsRGB pHYs+%IDATx^/6ǽ@r:˶09–aWvz00f-=c1۰ I-ǒm9'?vWHGwoo9@@9bq B3]iyM풀  p0?tM.l~ L{#? %A@KƉ_xKGc'mI G^C  `A?h{?{Z/b0LQ" .BwgK;se;?mOw662՜j#d4-Ђmid55qlm_O_5ytȦsV峐Ƕ|Fʙ5u}]p(Gp/ީtWK4)UJmi#d2Nޟ^0N/h L/rNVsdgJW?;Y‚DudfK9wHT'%s3_PX3+wSB~jH\ޏEyLӗl/ѡdߐJՖ: Sm=*3p8pR1Gn5":I$ɯ!DQ EP\^=t{þ/1`դ.:LZF:~Zb?SF#ob]-ܮ<{.*܆-pt<\O# %sYF71sO7zs7n^(X'y(Q6bxN MZ0ΆG H΂5oOd<9Qkrj0fw5Rߺ"trɨЛ3 Dxحn3ۧL}ljKFYJ,٘;IIJH*&2brֽzP§ntw(K֜TY$^gwV \'3˂zirCee 3oqii*MbnrTMx?t^} hfZ e\H֝,Bor3RuuL-Ӕg##z6«kcl9MfI iOA}",Sܵ)Tn d APo¢v[)rY`&Cț{4'FN*t9-YGؑuN G8}tCvSAl}H ג5TLz*hTcB|BF4tff<}z9 K3&BQe"T1P^:)IuYy)HaITQ?_2Np)isMQpiUpEsM{!~KP(z{'N.CWȨ/{gJh0H7NoފLBc?U]z5]{i/Q&9{G>Os:Ȫ\Y.3i di:5)f|^޿v/,ߩ)䳤ffcf;'5#upd2(\5FP+[]_Ns=ARʫ[OyYxU$Q%Tei7J[j@M|N 2Cul*{kۢF\rgh\uJ)mp7١ͣ!i;>zl(S!w83䣯P ];g24K3z qqA_[BeΨv&,Cjk9u0 PLp~zn<}.z?IG*sŴD4 /fr/k`˦~1q0~7ڭJX ?j?=07K<.MUݪ]Q+'`U졦%y+FA\"ЗyGa,VS$m˔~w*Sҵa!Gd&X[plXN9Xy>k`Y&4dtpS:1~ L :](ӧs׈y(K+i7*IKͫ;rğ]& $5Ȱ$1?no%5|(ωkb'{wݦR"pľ1O)K\zܐ"mr_' )Ph,Y`cC9DU9P?K( ZLY0p>qje,n3`6)cH9yhmUS4h[;Blc(<]+y)i ;yLK&82?=ǑFZ>ICU9zvΧӘڲS5stbA|^)CR9-' )sAK.>L[ӜZS0J.pT)bpm֣dd>gm?`5o. ?$3<^ȱ噘Z0`;%rԗ$) ٭kiv-,==}fNޡ]Utq [*:y8Ƣ~/ouc9 K_%9LY{<8k±LzS^5>F=(ʯn+GPbʖ[n#ap4U_ tX忶s݌fnݔ4OE=Tzb%= G(~+'oAMg9lZrRMi=~4ۏr_jZzܔʓӔާ%Ye$J{n9sR*?/MV2ַ'T~܉Q'vU.Bv M /{uX*^窟DR6:ێ~ͥ) Goq皿TϦ8-.F]NG4wkxstbWMv{CLX)ܤ幦7 OpfuSʜfQ;$fq&%; E  a  F73up@J @@@ _yC=GOwpz .|3?R(NIk6,]gՓI=C gz+_U~o cP SVKah[зse}(EeЯ4:_ Wݎ]\5tzd0,ӿ?jS]hq&ʴUO;Oi*tsHsoK߶z;/^_n_R()~u?c=Iۋru4tNV@4cړ{CJ1 tXMDv KW\j N~>d7^<-x0IBAH'F `H0(#o۵m=F%_λ;i.h#,'E3?S d;3vPVaz90 Y"]BpFn&}CkD/KSo_`O؏CΌ'L{OɥdgاCǴRz$ڳʧ:-mbMWoo4[W7-C"[芈_߻;W;Lb[͝/ߨշ/h^~ Lݎ_pM^)N&)&VI[]_ʛLDUGB)Q<+}s3$aN[&[!$Ι ά\[Yƍ}HJuTa*I֧YqXyđ0(ɺord~ILݢJ i\ Ԋ~>Wq ?O+mMY/W;K~'ϒߖTVryڗE*J;G&=42w;C =˦9JX41ikAlVGQtKf ~)0wϴ0_خZ[%`; &^ĮڞϞH 2rR?Bp(ipDi&U!n.R 3 2&F!B_=D:^VزWed44Kp(y\9%fg2PE*$iX>˯//1zd:>e!<iwׯ>򡍛gLBZ+*Zv٨}We~[u!i''e5yA1}qe\(uɊB5Q&OSY1!!R> LNhɞH9-Èf'u:lH>Ti۾^a=³%=ʦ}ΟT;1RU ݕDuj4mw=Q;$#(R8ݧ!_e)G婗R$5v@S~^WGak&gvz@]jVO-'ZB(zk>~><*hRfg֒ O4uSSL6)DtӁa6{ӸÍ5{{,GǓ.DNz\-%g7egn[sp;Eߠ hInJS7@@J\sD8ON z  G+'G:^y~CgYigI1Nci!~;Oh^h @u_gE Ө4MeT%-$W?vϩŭr8:ʅvY?&jE4ȟ (I\+H/?~4eQ,}MJB*jӤ/ToS_4"p1-,Gߖz(y[6gi p.ѻJJ,2V; l,3'9~3٠4]}CyZH~ .GM1.Wfx2jr'kqSZR7%!ӹ;yxUTk$B=TʆmLjK+S l gKOh1D45A~ZKͬWmT@Jt@CVak#}?n6w1DlApG' @6lFM tDc?&]  @:"1 . G@@N-XhteIDA@N/FB'иz:ǻ @IDe\sRso=~L\@GD Ñ_G-^G@b89{ԍD`/cC  p>قŕaT'q,<90'F(m2\ 8z )/P8w#+UX9,H" ;̓@i>e5e[c>!}( WC$S7WC @ w 2w^@:H?^jw!2(jN>G $A@"zZ(  " D,TCX@@ `;>X.nCs!G# 5An=4p7P@v nCs!G# 5A--E Lhm_诡yz  G+'G @@6 WN;=l@w08ztX0mŕa͇;@o g@gw (4#GߌLWAPhF7 !Gߙ  Ќ}3n8 @:C3]AA@8fp@q7p*  '#G2h@C<*P!88pG  p2p'C@@<џ 5?w  '#G2h@C<*4 sM }8@DKYA@8p t}z @p 8.d@)  %p]-   7S@@K[@ d+hol>> 7N \?8ch po>> 7N \?8ch po>> D 8֠UX8k2 p8w0Aosa6o[nCFb>?YE  !}9r?n6pu 9zr۳ 8~ }A@9^\wxR=ZFa8$+pVP@G{}A@.^Ab"Go A@{g@[Ba8$+pVP@G{}A@.^Ab"Go A@{g@[Ba8$+pVP@G{}A@.^Ab"Go A@{g@[Ba8$+pVP@G{}A@.^Ab"Go A@{g@[Ba8^=G}! CƉ_xKGc'm G1A@@ۛ>>cPf>~VG_ .BwgK;se;?m/ Fɶe?(5`!a  pV<]W{8v+2PSM:ETIupVQ@Oyyǡ/= /x @@['c"N bYOO,ޞ43Aד8PLD8uZ[JĞzk냣Ō  p6=zq,џ0F8O{}{$O<="Èl8-<6<*zJ"i~ ջm޳zf[,/c7?8@nf3^;:F\>oټׁ2  pfm/~lo M<Y9SC{hl7Y 4  6,6#L\^P@@ #IENDB`P$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5H| Dd T  0Ar_b čEY)  n čEY)PNG  IHDRYOsRGBPLTE3f3333f3@3ff3fffUf3f3f̙3f3333f3333333333f3333333f3f33ff3f3f3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3qodffffffff3fffffff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3f̙3f̙̙3f̙3f3333f333ff3fffff̙̙3̙f̙̙̙3fį3f3f3333f333ff3fffff,f{:nF]3E@_Ђyd.yډq 9r(5t?tSX>7r:;DA}43:Ikǫ0qpbFqdpq;ruܸ4?i4ұ+QC!^׋Ljpo}z-YK?X&x Sҏ>sWznK=ZLI=N}Y;#0j#L}T끶BЅ=1z,^+k:GbtyC0CEkK{P!zTgԶo} G Ӿzdj+eJ '1B:"w:|G_httJмȷNuF%u-AI(щ; if 2jU,HJjVä$a5PV'iMpKm\o[q,0[8r"s")ORh3Rv_Ydҷu# 3Alk_Q|gQc?}Г: ް,Op=7fA?Ԣ@m[Okyjվ~ڷAlm$Wג nh8ir.]W-61*K ]2 v!ܛ!.#hO麂t a$iPo0qm#vJgdݲuza!5bkuJo#KܳPWnh͚e 0a4bԌHA|[5_5!uz3-A+: bUni#c!Dc+UXB݉izaZrz{j]pj͖'i}[f6ifBO V9Xzj]V!]qJew{p'2o)4'n1P'?#n 25>EOudP^]?A<~<Փj3ૌ'us]c;KhY13Vugӣk[m6R8O6Ə<1Ә{R{EҲWkIz]U^@$È*bے'߬5Gf=uP{>h&+Ej5葾h*L5Qr̀@E;!u!U  he poo8OL<,3Rb7p3G@MkDk4X4d{_yjo= Bbg豑yo$c&՚3K1zөKC][Q6uˇ Ktg֏h2 z^^k>|T~;grQVִUFkP˄ ]Sz*M(?Z?g?Sg=~~mZxU֗iȨ}gKBӘJw|A*ui',Lpތc6A; YH)pGxͿ4:@l^;D&=5pHMq(ebDZ=TAaƠ522-ҋkw&B(B@i1u+{b΍ ՐܶuԲqDه0~IG! i^_YI"etcmc͇'9۴5VִzM vuïبYt}i^N}ëL yjV6DhzY#LMj Ӵ&jOV&yj ӴˈcVkA?&9NvNyZ1ԍLU2i֢MPR0L,e;o"RZ2R7d)MFC 7⺋v]ׇ!'XͰ'TMfO4Ϝhb=iSj2šm0㣌`$q"|Ta N]3ՋJS^L9SQJw=g®]$iHhwjkcl-kQfM֦6ʜkUBWk$>c³ũlcO;t"#͚*];QMY*3;̌FNfwԪkq,Ҹ?o_mgwtYN}^ &MvGB4KϧG> . ~i\FȪhi}8/n'Omgwk&k'уpa0f P̴VYE]kqn;#%60 R%!՘ JB2>Jt !H]]ldj/AFbl,^TԴ?¿ v O⧕lˁo3C)͜!uҎ$,yh8ڕv4AA}&5F׃?"/M5fmֹͦΥ&ŻGiHp3py̭UٍUN1שYdm!h{7zk׎Q<0 _tlRzw,zzR? ӣ}' VIENDB` Dd T  0Atab NvpY7( nNvpY7(PNG  IHDRYOsRGBPLTE3f3333f3@3ff3fffUf3f3f̙3f3333f3333333333f3333333f3f33ff3f3f3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3qodffffffff3fffffff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3f̙3f̙̙3f̙3f3333f333ff3fffff̙̙3̙f̙̙̙3f̙3f3f3333f333ff3fffff,f=}imV$1Eϯ|)FO- !zC&SgW3Ud+SMՉh(e0ÄN]Kp4<$Ol)2u,|:r2e\5gHaF骚h׀R+z,^5hr;ҝ-w5Ȝ4WU= /ki"gmMgߣ%T82tak̃eՏcYU+m6ʒxZ.:Wgm @oT^>ƅکtRA'/CJU[ g4܅ E#G(OkOV;N'LZ0BbT]lYg8ZM_7GmjWUPֳCzkƺ3OhdLG<3ZsL:7Σ=Hst1i=䳮v[V0EBP5)]X/TcUo&e I*Xr4bIXEzդD5|E/ l̗]M)*o,Kq<.ŬU/XMr$;@5mzqVDG.V ;{ḃ愓VI2nb/]Yc;*k62c;Y=ZM:㵚&!MXʚXYk5Vrݸ$kz&eEՒz5Ix%U/unK3$wzդc*3XNZΓ _Y\H֢v(Ӳ}#$uPԲqio!qVDN gT\br{e-gj2|3Er{e-gT\br{e-gOW-/krK6/փxսp}Pٟv͵=[vw2n`w? .kqXs@Wɺp: OӲakT_Et~pPg [Ues鮭dž[:T٘(3D3uvslʶSuіZvUΐڂjS -(k*v;eΐڂjS -| E>;ߛԇ#57zo֚~g){_o_jiYSb6_> އIENDB`P$$If!vh5D 5 #vD #v :V 5D 5 P$$If!vh5D 5 #vD #v :V 5D 5 P$$If!vh5D 5 #vD #v :V 5D 5 P$$If!vh5D 5 #vD #v :V 5D 5 P$$If!vh5D 5 #vD #v :V 5D 5 P$$If!vh5D 5 #vD #v :V 5D 5 P$$If!vh5D 5 #vD #v :V 5D 5 P$$If!vh5D 5 #vD #v :V 5D 5 Dda T  0Aubb v|gB  3 n v|gB PNG  IHDR 1sRGBPLTE3f3333f3@3ff3fffUf3f3f̙3f3333f3333333333f3333333f3f33ff3f3f3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3qodffffffff3fffffff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3f̙3f̙̙3f̙3f3333f333ff3fffff̙̙3̙f̙̙̙3f̙3f3f3333f333ff3fffff3f3f̙3f%ţ pHYs+ RIDATx^][( wj[OmzY+tWb+뿿G9??g Bwyg g!ǞFFF1^$|4?_<gwzqk 4"'d 84)p;9|zT-#[ J p%n27KKxs128/\N\:2/N\=n{U%uUAҁܖ4Kg9e86ldPt8qS8C5\qٯj&E뻁/~ߚugȿB2Cj،ϓ9|8W 1h2J/C\9[BlDGxEkOϼOBPXˈvd*`Pç:~*u_95㠥O_  rL(mP_c<7䁼rvqc1(n2'_^4ީȟqV#1]HRؠ6v|.p]<]8ӈce/O6"g\)g|\t;:+匏˝rT/{]99po6-1vƝq0׆_K9uuzeRŭ>Is\w-<= 梖SO-s._4t6O jwZύ*猏ʜng\Qx4n L+B"9ܨivƵU9θs0~ێ&X ;]3R Zn|#5# yw)vck&DJ U` ZF욲W_.5#,8fYRz׌~ۮw=fC3Pd ^ FYV]ʌ+匏˝rg\qq=wSriLtIAW:}>[CC]?~5CCC>rU*zqV$9^khi.j9ԋ=^tϲ6 4W7wygxgwƛ§3^"fJYP\i:w;8Jg;(wuN@Bn=q̭ VQpa>=_2: Ƭ5Z7Bwá!|?G Rx`c'/P/_19ÿe Y zʁG3Sd";ID[cbEMԅtIP1#px0Ȅ]11.s2E5 ]1Nd;9C8>ʁp, 4XN8&yε /% RH@}k#TQ// x\):`|#"M(G%U@!9xHr|uxy*9]ju/d 'p[fhzqZ:7A"8OîP},r^)EEe˲ϊ>qBxflPlW !1bGDehQ/wkeo*OvUtst&7?%pϿ!-$@~+X $P˗/OO'Ň%U Uyzs27j>D=>\L?~y|t!8h,H*F 933oكTZqmQ|V\=ywwyk-86] 6VtX!8 >/3}~?N>/E?~d<<Z{Gl??8Zݬ¿GsA5{oc=b_lԫ8weOaף! Z.29NAHRqc#v%tOTjq[">Є$]m,a\آ:W*u!p#4`uS$!!'37 J̰]!5 >>IHA+ ^C \S'hbNO+$c]߲p3Q (>1>POIY>AH.ZE9QC nC- 9e]%"} FD%kҐA*_5_;W1VXrft 9jY[oD^~kQubEz% v#J; b GCBb*GCB"q w'jA%?$Dqnp~VGƇpTA j5U\.=(2t!3*>*KuYc4[PڹA>>jb-YH`+bT!x{ 6NvH/"|8ѧK`% (.{Q=4s-=ZSkq?cPܼ-}Gy:=4[%"5%۷:S>t{cO0H'I >=<9j՜E$gG~h4Ȥ<>FQm#P zxsww7 bakGuA- O޿'QP$\6e]A~24 ǽ8(lCZPb~ҿ[7H@˪}߶A!n->p?jR^*>B$O>L?P|^ j^[N- :b 46 ?<9\Go:+Giwj=uZ#A\õ6 G?Ի @]*Aތ?ɑ>td0]?#A7.>9mƟh!6eطw*64CI%rG`l֢Z }؍V RMV3OHko7s^l(آ:KAYTY n,v ?y7|^{ )_G3܋;  )0CU|47O1%ٷ4uT]?C(UE k3$Ňu\Lh~S Fe~m GlgI-|hGΕ+G3m?/_n3<'9>0?|Y0n>'<,(hP!HCӸ 4)nuz986ҵшAa7=,xIF#U!>$ 7&O)>Ry4[+=b7Ft\2@2Nú l2# M̾1Bn-p)Z}^[m:#++%<  4@D ^|{if^Q/ϢֵR=j}?<9\ǟɞj+qM7Taz}qRnFe "B)/⓫L;8@0ܬsIj +C72꟯GgZo6s lBl6 &.KCzK7IJㅟ\[w c$a1e4^(\Yl>P/oVŁ TX݈Sɇ8< k3Dq?NCjA`a$_o0 bDsUWщ6F^9ċ¯Vn]Znv8Jg*%Tt3ƨM$S0En8v$x7'orl$D=Sdr=ڣN][̶h[k4U:7˞7Tn>&JVHOl[3[dO2=*G%mH\n`K}HO:jVe.Htq9bs1,~!/֔BjÓhzR\ (:O9 sq~7q[|7=.&y=f{$ӐbEQ-?~7Е'$ M.+fmXXq(Fvڷy~ dCnt9 >>OV(LzZchG27df h$u [\#bm_NݑVzTLO޿'h6 op]?nyeqZw/1OrHAv_t5?3:>) &X"xS͵hHV\9cfL~B[e F_?rraeӟB?Ca{@Z"@on}E)Nd]>\cbOfo?7|T-FDuOM6>L8 to7,!+GO::a{֞UǟU ~4bW4Heb|2Rng46Z}O!C0~G0+> 'ͯ$wx/ɟl+!tK/I?u|ԯGoOXcOJײO `P|. vS]H#??x6zI>hg%uIOZvFgNYʟ^"hG]>h&|Lzq4[">i`H x-U(Q32[q(8pIH^5y:3 d{_YG\a #+gP7;-@!hEh >v;p_7=^!uDy͙z;| \|\(qT8ßoDg-|Lynef.Md_G?#W_VaE_G6_g-7SMVş; etک# *ҡ3sm))>ʟHv!)tgI7}>Qi]P:B&pWVOy7=$ZcR|E(Dc$ok)>$HNN|}?zFm)>!Ϫ̷&]GiIQXZjOXZjOXZ|{Ka2ߌOA$K2EZIb4?o5يp?I7o QMT|ҝG?a--܇G?RyKˏGڿK@(>-Gl \ .(Sc?IENDB`P$$If!vh5D 5p#vD #vp:V 5D 5pP$$If!vh5D 5p#vD #vp:V 5D 5pP$$If!vh5D 5p#vD #vp:V 5D 5pP$$If!vh5D 5p#vD #vp:V 5D 5pP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5H}DyK _Ref182909666P$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5H$$Ifj!vh555D#v#v#vD:V 555D/  / / / 4+4 xa$$Ifj!vh555D#v#v#vD:V 555D/ / / / 4+4 xa$$Ifj!vh555D#v#v#vD:V 555D/ / / 4+4 xa$$Ifj!vh555D#v#v#vD:V 555D/ / / 4+4 xaDd#B1 %T  0Awdb1! ^ xP , n! ^ xPPNG  IHDR,sRGBPLTE !}307 4k=Gff3fffSa3f3f̙3f"333f33333450(=^33K333f7e.3ff,N%\3q3J-3f3333333f3̙333333f333ff3fffffbDU?0f3ff3f3f3cSr[-`agffffM}fWAh^dp`ff3fff̙ffff3fffff3f̙. |ha_w=@Upl}|>hzo>__/*ЇFtNV8&W㿿 -5G S$xf~V'ʷ~\{|Ǐ= Gg"v><3tnц́%! ؞d ٿjD _>鷇+'gϮf:2뗧X=6wiYGRWX#ټs}>C ؓ-4_.96| i7b:6* 77ǀ!8ŋ~~X΅i >”G0A0Y)OmX)ʊJɼk{.㋸#S0O?i{?zǏ|0iNv0=U;O$_z.{ay%?|;6IpY|_,8}|"WWO~}ɓW Xܩ>5d6** M(W` 5BrfS2;<f ^ 6L,8 ?]}yz+p#lFY1h ;ֱ'PV]:U/7,΃aVuv0hg^=[F'Cս_?},:ޭByV԰>ݸC|\OwßE0/g4ߓ(P/~ϳ " TڟUʓt@Q<P}a>c]+8#+e07I``p޽O|ϟ?}l:<>wmMMcFeP܆uce>-_-2 *) Xz``#`{_8ݫѵL"Hgyحg\y ?AJvRڄՠVAŒۗl"a) Gs8pz8U*|&LCq)e ԚLK߁ٯ^W߼yq7N6)Sa^X){xTt-Qp2e^ 6ewXS0e˷:Wv?7M?~L={OB(W. ,gͯͳc@.3]^Uq[71(wrANg&L@A.' *DI YyOtA&o;"pwDՌ@@ĘN# LJ'ʷ؜;΍ڐW/t5 /d Fۂ_*o;ll0 )|tLkKu`vRcͼOMOg֎: iiFG6qTq050+g6; 84GUI]aRv jL f5nWW{:]YZ[oY7kisjCڠeOm\ݜvkeIHJ2aG%ҾAJ$#t]DalS]bZD?ӽq|О敲֨NRƷv46[,S@mjLջyᓐQ`}=,Ge㙲hز\wkƍOTC.rk/ڎAk/1~u[jWak-ᚙ;}Zng:^r `>&`p; v; >o$nβ0líp04KZ$ <"zҼE=뫴aLoy BPto IM5g+_譨F op=+t{ KnP8"\_WjUylY>U)?gjQ.o~,UbU묺YmV>7'7.AtӬip֘ ӎ“Y@}uhlF e6Xm{~]-LBdX@#QL<={$ۅGN#7 p70r''y7'z|̻8?#` @yɷ'nwkkYrZwi7q:o 7}W̳ow7XDF0N!|Ir@[*`Z<ݹs8pCpptv +6xvUgr$A"Bl@7M9>SHl X7!9tQfpp#=&홂:=&7o {-5!凵xXcvA`<1 vam0]kpv6k̮5ѓJGq||pR]+Jח9~ҵk/w;0P|+eqGm:vDj5Э \\7Ú-:/Wpͮ?0wzC׮C=ٶ 8zkfEBO.=> 39ǀ [s¡1 Xoӿ~P57'(lny\.`sv^'r1; x0GG'nqdtO^w3h[se'D<_ 哐}^ۗ**eڧwk2- [[+n+rv?2 @i~8{p L ?#NkNq|c֎#vf>ohX~q=_vŅ(cy+`3uˋs0kˆ~0]Vz;ߎv\ W(v<:2pY ^;4Cp^+`2^;gUB;^^B?8>EjpxVruX]o"A*}[7,qJ_ޚ#'NEftmN:{W#j&n0y XۜH҉I= ɽa=k>:;w(`><z`kV֓ޭ97ppjֈp]u|r;gU':`_~DD@A)"*!oDhA)ׄ(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~gJ@X )`Q'~$ PE(@@~ErL p..bqI3A`2A@&LHנȻfIENDB`V$$If!vh5D 5H#vD #vH:V 45D 5Hf4V$$If!vh5D 5H#vD #vH:V 45D 5Hf4V$$If!vh5D 5H#vD #vH:V 45D 5Hf4V$$If!vh5D 5H#vD #vH:V 45D 5Hf4Dd.:= GTTT  0Axebmٮ{$D8II nAٮ{$D8PNG  IHDR38sRGBPLTEf3333f3 "3uf3fffff3f3f̙3f3333f33333?@?6FV3333333f3f3>P`<`3f3f3333f3L33333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffMNKpnd`sRffff3ffllffyFfff̙ffff3fffff3f̙3333f33̙3ff3xff̙f3}Ι3f̙ޥ3Z̙3f3B3f333ff3fffff̙̙3̙fʢ̙̙3fÿѿ3f3f3333f333ff3y_fff3f3f̙ɿ3f{0 pHYs+IDATx^;v:= 9>n$9DӊzqL$*f(Y “?mwj |Ir r{VH&YgP3'`0sr6 lO3(zs`̬@_̬XN©:fV'ZVuj̥?x?].*9i%3[*Lu0uNݭB(Yq뀷Ϻv/=;̰p|^$^tvq.&8ffuz .f2w=4m3y}т@2C_˲atKb#x~o7Uءvp3@ڬkrA!M7͋)P=3߻K,f:c;,q_19oLSd(eXOꤝyߗ/y$F1BDWi2[`%''Y0xv]Xfq߿j|nj#̌GJafnw43M:~zz<:x/|)3}r+*:_ipԻ#^jG2Cr㹶fUVmN_Pji.n*43?_zc}tjl+"IvlߤV0|tq,>o=>sޯtkr vׯ3uΌ.8Ya2abF̝|S+̐"|HtZrg@|GM$nvFs1ԗKό̴eFh`qrN1p,7Ib"^կ,MTdlE:؀9H8\;2l6j0o023.Vu -f8f&ʪ?2V״O/W2S|hG"RԞs+4NJM"K90J=ԲSp΁UIU3ĕeGv6x ̎YN=")ה30Sf)W7 ̔rfM=sڏgkTwPQyӪ  N8 N烙HṲt;퀙vtj$`&i̴T#aFQz!*O+\n1p*3nj`)3O13@`fS3 A̤V]1p*71a@6)jrgI)ކ3"1&I3xx}Ӵn^X=Z  և&m=bl}mpbAB$ȎQi &3n#x:̹}h9fa|Y@_BIMF79b#=H}?If8>2#M~fJ0 2cHs3G7J>f^ex:̛\S273MQR32LQGɒ\~!|ɍc4 ʌoqQ%;K,C?c4U& 7raLker`jR.j j`g).~f f$EF0ߔQ&3SRac f5Ad7X=iPf" LJ<$Ӌ,3 *5\f :"ov;o*09BliLl W?iOGfbKL{:= 3 MwsWܡU}̔D- LMՈ87?eF`eF~^|8D L3u= f-3mr- V$9&t"#_L xpNlil\($3$cƉcpv&^c!47cemgLC13'M  ˆM~r'M3ΰ*PǮDrE~xS% vfVfff޴hM\}]P,ؙQ;IO3'Ua;`椊1l0Cx'=̜T;;驰3'Ua;`椊1l0Cx'=̜T;66xBOrF=YS\f림@33 l׵smߓF3{=W]Qylrה/`<23 `32h_Lό?@ 6i۱iTȌbd:Qdj8ɦ*w;S,3d$5w;pᏝ4"480ؙb3c6dlFt11 .2%-h  ݙ5iBڕ04'2Sk9/{UM\;Xyf2 fLu0I7 f*V^LYTL]$3+/SL&W,Xyf2 f={!yr}4f7 5~bƼa~f`YhÞC(fcfإn£{J;`}Y0S-3NS;G7/T0޲fEv xC3!wdK3w@(oؙb 3#wonff7\{rw_1L} mMX)p!`E?~obԖ#>f$)޺dUTA{hh!{ ;S2v ꍍ=[{*3BV*eq3PML62g73&geG /bDG1Q ff;32ʍ`'nOh'f$63s͌ʧDec\ g;3/ y-#&"gZۙǶnLLglic+FK 8|R$D.3ͩ4Lt7iNfLs*> 0]5fSi"n0ӜJDqs T}@`&k4g[ bp[%7 :oPaНR$`13ѭ^`z&I.3ի0LrW ^fL*L>0\7fWa"A H`vХ\ C?j@FM_=IENDB`}DyK _Ref162689531}DyK _Ref192064881}DyK _Ref192064901}DyK _Ref192064917}DyK _Ref192064930}DyK _Ref192064946}DyK _Ref192064954Dd T  0Ayfb(sF6Fke n(sF6FPNG  IHDRXo PLTEf3333f333ff3fffff3f3f̙3f3333f3333306<6FV3333333f3f3>P`<`3f3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3vxy`sffffff3ffl}fff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3f̙3f̙̙3f̙3f3333f333ff3fffff̙̙3̙f̙̙̙3f̙3f3f3333f333ff3fffff3f3f̙3fqI]IDATxu 0DaUw_ _56]-lX\)/Yܫ]ktIKmVo@ VdAoZT`PyXL)4]JK'NUz;7cmyZJӶXX)r)4$zRv"e=Դ$6Njȃ 'bvdlVƚEeHN^8|Le]=KheVfT tbO7z鯾o͊~ݡ=_Vgy#gWNr=hsN8"]=2Lߓ2 zkЀL} XB+AIvJ kzD'Zg'VBf%>ȿnDgbu+|e+Ў/VAֽI򝯝os|dxo%yQwwU? Z]4?q_P Ȍ),Ɉ73LN[S2dIcd90Vz,O:º+: -Bi/N;ӓΔH'=Q(c#Q)dUIe\=S{I{]!UùG&^qןZ HKO䈳; Y2x8+*Ĉ>鴓NXql8~8z`]ɿq:R}ɲmfPIʗRId{'w5әV̍w^x}!+995kW'Nu^?fXg[cIxw,ܵ.-B wk`KVzJ+2٬\ԝڠ @ah;_%ueu֨gWҰC+)r\pˉrxW(2lE99gjZ^Ywzq/,'W/0d䞃߸촍tޛo>ovv=qV{EkAvm}W!j_*-;w<ڝw[sO6?U9GXYZc/q \sKW j VΪ\]I@+\k޿;G^wwmX9b uLdY{ 5-ž䬷_s׳-hӅ?XG pĝ]]ܓ2 oz2'~]"-U돊;MSv[a/T4NtYW֎$Q+y2N-(IJ"u*?vԇ<'O|e>yjI<]Wt'D=dwL;Y-8;F7@e>[]yx[|ꙟtKZutab1~ Y`~zw_.SAdϜi=f{۪ԋT)(U5 `ɵAI\:w}J3Gr-e/N.&mewjCmoծD> VSDdvv}CZgg+:l[VȈ:mU]⒄%RܢtʥvrrbyGr/-}mK҉_r_n{9?xd[=*vU*vwzָGU-PWT5_ȧѕV*߰@%[6[>z[MS[ROފϞ=Kd\kk7~_ E!pks0l %jME=v ;o[,DڕȧJPӜt84,k/v}RgJlQ-d`DJž8DR@?d"_]Sۿ{o'.{;^z _7VPu+Ν+)ѯ7Fa9KT<,6]i%v`+rnֽI =#e}}Wm=1n">"ԭ3_ҲTQY0 8?Y;dTRFC&ffɣm̈SشAkwfW׮D> VNP*CEYRY/+ k7+/rD";.[ΠA%۲׎;Nztd_~xi _?:}Ga.y}ኯ'c };o,uq]r\[ܹn3\,/Le9ٽfˠKgTj2^m@iߧU V=]f^e4Ox]6~i_HS E}jZ=(Wɕg-rdWp$:}%_kJ`%)Qg5lAɠrmR]\מ 'NE4ZQ&t-̒Ax"7NtVr (:Q==5}_y`褬QIg'#rSg=:| #;.]RT$eFaR-/w=q{7&I5BK'-PȫShx|ekZUUVߵ:^q0PU zf=_۟̔Cuco7bK@MaVcj౫zk! J,-c֮gW"okJ.%+QDnhWtXXp*}[_I 2|sPA lHaQ;}˻MO 7!WG&2l}`x6_?+N*){QV¤RMȼ;82AAȋdju+/^jVy[R+w ,{ y[ٮF:om5^;],r:P37\[i媠r9)P)/WT \.U"Ȅcw8Wn-ck~}*w~蜷郫es zWf8Wx x{F)o׵Wpg_TOZa-/V+*zkP@f(+MH+.5! ~u&&Zd|;{$q .*yW ʁx_~]۷J+*i9v)ɣ3OHwJrcCh9>Vo~jKn۝&S:˭֒'c^#-Fǒ_\?hѠqpqdUWh}zμLz;.wV Ju}u*L:=wz1@ W݆:U@lmSkM=r8ΞX^<`N*)lri.:eIvPs䩥r+z_pW%˃vJkqb`O˘x6Ύe [ǝo->V89kL[;^u/Zo8T '2^:^e;ak띩ߥؓ-r`qۜc?jz3V0ܰ?r_ 7>r`~[i'&ʜ E[f[u%%?'za"%/M ,Vr=I][d:]BvZ ddq;Je񚗬 |*-H;i(ndٛ~Kb({.|}H'+:zD,cDDf  WzPFe1-X뉓G|ޯz4FCSgKO=?K 9&b@|s?}_;dD 5*K'7$(K nH2yh_y7uTrSmpOs;{{dBFZ-JUS IY],$dZ!oY^sI叿qOdv^a-_ƠEe$;Jc2\'@JeTYs"v%ܮˑl(]kzz{Ƿۮūڴ7稹̦T%yQ<,m*k;ӛi2S!r tbJMpsg5Z;եeuַ.m#j͢yn?$[@u u;HHҒEIO`$Y[?)jΆVȔu&W]Ehxe K,캡b{;5QjQ)$ڞd˸[!c % -f3 '$ByErD鸫2#WDj=nUh_%Jz/LƊm.wy͵4+4[,/_W qSya|9 NXyZk|Ekl{@r' m@!@ J640@@0mh`0 M `(` >@P,@4}@#҆ x[)'x! @qJ@ ! @wG!:Ae@; 'bHaqW-xǟgaU 9t1..j|}ZB<>W!뵧p=~-[$pU_\:=6Qף<$_:nj@nE'(k*XIpm}& PsLlr R_7mrT9=" 4cБ 8AQ!@G%Da~~mcڸ` M'@g+gY{o+[Lf@͈V,@7;ֻ[qhqv@&TZ),mLW&с wKI"FX@h2\12hyѰ0DR4fd@UGd'3@+fH}]E 0%ɠו@;s{K mC`+(~icl2tp unTCnv}k%0Mqِ%9ks$5֔J*>%m{JAG;19FtlB@@-b۝lwN۱c莡a@ ΎhS3ۖE`!28dNfqh6*_xct8 kHcTgU6iAg<:!uy3+ OkYM <@Ia=2/fG"!= SfB:i2S?qc^MlB8̴63.X}я=D  AI*!AQ&+ P/ǁQ%_ P%<+J·@Cs}䡐KYbv$;l U:l&bZy_Z7NzB@AsnvF7Cw;” E@:: h9fMy~-a ІsHYSzXnR':&H`^Y:&M SR2F;qs'@ϝgO`aǚccpH{')cX"tRmg4>iV!TtSqRYxҌ:w.dtR]Gi|mul}Duݾ&i '3-Π閃6e o26d}MZFnZ*;ǞIn&M DtaR f@I 4DT@fҤ.@M$Cc3U5|&wm$$8,5I8lm{J!z ]a4aaqm3z t@P,@4}hCYh C І  @P` O%Q&gt !x@wAD@ x!. @wA0':qk@  ]$LIgJmK1@\4 :.O@ ]2 BK:tׅ !@im}V qSs`O<ܖn\6پtmi=mk Ͽҋ6קmQ*>+YkmO[ay 輕ͶG n6W_]ùl&b{G0h q8B]CPa( 7<56nq_@ AwA0':q7k&g_)λZN@K -K$=ݔԭsq@qT u{ڨSN=9M{o t2A ,F4EJ@'^ګZ[vOOIZ{BX@cv-$ڟ>kzMehC4 ƋxwZ%ںˋrk!PIWJ >Wj3bIch X_֫:!n8kUP,Nxhl V&"#Pj~x5xC"aS6FZܭ'D8DЄwD_ T, yOZgM@5rؽpa 5@`y(Bb] .'@wy1.Iض˳$LŴU&afzyt,D}uGa?<46mkt{8ǷO.Fn-ux1$) @1@ h桱Q@A 4@+z(@M6@s%@ϕ!^2UcCwܔe"g"4\I.V gJT6,TA6P@~X#9- 䲙m t  @Cs 4@`>P@m @2MT'ce> 75]Oj@ΐ#0zg%A!>o%OCEIu 5hbadFWV2=7xQ XOÔ: [o@&\\iPD;L74#! AQ#`&ބ"@w<Q:vNn0LO ~tbZ.^K뗩<=L@MH_7|(_5QY_i0}m'@9 BGljRNn;r  v4@ jhL{I~<0amS<4c\}#LzG8q nR_eOH~}Í}OzgEI@"A@~4hCYh C І  @@ fA@ %@̂ @ J640@@0mh`0 M `(` >@P,@4}hCYh C І  @@ fA1&`[qu@l:@ ! f @c|\&@bLqq0mv|1:u@l:@ !3 8e+h3Uh S AbO} `*` {t S ЦF @cJ652Ğhl `2h5<4hCYh C І  @@ fA@ %@̂ @ J640Ęmscyhl{C 6=BĖ8 `:a [tlCh#}@l б =C@MA%@68N6=BđFz|aH@ 8F! @wE0#:Qg@+ ]&Hc tW #!8@u|aH@ 8F! ꉱ!F 8@}|&@Ls0mtx03:w@h8@ 8G! F 8@}|$ UOE VA@L%@mjd =:]hS#]@ бL%@bO} `*` {t S (V+ @zn,9@ t@@ fA@ %@̂ @ J640@@0mh`0 hGc C2B ̀ PC @@ fA@ %@̂ @ J640@@0mh`0 M `(Xkhx0 +uZb':㦜bOψ+ˏؿoΉti>o |}VJY۞54 4^>w %7!@@s-> !t, FF@̺Hg=!3h`1V}o t@Mσ}4 @ 8ƶ/8 ` dWHh`p0 "@ J640@@M[;͒@ӽ}#.(1@{5@z \94лIߒJ\5?"q!8G!S hSÃ]@ бL%@bOY2 07JNV}F&ķ4㵧0=ȵ]A|. w@G? ~f ::q@ bw @K<"FX@q,7,N:d4tnza @|MYm'dTG| =[uӸ%PBTHB>M=DUBm7fc'L4fu0h+T5 qv%քh}uiBaiܱVzm1``hmg!K+8X2 @YiU0[1ܹlXV3B  _Ex̚u Ò 8baO |d>َEVAoIX8FtxDZ10Ϗ gC g&nj${ZM `#g^ztY2oЗqDZҾm+K=t\WAjyݶyXZAkXSIOnh⫓[}e~d4xF;(P iʎ1BpY淒c|pd9yף_~.;_^Y||@Lgz8 Bue1 {Jckc  ChӽfoNU CL2oA/~kzR52/4VAk1cwfSa"RK]y̙_[o:QMШ[X2B,s) Bu ]z6U oG:uP5s!dzNl?7ux; P<IENDB`Dd44 @@T  0A}jbGrY̊872#C nrY̊872PNG  IHDRabKGD pHYs  tIME  73IDAT8˥KA?3"ilkh@݋/JB/J XBdC(Mb51MV6zp;&QJ|y}?T|V\'+(Ctf+v|>vV eFa!=MVDPM4RPj^Ki~ jZ.N f6$,lPTr.\K1;7 Ӑ(qIyJ#jUp~8~op d?lZۦ1Qm}N1O9Њ%&r0σ):&?% ~1y=W« }=W%+{rӺ۝*IENDB`gDd T  0A~kbD#S$2 nD#S$PNG  IHDRabKGD pHYs B(xtIME +0WIIDAT8˕oSszN{glMqsQ= "xk$^( 6c xiĘ-Jd2M&ufjRnd\G\WK[۝Nj&o|7~ e˲=$rsu ,""'O:+cY*0)خkiyoÄa4Mw p ̒v7PD<~[,0Zhyw{YQs; k%CgiPC$Q*:Z"̗uE H$*cķ `.؎Kz W6'+޵EIѪkX_ĴLrQrǰ]%gJ4Ld-ľ6C_!Қ87;"_tD"_͐-d &r6 P`<`3f3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3vxy`sffffff3ffl}fff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3f̙3f̙̙3f̙3f3333f333ff3fffff̙̙3̙f̙̙̙3f̙3f3f3333f333ff3fffff3f3f̙3fqIYIDATxc0ud*#H [G!R;%;ar,Wuc hc+Jc 8'/|LbIENDB`P$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HV$$If!vh5D 5H#vD #vH:V 45D 5Hf4@Dd= "$$T  0Anb?P>$a? n?P>$aPNG  IHDRU䙦sRGB pHYs+?IIDATx^KnWqgځ&+ٖ% !Kɬ[̀LF1#CR$Q=_J #; E[>{ޏe+QkoGGWoZUZUk}n 0~K|?εZԙ\7 ת\֗mwk􆶝Pru&4*6\֗=$LcH,Fg/WZӗ@@TԿ>ʒ  ;'C㟃"2gD.Tot]X0%L^AuP R?Lε}`{{7QduG:+GFI>K"`coEX/iay*wP21O8l8u>!QvST{ tJE"n;u|4վ[c%31? rQ"8[BaŒĸ\){$鯬OfM$'aLDa D[ G7dqIZG]"p7E21T8ŏDܪn_C *7Q|EK%Xz N{9[Jf/.$_g :f!vH.!*a B=? f4OU\uݿKih    = I`Vgrݬe / *}YmA@@ H  Fk:l@C A@_54E%}p݂ϛw eb@ZYV'srLpgJ2ǜ.ljoQ>r ΚD"8 sȴN"(SEEJE`t"hǝf[Iz}9 8}tX9:7N_a9wu{1McίTxhəbVJ-91|?Ǯl[7|~Ma9OzXLKo!c3@NWNrnP/dchL, K&B!brf@PxxtPQĴI9c̒9[+yB hm[#zLzE{,pq0q9Kr?(ҔbǨZ7hzVfi_1}#ۭZ /vlK.;@He.:H e2,31ƣZdBeXQP,J%b?~Glۄv s*gG>{HK ZϧsQsU%h6Bs2j1PArc H[lI v|x_tR&; @, y ڎ'a0 XHי\7k$cUT;k^ϝ q  .( 9fD+z_;Ei!+Wy5Ugrݬ9$Nru%u)̌KrwY䢢K|~9$9[/ιc`Zbf'ŀk9BKu9qfb |b3bB`}N)i 8m믞#c@ \5+Gpr [ΊZrbk -9J^ʩ(˱spc ]T oKZT,ҝ+;(_>ﹹJ6\8~-QZu`F ؜[ )\t6&* `cK8 술 \NHi$j@~HϐU[0SYꌩWk {M h1%`g$_3 $9ÝWyqwDoL~d8˸)~I+;~?#m qxi?ZN݊,r1Q:fzgd[[eu D(\>0m.#nΗ[QWioڟK\-j3ebخtGUgrݬ1zbHpH3OB]z)rZ%vfX@@`?wn {:fu S.˧mA@Fvm  w T}nnL)e _\mA@tp/hO`p÷^*}h{IP5~L,(/%:^)Li0'YˏEz3M F"j,@0ñ_b 102('MK= Т1d5/m 9rr(R/m|kM.P!t cp1?#$Xscs!Ć{~ʜ!W{q rx{(5K r7(7<31s MGՒ6MG\zM %/,' Gkd׿Dl_g"I1`xslj ҵ `J *B=oSڎN}tfdU~Ksdl]x܅Hվ 'lJAֱgnb9ѓI~tE c4İHLc-f+t%eLN̒R!\[]d1 ~keC:q+%g#/AeS2a; 2ޞc)WAcҘ1H#,k$SH1@@`:?CXQ˖lls $@7,  6k8Kw<@ǯwbbSL/h_e@@@GH?_O>z}9Gm#nrCaXPyY3lx~N}cd;^).\-6|Z~,SHX aW/?ivү bs_d3덳c8">E o'r9IIΥz ;?(@uj-'/bFUy8I(G uߠ:$Ճ #I19B';}b "=$瀤R zE!V] *& _T0 ZrJcUR>&X#&F*L* Y_?h   N;[6kES[7y\*>gN=^NIpO19||a| vLD(KPR}c W[m&\zѩ޻a7;"`{)-&Gdq>N`E]G%-#I05_fcԕɦ߮úI{}6[8Xd#GKκc=W |9}ug,6\ y5fol|,-J,BȪ%GxhY_tj,^?:f͟oN"k OYv_iSSWM֤%[X5{['+z|#ciV|Z^̿C̏r45jԒ5)Eyb#'OA j7h<*rۮ|yj1WήíA?PdUu<\l"3AS3}"=ׂ5=ϩA~l70& $6V*gYnTc't,Iu0u|{qP֧AԩUnϢ6s tU`BSڎ_{9}ytT(K}COx!p_Oki[-?3|AzAN(r'rc- 38%qS7'fZX ]Q&`yIصwc}dM%?TRL꙯NVO6RK+'Xi*ϵLhVOXx}sbrd*rthMI* }8U˶I9xVO:KWQ/TB@@tB;-X; dþ(OfcE߿]y|X)yƭ<~m彫dt6{0OBPS.˃pٗˠ-?E͋}Ϗ?:ӟ,RA` >ݻkP#m{wD/> vAy]ys<xگ^˿yg9^?cPiGiBz{0 ,K sW~ 62(S/1p\yύ-?ty08$$8O?t9=;0w_o/9% -t=n0hP-z]7i\A=+mzbӇ6svn.._c/ǟxk,"QlR}?#ڋ''xR%G',yN$Q\Dr]'~mD &U}=sL֎+-u6ΑslNə9?5<`eZrBӛ*Zi%'OS'JyN#b24#tp]_-_'Mt%%B3qVp5>82;=9<2GȜ_.'ᓌɉ9"A\yU )l^pIH"9S2:/"xxczd0t"&Us Af!QMo}Cд9}^Lߞwۿcn6wmstxON2xغE:/~Tk期_bӖR) ؖȺho/f]gx`No/P5_/`%g _L'udV`.~b*ɏ }[]s^?ZCi@/9@J!*ZZrdb[tSBHN)vtΔmݺ|:[OV+ 3OyrZϭ?6g.fO~]?;|Tbc?/uP*FGcI?80>无]r -Mꛎ~g2{ICV5*qc[6?;rm@7-ִ)n:UA@5c?[4N`=2C1 c[ NrۉX@@`o} %Py^`|[{1q ~vuvo5r௹/@@@`PY  m~1ޟZrk F%z_<~6wP i19|da|f;$v┊EK'g>lW'@϶KВ dLN U χHNsU0#CIT2ڬCml]G /m>% @`j6Ub|1[̛oG^֫(+!mi9ŏ|9 Ϲ1eƊ.|<L3$%1q|$îrouͩUmMN+_䴆#}DKjϞUIw ëv0I&v 2^%͓1Mi[jƦG=$#K_U)߄ȗ*#/K4UYIsXrsdZ4]=iú}"%KwFm9HyQ1s-`~fpU8g ٖ sXNndSZhK>VB,mLm,ƨ~aT _coS[^$b@,pĶhjsn(J ;7 coxU~?YHёOc\Mwj3_JI4koH,$rΓO?Dɑaw'ߔv-&dJQtvc$g[<ܾ䄩!:O,G>/y>/!>y8!*C,[wNb`?Ui7T[Qp`!KؠrLPnhG5M@@P1ll=  ]kAyJ0 @@k6_޻w`rkvE2E38c 5(/|{l셍 ?|s$TG4Dל+CQ>[ڑ+>1d/Ae(R#+;p!ǶJJRgFhlWdҩS+D#uZBi':gn>>7Cs¼O>I躨1K5GNGWȡ)9U6&{i<'rr5xAO/Pw5ƜG< Bv'(9.c#G? ÿ<,KN)#Vr"9}=]gfkdOwߛw̯ͻ*5G[w }*+BYt^ z*?[fOڵO~:OC_Ob|p\_[_-*Z+o$[{~#sȼsj.0o_őBW*9tX/\ae%ܢKu* ă h:ꟼ0?S< m AYER0jŜr6l/x;{~'ۓ3svlNyE xrpu6S.jNѵf,l)C*[oдb\P֕:U7 }oU_9x{';ǧGx<5gg7?Z:P1U6N1v$3$gW/$%\LtX` [6R9o1g'wO~7oָUS D_TGhU{3x/m◌'Y/8/}0ŗOON'#IƇuR?Cp( `sϚ0|i?tu`R `.#'.9Nb;q1>E YN^33aI- Y$;LXcvGU]$xC2A[w( ZULs>9mWoPKN1IQKN5|o H)t[ۍ|K'|?"}`BL-]^לlLR*opbo+6,rP,}G[ĞJ?fVJSpA,)Bq.(?yW% [;ye|nS yҵx&\A84 KRZ߿lfucK'EE_ѓo)F$'r aRq¬IMF mTn;o f^VҒ3R)MBE]溙{KQ4Ò`<}*l}mx'5llR}2ut>OKv6%'w N:#-1crT!!i'=Գu'?#吧0{]ew/ho ;U`L8Z_Ipw2u`E†V_ RZd'; -52tGdZVgrݬ1zbHpH3O_X\6DND֊ߜd-n?ܬ̺)/'/WĨ" PSr)'bľ&Ju&ҹ9`sQQNA̶ִљѥǗG$$7A95f OLE`H̍Cnj"!m!FRP*FQ-T ~L21I.#0Q<, KN) *ZW3|E.]  hſ6o =-NAڵO~ʶOC_ʗ1交Ryl]$7S?L(k)\N34d܉6'+/i!Ғyt^r0?y r򗨆Pȉڀu}Pp;G0 &bK~NV r taccU\\Q(zN}Q19voϼ+os|P!E/6.\vr*/$,%D>;^2R#js'cz?ÿy\cmoch *c%sIŌ,fKɟ=|t'.g҄1SQ +}t*ޣ?> s|nN.\\s~nydwhC_ړ{.'q9*XrUNsMof!-\b*>/ͧgR%C`~yGc} n兹r7^ūsd{rtfΎ9<4oS݉ʶ%;UfGg>CUs#h0,[ 4+;9>8:69;3oצ^}6ǵlγJiGՉVf(~IopZ~tG@ə/lOĜ=ݸgSwq5$3ȹM{VMsiyqU^=̗/䞕tԍKNfƜNHEQ ?y߽`~!' DɑϹ/] mdIG"nB6|9Y"aiOSt*9ߟvGu Aɑ7z~Zr2|Be)mx:} ePlDLsRQt|LOnGA-wLb`scc~洜Zʴ/'D QLN])!)_Z˄=WU Gk BHB_38j_"XYInNixC /!;IXc?zΘlm-(V;'Ű.T$'+"ؘ}Жa-NEݩ mIQoZ"US#+TD_ӬX ST&,gS'TLۭԊRiO˹:?@4 R SgKVSvJLhDcGF[o`Џàb[grݬ9ZS[ -9<3rv'kà}#n'g\~oά[ZoK#י\7ZILO.pN ϡ6?d7r-ofi<  H@SQ'Z0u&Zpo\־ mA@$۠S*?' ,C 5.lVuV5c<"3Kڂj]wI޼㫛]ꁵA`lF4Ln}˜bE[5Q,~ϭ >;7wy=f_n;^VU#8"scqL|peA/%N̏E %C~b#KSMuvKW|z}f$8b?Dϭ퇳nl|AO?=0WϞ/tR¦s\ؘbzΥu)6ef'1P8;&,_mX82Qܪbwͽ;Ĝa5O<:EfLNa|GZ&L*4qozXQNMm_o#0 S$^&C2r %Mk-kab> -v/Q DkS<\2bnP hhpcBEx.Xl,ǜg_o^{s1n;9:<~''j\2Zo&LUsc0g(~? *-/ΰ.ϙ̡(v:ke"/۟ŋ{˩@.ZΝ%K &%3`jct+ ;j(*Q>$R|g^'72g|1>*`jwvC痜<xlSۜ>ˑ/P%:VuJ$@vљN3RE~_ʁ,q4L\6 שTp!@@e-{- |G|X#aM'vJ;$&;#rE'AVȱ&;?֧?{vdn}z/~{ kHQ"ΗDŌIlk%x_B67̠P:(+֚@˔c{w\N{虛ơy90/O.$ B4l~)&?G I9ǶJ ņ{?4ҏr*!M]'ĞR]Zbo=^ UoyS_ocr"VEd-qZ/WN__.'g|9 QL6\/9aħ8}!B\$$;kUEL>L9g_~RTNH-rLNkyGc} n兹r)^C_i3'1h|lAϠ\[<*ikŨrZKabsy߱y<2˳ss~f..r+wd7 \Nfd/dE/\J9()]BWX/xlUh3uh?W%~cb[6SQи|\ v`nlOٱ9=7歟n|G^0(lfB}Ab) 3?Y럃9dcx.Δ@o gMWkmNl_9x{';ǧGx<5gg7?ZfJA2c'KK(:+^h-\ ;kI&p3I|VҘ~qӟ۷9;{q}ϬMZ?7VV)} /m9зO*:X I$_RYcvqUrezɐIhsG\F(-VHm>y c.͗C])D1y:;b[[p}7RlVܜ(],A+ʼn\?O@Hb1S:#F9`/sW۽&g?7ϮQm|b7 :1 @ T!3J`=2Jaݵg{=u ʃ@/@ Tέ&[ [{gM3nVךּ.}/-j 0@VMlvHw _P^~pPxiJp*#LL4q>'5?_ˏE%gԿ"Frl_(0 ?/oХopp&s.//0%ApsnSqs,X|c]\~lKgn!}`fWf+dQS_ʫȯR7+=)xO͖)=ZcS?u.98׾.*Gu7NǼn'!| f;zGAK19bZQo?peN؅rb3= N[ɑrbpxҶ6v.猱O+J^JCW+9?A&99!qKr9$:?%Bw d!1KT';}IENDB`V$$If!vh5D 5H#vD #vH:V 45D 5Hf4V$$If!vh5D 5H#vD #vH:V 45D 5Hf4}DyK _Ref162942176V$$If!vh5D 5H#vD #vH:V 45D 5Hf4V$$If!vh5D 5H#vD #vH:V 45D 5Hf4Dd' T  0AobPeWA,n n$eWAPNG  IHDRZsRGBPLTE3f3333f333ff3fffff3f3f̙3f3333f33333???33f3333333f3f33ff3f3f3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffMMKpndffffffff3fffffff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3f̙3f̙̙3f̙3f3333f333ff3fffff̙̙3̙f̙̙̙3f3f3f3333f333ff3fffff3f4f3f*vW pHYs+IDATx^kv{?9M3$&ۙ2!0%z&I%3[f߀]]g. T|/`MyO`rw,~Zb(dd$2 W~]DW $׶xoօ~T3HA/) =r>'K/z"̥WHuOǩk(0>N1X` 8cO?˺~wBg{' *lw0߷e-^LP`—{d]Jzżc2a䕡`p[[?e6 %3s՞ ntJ> w/{f.}G7ybq_K~?ZɁ3L~Tmiqɾrn0g gg @h=$'t ZLx6'-EO[N?~PxUv3Wg{*ϚSڠ.|rFz%g[Rᣁt!zp煴`Dy[,Am**w҆v-Zd̎Ġ-}|}:o/Do Lgswp7~|a_5`[> W71k|8| ܐzg@Q aZ|9__0V*9|Og(bzgWgwxg cαAT  `zf Wt҆(B|5O@@A`euWsuldfzP,&CP>Uw||֔<9U!_s,50/# eԕ+0xW.CqBh=b D*% *I)(a.R0xAzpqQ)Y%% =hK) `7xw*)aP CVSex|ao ,Oho~g B9 H[*m&ʘy`AzzY P}e㣗cݰYQI̼ᷫ*J_A|ŠG[eov l[䗃)zxΐ~E1hRU=<2a]`{216~2XA`Pٍ3+\AQXvDj`D.;(a~zP S{ڲgVP 5 ?u\e:1E..@b~y4Z u7`@?+D|}k9D`Tpliԃ,A !` ЃK&l1]=Vc?l|tο1PQcp\[?t?` X7)ۿ,[V7[*(a/"*@1hK[r<\{H+/A1.*lmQ7, /tN(aPt5Eq]Jԁdɶґ % Vz)Hb ZS,6qzy$BA|9g##=KxA/¶bkfޔ~ZG:xoݽ|Z*ᔥ7NKM&}AG"i+R*GçVvEѶR佔j t?`bZ ^}rc ra% fR@BeH6;n!{e"حTP€2mjE gŅ+(aЭ~8a{&,{8Bz@?v]Z vR Uvd(0`(HA-Ɵ殄ITP€- Iŋ.@B@'q,nV"? z` I\DQePN0փu C ^=z`14$/\A V=uw#,RvA% Ͻ9.Jg/\A V=`=XփQ υ{XTؗi4IMlXb{J"?|=0 ΀@ۼ[@0KoZLf:. \oڡA|I!;/K.aOlk?#zR W(^MeNg% ETҪg '[B>H;ub*4rJb 4!R?h1Y?`+ Jl6->v҃vz8C?;mPh`ۣLȱ'U M/ v;p'BF ,Az9 ;`o&+"SHd鰃 Q4~ Y6{6HRPoF1@tؚ|| ƀ#.|q){ack^\c9 P[QPmlbBWZlpi!<$xch[([:ܕDçS7TO_Ճ3vQnàA\ᰃ[٢?«" fXB\򰃛%; E .zBU-,? l YC (=h7QJ/\weS1e7}.S2Jb^y ,kP l\Dh JO1 2 >҃ A^M;U̎@p(%\[ߊAoΫ[11*Ad݊֊p++Ō݊Ġ1VdHtŕ"tWa'[KJ˘F"tWa. ӕ(6.exŠ=̎Tm?·H9^Et` LtF,Ǡ?vE;+ W H6qh7.~A=`ˀwϜS|zXZ~p*p =ٹ-AE/G"mI1qQ$Q 8 >`>:zPzn e:m>e㳫IA`ަ!z4'k A`g2 EnVKڌ^dxO*rTe@AU3f\$1`(0,l{avvA{fd聭?`I0Šk\kNkCbs6뼊'e|I/ŷb@AyBͽڢ?Q pމ2Qyˠa\73/w݆Ae,nW8,W-j]+|5c0EEoa8VI*f7-UIG5ƀe'UHIc/;@J~I4RoN1d;Ơ_vR5$1i $ߎ1藝TMc %vAj)Ic e'UHIc/;@J~I4RoN1d;Ơ_vR5$1i $ߎ1藝TMc %vAj)Ic e'UHIe ݧ_Sj*c0EG/08E\>طd0I" 3Y`2oRIENDB`}DyK _Ref162768942}DyK _Ref162768942}DyK _Ref162853460}DyK _Ref162853521}DyK _Ref162866493}DyK _Ref162866493}DyK _Ref162768942P$$If!vh5D 5@ #vD #v@ :V 5D 5@ P$$If!vh5D 5@ #vD #v@ :V 5D 5@ P$$If!vh5D 5@ #vD #v@ :V 5D 5@ P$$If!vh5D 5@ #vD #v@ :V 5D 5@ P$$If!vh5D 5#vD #v:V 5D 5P$$If!vh5D 5#vD #v:V 5D 5P$$If!vh5D 5#vD #v:V 5D 5P$$If!vh5D 5#vD #v:V 5D 5u%Dd#  T  0Apb$9'2r$a n$9'2rPNG  IHDRSEЬsRGB pHYs+$5IDATx^]ͯeQg<_XJȋ`YYDXDYDbH,B=<Ɗ 6B(D EHH"eAv`y>gz}N>xϭ߯NwUw7La`b ,&W jW߻~&@d)R6%Q^)ys^ew/ӿ|Dd)ޕqs۳fܮvm7۹ v~^owc?~>|rGumb%?|D~*C'RёW6W/N׳jws ٜ=_\Ty1a\l^Ef3߬f|٭ֻͪ f6s-Wr)˄ 0\oլ~Uoβt5gs;ĭ;̈́Eg=00n$^[}{y~;Mc+?nlUS/ n_Pj]11('KdӽznsWɼղKׯ^z^T']os~KTzԿ扖h0$8o+ʠ\?e_y ߽ٞ[UiIM(yÞVfnwoĞ5S_&A$NQ PN<5a5O~տg{{2 ie8$j?ءDGUa7?z W?wy/f*~7J=`DjUH QH$e]*wsPWԷ:T_ݯ|`uھU!O(R6H` Zն9wvoܩՑT3=g_YV@ d࣏Vww;pޮy9_-fXࡲm;_?)RIN5*C'Ro|'x_~U;"Rda(T/~;7|JUk{]ޟ=g_GN>G{1f訤;YD??XܼD>&N9oP/8a~7s?:ZKH 2<{GX4;kKo!_pe}zWx*Ͼa>D5_X"v_Xd"/uClo8rQ="yCV#_j~D?i^ow*SIr#jض/G$z"3X, ?ߩНwfvG)~6-i&q!&2.#m+[.p9@DXFq U?FoO.h)Fd .dd`G^ <cNt8~z|wUϻZ`v9~~DBw~G?C7n/>dibXD!.l6lGF]t]ÓFn|q~RjW=hDyzΗ>qbP:J\N 8FMԕYBD|jgC ]îoS& ?=eh($BF^/z-SEne/Z)ܰTSCXD?sy؜o]D.@pyNZ@GG1dOzb@"0{g"61a@(|n9",}%¤.M*Cbe<ɓu_O1Sc'v7M-hCDe/͒zHWxtokvCrWf 5j D R:R~w+I}T }%^Qǀ&+$F' 鉛FeB))TSw*fT7Z$U_dq6C#ˏ]-":}x%\dz̄ܳۚSwuCְMljm/jBCXFcq#GނK: b@"SzQ- z{Vvǫ28t,p"E``P=7 X[IX{ D¾fsy )`3t-D|Ԋ.HW>yxC M0 atG^ PۯdetQ+5, A>{p ,|֬()(ij {<|ЀIX&!$\=z/a;YL^0Õ/`J { #eA,3uY7U,ձ,>Ƣ=pUqݗ+_ue>v`w 9?.m 2R4?- [#|?DEWiBlZ =E!!+Qxן #Iϼ_+i]\P*cC{CM28E-,pt>0 ?; ]l.ag =6& H#e@v)G" p oaqv"G)A K]9Ed=HcFڦv^~3;^~&h6.uT-[ ۡ)' OVޤObZewiզ kуٸAdu3(O|z;Ii>V0C$rt!'olz*Pe5]`[6ޣVm ÊAV79ɨ1.p xQM%G(>ۢ[#ϩ8-Ma Gi6OmMG_$zȯg,0@g@ѹIa8ސTvǫ28,p"E%J)cAS=Moo${l]xACG |QpfqcnްAbPTSlWZF.@w$4,ic c k&Kx#YPFr͛RB ZZ櫃#.[,n)z>Ї>6ԩcG u])5%hS+6vcGVՇ}ro1{!Slvt<߆^k3< Ğ[4ꏊ \~t+?Y;y $ݏ1JO!q]Nz$L@grQ+ ̀D~# z@ ]=+Uz@L8,wDjk D[[SׅK ON~?IAן#I/GickWc>jfWwY6'S=O*T;ptWdA No\w'GŀD~`D413-6BG}DBԸӭ:]md>+鍰`Mq>Qg|5Hx݀n94x}%)}]maSuv@d Ջ7{n5 BDU-t.=`Oa[Wuu@I@%DV~懢HA-@Ť~RlRg:&y~G00J$G9lb0Бב@i. ɀc;^d)rWOm] :cBba{ ' ?o;Fo 4%ED%"799\z[7l#qCf)LȏAC}>W/"o-! (Zj8CtJfBWjsڞA\=]ޛ JR֬𕟉 86 H~;8L$𑳃͖~Gy'B@fN<K9߂묐$hodɜ_I@v$S,2 w 1I2 wWepN=M8,wt-m2$q~5 P?9 ޽yoLq;_ruX zۙxÞorS׾ݧ~nɁ afbRዧڇq-R{00]m\~Jo[yQc+ujSq߷%ã37ƕO`wP Љ`u*9<+PxE@/t8g{oN6@ :;2'S:"Kb @XDc@aE}^V hW(M榝&QpyDS BG@ڄˏ6F1e)%wm9.֧wGF9 jɧzjz/\~ TӍJsa@(<:b0Y+ #;^d)zDb#V#kQ}$roU n(fin</3|\ӏAs -=Hz퉲#J+G#TitPxrZwsB;?QNo,FQ" x'Gu.:N rϢ|X9Ǣ# uIe5"~ t:{$ЫY #_zmR D"_,@B?\=&mk-O"" jK]D;g~y>{^b]2­].y ʯwF>~;Gx߱i. 2 _ࠈI@v^va rWoxUN(]=]mvw8X4 [Ajf[;IAxG4sS=NvW |犺AoaBg:M֧seK! ykc_ 2\;!Tϓ`헿גh%z k"u,hk6ƶ~?JmW7c9.ŀD~m:CBtìLx9(i&|/p;wGJ*[GHC"? T%6ƪS0@f@"LUgAZֽ܅^sS{7$'t$842դv$Sm핋 }Npr@y|NR@ y\+6x}[s /Qޕ|j?D 2 _Y@V^VzE0oew*C'R]=eVQi"M1nm@5o-a/W&v]D%(굨:."RUn$ 7-qb7-v8;zI@[t"m `{\yRgsH!hCf C ,I-&7B щ}F-2P)D"?m$Mҭekw-x #{M"?~4 -l2+ zϒ25!cH{T܆gH1flW GlVvcus 8Iޗ1sy#]$4;f dJ4[ fLT.lQJD?mM#rF<)_7iVLj*|s?;ͳK$zw'|~p;Z9eisnڄma Pj(/2edG)Dzns+ȷ_N{z!CyzRPH`t1#z|wt"B?F؅|m|2x Y|o "tz9 oy?-鈓͐}, p> -fyx&Od函kH1 [, ˀ+wl2a Ȁۣ;^ z,p"Eճ%cܵ :Js <ņT2,r~Sꉰ-CDfЅ/>r•_~CΝp|r^,Cm[?1; on*eg<A\0>@˕)mߌn@NEysqs۳fܮvm7Ɔv~^owc?~>|rGY(wҖD╎G2mgW/._<|G.=rՋ'W..<TZw-CH'0: !$'j?],7r=_mvno6F-gݍ[?b#?"陈,yOecW m6x:o(FX;r=*7g'6j~;$ܬug=Jț5Q6Eu b0%kv7:y L䲡&z&ߪ^Mg?7?Vsz7kjtN5J32<*UUO_|b߹vK/=U0(e*z?HÛkڃɀBtjJKׯ]펏Lz<ϾwGph E5䷭կy Fp]S`&Կb<}V z1wFҽuM_!=s%# VR?.Eq|-~k5;uثUث}~C`O[P21w竪~{zO9۳7K/XZa?Ta_%𪶯{xlo^;Rvb6H7<ғ0}zk߾}` M%o-g_sy#l_?ƿǎxn?}*}нO,ٛ,p"EWuNjY|vy,6_)jه׺0JcO^6XHH w(rņ8нx㣏Vww;թޮy9_-Un6.?]iF Ad #.G&ʌ_`qp hB作@~s'Ru{8 \/j{o,>(X||]EqSJgyLo<ȷǔBW.G⤇^wn[ա:ɫjo/"W/|S.V7"?9YPJf@vJMxKđIENDB`P$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5H}DyK _Ref182909127P$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5@ #vD #v@ :V 5D 5@ P$$If!vh5D 5@ #vD #v@ :V 5D 5@ P$$If!vh5D 5@ #vD #v@ :V 5D 5@ P$$If!vh5D 5@ #vD #v@ :V 5D 5@ P$$If!vh5D 5@ #vD #v@ :V 5D 5@ P$$If!vh5D 5@ #vD #v@ :V 5D 5@ P$$If!vh5D 5@ #vD #v@ :V 5D 5@ P$$If!vh5D 5@ #vD #v@ :V 5D 5@ !Dd W %vT  0Aqby2ev!1U> nM2ev!1PNG  IHDRz*K !sRGBPLTE3f3333f333ff3fffff3f3f̙3f3333f3333333333f3333333f3f33ff3f3f3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3qodffffffff3fffffff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3f̙3f̙̙3f̙3f3333f333ff3fffff̙̙3̙f̙̙̙3f̙3f3f3333f333ff3fffff3f3f̙3f-r pHYs+IDATXGXA %?a-h:I$xu?S~ BJeo-؊~ʐʎ`$p^q.Lx3|}_9ל[xUF AD<{uPoJj,ŻFYIENDB`P$$If!vh5D 5#vD #v:V 5D 5P$$If!vh5D 5#vD #v:V 5D 5P$$If!vh5D 5#vD #v:V 5D 5V$$If!vh5D 5#vD #v:V 45D 5f4 Dd7 LT  0Arb '}b5XW *E n '}b5XWPNG  IHDRUsRGBPLTE3f3333f333ff3fffff3f3f̙3f3333f333333332@q3333333f3f33ff@Q3f3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3VVV_g^yffff3fffnjff3fff̙ffff3fffff3f̙3333f33̙3fe>o[ff̙f3}Ɇ3f̙她3f̙3f3333f333ff3fffff̙̙3y̙̙̙3f3f3f3333f333~f3fffff Z3~ʙٷ3fC*t pHYs+^IDATx^;v: tڋYGREN3tTvd*q;$HaIAI0ilYEU`eKPO 6sC}RVϒ~w89c]2Lԑ0B5RA+GiȻu$I$DнZh^7YFN5h>辣ŸZ?8hx pwAie 32Xg.кx=Ԏ PrF\FF#o1t'agF}(2ݎm#@ݐf7&[kzCiT3ZvL;#ټq(|mhp;g1&= :ٖi&%nNk5W܆D }CPJϤGt U-X XxIT)m'(u}(BF)ˊ1> j&g¾dwѲ֚:JW8z%P:d1!,n6Tn风iɚŵ}U:߾?/g)+%|9X"X{CHo|y,_M㠍ΕHUS㠁rŬ?Z.5u4 ⢋4͢FkcP̻ sY 1v<sm`,լE[c}B4L|6mA>`Eb]t ڄB0h١sD+6*KEDFMB[3:stDf)4,Y%ߊ5֒EsUhtѭ ZoCv&ySoC׼ZBp4RT Y#:RK-0;.z%vm;]ߗ4`ZK+.`XٯWXYdI"[ب:JE "5c ]']uUZ|OS4[.RO1uQ-rU$|EIStfXVul٧.KY2G칋4qD* z:w{/1GY~N',v&wѯyCS/kkG)n"5ţ)2Srj&g?mhhb\2Ek:3r+4U'`>Ո{6u"-_@W:Kt?R}:C-Z媪78Z7T Yۤ:30+ݍ?jf\A;fEPHK lJ=4}x7]\81dj`qǠqj~Lq<#Ҭuth"l;ŷ/rcI9ht=lX9ӵ݃6FKM6ڱݝf {87}Ӟc<,d$63g1'uNn'ZEz2LK:ߜ8{~teUw72Sn8-vk٠HX8np N4wdR Mw 6z\ +.`X/؉l11 YczM11։FɲIENDB`}DyK _Ref184811508P$$If!vh5D 5#vD #v:V 5D 5P$$If!vh5D 5#vD #v:V 5D 5P$$If!vh5D 5#vD #v:V 5D 5V$$If!vh5D 5#vD #v:V 45D 5f4Dd e&T  0Asb&)Lz8diR n&)Lz8diPNG  IHDRKiE.sRGBPLTE3f3333f333ff3fffff3f3f̙3f3333f3333333333f3333333f3f33ff3f3f3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3XXXffffffff3fffffff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3f̙3f̙̮3f̙3f3333f333ff3fffff̙̙3XҥŬ̙3fٵʹ3f3f3333f333ff3fffff.^鯆3f3fb pHYs+bIDAThCK09%q=7+1י y,B,+|No7zC=vjˎclq,BVŬ rPŐ<ւBEոBЈYdA~y߰xsqҬZvN@g9`iViӜYic1m~zbygwc27cl\== WZ)5;ńT֩pEX^ò1r8۵OD toz [Y,Nan''NHKDZIU=q\;=/v0 i_nqɊ/E9ܿX-,6F|Rϕ!kXGB_qzB̫__WWKuezwÚg|F$=)0Ա‚Ha߽K^.2WezU/'^kD9K Uk[-'S' I{KqCO?ҝ*ҫ~IENDB`}DyK _Ref191370312P$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5H}DyK _Ref191454702Dd  :T  0AtbF<3&[ nF<3&PNG  IHDR?&l~sRGBPLTE3f3333f333ff3fffff3f3f̙3f3333f3333333333f3333333f3f33ff3f3f3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3vvvffffffff3fffffff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3f̙3f̙̙3f̙3f3333f333ff3fffff̙̙3̙f̙̙̙3f̙3f3f3333f333sf3fffff3f3f̙3fjC pHYs+RIDAThC PW~*B;AB۹hau3_NFh{"h.,@~N3#4RTbr.6?SCC Տ|(~ʧ+W&u]OӇ4 Hͯ>ǔu?PڗG95B?Hm+>SL =ӏ~1X7G@_L /&fy ^=>:g@1~u(~aހV]IENDB`Dd! *T  0Aub  u&%-a n u&%PNG  IHDR@%sRGBPLTE3f3333f333ff3fffff3f3f̙3f3333f3333333333f3333333f3f33ff3f1j3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3srmffffffff3fffffff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3f̙3f̙̙3f̙3f3333f333ff3fffff̙̙3̙f̙̙̙3f̙3f3f3333f333ff3fffff3f3f̙3f&C pHYs+gIDAThCQ `Y<:enӇ65K Lf_ Ccc '7L`` Q.z7A4?Ad8jm&(s?î]~vZp-@:@H6NJrƊp7X^d,V=%=/} G4#S8k`B <Id:+I\:^$ NKO qViJ&z:#}T`b8"a=u8zL}ʡN_>A'PtmmjϷp;Z m/+9bIENDB`P$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5H Dd :T  0AvbYןt1dCtb5(h n-ןt1dCtbPNG  IHDRbI`sRGBPLTE3f3333f333ff3fffff3f3f̙3f3333f3333333333f3333333f3f33ff3f3f3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3srlffffffff3fffffff3fff̙ffff3fffff3f̙3333f33̙3ff3~uff̙f3y̙3f̙̙3f̙3f3333f333ff3fffff̙̙3̙f̙̙3f3f3f3333f333ff3fffff3f3f̙3f/6 pHYs+IDATx^K0 9%qE^ϫHί2SQ򑤯4 k-C)T6e ˒$*6W*%p*㑙 S(f#/`-L] Q!R0 TCa,@KT#cT Ml,GTU>cЂ.3mTA$U^`[,#nti(΁h.`+3J!qjn(,G N;# q29p[ ;P ,*Ί;>tDOF܇bD-7Nh3cZ6wd+wU (r.4_KTnr CRQ-34E*ޝ@7̀p8I$ *DPe> )-cK0|V;T9REe>Ń^ʟ*߿G:ڦQ6D۳l%MSLm~s_GeEeb KvAàjĉ?k|@ bZI>2o^^^?BX pQ+˻sA&:].eʺb^P+TAIn:+TDN:e݃Ji=JR(7-3i^^%Qwv%$kzlrFP H0!eǃAifă"Q-@Bn Y-&.3Σo>GM%PȁL3M+*ʐ̏ " tOڧcԝh^O8ƊǑ:a,T[ G|LV9a(?H@\hD7 w[%So+<\4d5)ʴʤ6뜷=en-E%o|6ak"TTֽfޟ_ylG=wyc]#XҼ{TqEfvtih 6sH}Ȟ!*X`=(KQ*Xd \FSIgh.PiĆGC%^48S` "f+lce4 8ĺNLס}0lXU> p6VT[6l{6- ɋu(ifgOQ[VwH؟+{y}[74@Ld>+&cIAuFwIKEf',PurXĔ+Cfv#B1E0M gerb2*&ɃxdLHWAbOԷI$IENDB`Dd; :T  0Awb~dib)q n~dibPNG  IHDRccV*NP3aAh2wT xv <)TBPG4m%@yBT(T)JpHc舊V*f8z ܑV`OuC{.}DQ+]rK%aRC9I07 ״5Q3Gc4G Lnr8(rw~u0>DeA'ZuGyy϶/L'ف7mȢR%vAǧAm#ƻ]B*bdw"h|?c*E,| ΀ \I^qFaI+YTR6+űC TqMyE lT)ϬT+Q*J)Q#3iԊ%p ܿ2 "9ܿa#T*oʞh&ݾWVv=zώKV t;P'{P!oY o6g&{rn¨OAa(Lsu;϶5Uf[VWG<~u?RA#Dw|PVZuZQVZ VZIi^QVZ i%]m׫+&QۦT,vkTJ V8DYY +T*^cYb)"ab*dY_ }ae($("@|8X3nX{ ¢Wrv&y%#(,Rramߖ֍A/ 0^p(̕c2_,G^Yl^ej8(nϊML#J=aa02:'Z)x<*'O?q\9< &}$L+ɬxgTY?+=IENDB`P$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5HP$$If!vh5D 5H#vD #vH:V 5D 5H<DdG T  0AxbXF++r(tp{ nhXF++r(tPNG  IHDRtS5qsRGBPLTE3f3333f333ff3fffff3f3f̙3f3333f33333333??p3333333f3f33ff3f3f3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3fffgg~~ffff3fffffff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3f3f̙̙3f̙3f3333f333ff3fffff̙̙3̙f̙̙̙3f̙3f3f3333f333ff3fffff3f3f̙3fY pHYs+IDATx^y0 3هuu,Y&'/99?cin=oԵqM*r mh'Ymsg]u4J;H]ݗMaXd:ᚬq:ʲmiq S6u$=t࠺Z0Vl7>!{Ka +ht$N+F/*s]#(VXY$bDbTc/Y D]Xt (m9lPS*eYSmv'=Ov"/l6& y&LKį5$Lm~ V@*Xݍ鸟clcyN|Ft?_u s)[{530M)eBq;RJ=_6sCJuyʏQ-+c u^$<&XhDxfxj t&ҺrD`!ON;r|/J^S+F !늅2tUeJQHL =ժeu?Ge" 9ms]sϹx} ~NuII%$#)X)Y>2qIR+~Ԯ<+g]SYdK,N@>2b"2V;~h\UdLy [H1X2VJY.a1]κY鷹 Ƥ<Gy#1n8\ ʃ'ᝆ{?#{Vs dd>s~ޕf|KO7=snn9,d`X|z=۽Y7JSXa"H>u-uIENPBkR5YrU JzPBVM Y1[gMsɣɮ喏ՖTmleՒau=fb nɺÒs=&Ϻ%5 Vz}N:9v܌uX4,{9ShIENDB`ADd )T  0Ayb2nla16uA nm2nla16PNG  IHDR6\4.sRGBPLTE3f3333f333ff3fffff3f3f̙3f3333f33333333@@q3333333f3f33ff3f3f3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3VVVgg~~ffff3fffffff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3f3f̙̙3f̙3f3333f333ff3fffff̙̙3̙f̙̙̙3f̙3f3f3333f333ff3fffff3f3f̙3fs& pHYs+ IDATx^]( 6MO_:3B<0Fn6EO\_z5Q:@N3F?&j_I 8LυPmo{ceh 0X 7itIv:$ȏzjcn@Gu:ܠ3 ^ewspr +$3R@  B@K\R T ؜vVʥ_Cy勗 q24 'd]t4e'T=c$7eg1W$ib4fQ.ԍq9@K>_$GZү/]$}:aCT=PK-\+J: ńlQ@MQ 8`?csL]9г=şf@rG3MwŨRFy6BuP-@nw CY@2Ph~2( s.@:}2s[0hh_w]|/3D@DBݿ3MPePPb/J1 6PXiGbL&RTS苦D1>z gTQGOCk5Tx`xw5@ĞJD,uPI$grDfTЬLЦ*PI,@Dɏ8K"/IMs)*%P\W 8V`t(m&+ߋq=V$ CogKn~u!*XdEPTVp#PXlvpv>33(m?e mӫĨܻ$›"Cs#H9u }x#.Z풩ų) U%!aP8H"TPgIxU$R#mMԪ$S]%Jwxt^"YB@GxvDx9GL%!Ҋ ̰$1QQcTi *%n7ƨ1tg0UJffJKLW)q*-3]Ykktg0UJKf]_@_tm.NfI.oPk3K#_k@/hu@ߠ#=.XWKw}$17M R+܏Ҁ)O=Xי_WgƎz+x/̽U[žnզb .qZK>#20lƏpŸifQ4 %_G(v)P)|n ل{Q4Ib!iSKOFMl(h(f6}@Gz4]LE,샪Q"ґQ<<2YEQ!{ydb/X|5؝{^)j ëx/Cb"R`]f7XzNe1e膃=~ $wc4BgT;rB&h E@{[$(mc*&PPir2obţʋbl8H{N{<Ɔzn:goٜ6g=ٱKcvXE}t/# Wbnze.5C{i-7`f֫kvqQt#r^9Dzl1mQK5JC!!D eP9*[kfFWH"{DJdRP18Oy]@C(2b4ޤ{|-u1uwY6  \V:3z6(e`U cmPPJCmp0712HsIDAThCݚks8p)` YJ`3Ҹz:=X26vvgPe֣sёl?Ra2(bIpUQH6ubrsP?9$:oTZ@{XT*EʯcRPjl3>>E%6ypycYj%gy5 A}Ώ:6|7x]k 6m1wqFz(v8ɓ/:=gV]K [FR,TF}HxZg-R <Dnu+  p'zSQSꉖ9~T/Bg)8m36PNBjSn2rPYgBjj#<雀zɑJEEgYź8J񨾎Ph4LڐnHS*!u*HaemQS޳Τ怪-cg)ug6]jD1tPj`}TOފ<łCT cl 'sP)+BeFl|M TEGoj2K%Ak̪(!pnO @clM~( ?&:@}B((yZtpؖ׉<˽Y:sE?f&qHi'oU.%(k*e *$?OcӁOF1+P듕:hj{6j躰EeK0Poʪ Za-Qdyx^j4Ij (NS\>< bu1쐉d*MT~PAGCQTS|GEIko"͒60/zw)(˄=z绒 Ee&D]̽o"]zU(|cdrث}^>!}5?gWFCpvاdowڭ)?_T|\\̶IENDB`DdE l T L 0A'b.^ѫ533 J n^ѫ533PNG  IHDR3APLTEDB@yxv_][(ōfffQOM$!ꑏ:74/,)YWUsqoJHE!+(&~|&# fff@=;XUS1/,NKIusqŽTRPpnl\ZX}{zb`^GEB<:7B?=MJH޶{ssm)FtRNSiDbKGDHgIFg>U cmPPJCmp0712HsIDAThCݚks8p)` YJ`3Ҹz:=X26vvgPe֣sёl?Ra2(bIpUQH6ubrsP?9$:oTZ@{XT*EʯcRPjl3>>E%6ypycYj%gy5 A}Ώ:6|7x]k 6m1wqFz(v8ɓ/:=gV]K [FR,TF}HxZg-R <Dnu+  p'zSQSꉖ9~T/Bg)8m36PNBjSn2rPYgBjj#<雀zɑJEEgYź8J񨾎Ph4LڐnHS*!u*HaemQS޳Τ怪-cg)ug6]jD1tPj`}TOފ<łCT cl 'sP)+BeFl|M TEGoj2K%Ak̪(!pnO @clM~( ?&:@}B((yZtpؖ׉<˽Y:sE?f&qHi'oU.%(k*e *$?OcӁOF1+P듕:hj{6j躰EeK0Poʪ Za-Qdyx^j4Ij (NS\>< bu1쐉d*MT~PAGCQTS|GEIko"͒60/zw)(˄=z绒 Ee&D]̽o"]zU(|cdrث}^>!}5?gWFCpvاdowڭ)?_T|\\̶IENDB`DdE l T M 0A(b.^ѫ533  n^ѫ533PNG  IHDR3APLTEDB@yxv_][(ōfffQOM$!ꑏ:74/,)YWUsqoJHE!+(&~|&# fff@=;XUS1/,NKIusqŽTRPpnl\ZX}{zb`^GEB<:7B?=MJH޶{ssm)FtRNSiDbKGDHgIFg>U cmPPJCmp0712HsIDAThCݚks8p)` YJ`3Ҹz:=X26vvgPe֣sёl?Ra2(bIpUQH6ubrsP?9$:oTZ@{XT*EʯcRPjl3>>E%6ypycYj%gy5 A}Ώ:6|7x]k 6m1wqFz(v8ɓ/:=gV]K [FR,TF}HxZg-R <Dnu+  p'zSQSꉖ9~T/Bg)8m36PNBjSn2rPYgBjj#<雀zɑJEEgYź8J񨾎Ph4LڐnHS*!u*HaemQS޳Τ怪-cg)ug6]jD1tPj`}TOފ<łCT cl 'sP)+BeFl|M TEGoj2K%Ak̪(!pnO @clM~( ?&:@}B((yZtpؖ׉<˽Y:sE?f&qHi'oU.%(k*e *$?OcӁOF1+P듕:hj{6j躰EeK0Poʪ Za-Qdyx^j4Ij (NS\>< bu1쐉d*MT~PAGCQTS|GEIko"͒60/zw)(˄=z绒 Ee&D]̽o"]zU(|cdrث}^>!}5?gWFCpvاdowڭ)?_T|\\̶IENDB`DdE l T N 0A)b.^ѫ533  n^ѫ533PNG  IHDR3APLTEDB@yxv_][(ōfffQOM$!ꑏ:74/,)YWUsqoJHE!+(&~|&# fff@=;XUS1/,NKIusqŽTRPpnl\ZX}{zb`^GEB<:7B?=MJH޶{ssm)FtRNSiDbKGDHgIFg>U cmPPJCmp0712HsIDAThCݚks8p)` YJ`3Ҹz:=X26vvgPe֣sёl?Ra2(bIpUQH6ubrsP?9$:oTZ@{XT*EʯcRPjl3>>E%6ypycYj%gy5 A}Ώ:6|7x]k 6m1wqFz(v8ɓ/:=gV]K [FR,TF}HxZg-R <Dnu+  p'zSQSꉖ9~T/Bg)8m36PNBjSn2rPYgBjj#<雀zɑJEEgYź8J񨾎Ph4LڐnHS*!u*HaemQS޳Τ怪-cg)ug6]jD1tPj`}TOފ<łCT cl 'sP)+BeFl|M TEGoj2K%Ak̪(!pnO @clM~( ?&:@}B((yZtpؖ׉<˽Y:sE?f&qHi'oU.%(k*e *$?OcӁOF1+P듕:hj{6j躰EeK0Poʪ Za-Qdyx^j4Ij (NS\>< bu1쐉d*MT~PAGCQTS|GEIko"͒60/zw)(˄=z绒 Ee&D]̽o"]zU(|cdrث}^>!}5?gWFCpvاdowڭ)?_T|\\̶IENDB`DdE l T O 0A*b.^ѫ533  n^ѫ533PNG  IHDR3APLTEDB@yxv_][(ōfffQOM$!ꑏ:74/,)YWUsqoJHE!+(&~|&# fff@=;XUS1/,NKIusqŽTRPpnl\ZX}{zb`^GEB<:7B?=MJH޶{ssm)FtRNSiDbKGDHgIFg>U cmPPJCmp0712HsIDAThCݚks8p)` YJ`3Ҹz:=X26vvgPe֣sёl?Ra2(bIpUQH6ubrsP?9$:oTZ@{XT*EʯcRPjl3>>E%6ypycYj%gy5 A}Ώ:6|7x]k 6m1wqFz(v8ɓ/:=gV]K [FR,TF}HxZg-R <Dnu+  p'zSQSꉖ9~T/Bg)8m36PNBjSn2rPYgBjj#<雀zɑJEEgYź8J񨾎Ph4LڐnHS*!u*HaemQS޳Τ怪-cg)ug6]jD1tPj`}TOފ<łCT cl 'sP)+BeFl|M TEGoj2K%Ak̪(!pnO @clM~( ?&:@}B((yZtpؖ׉<˽Y:sE?f&qHi'oU.%(k*e *$?OcӁOF1+P듕:hj{6j躰EeK0Poʪ Za-Qdyx^j4Ij (NS\>< bu1쐉d*MT~PAGCQTS|GEIko"͒60/zw)(˄=z绒 Ee&D]̽o"]zU(|cdrث}^>!}5?gWFCpvاdowڭ)?_T|\\̶IENDB`DdE l T P 0A+b.^ѫ533  n^ѫ533PNG  IHDR3APLTEDB@yxv_][(ōfffQOM$!ꑏ:74/,)YWUsqoJHE!+(&~|&# fff@=;XUS1/,NKIusqŽTRPpnl\ZX}{zb`^GEB<:7B?=MJH޶{ssm)FtRNSiDbKGDHgIFg>U cmPPJCmp0712HsIDAThCݚks8p)` YJ`3Ҹz:=X26vvgPe֣sёl?Ra2(bIpUQH6ubrsP?9$:oTZ@{XT*EʯcRPjl3>>E%6ypycYj%gy5 A}Ώ:6|7x]k 6m1wqFz(v8ɓ/:=gV]K [FR,TF}HxZg-R <Dnu+  p'zSQSꉖ9~T/Bg)8m36PNBjSn2rPYgBjj#<雀zɑJEEgYź8J񨾎Ph4LڐnHS*!u*HaemQS޳Τ怪-cg)ug6]jD1tPj`}TOފ<łCT cl 'sP)+BeFl|M TEGoj2K%Ak̪(!pnO @clM~( ?&:@}B((yZtpؖ׉<˽Y:sE?f&qHi'oU.%(k*e *$?OcӁOF1+P듕:hj{6j躰EeK0Poʪ Za-Qdyx^j4Ij (NS\>< bu1쐉d*MT~PAGCQTS|GEIko"͒60/zw)(˄=z绒 Ee&D]̽o"]zU(|cdrث}^>!}5?gWFCpvاdowڭ)?_T|\\̶IENDB`DdE l T R 0A-b.^ѫ533 x n^ѫ533PNG  IHDR3APLTEDB@yxv_][(ōfffQOM$!ꑏ:74/,)YWUsqoJHE!+(&~|&# fff@=;XUS1/,NKIusqŽTRPpnl\ZX}{zb`^GEB<:7B?=MJH޶{ssm)FtRNSiDbKGDHgIFg>U cmPPJCmp0712HsIDAThCݚks8p)` YJ`3Ҹz:=X26vvgPe֣sёl?Ra2(bIpUQH6ubrsP?9$:oTZ@{XT*EʯcRPjl3>>E%6ypycYj%gy5 A}Ώ:6|7x]k 6m1wqFz(v8ɓ/:=gV]K [FR,TF}HxZg-R <Dnu+  p'zSQSꉖ9~T/Bg)8m36PNBjSn2rPYgBjj#<雀zɑJEEgYź8J񨾎Ph4LڐnHS*!u*HaemQS޳Τ怪-cg)ug6]jD1tPj`}TOފ<łCT cl 'sP)+BeFl|M TEGoj2K%Ak̪(!pnO @clM~( ?&:@}B((yZtpؖ׉<˽Y:sE?f&qHi'oU.%(k*e *$?OcӁOF1+P듕:hj{6j躰EeK0Poʪ Za-Qdyx^j4Ij (NS\>< bu1쐉d*MT~PAGCQTS|GEIko"͒60/zw)(˄=z绒 Ee&D]̽o"]zU(|cdrث}^>!}5?gWFCpvاdowڭ)?_T|\\̶IENDB`DdE l T Q 0A,b.^ѫ533 N n^ѫ533PNG  IHDR3APLTEDB@yxv_][(ōfffQOM$!ꑏ:74/,)YWUsqoJHE!+(&~|&# fff@=;XUS1/,NKIusqŽTRPpnl\ZX}{zb`^GEB<:7B?=MJH޶{ssm)FtRNSiDbKGDHgIFg>U cmPPJCmp0712HsIDAThCݚks8p)` YJ`3Ҹz:=X26vvgPe֣sёl?Ra2(bIpUQH6ubrsP?9$:oTZ@{XT*EʯcRPjl3>>E%6ypycYj%gy5 A}Ώ:6|7x]k 6m1wqFz(v8ɓ/:=gV]K [FR,TF}HxZg-R <Dnu+  p'zSQSꉖ9~T/Bg)8m36PNBjSn2rPYgBjj#<雀zɑJEEgYź8J񨾎Ph4LڐnHS*!u*HaemQS޳Τ怪-cg)ug6]jD1tPj`}TOފ<łCT cl 'sP)+BeFl|M TEGoj2K%Ak̪(!pnO @clM~( ?&:@}B((yZtpؖ׉<˽Y:sE?f&qHi'oU.%(k*e *$?OcӁOF1+P듕:hj{6j躰EeK0Poʪ Za-Qdyx^j4Ij (NS\>< bu1쐉d*MT~PAGCQTS|GEIko"͒60/zw)(˄=z绒 Ee&D]̽o"]zU(|cdrث}^>!}5?gWFCpvاdowڭ)?_T|\\̶IENDB`DdE l T T 0A/b.^ѫ533 $ n^ѫ533PNG  IHDR3APLTEDB@yxv_][(ōfffQOM$!ꑏ:74/,)YWUsqoJHE!+(&~|&# fff@=;XUS1/,NKIusqŽTRPpnl\ZX}{zb`^GEB<:7B?=MJH޶{ssm)FtRNSiDbKGDHgIFg>U cmPPJCmp0712HsIDAThCݚks8p)` YJ`3Ҹz:=X26vvgPe֣sёl?Ra2(bIpUQH6ubrsP?9$:oTZ@{XT*EʯcRPjl3>>E%6ypycYj%gy5 A}Ώ:6|7x]k 6m1wqFz(v8ɓ/:=gV]K [FR,TF}HxZg-R <Dnu+  p'zSQSꉖ9~T/Bg)8m36PNBjSn2rPYgBjj#<雀zɑJEEgYź8J񨾎Ph4LڐnHS*!u*HaemQS޳Τ怪-cg)ug6]jD1tPj`}TOފ<łCT cl 'sP)+BeFl|M TEGoj2K%Ak̪(!pnO @clM~( ?&:@}B((yZtpؖ׉<˽Y:sE?f&qHi'oU.%(k*e *$?OcӁOF1+P듕:hj{6j躰EeK0Poʪ Za-Qdyx^j4Ij (NS\>< bu1쐉d*MT~PAGCQTS|GEIko"͒60/zw)(˄=z绒 Ee&D]̽o"]zU(|cdrث}^>!}5?gWFCpvاdowڭ)?_T|\\̶IENDB`DdE l T S 0A. b.^ѫ533  n^ѫ533PNG  IHDR3APLTEDB@yxv_][(ōfffQOM$!ꑏ:74/,)YWUsqoJHE!+(&~|&# fff@=;XUS1/,NKIusqŽTRPpnl\ZX}{zb`^GEB<:7B?=MJH޶{ssm)FtRNSiDbKGDHgIFg>U cmPPJCmp0712HsIDAThCݚks8p)` YJ`3Ҹz:=X26vvgPe֣sёl?Ra2(bIpUQH6ubrsP?9$:oTZ@{XT*EʯcRPjl3>>E%6ypycYj%gy5 A}Ώ:6|7x]k 6m1wqFz(v8ɓ/:=gV]K [FR,TF}HxZg-R <Dnu+  p'zSQSꉖ9~T/Bg)8m36PNBjSn2rPYgBjj#<雀zɑJEEgYź8J񨾎Ph4LڐnHS*!u*HaemQS޳Τ怪-cg)ug6]jD1tPj`}TOފ<łCT cl 'sP)+BeFl|M TEGoj2K%Ak̪(!pnO @clM~( ?&:@}B((yZtpؖ׉<˽Y:sE?f&qHi'oU.%(k*e *$?OcӁOF1+P듕:hj{6j躰EeK0Poʪ Za-Qdyx^j4Ij (NS\>< bu1쐉d*MT~PAGCQTS|GEIko"͒60/zw)(˄=z绒 Ee&D]̽o"]zU(|cdrث}^>!}5?gWFCpvاdowڭ)?_T|\\̶IENDB`DdE l T V 0A1 b.^ѫ533  n^ѫ533PNG  IHDR3APLTEDB@yxv_][(ōfffQOM$!ꑏ:74/,)YWUsqoJHE!+(&~|&# fff@=;XUS1/,NKIusqŽTRPpnl\ZX}{zb`^GEB<:7B?=MJH޶{ssm)FtRNSiDbKGDHgIFg>U cmPPJCmp0712HsIDAThCݚks8p)` YJ`3Ҹz:=X26vvgPe֣sёl?Ra2(bIpUQH6ubrsP?9$:oTZ@{XT*EʯcRPjl3>>E%6ypycYj%gy5 A}Ώ:6|7x]k 6m1wqFz(v8ɓ/:=gV]K [FR,TF}HxZg-R <Dnu+  p'zSQSꉖ9~T/Bg)8m36PNBjSn2rPYgBjj#<雀zɑJEEgYź8J񨾎Ph4LڐnHS*!u*HaemQS޳Τ怪-cg)ug6]jD1tPj`}TOފ<łCT cl 'sP)+BeFl|M TEGoj2K%Ak̪(!pnO @clM~( ?&:@}B((yZtpؖ׉<˽Y:sE?f&qHi'oU.%(k*e *$?OcӁOF1+P듕:hj{6j躰EeK0Poʪ Za-Qdyx^j4Ij (NS\>< bu1쐉d*MT~PAGCQTS|GEIko"͒60/zw)(˄=z绒 Ee&D]̽o"]zU(|cdrث}^>!}5?gWFCpvاdowڭ)?_T|\\̶IENDB`DdE l T U 0A0 b.^ѫ533  n^ѫ533PNG  IHDR3APLTEDB@yxv_][(ōfffQOM$!ꑏ:74/,)YWUsqoJHE!+(&~|&# fff@=;XUS1/,NKIusqŽTRPpnl\ZX}{zb`^GEB<:7B?=MJH޶{ssm)FtRNSiDbKGDHgIFg>U cmPPJCmp0712HsIDAThCݚks8p)` YJ`3Ҹz:=X26vvgPe֣sёl?Ra2(bIpUQH6ubrsP?9$:oTZ@{XT*EʯcRPjl3>>E%6ypycYj%gy5 A}Ώ:6|7x]k 6m1wqFz(v8ɓ/:=gV]K [FR,TF}HxZg-R <Dnu+  p'zSQSꉖ9~T/Bg)8m36PNBjSn2rPYgBjj#<雀zɑJEEgYź8J񨾎Ph4LڐnHS*!u*HaemQS޳Τ怪-cg)ug6]jD1tPj`}TOފ<łCT cl 'sP)+BeFl|M TEGoj2K%Ak̪(!pnO @clM~( ?&:@}B((yZtpؖ׉<˽Y:sE?f&qHi'oU.%(k*e *$?OcӁOF1+P듕:hj{6j躰EeK0Poʪ Za-Qdyx^j4Ij (NS\>< bu1쐉d*MT~PAGCQTS|GEIko"͒60/zw)(˄=z绒 Ee&D]̽o"]zU(|cdrث}^>!}5?gWFCpvاdowڭ)?_T|\\̶IENDB`DdE l T W 0A2 b.^ѫ533 | n^ѫ533PNG  IHDR3APLTEDB@yxv_][(ōfffQOM$!ꑏ:74/,)YWUsqoJHE!+(&~|&# fff@=;XUS1/,NKIusqŽTRPpnl\ZX}{zb`^GEB<:7B?=MJH޶{ssm)FtRNSiDbKGDHgIFg>U cmPPJCmp0712HsIDAThCݚks8p)` YJ`3Ҹz:=X26vvgPe֣sёl?Ra2(bIpUQH6ubrsP?9$:oTZ@{XT*EʯcRPjl3>>E%6ypycYj%gy5 A}Ώ:6|7x]k 6m1wqFz(v8ɓ/:=gV]K [FR,TF}HxZg-R <Dnu+  p'zSQSꉖ9~T/Bg)8m36PNBjSn2rPYgBjj#<雀zɑJEEgYź8J񨾎Ph4LڐnHS*!u*HaemQS޳Τ怪-cg)ug6]jD1tPj`}TOފ<łCT cl 'sP)+BeFl|M TEGoj2K%Ak̪(!pnO @clM~( ?&:@}B((yZtpؖ׉<˽Y:sE?f&qHi'oU.%(k*e *$?OcӁOF1+P듕:hj{6j躰EeK0Poʪ Za-Qdyx^j4Ij (NS\>< bu1쐉d*MT~PAGCQTS|GEIko"͒60/zw)(˄=z绒 Ee&D]̽o"]zU(|cdrث}^>!}5?gWFCpvاdowڭ)?_T|\\̶IENDB`DdE l T X 0A3 b.^ѫ533 R" n^ѫ533PNG  IHDR3APLTEDB@yxv_][(ōfffQOM$!ꑏ:74/,)YWUsqoJHE!+(&~|&# fff@=;XUS1/,NKIusqŽTRPpnl\ZX}{zb`^GEB<:7B?=MJH޶{ssm)FtRNSiDbKGDHgIFg>U cmPPJCmp0712HsIDAThCݚks8p)` YJ`3Ҹz:=X26vvgPe֣sёl?Ra2(bIpUQH6ubrsP?9$:oTZ@{XT*EʯcRPjl3>>E%6ypycYj%gy5 A}Ώ:6|7x]k 6m1wqFz(v8ɓ/:=gV]K [FR,TF}HxZg-R <Dnu+  p'zSQSꉖ9~T/Bg)8m36PNBjSn2rPYgBjj#<雀zɑJEEgYź8J񨾎Ph4LڐnHS*!u*HaemQS޳Τ怪-cg)ug6]jD1tPj`}TOފ<łCT cl 'sP)+BeFl|M TEGoj2K%Ak̪(!pnO @clM~( ?&:@}B((yZtpؖ׉<˽Y:sE?f&qHi'oU.%(k*e *$?OcӁOF1+P듕:hj{6j躰EeK0Poʪ Za-Qdyx^j4Ij (NS\>< bu1쐉d*MT~PAGCQTS|GEIko"͒60/zw)(˄=z绒 Ee&D]̽o"]zU(|cdrث}^>!}5?gWFCpvاdowڭ)?_T|\\̶IENDB`DdE l T Z 0A5b.^ѫ533 (+ n^ѫ533PNG  IHDR3APLTEDB@yxv_][(ōfffQOM$!ꑏ:74/,)YWUsqoJHE!+(&~|&# fff@=;XUS1/,NKIusqŽTRPpnl\ZX}{zb`^GEB<:7B?=MJH޶{ssm)FtRNSiDbKGDHgIFg>U cmPPJCmp0712HsIDAThCݚks8p)` YJ`3Ҹz:=X26vvgPe֣sёl?Ra2(bIpUQH6ubrsP?9$:oTZ@{XT*EʯcRPjl3>>E%6ypycYj%gy5 A}Ώ:6|7x]k 6m1wqFz(v8ɓ/:=gV]K [FR,TF}HxZg-R <Dnu+  p'zSQSꉖ9~T/Bg)8m36PNBjSn2rPYgBjj#<雀zɑJEEgYź8J񨾎Ph4LڐnHS*!u*HaemQS޳Τ怪-cg)ug6]jD1tPj`}TOފ<łCT cl 'sP)+BeFl|M TEGoj2K%Ak̪(!pnO @clM~( ?&:@}B((yZtpؖ׉<˽Y:sE?f&qHi'oU.%(k*e *$?OcӁOF1+P듕:hj{6j躰EeK0Poʪ Za-Qdyx^j4Ij (NS\>< bu1쐉d*MT~PAGCQTS|GEIko"͒60/zw)(˄=z绒 Ee&D]̽o"]zU(|cdrث}^>!}5?gWFCpvاdowڭ)?_T|\\̶IENDB`DdE l T Y 0A4b.^ѫ533 3 n^ѫ533PNG  IHDR3APLTEDB@yxv_][(ōfffQOM$!ꑏ:74/,)YWUsqoJHE!+(&~|&# fff@=;XUS1/,NKIusqŽTRPpnl\ZX}{zb`^GEB<:7B?=MJH޶{ssm)FtRNSiDbKGDHgIFg>U cmPPJCmp0712HsIDAThCݚks8p)` YJ`3Ҹz:=X26vvgPe֣sёl?Ra2(bIpUQH6ubrsP?9$:oTZ@{XT*EʯcRPjl3>>E%6ypycYj%gy5 A}Ώ:6|7x]k 6m1wqFz(v8ɓ/:=gV]K [FR,TF}HxZg-R <Dnu+  p'zSQSꉖ9~T/Bg)8m36PNBjSn2rPYgBjj#<雀zɑJEEgYź8J񨾎Ph4LڐnHS*!u*HaemQS޳Τ怪-cg)ug6]jD1tPj`}TOފ<łCT cl 'sP)+BeFl|M TEGoj2K%Ak̪(!pnO @clM~( ?&:@}B((yZtpؖ׉<˽Y:sE?f&qHi'oU.%(k*e *$?OcӁOF1+P듕:hj{6j躰EeK0Poʪ Za-Qdyx^j4Ij (NS\>< bu1쐉d*MT~PAGCQTS|GEIko"͒60/zw)(˄=z绒 Ee&D]̽o"]zU(|cdrث}^>!}5?gWFCpvاdowڭ)?_T|\\̶IENDB`DdE l T  0Agb.^ѫ533 < n^ѫ533PNG  IHDR3APLTEDB@yxv_][(ōfffQOM$!ꑏ:74/,)YWUsqoJHE!+(&~|&# fff@=;XUS1/,NKIusqŽTRPpnl\ZX}{zb`^GEB<:7B?=MJH޶{ssm)FtRNSiDbKGDHgIFg>U cmPPJCmp0712HsIDAThCݚks8p)` YJ`3Ҹz:=X26vvgPe֣sёl?Ra2(bIpUQH6ubrsP?9$:oTZ@{XT*EʯcRPjl3>>E%6ypycYj%gy5 A}Ώ:6|7x]k 6m1wqFz(v8ɓ/:=gV]K [FR,TF}HxZg-R <Dnu+  p'zSQSꉖ9~T/Bg)8m36PNBjSn2rPYgBjj#<雀zɑJEEgYź8J񨾎Ph4LڐnHS*!u*HaemQS޳Τ怪-cg)ug6]jD1tPj`}TOފ<łCT cl 'sP)+BeFl|M TEGoj2K%Ak̪(!pnO @clM~( ?&:@}B((yZtpؖ׉<˽Y:sE?f&qHi'oU.%(k*e *$?OcӁOF1+P듕:hj{6j躰EeK0Poʪ Za-Qdyx^j4Ij (NS\>< bu1쐉d*MT~PAGCQTS|GEIko"͒60/zw)(˄=z绒 Ee&D]̽o"]zU(|cdrث}^>!}5?gWFCpvاdowڭ)?_T|\\̶IENDB`DdE l T  0Afb.^ѫ533 E n^ѫ533PNG  IHDR3APLTEDB@yxv_][(ōfffQOM$!ꑏ:74/,)YWUsqoJHE!+(&~|&# fff@=;XUS1/,NKIusqŽTRPpnl\ZX}{zb`^GEB<:7B?=MJH޶{ssm)FtRNSiDbKGDHgIFg>U cmPPJCmp0712HsIDAThCݚks8p)` YJ`3Ҹz:=X26vvgPe֣sёl?Ra2(bIpUQH6ubrsP?9$:oTZ@{XT*EʯcRPjl3>>E%6ypycYj%gy5 A}Ώ:6|7x]k 6m1wqFz(v8ɓ/:=gV]K [FR,TF}HxZg-R <Dnu+  p'zSQSꉖ9~T/Bg)8m36PNBjSn2rPYgBjj#<雀zɑJEEgYź8J񨾎Ph4LڐnHS*!u*HaemQS޳Τ怪-cg)ug6]jD1tPj`}TOފ<łCT cl 'sP)+BeFl|M TEGoj2K%Ak̪(!pnO @clM~( ?&:@}B((yZtpؖ׉<˽Y:sE?f&qHi'oU.%(k*e *$?OcӁOF1+P듕:hj{6j躰EeK0Poʪ Za-Qdyx^j4Ij (NS\>< bu1쐉d*MT~PAGCQTS|GEIko"͒60/zw)(˄=z绒 Ee&D]̽o"]zU(|cdrث}^>!}5?gWFCpvاdowڭ)?_T|\\̶IENDB`DdE l T  0Ab.^ѫ533 N n^ѫ533PNG  IHDR3APLTEDB@yxv_][(ōfffQOM$!ꑏ:74/,)YWUsqoJHE!+(&~|&# fff@=;XUS1/,NKIusqŽTRPpnl\ZX}{zb`^GEB<:7B?=MJH޶{ssm)FtRNSiDbKGDHgIFg>U cmPPJCmp0712HsIDAThCݚks8p)` YJ`3Ҹz:=X26vvgPe֣sёl?Ra2(bIpUQH6ubrsP?9$:oTZ@{XT*EʯcRPjl3>>E%6ypycYj%gy5 A}Ώ:6|7x]k 6m1wqFz(v8ɓ/:=gV]K [FR,TF}HxZg-R <Dnu+  p'zSQSꉖ9~T/Bg)8m36PNBjSn2rPYgBjj#<雀zɑJEEgYź8J񨾎Ph4LڐnHS*!u*HaemQS޳Τ怪-cg)ug6]jD1tPj`}TOފ<łCT cl 'sP)+BeFl|M TEGoj2K%Ak̪(!pnO @clM~( ?&:@}B((yZtpؖ׉<˽Y:sE?f&qHi'oU.%(k*e *$?OcӁOF1+P듕:hj{6j躰EeK0Poʪ Za-Qdyx^j4Ij (NS\>< bu1쐉d*MT~PAGCQTS|GEIko"͒60/zw)(˄=z绒 Ee&D]̽o"]zU(|cdrث}^>!}5?gWFCpvاdowڭ)?_T|\\̶IENDB`DdE l T  0Ab.^ѫ533 VW n^ѫ533PNG  IHDR3APLTEDB@yxv_][(ōfffQOM$!ꑏ:74/,)YWUsqoJHE!+(&~|&# fff@=;XUS1/,NKIusqŽTRPpnl\ZX}{zb`^GEB<:7B?=MJH޶{ssm)FtRNSiDbKGDHgIFg>U cmPPJCmp0712HsIDAThCݚks8p)` YJ`3Ҹz:=X26vvgPe֣sёl?Ra2(bIpUQH6ubrsP?9$:oTZ@{XT*EʯcRPjl3>>E%6ypycYj%gy5 A}Ώ:6|7x]k 6m1wqFz(v8ɓ/:=gV]K [FR,TF}HxZg-R <Dnu+  p'zSQSꉖ9~T/Bg)8m36PNBjSn2rPYgBjj#<雀zɑJEEgYź8J񨾎Ph4LڐnHS*!u*HaemQS޳Τ怪-cg)ug6]jD1tPj`}TOފ<łCT cl 'sP)+BeFl|M TEGoj2K%Ak̪(!pnO @clM~( ?&:@}B((yZtpؖ׉<˽Y:sE?f&qHi'oU.%(k*e *$?OcӁOF1+P듕:hj{6j躰EeK0Poʪ Za-Qdyx^j4Ij (NS\>< bu1쐉d*MT~PAGCQTS|GEIko"͒60/zw)(˄=z绒 Ee&D]̽o"]zU(|cdrث}^>!}5?gWFCpvاdowڭ)?_T|\\̶IENDB`DdE l T  0Ab.^ѫ533 ,` n^ѫ533PNG  IHDR3APLTEDB@yxv_][(ōfffQOM$!ꑏ:74/,)YWUsqoJHE!+(&~|&# fff@=;XUS1/,NKIusqŽTRPpnl\ZX}{zb`^GEB<:7B?=MJH޶{ssm)FtRNSiDbKGDHgIFg>U cmPPJCmp0712HsIDAThCݚks8p)` YJ`3Ҹz:=X26vvgPe֣sёl?Ra2(bIpUQH6ubrsP?9$:oTZ@{XT*EʯcRPjl3>>E%6ypycYj%gy5 A}Ώ:6|7x]k 6m1wqFz(v8ɓ/:=gV]K [FR,TF}HxZg-R <Dnu+  p'zSQSꉖ9~T/Bg)8m36PNBjSn2rPYgBjj#<雀zɑJEEgYź8J񨾎Ph4LڐnHS*!u*HaemQS޳Τ怪-cg)ug6]jD1tPj`}TOފ<łCT cl 'sP)+BeFl|M TEGoj2K%Ak̪(!pnO @clM~( ?&:@}B((yZtpؖ׉<˽Y:sE?f&qHi'oU.%(k*e *$?OcӁOF1+P듕:hj{6j躰EeK0Poʪ Za-Qdyx^j4Ij (NS\>< bu1쐉d*MT~PAGCQTS|GEIko"͒60/zw)(˄=z绒 Ee&D]̽o"]zU(|cdrث}^>!}5?gWFCpvاdowڭ)?_T|\\̶IENDB`DdE l T  0Ab.^ѫ533 i n^ѫ533PNG  IHDR3APLTEDB@yxv_][(ōfffQOM$!ꑏ:74/,)YWUsqoJHE!+(&~|&# fff@=;XUS1/,NKIusqŽTRPpnl\ZX}{zb`^GEB<:7B?=MJH޶{ssm)FtRNSiDbKGDHgIFg>U cmPPJCmp0712HsIDAThCݚks8p)` YJ`3Ҹz:=X26vvgPe֣sёl?Ra2(bIpUQH6ubrsP?9$:oTZ@{XT*EʯcRPjl3>>E%6ypycYj%gy5 A}Ώ:6|7x]k 6m1wqFz(v8ɓ/:=gV]K [FR,TF}HxZg-R <Dnu+  p'zSQSꉖ9~T/Bg)8m36PNBjSn2rPYgBjj#<雀zɑJEEgYź8J񨾎Ph4LڐnHS*!u*HaemQS޳Τ怪-cg)ug6]jD1tPj`}TOފ<łCT cl 'sP)+BeFl|M TEGoj2K%Ak̪(!pnO @clM~( ?&:@}B((yZtpؖ׉<˽Y:sE?f&qHi'oU.%(k*e *$?OcӁOF1+P듕:hj{6j躰EeK0Poʪ Za-Qdyx^j4Ij (NS\>< bu1쐉d*MT~PAGCQTS|GEIko"͒60/zw)(˄=z绒 Ee&D]̽o"]zU(|cdrث}^>!}5?gWFCpvاdowڭ)?_T|\\̶IENDB`DdE l T  0Ab.^ѫ533 q n^ѫ533PNG  IHDR3APLTEDB@yxv_][(ōfffQOM$!ꑏ:74/,)YWUsqoJHE!+(&~|&# fff@=;XUS1/,NKIusqŽTRPpnl\ZX}{zb`^GEB<:7B?=MJH޶{ssm)FtRNSiDbKGDHgIFg>U cmPPJCmp0712HsIDAThCݚks8p)` YJ`3Ҹz:=X26vvgPe֣sёl?Ra2(bIpUQH6ubrsP?9$:oTZ@{XT*EʯcRPjl3>>E%6ypycYj%gy5 A}Ώ:6|7x]k 6m1wqFz(v8ɓ/:=gV]K [FR,TF}HxZg-R <Dnu+  p'zSQSꉖ9~T/Bg)8m36PNBjSn2rPYgBjj#<雀zɑJEEgYź8J񨾎Ph4LڐnHS*!u*HaemQS޳Τ怪-cg)ug6]jD1tPj`}TOފ<łCT cl 'sP)+BeFl|M TEGoj2K%Ak̪(!pnO @clM~( ?&:@}B((yZtpؖ׉<˽Y:sE?f&qHi'oU.%(k*e *$?OcӁOF1+P듕:hj{6j躰EeK0Poʪ Za-Qdyx^j4Ij (NS\>< bu1쐉d*MT~PAGCQTS|GEIko"͒60/zw)(˄=z绒 Ee&D]̽o"]zU(|cdrث}^>!}5?gWFCpvاdowڭ)?_T|\\̶IENDB`d@d Normal$*$1$A$a$+B*CJOJPJQJ^J_HaJmH sH tH@ Heading 16$$ & F\d*$1$@&]^`\55B*CJ0KHOJPJQJ\^J_HaJ$mH sH tHp@p Heading 25$ & F0d@&]^`0CJ*\]aJf@!f Heading 32 & F@dX@&]^`@CJ$\f@1f Heading 42 & F`dh@&]^``CJ\l@Al Heading 52 & FPd@&]^`PCJ\]aJf@Qf Heading 6, & F<@&]^`5CJ\aJP@aP Heading 7$ & F@&]^`V@qV Heading 8$ & F`@&]^``6]X @X Heading 9$ & F0@&]^0`OJQJDA@D Default Paragraph FontVi@V  Table Normal :V 44 la (k@(No List 4O4 WW8Num15z0OJQJ4O4 WW8Num16z0OJQJ4O4 WW8Num17z0OJQJJO!J Absatz-StandardschriftartDA@1D Default Paragraph Font2OA2 WW8Num1z0OJQJ2OQ2 WW8Num2z0OJQJ4Oa4 WW8Num14z0OJQJ4Oq4 WW8Num18z0OJQJ4O4 WW8Num19z0OJQJ4O4 WW8Num20z0OJQJJOJ WW-Default Paragraph Font4O4 WW8Num12z0OJQJ4O4 WW8Num20z1OJQJ4O4 WW8Num20z3OJQJ4O4 WW8Num21z0OJQJ8O8 WW8Num21z1 OJQJ^J4O4 WW8Num21z2OJQJ4O4 WW8Num23z0OJQJ8O!8 WW8Num23z1 OJQJ^J4O14 WW8Num23z2OJQJ4OA4 WW8Num24z0OJQJ8OQ8 WW8Num24z1 OJQJ^J4Oa4 WW8Num24z3OJQJ4Oq4 WW8Num25z0OJQJ8O8 WW8Num25z1 OJQJ^J4O4 WW8Num25z2OJQJ4O4 WW8Num25z3OJQJ4O4 WW8Num27z0OJQJ8O8 WW8Num27z1 OJQJ^J4O4 WW8Num27z2OJQJ4O4 WW8Num29z0OJQJ8O8 WW8Num29z1 OJQJ^J4O4 WW8Num29z3OJQJ4O4 WW8Num31z0OJQJ8O!8 WW8Num31z1 OJQJ^J4O14 WW8Num31z2OJQJLOAL WW-Default Paragraph Font12OQ2 WW8Num3z0OJQJ2Oa2 WW8Num4z0OJQJ2Oq2 WW8Num5z0OJQJ4O4 WW8Num14z1OJQJ4O4 WW8Num14z3OJQJ8O8 WW8Num16z1 OJQJ^J4O4 WW8Num16z2OJQJ8O8 WW8Num19z1 OJQJ^J4O4 WW8Num19z2OJQJ4O4 WW8Num19z3OJQJFOF Default Paragraph Font1NON WW-Default Paragraph Font116U@B6 Hyperlink B*ph>*LOB!L Char Char CJOJQJ_HaJmH sH tH@O"1@ Figure Anchor CharCJLOBAL ParameterCodeOJQJmHsH65]8OQ8 C-Crossref B*ph>*:OBa: C-LiteralOJQJmHsH8Oq8 C-Variable mH sH 62OB2 C-SubscriptH*DOBD C-DefinedElement mHsH50OB0 C-Emphasis6,OB, C-Strong5VOBV DefinedElementCodeOJQJCJmHsH5\.O. SubscriptH*.)@. Page NumberFV@F FollowedHyperlink B* ph>*NON Footnote CharactersH*OJQJCJB'@B Comment ReferenceCJaJBO!B C-Highlight5fHq 2Ob12 C-Parameter6BOAB Footnote Reference1H*@OQ@ Endnote CharactersH*BOaB WW-Endnote Characters@&@q@ Footnote ReferenceH*>*@> Endnote ReferenceH*FOF WW-Footnote ReferenceH*DOD WW-Endnote ReferenceH*HOH WW-Footnote Reference1H*FOF WW-Endnote Reference1H*@&@@ Footnote ReferenceH*>*> Endnote ReferenceH*NON Heading _x$CJOJPJQJ^JaJnB@n Body Text`d1$*$+B*CJOJPJQJ^J_HaJmH sH tH</@< Listah]^h`b"@b Caption0b Udx<]^`U 6\aJ.O2. Indexc $^J^@B^ Header3dd,  $d%d&d'd6N @ARN Footer(e   $d%d&d'dl>@rl Titlefd1$*$p25B*CJHKHOJPJQJ^J_HaJHmH sH tHFJ@aF Subtitlegd8 CJ*^JaJNOaN Cover SubHeadshdCJ5ROR Nondisclosure Texti$a$ CJ^JaJLOL Nondisclosure Titlej$a$5@ TOC 19k    d,*$1$]^` .5B*CJOJPJQJ^J_HaJmH sH tHJP@J Body Text 2l]^`JQ@J Body Text 3m]^`Z0@Z List Bullet)n & F]^`V6@V List Bullet 2!o & F0]^0`N7@N List Bullet 3p]^`R1@R List Number!q & F 0]^0`V:@"V List Number 2!r & F ]^`Z;@!2Z List Number 3%s 8]^`ND@BN List Continueth]^h`RE@ARR List Continue 2u]^`ZF@bZ List Continue 3"v8x]^8`X@X TOC 20w    ]^` 5P@qP TOC 3+x    ]^` DO"D Figure Anchor yd$CJxOx Function Signature.z$]d,*$]^]` OJQJPJ d@d  Footnote Text({bdx]^`bCJaJO Table Bullet'| & F *$1$]^`+B*CJOJPJQJ^J_HaJmH sH tH~O~ Table Number }*$1$]^`+B*CJOJPJQJ^J_HaJmH sH tHXOX Note Text+~$$,]^`a$FO@F Note Heading ,$65DOD Caution Heading B*phZOZ Code$d ` OJQJCJmHsHDZ@"D Plain TextCJOJQJ^JaJtO2t Code WideC ` 00d]0^0`CJlOl Heading NoNum+$`d,x]^`` OJ QJ 5L@L TOC 4( p  ]^`@Ob@ CopyRightdCJFO"F Figure Anchor Wided,<O< Table Contents $FOF Table Heading d,$65BOB Table BodydxCJ\O!\ CaptionFigure(d]^`vOv Example5$$d%d&d'd]^`CJOJQJaJmHsH<^@< Normal (Web) >@> TOC 5]^`H@H Balloon TextCJOJQJ^JaJ<@ < Comment TextCJaJe@ HTML Preformatted7 2( Px 4 #\'*.25@9CJOJQJ^JaJ^O" ^ Appendix/ & Fd,]^`CJ*O2 Preformatted Text^  ` @ %%d$d%d&d'd*$1$]%^%`PJ^JaJmHsH@j@  @ Comment Subject5\vM@R v Body Text First Indent(dx]^`OJQJ\C@b \ Body Text Indent"hx]^h`dN@a r d Body Text First Indent 2h]^h`fR@ f Body Text Indent 2(hdx]^h`hS@ h Body Text Indent 3"hx]^h`CJaJ$L@$ Date<+ <  Endnote TextCJaJ:`@ : HTML Address6]B B Index 1]^`B B Index 2]^`B B Index 3]^`B @B Index 4]^`B@B Index 5]^`B@B Index 6]^`B@B Index 7]^`B@B Index 8]^`B@B Index 9p]^p`H! H  Index HeadingOJQJ5^J\@2@r @ List 2]^`@3@ @ List 38]^8`@4@ @ List 4]^`@5@ @ List 5]^`N8@ N List Bullet 4]^`N9@ N List Bullet 5]^`ZG@ Z List Continue 4"x]^`ZH@ Z List Continue 5"x]^`N<@ N List Number 4]^`N=@ N List Number 5]^`-@ Macro Text(1$  ` @ *$+B*CJOJPJQJ^J_HaJmH sH tHN@" N Normal Indent]^`>> TOC 6]^`>> TOC 7]^`>> TOC 8]^`>> TOC 9]^`\O\ Editor Table Heading$a$ 5\aJHO H Footnote Marker$$OJQJRO R Table Code ]d]^]`CJRO1 R Contents 10" &  ]^ `8O 8 Frame contents0O 0 Addressd,95W7F2GhUܻ^R |;=$h "difN9 f j / 2      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~""""""dddddddiffN f f f f f f f f f f j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j / / / / 2   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ Lyn Pierce Janet Swisher}]]p_moV%'DߟUh Lyn Pierc Lyn Pierc Lyn Pierc Lyn Pierc Lyn Pierc Lyn Pierc Lyn Pierc Lyn Pierc Lyn Pierc Lyn Pierc Lyn Pierc Lyn Pierc Janet Swi Janet Swi Janet Swi Janet Swi&>dN169n++Eup/<9:;$%&@A)))77klm;h.fҊ Arԋ6gɌ+\(]!VE!z!z !z!z #zzzz !z!z!z!z!z!z!z!z% z% z% z% z% z%z!z!z!z!z!z%z!z!z!z!z!z!z!z!z!z!z!z! z!!z!"z!#z!$z%%z%&z!'z!(z!)z!*z!+z!,z!-z!.z!/z#0z1z2z3z4z5z6z7z8z9z:z;z<z=z>z?z@zAzBzCzDzEzFzGzHzIzJzKzLzMzNzOzPzQzRzSzTzUzVzWzXzYzZz[z\z]z^z_z`zazbzczdzezfzgzhzizjzkzlzmznzozpzqzrzsztzuzvzwzxzyzzz{z|z}z~zzzzzz!z!z#zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz!z!z!z!z!z!z!z%znn#++29NAEIOU[`fjm,r3r~rru}{~1͞`ƴypF0dz t  #)/X7<CG&NQX$\d~lt {?؟qקʵ (2Y9:;U7 &)1i9@ HNU*^bhl\ptzDƶ $%&@BKK]nR.@Aw n&)))/27778v<@FIN\RV\agllqtu*{\vw9rĢ<v=Jq[1p/  %*/3'8?>FuLVS\ckQrwz1g6klmu@;shI77, F m FAdWl#C 7!"0#C$%&='u()&*+,v-J./ 012m3435607O8/92:";<{=>?@QAlBC~DEF5GHI8J+K)LMuNtOP7QKRSpT.UYVWyXYYYY)Z&[\]^C_`abcdQelfg~hij5klm8n+o)pqurtst7uKvwpx.yYz{y|}}}}~~)#6 *WK&M0Mq7'/+{Ql~58+)ut7K.Yy-g +DnA F  B  V 8 m $_P+a.g1q X8z4sBW Cz7xO%X0h$X0c6k @ y !Z!!!"Q"""#@####;$o$$$4%%% &Z&&&'Y'''(F(}((()W))) *T***+G+++@.o.i111$2R222424667G:Y:;@=='>>e?f@ANAAEFGGHIH~HHHHHHHHI%I&I=IXIIIVJfJ[KL#M]MMMMMNN0NENYNnNNNNNNOO)ONOOOOPQQrSSSlUZ[[([4[A[Z\[\k\r\x\Y]Z]p]]]]]^^^^^^____```````aacdqdddeSeneoeeeeeeeee)fVffffffggggh]inijjkkk%k&k.k5k=k+l,l;lAlMl[lelolxlllllllllllll&m'm=mJmWmdmmmmmmnnoooooo]p^prp%qZqcqoq}q~qqqqqq3r~rrrrrss5sgshsossssst[t\tbttuu uBumunuuuuuuv=xhx"z*z1z=zHzQzYzdzzz~~~~~~~~~~܁'NƆ)bcLj%:Ncd~߉89PuG;GTUahiv~njЌьe16L‘ȑϑՑߑ~ʒޓߓ )*<@Sٙ"͞Hrݠ0DYZt-gɢ`?eЧ#7LMgxy Z©+eѪ+,D[\IH h{:H޻  '5hy4G&g(9KZij&Ca~$ALov &Cq+jX?O'KLg9Yp` Ib8T0V Oc7d*MeEa);BN]^p1w:;U ){i;[\h<ij U y z        , G H h        W {    t ^,COc:#6kcz_a\g5:@EJT  " #6#'$g$$$%9%:%K%h%{%%%%%%&#&A&^&i&&&&&'''B(((((((()))O)P)a)p)))))1*S*x******+!+"+<+q++s,-//13556H6t6u666667#7:7V7W7X777788:8[8r888889:g;;;-<< =]===L>>>;?_?l?|?}??????????mAAAAAAAAAAAAAAAAAABDEEFFFGGGHGdGGGG H/H0HLHtHHHH%ISI{IIIIIJ>JCJeJJJJJJK@KkK{KKKKKKLL9LfLLLLM,M@MeMMMMMN&NHNkNvNwNNNNNNNNNNO(O)O=OOOQQQ(RRRRRRRS!STVYYSYbYYYv[$\\]=^^t_```ce*hiijfjjjjjjk~ljmOnoopyppqq.r@r|sscuvv#x3xZx yzz {{{)||}}~7Ӏ,`amtupqt L}=ԉ̋bƐ+>H$:L[f” Sڗ%tԘ!mP]jstޜߜz{ .؟ڟCl=_̡./>?]| -Pqrsڣ#DfgstѤפ%?EVkХ 1T]lԦ=Lḑק>OP{|HId{ȩ0IJinϪ()8Saҫ+gʬIp˭Fmɮ>mЯ3dŰ,ẖBjòAj@ioqrߴ.WʵAbݶ-E`չͺ>dӻ %ý?mľZ?`}'Uy*\!Q*X~"cj$[`rH2j TK{)]2u4YFe>?;IVyzWgtKZg#$078LSThno4@M\]ipqT3@FGSZ[ovw(?LTUahi}*7=>JQRfmnjkw~UYlm56;TU~TbW\bht7]jz{l   > J W g h t { |       X 23O~7_>f ).Py+Vf$Q|+P|3Vab}( !#&&>&M&&&a())s*(++_,---0x25666Q7n777777i9U::;<o<=d==\>?+?g@t@NByCCEEEE FGG HwHHII|JJK L"LLMNN OOKOLOXO_O`OtO|O}OO[P\P_QQRSS T7ThTT(UUmVVWXXYM\]^__)_3_`%`7`F`Q`aabbbd>d|dde_ee fXffh;iHiUi^i_ikirisiiiiiejfjjllll.mWmmmmmm(nJnjnnnnoo)o*oHogowoooooop;p\p]p^p{pppppq/qQqRq^q_qrqqqqqqqr*r0rArVrsrrrrrrrrss?sHsWsmssssss(t7tOtutttttuuu)u:u;ufuguuuuuu3v4vOvfvsvvvvvw4w5wTwYwwwwxx#x>xLxwxxxxyRyyyyz4z[zzzz{1{X{{{{|)|X||||}O}}}}~S~~~~-U,UԀ+TZ\]m{ʁBlނ,Mqȃ0Ku܄݆)Oي*XЋE*ߍKh֎@dGxۑ <oߒCi NUۚFuۛK]3ΞUģԣԧ?Ȩ6f٩HyϪo`D߮1Ptðʰ˰߰˱ұӱ)* &4AdeqxyBR_mnz6ERuv kƺ"#7>?SYZ+8GHT[\pwx? +12>EFZabvjl*7?@LSThop"()5<=QXYm UVbij~@DWX !&?@i?M|BGMS_n~m ZKt=)xk$%189MUVj458jnxAqF`& *U81JaxdTJ 'ilApF(*o;>   w   Y<>[]u9HA C    !"P##{$$%%%&%\%%%%%%%&5&[&&&&&$'R''''%(M(N((((()<)v)x))),D, ---..... /"/#/7/>/?/S/Y/Z/0001]111112;2j2o222222+343j333334H4_4~4444"545J5e5555555555556 67777777777H9991:3:n:}:::::::::::8;9;v<x<<=:>L>Y>^>_>k>r>s>>>>>>>?? @u@@OABCDDDDDDDE E EE&E'E;EDEEE@GBGzGHHHHHHHHHHHHIIJJNJgLNNN`OP\RmRzRRRRRRRRRRRRyTTTT2URVdVqV{V|VVVVVVVVVVWWW!YY,ZZ[\!\.\8\9\E\J\K\_\\\\\\]]\]]^^7_`aa)bZbbbbbb"cHcpcqcccc,d^dddeeeeeeeefff*fcfdfggWgiJjjmmnnnnnnnnnnnnnnooplqnqqrssssssssssssttqusuuu v@wxdxxy9yyyyyyz z&z3z;z=zVz]zdzmzzzzzzzzzzzz){*{{{||}N~~wx+ofˆ̆؆ w߈"S=yב Arw/jVƔ 4Wݕ dޖߖ9ikȗɘ  29:N5 57qǣΣϣդ֤/<I\]ipqèШ֨ר|}()07<FGhʫ4=FQ]^ĬЬѬ#.:;=w 9LasduҰٰڰαڱ*+?<ҵ\öжضٶ ")*vx˷ϷзܷZ[ovw׸ظJLǼռ !5<=R`mstվ־ſǿ`n{-JYftu,jwu (,/0C#+-p X"T|AiPTc*T],=kp4Kv9Z[)7DWXdkl rt>kNaXbs%7V#=Xo4Ij/5*"-:?N U i  =    B V t\l%&:BCW!"%W[e.^3Mn}w !!!!!""" ##s$$%%%&7'u'' (X(()Q))*4,A,N,W,X,d,k,l,,,,,{-|- .//// 0x0000171V111112K2~2222222 3313X3]3}3333334*4M4X4s444444445!5'595N5u55555555 6 696S6Y6k6666666 7$7=7a7777788'8_8e8g8h88888881929H9_9999999:3:L:::::::;Q;x;y;;;;;<"<H<{<<<=>=k====>?>j>>>>?=?h???? @Q@@@@AHA|AAABHBlBBBBC=CgCCCCD9DcDDDDDDDDD E/ESE~EEEEFCFVFFFFF-GKGcG}GGGGGAH?J\J7KbKKKKL=LuLL-NXN|NNNN.OOOOPQR!RwRRSSTHTnTTTU1UcUUUU(V\VVVV"WY$Z[z\H^^_9_h___>`P``&bbbcHdfggijkkk2l}llll)mYm~mmmn;nlnnnnoboopmqq,rQrrr>s]sttttttttttttttuuuuuuuuuuuv6v7vwwMw[whwwwwwwwwwwwwiyyyyyyyyyyyyyyyz{{{{{{{{{{{{L|M|} Cǀ1?LRS_fg{co|Ѓ "g|ԅ*+Ȇʆɇч҇އ68Ŋڊ2NO[bcw~9=ҐӐߐjkghmƖ̖Җޖ(f^ם;p 2cnF%]bxѫ~ڭ%<hűDz7.;o -.2=fgmɸʸ˸Ҹ1<FGLWXY_klmuŹƹ˹ֹ &-OPU`rsy˺MӻԻջ&12;JKLPmɼʼ˼ټ=>?Gdopx^fWvzLT-HkUp)2UD`7Zi ri  H | | ]Z ]Z ]Z ]Z ]Z ]Z ]Z &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# &# LF $ } $ $ $ $ $ $  $  $ $  $ } $ $ $ $ $ $ $ $ $ $ } LF $ PS  PS PS PS PS PS PS PS PS PS PS PS PS PS PS $ | &# } $ $ PS  PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS $ ! &# $ $ } $ $  $ $ $ PS&#&#&#&#&#&#&#&#&#&#&#&#&#&#&#&#&#&#&#&#&#&#&#&#&#:/&#&#&# &#V<&#&#&#&#&#&#&#&#&#&#0&#&#&#&#&#0&#&#&#   $ $ $ $ $  $ $ PS  PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS $ W &#  $  $ $ PS8&#&#&#&#8&#&#&#&# 8&#&#&#&#&#&#&#&#&#&#&#&#&#&#&#&#&#&#&#&#x88&#&#&#&#&#ri 8&#&#&#&#11&#y--8&#&#&#  $ PSP&# &# &#&#P&# &# LFP&# &# aP&# &# ari P&# &# a P&# &# aLFP&# &# a+ P&# &# a+ P&# &# ari P&# &# ari  LF $ } $ $ $ $ $ $ $ $ $  $ PS`&#\&#0&#`&#\&#0&#n`&#\&#0&# $  $ $  $ $ $ } $ $ PS  PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS $ 5 &# $ PS&# &#&#&# &#&#&# &#&#&# &#&#&# &#&#&# &#&# $ $ $ $ $ 1 1 1 $ $ } PS&#&#&#&#&#&#&#&#&#&#&#&#&#&#&#&#&#&#&#&#+&#&#&#&#&#&#&#&#&#0&#&#&#&#&#&# &#&#&#&#0&#&# &#" LF $ $ $ $ $ $ } $ $  $ PS  PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS $ W &# $  $ PS  PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS $ 1 $ } $ $ 1 1 1 $ $ $ } $  $ $  $  $ $ $ $ $ $ $ $ $ } $ $ $  $ PS  PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS $ 5 &# $ $ 1 $ $ } $ $ PS 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 LF $ $ $ $ } $ $ $ } $ $ $ $  $  $  $ $ } $ $ $ $ $ $ $ $ $ $  $ $ $ $ $  $ $ $ $ $ } $  $ $ $ $ $ $ $ PS7 &#4&#&#&#7 $4&#&#7 $4&#&# 7 $4&#&#ri 7 $4&#&# 7 $4&# &#V<7 $4&#&#   $ $ $ $ $ $ $ 1 1 1 1 1 1 1 1 1 1 $ PS  PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS  PS  $  $ $ $ $ 1 1  $ $ $ 1 1 1  $ $ $ $ $ $ 1 1 1 1 1  $ $ 1 1 1 1 1 1 $ $ $ 1 1 LF $  A PS $ " PS $ a$ PS } $  PS $ } $ $ $ $ $ $ $ } $ PS  PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS $ PS  PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS $ $ $ $ $ LF $ $ $ $ PS  PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS w &# $ $ $ $ $ } $ $ $ $ $ $ $ $ l $p&#&#l $p&#&#l $p&#&#l $p&#&# $ PS(&#&#T&#&#(&#&#T&#&#(&#&#T&#&#(&#&#T&#&#  $ $ P4 &# $ PS  PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS l $p&#&#l $p&#&#l $p&#&#l $p&#ri  $ i& &# $ $ $ $ $ $ $ $  $ $ $  P4 &#  $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $  $ $ $ $ $ $ $ $ $ $  $ $ $ $ $ $  $ $  $ $ $ $ l $p&#LFl $p&#&#l $p&#&#l $p&# $ $ $ $ $ $ $ $ $ $ $ $ $ $ $  $ $ $ $ $ $ $ $ $ $ $ $ $ $  $ Ө PS $ $ $ $ $ $ $ $ $ $ $ $ l $p&#&#l $p&#&#l $p&#LFl $p&#  $ $ $ ) &# $ PS  PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS  $ $ $ $ 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  $ $ $ $ $ $ $ $ $ $ $ } $ l $h &#&#l $h &#&#l $h &#&#l $h &#&# $ l $&#&#l $&#&#l $&#&#l $&#&# $ $ PS l $p&#&#l $p&#&#l $p&#&#l $p&#&# $ l $p&#&#l $p&#&#l $p&#&#l $p&#&# $ l $p&#&#l $p&#&#l $p&#&#l $p&#LF $ $ $ $ $ $ $ l $h &#&#l $h &#&#l $h &#&#l $h &#&# $ l $h &#&#l $h &#&#l $h &#&#l $h &#&# $ $  PS l $&#&#l $&#&#l $&#&#l $&#ri  $  PS $ l $&#&#l $&#&#l $&#&#l $&#  $ (D PS $ l $p&#&#l $p&#&#l $p&#&#l $p&#LF $ s  PS l $p&#LFl $p&#&#l $p&#&#l $p&#LF $ / PS l $p&#&#l $p&#&#l $p&#&#l $p&#LF $  PS  - PS $ $ LF $ } $  $ $ $ $ $ $ $ $ $ $ $ l $p&#&#l $p&#&#l $p&#&#l $p&#&# $ $ $ $ l $p&#&#l $p&#&#l $p&#&#l $p&#&# $ PS(&#&#T&#&#(&#&#T&#&#(&#&#T&#&#(&#&#T&#&#  $ $ P4 &# $ PS  PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS l $p&#&#l $p&#&#l $p&#&#l $p&#ri  $ i& &# $ $ $ $ $ $ $ $  $ $ $  P4 &#  $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $  $ $ $ $ $ $ $ $ $ $  $ $ $ $ $ $  $ $  $ $ $ $ l $p&#LFl $p&#&#l $p&#&#l $p&# $ $ $ $ $ $ $ $ $ $ $ $ $ $ $  $ $ $ $ $ $ $ $ $ $ $ $ $ $  $ Ө PS $ $ $ $ $ $ $ $ $ $ $ $ l $p&#&#l $p&#&#l $p&#LFl $p&#  $ $ $ ) &# $ PS  PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS  $ $ $ $ 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  $ $ $ $ $ $ $ $ $ $ $ } $ l $h &#&#l $h &#&#l $h &#&#l $h &#&# $ l $&#&#l $&#&#l $&#&#l $&#&# $ $ PS l $p&#&#l $p&#&#l $p&#&#l $p&#&# $ l $p&#&#l $p&#&#l $p&#&#l $p&#&# $ l $p&#&#l $p&#&#l $p&#&#l $p&#LF $ $ $ $ $ $ $ l $h &#&#l $h &#&#l $h &#&#l $h &#&# $ l $h &#&#l $h &#&#l $h &#&#l $h &#&# $ $  PS l $&#&#l $&#&#l $&#&#l $&#ri  $  PS $ l $&#&#l $&#&#l $&#&#l $&#  $ (D PS $ l $p&#&#l $p&#&#l $p&#&#l $p&#LF $ s  PS l $p&#LFl $p&#&#l $p&#&#l $p&#LF $ / PS l $p&#&#l $p&#&#l $p&#&#l $p&#LF $  PS  - PS $ $ LF $ } $  $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ l $p&#&#l $p&#&#l $p&#&#l $p&# $ & &# $ $ $ $ $ $ $ $ $ l $p&#LFl $p&#&#l $p&#&#l $p&# $ $ $ $ $ $ $ $ $ $ $ $ $ $ $  $ $ $ $ $ $ $ $ $ $ $ $ $ $  $ Ө PS $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ l $p&#&#l $p&#&#l $p&#&#l $p&#LF $ s  PS $ $ $ $ $ $ 1 $ 2 &# $ 1 $ } &# $ $ $ $ $ $  $ 1 $ } $  $ $  &# $ d  &# $  $   &# $ $  $  &# $ $ $ $ $ $ $  $  &# $  $ $ $ $ $ PS  PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS $ $ $ $ $  &# LF $ $ $ $ } $ l $d &#&#l $d &#&#l $d &#&#l $d &#&# $ C &# $ PS  PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS l $d &#&#l $d &#&#l $d &#&#l $d &#&# $ $ $ $ $ $ $ $ $ $ 1 $ $  - &# l $&#&#l $&#&#l $&#&#l $&#LF $ T/ &# $ $ l $&#&#l $&#&#l $&#&#l $&#&# $ $ $ $ $ $ $ $ $ & &# l $ &#&#l $ &#&#l $ &#&#l $ &#&# $ 7 &# $ l $d &#&#l $d &#&#l $d &#&#l $d &#&# $ !x &# $ $ 0 &# $ $ $ l $d &#&#l $d &#&#l $d &#&#l $d &#&# $ 1 1  &# $ l $&#&#l $&#&#l $&#&#l $&#&# $ | &# $ $ $ $ $ $ l $p&#&#l $p&#&#l $p&#LFl $p&#&# $ x &# $ $ $ $ $ $ PS  PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS $ l $p&#&#l $p&#&#l $p&#&#l $p&#LF $ / &# $ $ $ $ $ $ l $d &#&#l $d &#&#l $d &#&#l $d &#&# $ C &# $ 3 &# $ $ l $d &#&#l $d &#&#l $d &#&#l $d &#&# $ 'f &# $ $ $ $ $ $ $ $ $ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 l $p&#&#l $p&#&#l $p&#LFl $p&#&# $ 6 &# $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ l $p&#&#l $p&#&#l $p&#&#l $ $  $  &# $ $  $ $ PS  PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS N  &# $  $ l $p&#&#l $p&#&#l $p&#&#l $p&#p&# $ ( &# $ $ $ 0 &# $ n &# l $p&#&#l $p&#&#l $p&#&#l $p&# $ & &# l $&#&#l $&#&#l $&#&#l $&#&# $ l $p&#&#l $p&#&#l $p&#&#l $p&#ri  $ PS&#@&#@&#&#&#LF&#@&#@&#&#&#LF&#@&#@&#&#&#ri &#@&#@&#&#&#ri &#@&#@&#&#&#ri &#@&#@&#&#&#ri  6& &# $ $ $ $ $ $ $ $ $ l $ &#&#l $ &#&#l $ &#&#l $ &#&# $ l $p&#&#l $p&#&#l $p&#&#l $p&#LF $ $ $ $ j;' &# $ $ $ l $p&#&#l $p&#&#l $p&#&#l $p&#&# $ b~ &# l $p&#&#l $p&#ri l $p&#&#l $p&#LF $ M &# M &# M &# $ $ l $ &#&#l $ &#&#l $ &#&#l $ &#&# $ l $ &#&#l $ &#&#l $ &#&#l $ &#&# $ a& &# $ $ l $p&#&#l $p&#&#l $p&#&#l $p&#&# $ =# &# } $ l $&#&#l $&#&#l $&#&#l $&#&# $ $ $ $ $ $ l $p&#&#l $p&#&#l $p&#&#l $p&#&# $ $ $ $ l $p&#&#l $p&#&#l $p&#&#l $p&#&# $ PS(&#&#T&#&#(&#&#T&#&#(&#&#T&#&#(&#&#T&#&#  $ $ P4 &# $ PS  PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS l $p&#&#l $p&#&#l $p&#&#l $p&#ri  $ i& &# $ $ $ $ $ $ $ $  $ $ $  P4 &#  $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $  $ $ $ $ $ $ $ $ $ $  $ $ $ $ $ $  $ $  $ $ $ $ l $p&#LFl $p&#&#l $p&#&#l $p&# $ $ $ $ $ $ $ $ $ $ $ $ $ $ $  $ $ $ $ $ $ $ $ $ $ $ $ $ $  $ Ө PS $ $ $ $ $ $ $ $ $ $ $ $ l $p&#&#l $p&#&#l $p&#LFl $p&#  $ $ $ ) &# $ PS  PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS  $ $ $ $ 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  $ $ $ $ $ $ $ $ $ $ $ } $ l $h &#&#l $h &#&#l $h &#&#l $h &#&# $ l $&#&#l $&#&#l $&#&#l $&#&# $ $ PS l $p&#&#l $p&#&#l $p&#&#l $p&#&# $ l $p&#&#l $p&#&#l $p&#&#l $p&#&# $ l $p&#&#l $p&#&#l $p&#&#l $p&#LF $ $ $ $ $ $ $ l $h &#&#l $h &#&#l $h &#&#l $h &#&# $ l $h &#&#l $h &#&#l $h &#&#l $h &#&# $ $  PS l $&#&#l $&#&#l $&#&#l $&#ri  $  PS $ l $&#&#l $&#&#l $&#&#l $&#  $ (D PS $ l $p&#&#l $p&#&#l $p&#&#l $p&#LF $ s  PS l $p&#LFl $p&#&#l $p&#&#l $p&#LF $ / PS l $p&#&#l $p&#&#l $p&#&#l $p&#LF $  PS  - PS $ $ LF $ } $  $ $ $ $ $ $ $ $ $  $ $ $ $ $ $ $ $ } $ $ $ $ $ $ $ $ 1 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ } $ &#&# &#LF &#&# &#LF &#&# &#LF &#&# &#&# &#&# &#&# &#&# &#LF &#&# &#&# &#&# &#&# &#&# &#LF &#&# &#&# &#&# &#&# &#&# &#&# &#&# &#LF &#&# &#&# &#&# &#&# &#&# &#&# &#&# &#LF &#&# &#&# &#&# &#&# &#&# &#&# &#&# &#&# &#&# &#LF &#&# &#  &#&# &#&# &#&# &#LF &#&# &#&# &#&# &#&# &#&# &#&# &#&# &#&# &#&# &#LF &#&# &#&# &#&# &#&# &#&# &#&# &#&# &#&# &#&# &#  &#&# &#LF &#&# &#&# ܅ PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS PS &# &# $ . Q &# . . &# . . &# . . &# . . &# . . &# . . &# . . &# . . .  . . . . +DcnA F  B  V 8 m $_P+a.g1q X8z4sBW Cz7xO%X0h$X0c6k @ y !Z!!!"Q"""#@####;$o$$$4%%% &Z&&&'Y'''(F(}((()W))) *T***+G+j++++@.o.i111$2R222424667G:Y:;@=='>>e?f@ANAAAEFGGHIH~HHHHHHHHI%I&I=IXIIIVJfJ[KL#M]MMMMMNN0NENYNnNNNNNNOO)ONOOOOPQQrSSSlUZ[[([4[A[Z\[\k\r\x\Y]Z]p]]]]]^^^^^^____```````aacdqdddeSeneoeeeeeeeee)fVffffffggggh]inijjkkk%k&k.k5k=k+l,l;lAlMl[lelolxlllllllllllll&m'm=mJmWmdmmmmmmnnoooooo]p^prp%qZqcqoq}q~qqqqqq3r~rrrrrss5sgshsossssst[t\tbttuu uBumunuuuuuuuv=xhx"z*z1z=zHzQzYzdzzz~~~~~~~~~~܁'NƆ)bcLj%:Ncd~߉89PuG;GTUahiv~njЌьe16L‘ȑϑՑߑ~ʒޓߓ )*<@Sٙ"͞Hrݠ0DYZt-gɢ`?eЧ#7LMgxy Z©+eѪ+,D[\IH h{:H޻  '5hy4G&g(9KZij&Ca~$ALov &Cq+jX?O'KLg9Yyp` Ib8T0V Oc7d*MeEa);BN]^p1w:;U ){i;[\h<ij U y z        , G H h        W {    t ^,COc:#6kcz_a\g5:@EJT  " #6#'$g$$$%9%:%K%h%{%%%%%%&#&A&^&i&&&&&'''B(((((((()))O)P)a)p)))))1*S*x******+!+"+<+q++s,-p///13556H6t6u666667#7:7V7W7X777788:8[8r888889:g;;;-<Z<< =]===L>>>;?_?l?|?}??????????mAAAAAAAAAAAAAAAAAABDEEFFFGGGHGdGGGG H/H0HLHtHHHH%ISI{IIIIIJ>JCJeJJJJJJK@KkK{KKKKKKLL9LfLLLLM,M@MeMMMMMN&NHNkNvNwNNNNNNNNNNO(O)O=OOOQQQ(RRRRRRRS!STVYYSYbYYYv[$\\]=^^t_```ce*hiijfjjjjjjk~ljmOnoopyppqq.r@r|sscuvv#x3xZx yzz {{{)||}}~7Ӏ,`amtupqt L}=ԉ̋bƐ+>H$:L[f” Sڗ%tԘ!mP]jstޜߜz{ .؟ڟCl=_̡./>?]| -Pqrsڣ#DfgstѤפ%?EVkХ 1T]lԦ=Lḑק>OP{|HId{ȩ0IJinϪ()8Saҫ+gʬIp˭Fmɮ>mЯ3dŰ,ẖBjòAj@ioqrߴ.WʵAbݶ-E`չͺ>dӻ %ý?mľZ?`}'Uy*\!Q*X~"cj$[`rH2j TK{)]2u4YFe>?;IVyzWgtKZg#$078LSThno4@M\]ipqT3@FGSZ[ovw(?LTUahi}*7=>JQRfmnjkw~UYlm56789:;TU~TbW\bht7]jz{l   > J W g h t { |       X 23O~7_>f ).Py+Vf$Q|+P|3Vab}( !#&&>&M&&&a())s*(++_,---0x25666Q7n777777i9U::;<o<=d==\>?+?g@t@NByCCEEEE FGG HwHHII|JJK L"LLMNN OOKOLOXO_O`OtO|O}OO[P\P_QQRSS T7ThTT(UUmVVWXXYM\]^__)_3_`%`7`F`Q`aabbbd>d|dde_ee fXffh;iHiUi^i_ikirisiiiiiejfjjllll.mWmmmmmm(nJnjnnnnoo)o*oHogowoooooop;p\p]p^p{pppppq/qQqRq^q_qrqqqqqqqr*r0rArVrsrrrrrrrrss?sHsWsmssssss(t7tOtutttttuuu)u:u;ufuguuuuuu3v4vOvfvsvvvvvw4w5wTwYwwwwxx#x>xLxwxxxxyRyyyyz4z[zzzz{1{X{{{{|)|X||||}O}}}}~S~~~~-U,UԀ+TZ\]m{ʁBlނ,Mqȃ0Ku܄݆)Oي*XЋE*ߍKh֎@dGxۑ <oߒCi NUۚFuۛK]3ΞUģԣԧ?Ȩ6f٩HyϪo`D߮1Ptðʰ˰߰˱ұӱ)* &4AdeqxyBR_mnz6ERuv kƺ"#7>?SYZ+8GHT[\pwx? +12>EFZabvjl*7?@LSThop"()5<=QXYm UVbij~@DWX !"#$%&?@i?M|BGMS_n~m ZKt=)xk$%189MUVj458jnxAqF`& *U81JaxdTJ 'il@ApF(*o;>   w   Y<>[]u9HA C    !"P##{$$%%%&%\%%%%%%%&5&[&&&&&$'R''''%(M(N((((()<)v)x))))))),D, ---..... /"/#/7/>/?/S/Y/Z/0001]111112;2j2o222222+343j333334H4_4~4444"545J5e5555555555556 6 677777777777H9991:3:n:}:::::::::::8;9;v<x<<=:>L>Y>^>_>k>r>s>>>>>>>?? @u@@OABCDDDDDDDE E EE&E'E;EDEEE@GBGzGHHHHHHHHHHHHIIJJNJgLNNN`OP\RmRzRRRRRRRRRRRRyTTTT2URVdVqV{V|VVVVVVVVVVWWW!YY,ZZ[\!\.\8\9\E\J\K\_\\\\\\]]\]]^^7_`aa)bZbbbbbb"cHcpcqcccc,d^dddeeeeeeeefff*fcfdfggWgiJjjmmnnnnnnnnnnnnnnooplqnqqrssssssssssssttqusuuu v@wxdxxy9yyyyyyz z&z3z;z=zVz]zdzmzzzzzzzzzzzz){*{{{||}N~~wx+ofˆ̆؆ )vw߈"S=yב Arw/jVƔ 4Wݕ dޖߖ9ikȗɘ  29:N5 57qǣΣϣդ֤/<I\]ipqèШ֨ר|}()07<FGhʫ4=FQ]^ĬЬѬ#.:;=w 9LasduҰٰڰαڱ*+?<ҵ\öжضٶ ")*vx˷ϷзܷZ[ovw׸ظJLǼռ !5<=R`mstվ־ſǿ`n{-JYftu,jwu (,/0C#+-p X"T|AiPTc*T],=kp4Kv9Z[)7DWXdkl rt>kNaXbs%7V#=Xo4Ij/5*"-:?N U i  =    B V t\l%&:BCW!"%W[e.^3Mn}w !!!!!""" ##s$$%%%&7'u'' (X(()Q))*4,A,N,W,X,d,k,l,,,,,{-|- .//// 0x0000171V111112K2~2222222 3313X3]3}3333334*4M4X4s444444445!5'595N5u55555555 6 696S6Y6k6666666 7$7=7a7777788'8_8e8g8h88888881929H9_9999999:3:L:::::::;Q;x;y;;;;;<"<H<{<<<=>=k====>?>j>>>>?=?h???? @Q@@@@AHA|AAABHBlBBBBC=CgCCCCD9DcDDDDDDDDD E/ESE~EEEEFCFVFFFFF-GKGcG}GGGGGAH?J\J7KbKKKKL=LuLL-NXN|NNNN.OOOOPQR!RwRRSSTHTnTTTU1UcUUUU(V\VVVV"WY$Z[z\H^^_9_h___>`P``&bbbcHdfggijkkk2l}llll)mYm~mmmn;nlnnnnoboopmqq,rQrrr>s]sttttttttttttttuuuuuuuuuuuv6v7vwwMw[whwwwwwwwwwwwwiyyyyyyyyyyyyyyyz{{{{{{{{{{{{L|M|} Cǀ1?LRS_fg{co|Ѓ "g|ԅ*+Ȇʆɇч҇އ68Ŋڊ2NO[bcw~9=ҐӐߐjkghijklmƖ̖Җޖ(f^ם;p 2cnF%]bxѫ~ڭ%<hűDz7.;o -.2=fgmɸʸ˸Ҹ1<FGLWXY_klmuŹƹ˹ֹ &-OPU`rsy˺MӻԻջ&12;JKLPmɼʼ˼ټ=>?Gdopx^fWvzLT,-./GHjk !:;TUVWop()KLef12TUwx ()CDEF_`67YZ|}./0CVn~Aa-fif0g0h0h0h000000000h0k0w0x0x0x0w0w0k0w0w0x0x0x000x0k0w0x0x0x0w0w0k0w0x0x0w0w0x0x0x0w0x0w0k0w0w0x0x0x0w0x0x0w0x0x0x00000k0w0w0w0k0w0x0w0x0x0x0x0x0k0w0x0x0x0x0x0x0x0x0x0x0x0x0x0x0000x0x0x0x0x0x0x0x0x0x0x0w0x0x0x0x0x0000000000000x000x000000000000w0x0x0x0x0x0x0x0x0x0x0x0x0k0w0x0x0k0k00 0`0+ 0++`0@.`0@. n0@. n0@. n0@.`0@.( 0@.@.`02( 0@.@.`04`04( 0@.@.`06 0++`0G:`0G:`0G: n0G: n0G: n0G:`0G: q0G: q0G: q0G: 0++`0A 0`0Eb0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E`0Ey0E0E 0EE`0VJ`0VJb0VJ0VJ0VJ0VJ0VJ0VJ0VJ0VJ0VJ0VJ0VJ0VJ0VJ0VJ0VJ0VJ0VJ0VJ0VJ0VJ0VJ`0VJy0VJ0VJ`0VJ`0VJ 0EE`0Q`0Q( 0QQ`0S`0S`0Sb0S0S 0S 0S 0S 0S |0S 0S 0S 0S |0S |0S |0S |0S |0S |0S |0S |0S |0 S |0 S |0 S |0 S |0 S |0S |0S 0S0S 0S 0S |0S |0S 0S 0S 0S |0S |0S 0S 0S 0S |0S |0S |0S |0S 0S 0S 0S |0S |0S |0S 0S 0S 0S |0S 0S 0S ( 0QQ`0` n0` n0` n0``0`( 0QQ`0a`0ab0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a`0ay0a0a8 0aa`0g8 0aa`0]i`0]ib0]i0]i 0]i 0]i 0]i 0]i |0]i |0]i 0]i 0]i 0]i |0]i |0]i |0 ]i |0!]i |0"]i |0#]i |0$]i |0%]i |0&]i |0']i |0(]i |0)]i |0*]i |0+]i |0,]i |0-]i |0.]i |0/]i 0]i 0]i 0]i |00]i |01]i |02]i 0]i 0]i 0]i |03]i |04]i 0]i0]i0]i0]i0]i 0]i 0]i |05]i 0]i 0]i ( 0QQ`0^pb0^p0^p 0^p 0^p 0^p 0^p 0^p 0^p 0^p 0^p @0^p 0^p 0^p 0^p @0^p 0^p 0^p 0^p @0^p 0^p 0^p 0^p @0^p 0^p 0^p 0^p @0^p 0^p 0^p 0^p @0^p 0^p 0^p 0^p @0^p 0^p 0^p 0^p @0^p 0^p 0^p 0^p 0`0u 0uu`0=x n0 =x n0 =x n0 =x n0 =x n0 =x n0=x n0=x`0=x( 0=x=x`0O{b0O{0O{ 0O{ 0O{ 0O{ 0O{ 0O{ 0O{ 0O{ 0O{ 0O{ 0O{ 0O{ `0O{( 0xx`0c`0c( 0xx`0H`0H`0H 0YvYv`0`0b00000000000000000000000`0y00`0b00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 `0 n0 n0 n0`0000`0`0 0YvYvb00 0 0 0 0 |06 |07 |08 |09 |0: |0; |0< |0= |0> |0? |0@ |0A |0B |0C 0 0 0 |0D |0E |0F |0G |0H |0I |0J 0 0 0 |0K |0L |0M |0N 0 0 0 |0O |0P 0 0 0 |0Q 0 0 0 0`0 n0 n0 n0 n0 n0 0`0``0`( 0```09b0909090909090909090909090909090909090909090909`090909`09( 0```0̥b0̥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`0u( 0uu`0Է`0Է( 0uu`0( 0uu`0`0 n0 n0 n0 n0 n0`0`0 0`0Ծ`0Ծ`0Ծ( 0ԾԾ`0b000000000000000000000000000000000000000000000000`0y00`0`00`0`0 0`0`0b00000000000000000`0 0`0`0`0`0 0`0`0`0 0`0 n0 n0 n0( 0`0( 0`0( 0`0>`0> 0`0`0 n0  n0!`0`0`0z0z0`0( 0`0`0 n0" n0#`0( 0`0K`0K n0$K n0%K`0K 0`0( 0`0 q0 q0 q0 q0 q0 q0b00 0 0 0 z0 0 0 0 z0 0 0 0 z0 0 0 0 z0 0 0 0 z0 0 0 0 z0 0 0 0 ( 0`0z0`0`00~0`00000000000`0b0000000000000000000000000000000y0b0( 0`0 8 0  `0} `0}  q0}  q0} 0} 0} 8 0  `0 q0 q00008 0  `0 q0 q0 q0 q0`0000008 0  `0 q0000000 q0 q0`0000 0`0y0b0`0y0b0`0y0b0 0`0y0b0`0 0`09 n0&9 n0'9 n0(9`09`09`09 0`0#b0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#`0#b0#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# n0)# n0*# n0+# n0,#@n0-# 0`0;0`0;0`0;0`0;0b0;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;0y0;00;0`0;0`0;0 n0.;0 n0/;0`0;0 0;0;0`0< n00< n01< n02< n03< n04< n05< n06< n07<( 0<<@0? @0? @0?@0? @0? @0?@0? @0? @0?@0? @0? @0?@`0?b0?@0? @0? @0? @0?@0? @0? @0? @0?@0? @0? @0? @0?@0? @0? @0? @0?( 0<<@`0aB@`0aB@y0aB0aB@`0aBb0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB@0aB( 0<<@0%O @0%O @0%O@0%O @0%O @0%O@0%O @0%O @0%O@0%O @0%O @0%O@`0%O@y0%O0%O`0%O@`0%O n08%O n09%O n0:%O n0;%O n0<%O n0=%O8 0%O%O@`0zS@`0zS`0zS@y0zS0zS8 0%O%O@`0YH 0YY@`0Z@`0Z@`0Z n0>Z n0?Z n0@Z@`0Z@`0Z@`0ZH 0YY`0Ia@`0Ia@`0Ia`0IaH 0YY@`0j@`0j n0Aj n0Bj n0Cj n0Dj n0Ej n0Fj@`0j@`0j n0Gj n0Hj n0Ij n0Jj n0Kj n0Lj@`0j@`0j8 0%O%O@`0rH 0rr@`0s@`0sH 0rr@`0vH 0rr@`0x n0Mx n0Nx8 0%O%O@`0{ n0O{ n0P{ n0Q{ n0R{ n0S{8 0%O%O@`0}@`0}8 0%O%O@`0 n0T n0U n0V( 0<<@0{ @0{ @0{@0{ @0{ @0{@0{ @0{ @0{@0{ @0{ @0{@`0{@`0{ n0W{ n0X{ n0Y{ o0{ o0{ o0{ o0{ o0{ n0Z{ n0[{@`0{ n0\{ n0]{8 0{{@`0)@`0)@`0)@`0) q0) q0) q0) q0)@`0) q0) q0) q0) q0)@`0)8 0{{`0.@y0.b0.@`0. n0^. n0_. n0`. n0a. n0b. n0c. n0d. n0e.@`0.@`0.@`0.( 0<<@0 @0 @0@0 @0 @0@0 0 @0@0 @0 @0@`0@`0@`0@y00`0b0@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@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@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@08 0@`0`0H 0@`0A@0A@0A@0A@0A@0A@0A@0AH 0@`0w@0w@0w@0w@0w@0w@0wH 0@`00`00`00@`008 0@`0H 0@`0?@0?@0?@0?@0?@0?@0?@0?@0?@0?@0?@0?@0?@0?@0?@0?@0?@0?H 0`0@0~0@`0@`0@`0 n0f n0g n0h n0i n0j@`0H 0@`0@`0@`0H 0@`00@`00@`00@`00H 0@`0E@`0E q0E@0E q0E o0E o0E@t0E@0E@0E@0E@0E@0E@0E@0E@0E@0E@0E@0E@0E8 0@`0< n0k< n0l< n0m< n0n<@`0< n0o< n0p< n0q< n0r<@`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 b0 ( 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 n0s n0t n0u n0v( 0@0n @0n @0n@0n @0n @0n@0n @0n @0n@0n @0n @0n@`0n( 0@0 @0 @0@0 @0 @0@0 @0 @0@0 @0 @0@`0@`0@y0b0( 0@0 @0 @0@0 @0 @0@0 @0 @0@0 @0 @0@`0@y0b0`0( 0@0 @0 @0@0 @0 @0@0 @0 @0@0 @0 @0@`0@y0b0`0( 0 @0 @0 @0@0 @0 @0@0 @0 @0@0 @0 @0`0@y0b0( 0 @0j @0j @0j@0j @0j @0j@0j @0j @0j@0j @0j @0j@`0j@y0jb0j( 0 @0 @0 @0@0 @0 @0@0 @0 @0@0 @0 @0@`0@y0b0@y0b0@`0@`0@`0@0@0@0 0`0 0`0( 0`0`0 n0w n0x n0y n0z n0{`0`0 n0| n0}( 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 b0 @0  @0  @0  @0 @0  @0  @0  @0 @0  @0  @0  @0 @0  @0  @0  @0 ( 0@`0v@`0v@y0v0v@`0vb0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v@0v( 0@0: @0: @0:@0: @0: @0:@0: @0: @0:@0: @0: @0:@`0:@y0:0:`0:@`0: n0~: n0: n0: n0: n0: n0:8 0::@`0 @`0 `0 @y0 0 8 0::@`0&H 0&&@`04'@`04'@`04' n04' n04' n04'@`04'@`04'@`04'H 0&&`0^.@`0^.@`0^.`0^.H 0&&@`0(7@`0(7 n0(7 n0(7 n0(7 n0(7 n0(7 n0(7@`0(7@`0(7 n0(7 n0(7 n0(7 n0(7 n0(7 n0(7@`0(7@`0(78 0::@`0?H 0??@`0@@`0@H 0??@`0DH 0??@`0E n0E n0E8 0::@`0%H n0%H n0%H n0%H n0%H n0%H8 0::@`0K@`0K8 0::@`0L n0L n0L n0L( 0@0O @0O @0O@0O @0O @0O@0O @0O @0O@0O @0O @0O@`0O@`0O n0O n0O n0O o0O o0O o0 O o0 O o0 O n0O n0O@`0O n0O n0O8 0OO@`0>Y@`0>Y@`0>Y@`0>Y q0>Y q0>Y q0>Y q0>Y@`0>Y q0>Y q0>Y q0>Y q0>Y@`0>Y8 0OO`0Cb@y0Cbb0Cb@`0Cb n0Cb n0Cb n0Cb n0Cb n0Cb n0Cb n0Cb n0Cb@`0Cb@`0Cb@`0Cb( 0@0i @0i @0i@0i @0i @0i@0i 0i @0i@0i @0i @0i@`0i@`0i@`0i@y0i0i`0ib0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i@0i8 0ii@`0 `0 H 0  @`0V@0V@0V@0V@0V@0V@0V@0VH 0  @`0@0@0@0@0@0@0H 0  @`0E`0E`0E@`0E8 0ii@`0H 0@`0T@0T@0T@0T@0T@0T@0T@0T@0T@0T@0T@0T@0T@0T@0T@0T@0T@0TH 0`0ٓ@0ٓ~0ٓ@`0ٓ@`0ٓ@`0ٓ n0ٓ n0ٓ n0ٓ n0ٓ n0ٓ@`0ٓH 0@`0@`0@`0H 0@`0E@`0E@`0E@`0EH 0@`0Z@`0Z q0Z@0Z q0Z o0 Z o0 Z@t0Z@0Z@0Z@0Z@0Z@0Z@0Z@0Z@0Z@0Z@0Z@0Z@0Z8 0ii@`0Q n0Q n0Q n0Q n0Q@`0Q n0Q n0Q n0Q n0Q@`0Q 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@0b0( 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̷ n0̷ n0̷ n0̷ n0̷( 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@y0b0( 0ǯǯ@0 @0 @0@0 @0 @0@0 @0 @0@0 @0 @0@`0@y0b0`0( 0ǯǯ@0 @0 @0@0 @0 @0@0 @0 @0@0 @0 @0@`0@y0b0`0( 0 ǯǯ@0 @0 @0@0 @0 @0@0 @0 @0@0 @0 @0`0@y0b0( 0 ǯǯ@0 @0 @0@0 @0 @0@0 @0 @0@0 @0 @0@`0@y0b0( 0 ǯǯ@0 @0 @0@0 @0 @0@0 @0 @0@0 @0 @0@`0@y0b0@y0b0@`0@`0@`0@0@0@0 0`0 0`0( 0`0`0 n0 n0 n0 n0 n0`0`0 n0 n0 n0 n0 n0 n0 n0 n0 n0( 0@0 @0 @0@0 @0 @0@0 @0 @0@0 @0 @0@`0@y00 n0 n0 n0 n0 n0 n0 n0 n0 n0( 0@0P @0P @0P@0P @0P @0P@0P @0P @0P@0P @0P @0P@`0P@`0P n0P n0P n0P o0P o0P o0P o0P o0P n0P n0P@`0P n0P n0P8 0PP@`0@`0@`0@`0 q0 q0  q0  q0 @`0 q0 q0  q0  q0 @`08 0PP`0@y0b0@`0 n0 n0 n0 n0 n0 n0 n0 n0@`0@`0@`0 n0 n0@n0`0 n0 n0 n0`0 n0 n0 n0 n0 n0 n0 n0 n0( 0@07 @07 @07@07 @07 @07@07 @07 @07@07 @07 @07`07@y07b07 n07@n07n07`07`07`07`07`0707`07y0707`0707`07y070707~07`07 n07 n07`07( 0`0d 0d `0d  0`0( 0`0a`0ay0a0a`0ay0a0a`0a( 0`0y00`0`0( 0`0y00`0`0 q0 q0 q0 q0 q0( 0`0% y0% 0% `0% ( 0`0! q0! q0! q0!`0!b0!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! n0! n0! n0!`0!y0!0!`0!0!0!0! 0 `0o*0o*~0o*`0o* 0o*o*`0o.( 0o.o.0c/ 0c/ 0c/ 0c/ 0c/ 0c/ 0c/ 0c/ 0c/ 0c/ 0c/ 0c/ `0c/y0c/0c/`0c/b0c/0c/0c/0c/0c/0c/0c/0c/0c/0c/0c/0c/0c/0c/0c/0c/0c/0c/0c/0c/0c/0c/0c/0c/0c/0c/0c/0c/0c/0c/0c/0c/0c/( 0o.o.0$6 0$6 0$6 0$6 0$6 0$6 0$6 0$6 0$6 0$6 0$6 0$6 `0$6 n0$6 n0$6 n0$6 n0$6 n0$6 n0$6 n0$6 n0$6 n0$6@n0$6`0$60$6`0$6`0$6y0$60$6( 0o.o.0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; `0;0;0;`0;`0;( 0o.o.0> 0> 0> 0> 0> 0> 0> 0> 0> 0> 0> 0> `0>`0> n0> n0>`0>`0>`0>`0>`0>0>0>( 0o.o.0bE 0bE 0bE 0bE 0bE 0bE 0bE 0bE 0bE 0bE 0bE 0bE `0bEy0bE0bE`0bE( 0o.o.00I 00I 00I 00I 00I 00I 00I 00I 00I 00I 00I 00I `00I00I00I`00I`00Iy00I00I`00I`00I`00I( 0o.o.0R 0R 0R 0R 0R 0R 0R 0R 0R 0R 0R 0R `0R0R0Ry0R0R`0R( 0o.o.0V 0V 0V 0V 0V 0V 0V 0V 0V 0V 0V 0V `0V0V0V`0V`0V`0V`0V`0V`0V( 0o.o.0\ 0\ 0\ 0\ 0\ 0\ 0\ 0\ 0\ 0\ 0\ 0\ `0\y0\0\`0\`0\`0\`0\`0\`0\b0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\`0\( 0 o.o.0]f 0]f 0]f 0]f 0]f 0]f 0]f 0]f 0]f 0]f 0]f 0]f `0]fy0]f0]f`0]f`0]f`0]f`0]f`0]f`0]f( 0 o.o.0o 0o 0o 0o 0o 0o 0o 0o 0o 0o 0o 0o `0oy0o0o`0oy0o0o`0o`0o( 0 o.o.0t 0t 0t 0t 0t 0t 0t 0t 0t 0t 0t 0t `0ty0t0t`0t0t~0t`0t n0t n0t n0t n0t`0t0t0t0t0t0t0t0t0t0t0t0t0t0t0t( 0 o.o.0{ 0{ 0{0{ 0{ 0{0{ 0{ 0{0{ 0{ 0{`0{y0{0{`0{`0{`0{`0{`0{0{~0{`0{ q0{ q0{ q0{ q0{ r0{ r0{ r0{ r0{ r0{( 0 o.o.0 0 00 0 00 0 00 0 0`08 0`0}y0}0}`0}`0}8 0`0`0b0000000000000000000000000000000000000000000000000y00`08 0`0L( 0o.o.0 0 00 0 00 0 00 00 0`0y00`0`0`0y00`0y00( 0o.o.0 0 00 0 00 0 00 0 0`0y00( 0o.o.0ŧ 0ŧ 0ŧ0ŧ 0ŧ 0ŧ0ŧ 0ŧ 0ŧ0ŧ 0ŧ 0ŧ`0ŧ( 0o.o.0K 0K 0K0K 0K 0K0K 0K 0K0K 0K 0K`0Kb0K0K 0K 0K 0K 0K 0K0K 0K 0K 0K 0K 0K0K 0K 0K 0K 0K 0K0K 0K 0K 0K 0K 0K0K 0K 0K 0K 0K 0K0K 0K 0K 0K 0K 0Ky0K0K`0K`0K n0K n0 K n0 K n0 K n0 K n0 K`0K( 0o.o.0 0 00 0 00 0 00 0 0`0( 0o.o.0d 0d 0d0d 0d 0d0d 0d 0d0d 0d 0d`0d`0d n0d n0dy0d0d`0d n0d n0d( 0o.o.0K 0K 0K0K 0K 0K0K 0K 0K0K 0K 0K`0Ky0K0K( 0o.o.0G 0G 0G0G 0G 0G0G 0G 0G0G 0G 0G`0Gy0G0Gy0G0Gy0G0G`0G`0G( 0o.o.0] 0] 0]0] 0] 0]0] 0] 0]0] 0] 0]`0]( 0o.o.0 0 00 0 00 0 00 0 0`0y00`0`0( 0o.o.0 0 00 0 00 0 00 0 0`0y00 0o*o*`0( 00 0 00 0 00 0 00 0 0`0z0 n0 n0`0`0( 00 0 00 0 00 0 00 0 0`0`0`0`0( 00  0  0 0  0  0 0  0  0 0  0  0 `0 b0 0  0  0  0 0  0  0  0 0  0  0  0 0  0  0  0 ( 0`0`0y00`0b0000000000000000000000000000000000000000000000000000000000000000( 00 0 00 0 00 0 00 0 0`0y00`0`0 n0 n0 n0 n0 n0 n08 0`0`0`0y008 0`0H 0`0`0`0 n0 n0 n0`0`0`0H 0`0"`0"`0"`0"H 0`0`0 n0 n0 n0 n0  n0! n0"`0`0 n0# n0$ n0% n0& n0' n0(`0`08 0`0uH 0uu`0`0H 0uu`0H 0uu`0j n0)j n0*j8 0`0  n0+  n0,  n0-  n0.  n0/ 8 0`0 `0 8 0`0f n00f n01f n02f( 00V 0V 0V0V 0V 0V0V 0V 0V0V 0V 0V`0V`0V n03V n04V n05V o0V o0V o0V o0V o0V n06V n07V`0V n08V n09V8 0VV`0`0`0`0 q0  q0  q0 q0`0 q0  q0  q0 q0`08 0VV`0 %y0 %b0 %`0 % n0: % n0; % n0< % n0= % n0> % n0? % n0@ % n0A %`0 %`0 %`0 %( 00, 0, 0,0, 0, 0,0, 0, 0,0, 0, 0,`0,`0,`0,y0,0,`0,b0,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,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,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,8 0,,`0pH`0pHH 0pHpH`0J0J0J0J0J0J0J0JH 0pHpH`0 M0 M0 M0 M0 M0 M0 MH 0pHpH`0O`0O`0O`0O8 0,,`0RH 0RR`0 S0 S0 S0 S0 S0 S0 S0 S0 S0 S0 S0 S0 S0 S0 S0 S0 S0 SH 0RR`0W0W~0W`0W`0W`0W n0BW n0CW n0DW n0EW n0FW`0WH 0RR`0``0``0`H 0RR`08c`08c`08c`08cH 0RR`0Mh`0Mh q0Mh0Mh q0Mh o0Mh o0Mht0Mh0Mh0Mh0Mh0Mh0Mh0Mh0Mh0Mh0Mh0Mh0Mh0Mh8 0,,`0Do n0GDo n0HDo n0IDo n0JDo`0Do n0KDo n0LDo n0MDo n0NDo`0Do 0o*o*`0s( 0ss0u 0u 0u0u 0u 0u0u 0u 0u0u 0u 0u`0u( 0ss0,v 0,v 0,v0,v 0,v 0,v0,v 0,v 0,v0,v 0,v 0,v`0,v0,vb0,v( 0ss0w 0w 0w0w 0w 0w0w 0w 0w0w 0w 0w`0w( 0ss0y 0y 0y0y 0y 0y0y 0y 0y0y 0y 0y`0y( 0ss0| 0| 0|0| 0| 0|0| 0| 0|0| 0| 0|`0|`0|`0| n0O| n0P| n0Q| n0R|( 0ss0ǁ 0ǁ 0ǁ0ǁ 0ǁ 0ǁ0ǁ 0ǁ 0ǁ0ǁ 0ǁ 0ǁ`0ǁ( 0ss0 0 00 0 00 0 00 0 0`0`0y0b0( 0ss0 0 00 0 00 0 00 0 0`0y0b0`0( 0ss0; 0; 0;0; 0; 0;0; 0; 0;0; 0; 0;`0;y0;b0;`0;( 0 ss0[ 0[ 0[0[ 0[ 0[0[ 0[ 0[0[ 0[ 0[`0[y0[b0[( 0 ss0x 0x 0x0x 0x 0x0x 0x 0x0x 0x 0x`0xy0xb0x( 0 ss0) 0) 0)0) 0) 0)0) 0) 0)0) 0) 0)`0)y0)b0)y0)b0)`0)`0)`0)0)0)0) 0 `0 0`0( 0`0`0 n0S n0T n0U n0V n0W`0`0( 0`0 n0X n0Y n0Z`0 n0[ n0\ n0]n00`0`0`0`0`0`0`0`00`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`00`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÷ 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÷ 0÷ 0÷ 0÷ 0÷ 0÷ 0÷ 0÷ 0÷ 0÷ 0÷ 0÷ 0÷ 0÷ 0÷ 0÷ 0÷ 0÷ 0÷ 0÷ y0÷{0{0{0{0{0{0{0{0{0{0{0{0{0{0{0{0{0{0{0{0000000000d00d00d00d00`00`00d00d00e00e00d00e00d00d00e00e00d0 0e00d00d00e00e00d00e00d00d00e00e00d00e00d00d00e00e00d00e00d00d00e00e00d00e00d00d00e00e00d00e00d00d00e00e00d00e00d00d00e00e00d00d00e00e00d00d00e00e00d00d00e00e00000000000000000000oqq~rrgss[tumuuiB0|^J0^J0^J0^J0^J0_J0$_J0@_B0 dgJ0  g 01 ;@Ysu!Dg02Lo(B\^x1To"""""""""""""""""""""""""""EGb}}}?Zuuuxy{KR-$ !#r%'(*,.0n2@J2OjX[`l;t8q~{ d(%9(S1:uJK\l:~$` 9%KdsK4+1^E;#z-p89FMLXdx.խY=gT2-:>ezo"r v#(Dbortuvwyz{}~  '-/46BKYabcghknopquvxz} 3579;=?CV7!6'-3fHVRWN`da4cYefghVn%s+ttduw]x}yzn{p|@}}(xLH4Jɖϙ 9bϷ|<V  s t$Y075[8D7KLMOOTX[a\_'qeʏ]*1' <pQw ;   !%(L),>OP\\`Hmvwz}tǎӽ'z[ky<b&AqmK  *37[<<d@B%CDGqHKK,NCR}RU?V__ccegijsNsx{~>>b%1Crn"ݸH s c*b)Ye7RiFKZ (49:?BvDQGTKvP4Tg\[dx~-oфĐ:V.;Mзf ?jX3 (j4.sUpsx|    !"#$%&()*+,.01235789:;<=>?@ACDEFGHIJLMNOPQRSTUVWXZ[\]^_`defijlmrstwy{|~     !"#$%&'()*+,-./012468:<>Dq MWX|w x  D F `    " @ B \    8 T V p  6 8 S k m "$?]_z8NPk)+F_a|,.Ieg/1Loq $VXs68Sxz24Oqs.@B]!UWr %AC^xz 57Rvx2MOj#%@VXs.0Kfh"$?VXs.0Kac~46Qik  ) > @ [ w y !!!:!X!Z!u!!!!!!!""4"O"Q"l"""""""###>#@#[######### $9$;$V$m$o$$$$$$$ %2%4%O%~%%%%%%& &$&X&Z&u&&&&&&&''7'W'Y't'''''''((,(D(F(a({(}((((((()))6)U)W)r))))))) * *(*R*T*o*******++.+E++r555C8^8`8j888':B:D:====>>->e>j>>>>BBBBBBtCCCDD DmDDDDDDDEEGGGJJJ2JJJTJLLLOOOOOOOPPP)P+PVQqQuQQQQ/RGRQRLSdSnSGU_UiU#>+>G>J>L>d>r>z>>>>>>>>>>???6?9?;?S?257O7DLhkm !39UXZr"*FIKc8;=Uck$')AOWsvx5BJfik (DHJbpx&:B^bd|*2NRTl{  (DHJbw:>0Jm#?B1IL.8E]`E ` c ~27A]`E]`d|  ,GMWsuJ b e !1!5!;!V!X!$$$))))))+8+=+H+c+h+s+++0000 11181;1999::R:U:<<<)DADKDDDDIGaGdGIJJJ4J7JMNN&N>NANSSTT UUsWWWWWW$]<]?]aaafgg&g>gAglkkkooooooppquqqqtttzuuuvw1wsyyy{{{4;Ead'CFB]cm"&0LO[twrƗԜלɠ&>VYWowD\_îۮtƹ޹ %(SknοQis)/4LO.1{>Vik4LIak$$$%%%,,,///S0k0u0000IIIPPPpQQQXXXZ[[q-q7qw5w8wT{o{v{)ADцg?WZ܉hD\_Βђ58\t~hXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX    %     % %   % %%   %   %%% %%  %        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  %%    %%   %                X % %%%        %           %             % 5@GIgnp!)>GOdgnq#*-?FILTirz%(/2OVYkrux +4<QT[_|"*?GNRovz}'<?FJgnrx!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!Lgk>YaB]c  7 > H d g 2 %l,b$tU03D3s@&(    <A3"H c $h34x_toc736 _Ref161646676 _Ref161646677_toc738_toc745_toc747_toc750_toc752_toc763_toc765 _Ref161136726 _Ref161136762 _Ref161137270 _Ref183856870 _Ref161043988 _Ref161205506_toc786 _Ref117064775 _Ref161645361_toc815 _Ref161136679 _Ref161136703 _Ref161137195_toc818 _Ref161204879 _Ref161204917 _Ref161209068 _Ref161209075 _Ref161645238 _Ref161645264 _Ref161037664_toc919_toc925 _Ref117066209 _Ref161205517_toc954_toc956 _Ref161037777_toc1041_toc1164 _Ref161136691_toc1166 _Ref162338864 _Ref162338878_toc1176 _Ref183843397 _Ref190748021 _Ref161039433_toc1209_toc1212_toc1216 _Ref161204588 _Ref161204602 _Ref161204755 _Ref161644929 _Ref161645084 _Ref161646655 _Ref161646665 _Ref161039990_toc1295 _Ref161204636_toc1376 _Ref161136715 _Ref161136737 _Ref161136774 _Ref161137204 _Ref161137218_toc1383 _Ref117065824_toc1386 _Ref162338927 _Ref162338939 _Ref161214128_toc1415 _Ref117065703 _Ref117065709 _Ref117066572 _Ref161645540_toc1453_toc1462 _Ref117066165_toc1464_toc1467_toc1469_toc1479 _Ref161204772 _Ref161204787 _Ref161645097 _Ref161645115 _Ref161650297 _Ref161650310 _Ref162083383 _Ref162083396_toc1483 _Ref183844204 _Ref161043936 _Ref161645426_toc1541 _Ref161037022 _Ref161204539 _Ref161644826 _Ref161205069 _Ref161645485_toc1562 _Ref161037026 _Ref161136752 _Ref161136788 _Ref161137284_toc1567_toc1571_toc1576_toc1578_toc1580_toc1583_toc1594_toc1600_toc1606_toc1608 _Ref161051460_toc1682 _Ref161205081 _Ref161645507_toc1734 _Ref161204620 _Ref161644958_toc1736 _Ref161116897_toc1743 _Ref161204653_toc1750_toc1762_toc1777 _Ref161036833 _Ref161136802 _Ref161137236 _Ref191725441 _Ref191725456 _Ref191725518 _Ref191794652 _Ref191725588_toc1787 _Ref191726098_toc1792_toc1800 _Ref191728658 _Ref191794693 _Ref191794618_toc1864 _Ref192072556 _Ref161214237_toc1901 _Ref161652944_toc1979 _Ref161204817 _Ref161645188_toc1983_toc1985_toc1994_toc2000_toc2011_toc2016 _Ref161204833 _Ref161645210 _Ref161214456_toc2062 _Ref161136597 _Ref161136642 _Ref161136666 _Ref192072575_toc2067 _Ref161204515 _Ref161204847 _Ref161645225 _Ref183843234 _Ref183843334_toc2069 _Ref182908600 _Ref182908620 ArrayEditor() ArrayEditor _Ref161718374_toc2133 _Ref182908648 _Ref182908661 _Ref161205317_toc2180 _Ref182908700 _Ref182908717 _Ref161205331_toc2212 _Ref182908732 _Ref182908747 _Ref161205346_toc2250 _Ref182908763 _Ref182908779_toc2281 _Ref161644779 _Ref161644792 _Ref161205358 _Ref161205371 _Ref161482798_toc2318 _Ref161482293 _Ref161482311 _Ref182908817 _Ref182908830 _Ref161205386_toc2351 _Ref182909009 _Ref182909033 _Ref161205409_toc2387 _Ref161205017 _Ref161645067_toc2443 _Ref182909127 _Ref182909142 _Ref161205433_toc2479 _Ref161558251 _Ref161558265 _Ref161205460 _Ref161205478_toc2514 _Ref182909187 _Ref182909205 _Ref161552507_toc2567 _Ref182909229 _Ref182909240_toc2614 _Ref182909259 _Ref182909274_toc2642_toc2648 _Ref161833094_toc2703_toc2705 _Ref182909329 _Ref182909342 _Ref161566322 _Ref161566341 _Ref161567129_toc2744 _Ref182909356 _Ref182909366 _Ref182910065_toc2774_toc2802 _Ref182909383 _Ref182909397 _Ref161575760 _Ref161643228_toc2934 _Ref162087703 _Ref162087715 _Ref182909462_toc2962 _Ref182909485_toc2998 _Ref182909518 _Ref182909530_toc3028 _Ref182909564 _Ref182909578_toc3064 _Ref182909633_toc3092 _Ref182909697_toc3124 _Ref182909761 _Ref182909779 _Ref163470800_toc3154 _Ref161204527 _Ref161645305_toc3156 _Ref182908935 _Ref182908948_toc3189 _Ref163545150 _Ref182909085 _Ref182909072_toc3220 _Ref182908979 _Ref182908995_toc3287_toc3357 _Ref161566483 _Ref162339121 _Ref162339134 _Ref162689531_toc3395 _Ref192064881 _Ref162087667_toc3401 _Ref192064901_toc3403_toc3413_toc3418_toc3437 _Ref192064917_toc3439_toc3442_toc3444_toc3448 _Ref192064930_toc3455 _Ref192064946_toc3458 _Ref192064954_toc3463 _Ref182909666 _Ref182991613 _Ref182909681TabularEditor()_toc3505_toc3520_toc3536 _Ref162768938 _Ref162768942_toc3762_toc3765 _Ref162853460_toc3774 _Ref162853521_toc3782_toc3787_toc3789 _Ref162866493_toc3808_toc3821_toc3825_toc3830 _Ref162942176_toc3851_toc3863 _Ref191800790 _Ref191800801_toc3865 _Ref182909796AnimatedGIFEditor()AnimatedGIFEditor_toc3893 _Ref182909831_toc3923 _Ref182909865_toc3951 _Ref182909946_toc3979 _Ref182909966_toc4013_toc4041 _Ref182909994_toc4072 _Ref182977843 _Ref184811508_toc4103 _Ref182977879 _Ref191370312_toc4134 _Ref182977905 _Ref191464188 _Ref191464244 _Ref191454702_toc4164_toc4194 _Ref182977941_toc4233 _Ref161136850_toc4235_toc4237_toc4247 AppendixI AppendixII+++@.246G:AEEEEEGIVJLLQQQQSSSSSSSW`adgg]ij^puu=x=x=xzzz~܁''''''''66͞͞͞```\ h:hhhhhhhhh44????ppppp 80ME;hhW W W   aa\ #'$'$'//5-<>      {$)))))------.....05553:n:n:n:x<:>:>:>DDDDHHHJNN\R\R\R\R\RTRVRVRVW\\\eeegnnnonqssssumzmzmzS  7qqqq/=ddddααǼǼRR```JJJjjjjuvw0))))tNNbX-?U U B B ns$4,//G?J?JuLuL.ORwRwRV>`bggn>s>s>sttttuuMwMwiyiyz{z{1ccggʆŊŊŊŊmm;i  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~v8    Rqq !"#$%&'()*+,-./01239:q4567<;=>?@ABCDEFGHIJKLNNOQQvSTUVWXYZ[\]^_`abcdiffghjklmnoptu+++@.246G:AEEEEFGJVJL"MQQQQSSSSSSS X`a7dgg]ij^puu=xgxgxzzz~܁'MMMMMMMć6K͞ϟ`˦\ h:hxxxxxxxx4F%?NNNp 80ME;W z z   )\& #L$f$'/////5-<a      $)))))------....0555V:n:|:|:<:>K>K>DDDDHHH8JBN~N\R\R\RlRlRURVcVcVW\\ \eeeBgnnnoqsssumz~z~zxZq/;;¨¨`dtαٱٱ¶¶ǼԼR_`mm,,JXXju0B)666N`bX-?U h B U ns$4,@,@,@,/ 0G?J[JuLL.ORwRRV>`bggn>s\s\stttuuuMwXwiyxyz{{1cng{Ŋييm'''niJ`-K`#!!i??i:*urn:schemas-microsoft-com:office:smarttagsStreet;*urn:schemas-microsoft-com:office:smarttagsaddress P1122)3233NADFMF}FF@GNGGGGH6HHHHHHHHHHHII%I&IXIII8K@KKKLLL M%M]M{MMMNN0N4NENINYN]NnNrNNNNNNNNNOONOPPdTmTVX[XXX)YYKZPZZZ([2[4[?[k\x\p]|]]]]]^^__w_~_____D`F`j`n`?dOdsdddddKeMeneoeeeeeeeeeeeee)fzFzZzbzzzr}t}x}}}~~dk#*؂݂ۄ)Obc%):>NRch~ʼn߉89uۊ݊Uaivnj%=etx1.8ڏ-4Ȑʒ OU֕ݕ<@DF )%+6>Gbd|bkFQןHd04DHY^txۡ-Jgɢڢ(%0aj/:?V#'7;LQgkx}Ψ =Zw©ܩ+EeѪ+,-.Iq~Ӷݶ=?hx:ELWtպ׺.9@PXZ'4.0Zjp{.>EP(* 'KT Y[(-.g(+9<KNZ]il&2COam~$0AToz &5q+\jAPX'6KQ (-.9NYny;Atzuw|~";A\_{5>WgnyT] gl;?lr 8:djZ`^gHQnp+1^nLNPV/EK^dY`}^px +=Ci;D[a.5<Uij $ U ] y ~            " , 1 G H h u          / 8      ^ ,CVBHmz6Fkczdns~GM^hK Q X b g r    !!;!E!!!$"/"i$9%>%K%O%h%l%{%%%%%%%%%%&&#&/&A&M&^&q&&&&'-(/((((((((())))-)O)T)a)i)p)|))))))))*-*A*S*c*x********+"+<+u++++++',1,,, ..?.J...6-6.6H6f6t6u6666677#7'7:7>7V7\777777788:8H8[8i8r8888899 ::t:~:::::<<%=2=v====>!>e>p>>>??T?\???????@(@AB BBBBBBHCSCCCFG3GGGHGdGhGGG HH/H0HLHPHtHHHHHHH I%I5ISIWI{IIIIII>JGJeJmJJJJJJJKK-K1K@KHKkK{KKKKKKKKLL*L9LPLfL}LLLLLLLMM,MOMeMtMMMMMMMN*N-N/NHNPNkNwNNNNNNNO'OWOOOOPQcQkQQ;RFR6SASS TCTfT|TTTTTTTTTUUUUUVV@VLVVV4WRWXX}[[[[[[+\3\^^w______````+bNbdbobbbbbbbbbSd^d@eKe~gghhhhi'ij#jfjjjjjjjjjjjjjllTmbmjmnmmmmmmm:n?nOnTnpnvnnnnno#oooppyp}ppqqqq(qqqrrYsasoszsssbtmttttu uuuuuuvvywwwwgypy0zAz\zfz~zzzzzz {){)|;||}}}~~~Ȃʂ҂Ԃ݂*,:FRT_aouɃˋ&'+2pw,129p~?M*+=akĒ$ft}K`S]ڗ%0t}Ԙ٘ۘ!'qwy}ΙԙPZ$&02;=F_lnx{̟ԟn =H̡С-1>?]a|Ţ -1PTqsڣޣ#'-1DHfistѤפ%*?EV[kpХե  16T]lpĦԦ!-/=XdtߧOR{|ƨHK{ȩЩ04IJirϪת(+SWai«ҫ +Ngʬܬ-I[p˭ݭ,FXmɮۮ*>Pm¯Я%3WdŰ ,OẖԱ .BTjò 4A^j۳0@Ritʹߴ-BWgʵֵ-.AMbnݶ-E`dƷ@HV^"*8@պ .>Pdvӻ V^lt˽$-0?Qmľ?HV^ u{/Ugy*N\!EQu*<X` ɠ#$')-.>Zuvxy|}D`ƹ )Soοpqtuz{!+<F!,HSdnLWs~ %0x6BS^ )5}!-in q3x3=$===>>BBFFGGGHHHHIH}H~HHHHHHHHHHHII$I&IMRbh}ʼnމ79OPtU`iuƌe0ǑȑΑϑԑՑޑߑɒcn<?&GHqrܠݠ/4CHX^sxۡ,JfȢkvx~>?deϧЧ "'6;KQfkw}Ψ=Ywܩ*EdЪ*,CDZ[Hq(j=@rz?GQXպغX[.18?(+ &fg'+8<JNY]hj%2BO`m}#0@IKTnsuz %5BCp*\iX&6JLfg (8NXnxI[6ahb8;dnq-6^ot0Yai:CZ`.6;<hj $ T ] x ~            " + 0 F H g u            ^,BJNV5Fjcyg$$$$$%%8%>%J%O%g%l%z%%%%%%%%%%&&"&/&@&M&]&f&h&q&&&&&&'''A(B(~(((((((((())()-)N)T)`)i)o)|))))))))*0*A*R*c*w************++!+"+;+6G6H6s6u666666677"7'797>7U7\77777778898H8Z8i8q8888899T?^???AB BBFGGFGHGcGhGGGGGGG HH.H0HKHPHsHHHHHHH I$I5IRIWIzIIIIIIIIJJ=JGJdJmJJJJJJJKK?KHKjK{KKKKKKKKLL*L8LPLeL}LLLLLLLMM+M=M?MOMdMtMMMMMMMN*NGNPNjNwNNNNNNOO;RGR6SBS@VMV5`9`ddfffjjjjjjjjjjjjjmnOnnoooopxpyppzzX{^{{{{|}}Ɂ́uŒ$9:KLZ[e RSٗڗ$%stӘԘ !lmwP\{l <H^_~ˡС-/=?\a{Ţ ,1OTps٣ޣ"'CHegrtФפ$*>EU[jpϥե  06S]kpĦӦ!<IKXctʧ̧ԧ֧ߧ=>NPz|ƨGIcdzǩЩ/4HJhrΪת ')78RW`i«ѫ *Nfɬܬ-H[oʭݭ,EXlȮۮ*=Pl¯ϯ%2Wcİ +Og˱Ա .ATi² 4@^i۳0?Rhmqrʹ޴-BVgɵֵ@Manܶ,E_d8Rպ .=Pcvһ ˽$>Qlþ/Tgx)N[ EPu)<W"b#$Z[U`;? >Ip{3Jxz (D\4XY?O;HWfKY+o{4?2(>2FK)q-8:@Zalr[aP\ %   > I    13NS}~6;^o =Bev  (2OXx*3Uf#;Ph{(*:O_{2;Ub|&2! - +#8# -$-1122Q7m7n7777777777U:;:;;<n<o<<=c=d==GGCHIHwHHHHvJzJLLMMNNN O`PnP__`$`%`6`7`E`F`P`aaccd=d>d{d|dddee^e_eee f fWfXfbf;iGifjqjkkWmmmmmmmmm'n3nInJninnnnnnnnnoo(o*oGoLofokovo{ooooooopp:p?p[p^pzpppppppp qq.q3qPqRq]q_qqqwqqqqqqqqqqqrr)r0r@rFrUr[rrrxrrrrrrrrrrrs ss!s>sHsVs[slsqssssssssss t't4t6tCtNt_ttttttttttttuu(u)u9u;ueuguuuuuuuuu2v4vNvOvevjvrv{vvvvvvvvvww3w5wSw]wwwwwwwxx"x#x=xBxKxTxvxxxxxxxxy9yQyuyyyyyyyzz3zFzZzmzzzzzzz{{0{C{W{j{{{{{{{||(|;|W||||||||}}B}N}s}}}}}}}~:~R~v~~~~~~~,?Tr~+ITr~ƀӀ*=SX\]lmzɁށ-ARk|݂+8LYp}ǃԃ 0JOt#=(;Na؊)<Wj~?Rcvǐ9FkwΑڑ 0;`nƒޒ'B MۚEFtuڛ@K&*ӧ)4[fǨ5ceة/GvxCDޮt*:ŲѲ&3BQʵ6D Zfɠ>ZD`ƹ )Soο!+<F!,HSdnLWs~ %0x6BS^ )5}!-i:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::DDDDZqZqoq~qqqqqFrFrUrUr\r\rerer~rrrrrrrsHsHsUsVs]s]sgshsssss(t(t;t;tCtCtPtPt[t\tttttttttuuUuUububumunuuuuuuu!+<F!,HSdnLWs~ %0x6BS^ )5}!-i0i     \^`\0^`0.@^`@..``^``... P^`P .... ^` ..... ^` ...... `^``....... 00^0`........hh^h`. hh^h`. ^`.pLp^p`L.@ @ ^@ `.^`.L^`L.^`.^`.PLP^P`L.hh^h`. ^`.pLp^p`L.@ @ ^@ `.^`.L^`L.^`.^`.PLP^P`L.hh^h`. ^`.pLp^p`L.@ @ ^@ `.^`.L^`L.^`.^`.PLP^P`L.hh^h`. hh^h`. ^`.pLp^p`L.@ @ ^@ `.^`.L^`L.^`.^`.PLP^P`L.hh^h`. ^`.pLp^p`L.@ @ ^@ `.^`.L^`L.^`.^`.PLP^P`L.hh^h`. ^`.pLp^p`L.@ @ ^@ `.^`.L^`L.^`.^`.PLP^P`L.hh^h`. ^`.pLp^p`L.@ @ ^@ `.^`.L^`L.^`.^`.PLP^P`L.^`.hh^h`. L^`LOJQJ^`OJQJohh^h`OJQJhh^h`. hh^h`.  WW8Num2WW8Num3WW8Num4WW8Num5WW8Num7WW8Num8WW8Num10WW8Num11WW8Num12WW8Num13WW8Num14WW8Num15WW8Num16WW8Num17WW8Num18WW8Num19eZ1jH6-X6XAXMXNXVX[XYY)YY[[([A[Z\[\k\x\Y]Z]p]]^^^^____``kkk%k&k.k=k+l,l;ll&m'm=mdmmmmmoooo]p^pZqcqoq}q~qqqqqq3r~rrrrrss5sgshsossssst[t\tbttuu uBumunuuuuuu~~~~~~~~~;GTUahiv~njЌь~ʒޓߓ )*<@;BN]^p1w:;_?l?|?}??????????AAAAAAAAAAAAAAAAANNNNNNNO(O)O=OOO,`amtupq]jstޜߜz{>?IVyzgtZg#$078LSThno@M\]ipq3@FGSZ[ovw?LTUahi}*7=>JQRfmnjkw~lm]jz{J W g h t { |       ( OOKOLOXO_O`OtO|O}OO[P\PHiUi^i_ikirisiiiiiejfjðʰ˰߰˱ұӱ)*4AdeqxyR_mnzERuv "#7>?SYZ+8GHT[\pwx+12>EFZabv*7?@LSThop"()5<=QXYm UVbij~WXt$%189MUVj45 '.... /"/#/7/>/?/S/Y/Z/55555555556 6 6}:::::::::::8;9;L>Y>^>_>k>r>s>>>>>>>DDDDE E EE&E'E;EDEEEHHHHHHHHHHHIImRzRRRRRRRRRRRRdVqV{V|VVVVVVVVVV!\.\8\9\E\J\K\_\\\\\\eeeeeeefff*fcfdfnnnnnnnnnnnnnsssssssssssttzzzzzzzzzzz){*{ˆ̆؆ )vw  29:NǣΣϣդ֤<I\]ipqèШ֨ר|}()07<FGhʫ4=FQ]^ĬЬѬ#.:;uҰٰڰڱ*+?öжضٶ ")*˷ϷзܷZ[ovw׸ظռ !5<=`mstվ־n{Yftuw (,/07DWXdkl %&:BCW!"A,N,W,X,d,k,l,,,,,{-|-tttttttttttttuuuuuuuuuuv6v7v[whwwwwwwwwwwwwyyyyyyyyyyyyyy{{{{{{{{{{{L|M|?LRS_fg{o|Ѓ|ԅ*+ɇч҇އڊ2NO[bcw~ҐӐߐjk -.2=fgmɸʸ˸Ҹ1<FGLWXY_klmuŹƹ˹ֹ &-OPU`rsy˺MӻԻջ&12;JKLPmɼʼ˼ټ=>?Gdopxi@uuAEEuuzdqrstuvhP@PzP|P~PPP@P@Unknown Janet Swisher Gz Times New Roman5Symbol3& z Arial?5 z Courier New71 CourierK@Palatino Linotype;WingdingsO& k9?Lucida Sans Unicode5& zaTahomagAndale Sans UIArial Unicode MS?& Lucida Sans#h%Dņa$F jlr!4dG3HP)?jTraits UI User Guide Janet Swisher Janet SwisherP            Oh+'0 ( H T ` lxTraits UI User GuideJanet Swisher Normal.dotJanet Swisher3Microsoft Office Word@d@6@l@fS jGVT$mG  jE   ."System &+`i -@Palatino Linotype-  2 X  'j@Palatino Linotype--)2 eX Traits UI User GuideY:K22C&u:%uCK:%}\2\K 2 e _@Palatino Linotype-2 X  Traits 3.04",',, 2  7@Palatino Linotype-2 X  Lyn Pierce$#%& 2 | $2 X  Janet Swisher% 5% 2  '2 X  Document 1"%8%2   Version 4)"$ 2  ' 2 9 X 3 2 9 x -2 9  Mar;  2 9  -2 9  2008 EA x,(xeBkǻoN`<jHg<~a5yT\{yZ-ǸsLtT%µsmDcgEfsW*|f@ȻgyTwW)jIb=mLsKza6d@ c? Ƕg=fCpOp_<a<hFa={\/]sS$7v!8h(u 6U(((u s]((((u rG((((((u HU/(((((((u Z](((((((((u Fn(((((((((((u  H5/((((((((((((u Z_((((((((((((((u ki((((((((((((((((u q/(((((((((((((((((u \_(((((((((((((((((((u kQ(((((((((((((((((((((u 4g((((((((((((((((((((((u fm((((((((((((((((((((((((u !6p((((((((((((((((((((((((((u Yg(((((((((((((((((((((((((((u 8h(((((((((((((((((((((((((((((u 6j(((((((((((((((((((((((((((((((u !7]((((((((((((((((((((((((((((((((u rG((((((((((((((((((((((((((((((((((u 6U((((((((((((((((((((((((((((((((((((u e](((((((((((((((((((((((((((((((((((((t rn(((((((((((((((((((((((((((((((((((((g4 H5/(((((((((((((((((((((((((((((((((((((j6 Z%(((((((((((((((((((((((((((((((((((((ir!  kn(((((((((((((((((((((((((((((((((((((m\ Hq/((((((((((((((((((((((((((((((((((((]Y Z_((((((((((((((((((((((((((((((((((((/56 kQ(((((((((((((((((((((((((((((((((((((Qk qg((((((((((((((((((((((((((((((((((((hf! f_((((((((((((((((((((((((((((((((((((%e k^((((((((((((((((((((((((((((((((((((gqH Yg((((((((((((((((((((((((((((((((((((pk !fh((((((((((((((((((((((((((((((((((((nr 6p((((((((((((((((((((((((((((((((((((_Z  7](((((((((((((((((((((((((((((((((((g4 !8h(((((((((((((((((((((((((((((((((((/U6 !%(((((((((((((((((((((((((((((((((((iF !%(((((((((((((((((((((((((((((((((m\ !%(((((((((((((((((((((((((((((((]s !%(((((((((((((((((((((((((((((/5H !%((((((((((((((((((((((((((((^k !!!!! !!!!!!! !!!! !! !!"! !!!! !  !!!! !! !"! !!!!!!! !! !!!!! %((((((((((((((((((((((((((G8 ! !! " !!  ! " !  "    !  !  !!  " " " !! !   " !! " !!  !   !!  "  !!    !! %((((((((((((((((((((((((%e! !! !    ! !  "    " " "  !   ""  !     ! " !     " %((((((((((((((((((((((g4H !    !  ! !! "        " " " !!!  !   "   !     ! "       %(((((((((((((((((((((j6 !  ! ! !! "       "" ! " " ! !    "  !     "! "   ! !    %(((((((((((((((((((nr ! " !   ! "  "        "  ! !   "      "! "        %((((((((((((((((((7 ! "  !  !          !  "  !      "  "    "!   "   !  "%((((((((((((((((((\ !  " !  ! "   ! !     " ! !    "     "! "     %((((((((((((((((((\ ! !      !!!     !"!" !    "  !%((((((((((((((((((\ !%((((((((((((((((((\ !%((((((((((((((((((\ !%((((((((((((((((((\  !%((((((((((((((((((\ !%((((((((((((((((((\ !%((((((((((((((((((\!11B!!!b11C211B!!!!N112311!!!!!!R3%((((((((((((((((((\QGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG8jGGGGGGGqHiGGGGGGG:=======d:=======d:=======d2BK= E`:31@MI >M!19@M> =!92========92========92========9%((((((((((((((((((\%(((((((((((((((((((((((((((((((((((((\G(((((((^n((((((((! I! I! I3` ?R:I I:CbE IK23 13 13 1%((((((((((((((((((\%(O(((((((((((((((((((((((((((((((((((\G(O(((((^p((c(((X((! I! I! I9d T S LNBI TS ST >:2` TS T <33 T 13 T 13 T 1%((((((((((((((((((\%(((((((((((((((((((((((((((((((((((((\G(((((X(^5((X(((((((! S I! S I! S IK S ?2D T `:W T b3 13 13 1%((((((((((((((((((\%(((((((((((((((((((((((((((((((((((((\G(((((X(^7(((((((((((! S I! S I! S IAE S W:= VJV S S M3 13 13 1%((((((((((((((((((\%(((((((((((((((((((((((((((((((((((((\G(((((X(^Z/(O(((((((((! S I! S I! S I: T ST S <D T T <9W T T T M3 13 13 1%((((((((((((((((((\%(((((O(((((((((((((((((((((((((((((((\G(((((X(^8g(X((((((((((! S I! S I! S I: S T T <1 T T T S BAW T S K3 13 13 1%((((((((((((((((((\%(((((O(((((((((((((((((((((((((((((((\G(((((X(^F%(((((((((((((! S I! S I! S I: S WM!;111N!`E T <> V`b111111:DV >R VK!B111;!DV T 23 13 13 1%((((((((((((((((((\%(((((O(5G(((((X(^6m((((((((((((((! S I! S I! S I9 KB DJJKW :2> T =B2b= D3 13 13 1%((((((((((((((((((\! %(((((O(5G(((((X(^Hn(((((((((((((((! S I! S I! S IL d3;W S T 9= IJJL T LM ?9R> S 3 13 13 1%((((((((((((((((((\ %(((((O(5G(((((X(^^((o((((P((((((((! S I! S I! S I@ W:JV S LC T 33> T 2: S @2E J3 13 13 1%((((((((((((((((((\ %(((((O(5G(((((X(^5(((((((((((((((((! S I! S I! S I2 T 9? ;R D; BW R1 B3 13 13 1%((((((((((((((((((\ %(((((O(5G(((((X(^7((X(((((((((((((((! S I! S I! S I! T RCL T I! 3 !: T R3 :3 13 13 1%((((((((((((((((((\ %(((((O(5G(((((X(^Z/(((((((((%((((((((! S I! S I! S IE T @2W T A< > S T <= ;3 :3 13 13 1%((((((((((((((((((\ %(((((O(5G(((((X(^8g(((((((((n7((((((((! S I! S I! S IA Lb `d T S L= T T ?3 L3 :3 13 13 1%((((((((((((((((((\ %(((((O(5G(((((X(^F]((((((l((mH7((((((((! S I! S I! S IK NI T >= T T M< T =@ B1!!!!!!!!!!!!D :3 13 13 1%((((((((((((((((((\ !%(((((O(5G(((((X(^6_(((((((((%k7((((((((! S I! S I! S I? T S WK 2= T << T =< T S W! :3 13 13 1%((((((((((((((((((\ %(((((O(%GGGGGGGGGGGGGGG(((((X(^HG(((((((((gF7((((((((! S I! S W!!!!!!!!!!!!!!!!!!!!!!= S IE S <9 A= T << T == <! :3 S @= T << T = N! :3 13 1%((((((((((((((((((\ %((((((((((((((((((((((G(((((X(^Y((X(((((((47((((((((! S I! S I3 1I S != T << T = B! :3 13 1%((((((((((((((((((\ %((((((((((((((((((((((G(((((X(^Z(((((((a((j7((((((((! S I! S I N b= T << T =W b! :3 13 1%((((((((((((((((((\ %((((((((((((((((((((((G(((((X(^8/(((((((((i7((((((((! S I! S I> ;C R= T << T =L S K! :3 13 1%((((((((((((((((((\" %(((((O((((((((((((((((G(((((X(^F](((((((((hH7((((((((! S I! S S IV S =R J= T << T =M T T E311111111111111111111123 13 1%((((((((((((((((((\! %(((((O((((((((((((((((G(((((X(^6_((a(((a((%67((((((((! S I! S S Id 2d = T << T =D J3 13 1%((((((((((((((((((\ %(((((O(5G(((((X(^HG(((((((((gF7((((((((! S I! S >1111111111111111111111< S Ib @2 S T == T << T =1 D3 ;111111111111111111111N 13 1%((((((((((((((((((\ "%(((((O(5G(((((X(^Q(((((((((/f7((((((((! S I! S I! S I2 T 3d b= T << T => J3 13 13 1%((((((((((((((((((\ %(((((O(5G(((((X(/((a(((((((e7((((((((! S I! S I! S I= =B S 2= T << T =` =3 13 13 1%((((((((((((((((((\  %(((((O(5G(((((X(((c((((c((47((((((((! S I! S I! S Ib dR == T << T =9 S MCV=C3 13 13 1%((((((((((((((((((\ %(((((O(5G(((((X(((((((a((U7((((((((! S I! S I! S IE T <R S A= T << T =` <3E L23 13 13 1%((((((((((((((((((\  %(((((O(5G(((((X(((((((((Q7((((((((! S I! S I! S IA T T V2! `= T << T =2> E9:W I33 13 13 1%((((((((((((((((((\ %(((((O(5G(((((a((((((((GH7((((((((! S I! S I! S IK T W!CBL >C= T << T =b T S <9J? >93 13 13 1%((((((((((((((((((\ %(((((O(^\\\\\\\\\\\\\\\\\\\\\\\\\\\\HG(((((((((((((_67((((((((211111111111111< S >111111111111119! S I! S IL `BCA@I T R= T << T =< ?;A:V W13 13 111111111111111N ;11111111111111%((((((((((((((((((\ %(((((O((((((((((((((((((((((((((((((FG((((((((((((]F7((((((((: S =! S I! S ICL T L==KM== := T << T =< T S ===D!M=L K3 13 1 3%(((((((((((((((((([ %(((((O((((((((((((((((((((((((((((((FG(((((((((((/87((((((((: S =! S I! S ICL T S T S := T << T =< T S N3 13 1 3%((((((((((((((((&'   %((((((((((((((((((((((((((((((((((((FG(((((((((((Z7((((((((: =! S I! S IC? T := T << T =K S T >A3 13 1 S 3%((((((((((((((/0$  %((((((((((((((((((((((((((((((((((((FG(((((((X((Y7((((((((: =! S I! S I; T ?3= T << T =1> S T <23 13 1 S 3%(((((((((((((-.   %((((((((((((((((((((((((((((((((((((FG(((((((((U7((((((((: =! S I! S IJV S W:= T << T =CM T S ER3 13 1 S 3%(((((((((((+,  %((OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOP((FG((OOOO((Q7((OOO(((: =! I! IR? S T I;C= << =3< ST >@3 13 1 3%(((((((((()*  %((((((((((((((((((((((((((((((((((((FG(((((((GH7((((((((: =! I! IJ =?@A:!!!!!!!BB!!!!!!!:CBD=E >=!BC!!!!!!!!3C!!!!!!!!3!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!C%((((((/0$   !12313%(((((-.  %(((+,  %(()*  %&'  #$     !  !    !     ! "        !       " !                       '-                           ՜.+,D՜.+, hp  pEnthought, Inc.l' 9Traits UI User Guide Introduction3 The Model-View-Controller (MVC) Design Pattern4 The Model: HasTraits Subclasses and Objects The View: View Objects7 The Controller: Handler Subclasses and Objects Toolkit Selection Structure of this Guide!The View and Its Building Blocks The View Object Contents of a View The Item Object Subclasses of Item The Group Object Subclasses of GroupCustomizing a View/ Specifying Window Type: the kind Attribute Stand-alone Windows Wizards Panels and Subpanels+ Command Buttons: the buttons Attribute Other View AttributesAdvanced View Concepts Internal Views Defining a Default View1 Defining Multiple Views Within the Model. Separating Model and View: External Views Displaying a View configure_traits() edit_traits() ui() The View Context Multi-Object Views Include Objects'Controlling the Interface: the Handler- Backstage: Introducing the UIInfo Object Assigning Handlers to Views. Binding a Singleton Handler to a View. Linking Handler and View at Edit Time1 Creating a Default View Within a Handler Handler Subclasses Controller Class ModelView Class Writing Handler Methods$ Overriding Standard Methods" Reacting to Trait Changes, Implementing Custom Window CommandsTraits UI Themes Theme Data! Themeable Traits UI Elements Adding Themes to a UI'Introduction to Trait Editor Factories1 Specifying an Alternate Trait Editor Factory NDEditor() KeyBindingEditor() TableEditor() TabularEditor() Title Headings8d,(W_O, _PID_HLINKSDate completedA+zFhttp://www.lpthe.jussieu.fr/~zeitlin/wxWindows/docs/wxwin_wxhtml.html!http://trolltech.com/products/qtD*http://www.riverbankcomputing.co.uk/pyqt/WQhttp://wxwidgets.org/_Dhttp://www.wxpython.org/0 _toc42477 _toc42377 _toc42357 _toc4233= _toc41942 _toc41647 _toc41344 _toc41033 _toc40720 _toc40415 _toc40134 _toc39796 _toc39511 _toc3923: _toc38935 _toc38655 _toc38636 _toc38510 _toc38301 _toc38251 _toc38213 _toc3808;| _toc3789;y _toc3787;v _toc37824s _toc37745p _toc37655m _toc37620j _toc35361g _toc35203d _toc35055a _toc34636^ _toc34586[ _toc34557X _toc34487U _toc34447R _toc34420O _toc34390L _toc34372I _toc34182F _toc34133C _toc34033@ _toc3401:= _toc33956: _toc3357;7 _toc328714 _toc3220;1 _toc31896. _toc31566+ _toc31541( _toc3124:% _toc30925" _toc30641 _toc3028; _toc29984 _toc29621 _toc29342 _toc28025 _toc27746  _toc27442  _toc27052 _toc27036 _toc26486 _toc26423 _toc26144 _toc25673 _toc25145 _toc24796 _toc2443: _toc23877 _toc23513 _toc2318: _toc22817 _toc22503 _toc2212: _toc21801 _toc21334 _toc20694 _toc20674 _toc20623 _toc20163 _toc20112 _toc20008 _toc19949 _toc19859 _toc19836 _toc19791 _toc19017 _toc18641 _toc18008 _toc17929 _toc17876 _toc17777 _toc17624 _toc17505 _toc17432 _toc17362 _toc17349 _toc16821 _toc16081 _toc16061 _toc16008 _toc15949 _toc15839 _toc15806 _toc15786 _toc15766} _toc15717z _toc15677w _toc15625t _toc15419q _toc14836n _toc14797k _toc14697h _toc14677e _toc14647b _toc14624_ _toc14530\ _toc14159Y _toc13869V _toc13836S _toc13768P _toc12950M _toc12160J _toc12121G _toc12096D _toc11767A _toc11667> _toc11645; _toc1041 "8_toc956 "5_toc954 %2_toc925 &/_toc919&,_toc818&)_toc815/&_toc786!#_toc765! _toc763"_toc752"_toc750#_toc747#_toc745$_toc738$_toc736Ew mailto:info@enthought.com Hhttp://www.enthought.com/ 29-Feb-2008  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~                           ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~                            ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~                            ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~                            ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~                            ! " # $ % & ' ( * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~       7Root Entry F@QS9Data cjz 1Table WordDocumentLSummaryInformation() ĨDocumentSummaryInformation8 P5CompObjq  FMicrosoft Office Word Document MSWordDocWord.Document.89q

    >䬮qRj' 9U/۝ [}83>0h *J;| Ԡt * ժPuD)<̗+5Z^\nzViI OS}=v?Gѻ?ѧtJSKQBSG#SUY:R@'e.CJ h68 PPU66::U帢zEL_y@ TE *B"4MeBvkBæ!&.}*j`W+ tHYD  pAn@ggcP)>:w5ϥ׉xa DsLXI6AC^_hJx{^cdj=yug|\2K4u#83Ϸ??^)&C Ј­~? C<&s퟉_~§r0A'Ry-PQܩ N\ vE;ĩjd UHNUHN i_vҾ| sV_KǤ缢^QIe/6ZFvvC- Fptq3GNK e)87^yꕿqݪ?̣0iz߽z̓*tB P W%Fv ע{СCuho~$gPv؝wL7f)4=, Ld@BT< D1W@VPɩڳ[0頑d$ gi<(9Z`kv$Xsq,NJXIaC$̒LR kUAtؐ,cҊg/Id{Pv)w[i]NUdPLʪ:lވ.{HXWXR ׹2>npL+첍rc4 LyzGG=!.;"d em>!L3Bos8 Nͮ.:@v ;[XfEڍJ: vl3,F;|Dh-/ٱI#4ATT! t{D ?`K8_iAj? KH˜|{k#Z58V=.JKy;*v Uu J{[,oZF] &0A ǰ>\kXx!=igzpww w!gjg"eKӰ ^Eujߖh+;Ԡ6T&O|Y1jter|,ckoVUD> LPiluxəgyL"R~S{Yw=sI.#AD+txMo #ɐ" 0-NF@;z+P{@lp i XW0ᖅ'DGvFK2j'04tBФ2^\)\\:P "w]9[]ҝwoX{-v7.}eo] \oGݦW dYS*O W44FD yʡœ9]8hS'pDAQ#7]>%Ͼ,x6L,FhrGƀ|'}do՗>?AςA b {>G 97D`S;R!jallgJ`Kb= q4vCF]pm J=+]/P/ 0qGG!F"FQ$ݸXv4{:j_ouZGfZ?_hL`Z 1j ,pe‚-~z_ʤc㨨e~L|ި9!6PWOvx^=X79=`|u4v>AN-iA?ugYB 4$0ڒTsvڪ~cW~t?ⵏh}}ׯ쵫vL W͚Z׺7||[[{vW=͕7|* бFU9$=-1fs evO?Yy;vC̀n`: 5R}3/wPi g1G TNpE(= ~h?P,"+)pDXA a1pJ=[$NĆLG0CI!60?Yi'Kql3\8ejVvۅ;LYJӖ 3|T4I(, ^ ƊH2,zGF)|+td`qS8XFTר}޲ 5hК4G3g4;ќa{s ; =U/Xyo ?ԞK6eeG]q;u,ݏuKvZ5;>X]]4MFߛEZ{ccx`PtHC'Mp\[pB)OՆO 4ON*4ik9%stC"087`zIoI04 / ϩp8\$x$*!/VKXj'71f*vm׋{K bO0y_y1yT"68ek|cP!|'L(`}cD+g@ç,n߸u}]58V8*_)YlAM ExkHI6w&?T_gkAY~e<~}XWN[C$}kf]e3{ ִ 0lY`>:bڼmÍۧ욱E\4x=QzN?d ޸쳻_XǑ7^{'{$/71g=o} BJ@v(C g+G}hskh` 0I96p(5 a6 6;K-VhyuK=[dxiD)6b6 8GSL"ttkNJ D(W@o\x]@"ӥhr+NCC^I+V`\.!n  P x xt# swGr&gR_adO AX5Q=W:R,5EEtD%:df &FpY*ˊp4<~(}_Fz}U/(kbP=ijKd3, oL-}*]%)?,/d2Q |lD`~PFO.LN٬fcP`itDA]&y$]arZEZϿ]ز+S _B/mž4e7vq(8*`Rf pa_IEHpfcSѶlz)3?֖|`baFt+јnnyC90ByQQ8HW$ģ8bVJ49X1g3rڸ#_P"Llrrwl m6J^o-\;o894>/[_{xy_^v؛Gov0u v[8.7@nL(̫ /yNUv-5y S|Eٞft,,.ŸuvG< xF~CߤHO }zkeP-y{[@SRT腋FF/*{[dŕ.G\\zkڭVC;"&g lHfJ2UEȂ#8B!*"Y-Df !cdV*>ƦW|F%Έ0F fa!lckaZND'P3@#fLM[CV\ndcT/i}&Sֈ ?_AaQ/ծWg_t*yېGɺPҼ]3z# 1!2-_ʿ$idkDiIMO/j۞.89Qpv;.p>rOX+=_xiر[2=>]g|7^|\EH4,i,Kp=B vn7nԏ}:g5GP,d%;U|4Sb#$2\3pʕpxDO6OV{Ѿ,{Ot=x:79g5{Mh"e=:̐[s]= "a3 #TG7)"S" _؈foRkNl 7+&pB<_62}OR-=",~l60 SdV`8 K ֏B~z.Q88k$13BRN3™vgBFr_S)~]*Fυ³;(ƑI+1PMii׭|#)!h;- +΋ /Rv1'@ZLoO+)|nWP<014G P/x vTlll2"= zϻe:}cM[Zsdmb$hv`q]ɋFF5H{ip`x{wzp\x6ӽȻ0^MWڮ7Il]4n(DZ\rAtւ?nF:Yj "֗1n@|.A@Imv$N\W\Y}'׬y\"oc_{ҙtP|ڴ5x+t-M#9-7m)U, T%KK_aC+O?ctnEk=<~} ֝7QO&)o<>(\6X@y>D۲]Wl1߽BR3Επx}y{šX, Rq.I6v\ms;[m:mgpqf Sg]AU6҃YS$z ȩ/[]rQ ~zhי#Myta:rgZ))56h4\݆q;0dg%[Ekv#iJ:Wi=1䤳%4 ](u/Ny8={q=Loߥex@Qmfe!D$K!$d_dda)H P/Sei7?}|35fq zZlm"Ovt6W&.E9&X?UG!tVQmrk2$5٦8ٞ'ڟl;4r*d|r.MC.C)bpPJ#hFUZ9I`Qq _bq:UUB8R<) 82qMTE8"4vap ZL71Zf&w) \RSόS2Oe}zD__7wְEܐm@~ۖ_9XhpE3>YOj? {􂼊wC{_R}&u/mJ^X>+#Gl\^Pw6m"YY V&C s{uEۻ=Dܶ0o9=\u zKMuӏ,DzgʼH^;iܫ/LO;`]\zE\}:.B*=ĸeFhe4=:4#k]uQBDB8u"Hqzg(`t2 D9)x@Y|Q2_'ɾzT{"o}VzRT|%|&  zŠa~gBq0i[zŽLI}(-/Ү^f%YxO;/iOtrh̯bT{(&Ė+7+Re&&XS@Iy/_Qܮ2de8HU"U3娉,$2OdRdfZOhy MilB=K UHJ|B(sn~r3: h? ];H GTD tzU9socmI_ߥ#Gx剁SO{KY@ٗ?^]ڹp㜾9#/);]-2nu ŎhY1۹CF#<ӌiަИ?`Y5WBf|lmvEEB?Y,/[R7͝:DNgFF.kJ]k/2Ըл`^ zA˂ <7v~M߳RS?inB[mfXi%C3PicbY2Mf؂nϳ?hHQ[@#;-f LY ٚs =!j+J ]u SҴ):F-=oa]߶?xwl?8rEkq4fzCVb_u:[ϽI+U0 [MSײ (h +0 {z-rvKC{ٶcG?1/ 3d%H?UUdUx>"A)">H <&MF|;o]h:/\*2[o Ggk875[m\zrMGa,; V , Ts;r5}p,rg>d0sr:i7#da(R Q7.N\R|@, gsEzS6ƸeYQ $=u?Eu> NHy빳ϿN 5Zlj\d*K_k1JW qnKGz_#~ K}\_e #9 4 E$H& O"<E!7[O ̇fM?HEl8bR` E}>3F zlV,~Ϣ92ǟ#BLD ŗ9߱oHlVYdU2C'F Ye4HXt>7?82l4V#GlZ8pfOCgRMS Ӵk2q*j@wk+^1/*F=W!d<\mLy2Xg:BNٌooU~ħH8('pTc o pՃ:znjV%Ȫă14DfI@ ;SM1C%XoeI_o!~~ٷ;0rfZIUL9V w"<-A:,̍"J ڧi@HFIg >dP2-){pBdK{yEJ+ 6)/+/|RgIx` 9յXOaou[J[>%=%]t]~ m/ߛx͒L~9%\}@ntYACJsMɥ1>~2"9"#JrDu.dD(C(UjOb$W _d[`_Xm~~quznV&6wdݍ^ф+) :Be!_'fZ5LqWAI@%{R |'_b.^b&DeIm"(pI:}Kaz<7x+q;n5ݽ#/U iWBUP'pQHrj^uM`1>ل mtاxFMlv9S-)+.Iϡ9d0ʼnۯK?fEcϽ_=z쓭NY{3c_n|A3u^Y\|i^wՇJFH?PCfaњ'N*npZ䔜q*l`J`PLQK;eT%5t}3ER\)&I"5)Wſ'įeK&MX)na%Oq ? 4˄TT<"E#lE m#xkM4Zs]Lz|1:';LvdER@h{:@^cl7Ppr3GTK5U"Y~~?) zgwmvE1:C1QfwOa{f,r}c"{< lWsW>+Mַ[Fk^mlO}^_$/ʮY4|!|,(^7DŽt1y/ƿy%ۿKo'<ߧރmL<Lc3o ootMKee7)tm67CMnnp3Y$/TdC}<|蘷{By6!zxrՈΈױzV 6tAz M}/-C;"pb6 gz a fwѯP< `g2}Λ_Q~ė.y?<}fw|"_8 _ܳGj/dY .%K92$R6bRm ?E6F>,DK s8)b7aB )8(Oj4İZ6 2(~<'pzp}^|f";N}]SyړkpwWPY30{3B!)m^ڛS̚effYȷ[e!1p;qjZ<10m&~6i6h#6~V۫V%dO0Bc1K0TG[tTRv߅-졯t k=lutܯqѥxMut  iځ6! $~g^I62gޗݤ h邶DYǭ[03Zt)3&s))d6ǽIX3*RWYW[BMePqM'Jž{%ڞӉ6i%ǷGwÓ|C0 _ypP)u(-M#-.+R6?)|e; ޸L{~xZu=ÍSٟmXg~۳WAn^z])tZ~JSrBmFnA BCu*LODjO5JG qªb(mnfݓ?MU|;*<ޢ${䎭E6^ Ѳ[tο|=MXx.Y^u[3١aF ?QlK4jP954!č 0!->P ,&MUCbp@DGF' | *"L8A>:Թ>iO[?ܼ;+k_$LjnWڮt֩Ie{fGZÑH1ڞe{4f8y"w8O|!Rg$*|Ng3$E]{e<[-MH/M={aJm|s}icw16U&R78 #3]V@I&giYXSܤ$,5i,&jw&nU gh:5hBN$yhܖs_;C6F?z}Ht=DTFy- 8MOE&ZD='Y+4SNwŖ)L_)f*^y ;A%*AÔ' ؊aU`H'ߣ,]}j5@Ҋ#]V:P+|>&0v>g$v*\0 g"[m뿭T] -tGtҩ:wȩkT*I]F7 R(tjeb:YcA̶\pR/7DhmuCůNJ{⇋+=@@bDU;kUj{KK0eᎢWJ  R]nO&_.g63LR;<Xdwd3X[k+FޓF%^;N$Jb^ՔgLE-ڙ\mSWjASf ^Bk )&&ft+@p ,^vYAHm%,nּ#x3wC·c߼sPb췂X*Twﰪa=s^ej=:ƣBW%|ߥy~D$oҢ5I$!ҼCʣv4V sllyN\ ]0iuڂEE3&B \4@8{No>R 4"ŐD~j`Z51 `ګS\ƕA~,pEA _+&LR&ݻmz]lGFo_ܑ|8oh2-YP2Oogo &}?8Ϊ'[FO\MI)aDap񋅒ؒ"[K,pٌ.!~7(4K]1im4;Q!%$DBM4Rx)\$R\|h U>K.D%C]9;Ř)|k:^~T:)u~|Gߕ(%fr3Iլׇ }ƍvCqVƻ?dEN1Q,FgAtM (#Et#'T;:ˆ+<)1[&#]~{ݱx#ٽzg{w5ݺM2&}s#oH1Bs;͝[n[߶؂]$_yx?ɦYQ wۭW=n-GÜ1Jq6:[z _e[93"fم_dzp.{gyؤ_v7[uw77?6l1 ՜lf֖Su*& JVjOOsّ_pN/l6i\ӃU] ?ͷ3Ubno`WtC}l|_!}?v]U'm&iB{L<,4^sRmU7CrzӪiU60&ʒ &ef={=)G(bM-h\eOxW,n,}t} vDy/nQW_U tRk4&mLfegqN:{UDTYV^mѬM6nJTb71dBr.SHv]*VY3t yvSnJayɂ@,-)kzV4 L!\Is2IY6 -^v2:s@Sc?^vKhuC4nn7=kB;{wl)}2ͦXs^5P.z:~04&GRJjV+Z* \. u9M W Lgn1э#k )o/ܜBuRVs0C&0^aҕ~0$]r$rá xf33U''U'ԧ5?rZ ͦu6FƤ;m~O '$ ӒiqYT6)QO4j>tJuƙtket`tYPmR(uN3e]*0!l&`Y.4ʵV\I݂I>riJ|niKkz+*=)+={>n~K^ౕjkr7˟|;| )włO]-TYB 0ST((QIUZ_@4C○'YRrRwT_7 =s+pӒE`TJ%eB~^~$<}`߼x,ht(C=;ܭ?ޞwPzn^:z.K{v˹":S . 3ZeP\FA@T2' Q ~΋0|gܗzq^_ȪxbFR9_I].tvwlLٵ#.מϦ>#31ԇS ՓT,s4s \ո,髋$e0}V=%]Spp'քFeZuW鉳5TN\++- w竤7 Z>Q7n^48}b_V,dGv ~,_#5yX¶6J~LùM CN<1h c0v76ǘ}Bi-/:~ͼi֢97P.<úo)>}~ױ]-"dz vSM5=|&e6Tgj[8)O{sj:wMvX"7zt7Zna]WߔXa |_g57P*U.ؓJ&ƕfKJ-=QxdX^%+n[>#B g>Zܻ[y,5]QxnuX|{毚 cΟL%zVl!J_Qz'VE\KO;/WAli(5IpnaxN!IMKc60s IۦqnqTUj {t!=~wLt+"c硌7|` }`Cp4x^ 5׀[xƲ/24y|$&O^,7FVHbHYIO  L>''P<_x9ЦTQWgc}:!}aq;X5٘bLzjF#i539[3=2B=@fo̹:GKzxRdc ?OM=^tK+Rbinҗ敝ߩH󪢪5:3i555R?ԍ_&RL}:ܱja$q[ҦOe 4UDG2$z >VSqa-aCU HFÚdDV&& S0#j H*VN +^U Ie kHt%eX|Y2'I{e@%TŠdAMȾ JBHu.+#9尚pX8E_ag2 O땿zK6pG9lⰔIOs8o84[@98R2a7 9+8<- a / V#lqץ4л4E?"trx 0QK=D  T})'J&&"} WʯT_ *Ceܷbtt@^G)@AY{e8m"\9syK<yڝqC<-)︿DL,KfS%_FoaN.Kcs\rM)S.wA!&AǟƹRKwyD]07 dyo'ʭ4N6wc @/6wPĹpo(C=boHE} R1&&6'"xUU%S*+khD\mᠯkq'[=Eٷzi   p(jNXǂfþ@/N R@G0 mbG&q/*zbc{{i]@'%R:¾΁^.t` v8 I/ ;C]L=}b d,l1 b[ "Jt/ݡp@@E/C5!@=|=" `@^`DBV;ŠV'  ݡPF_? @_xHm}h8vCF#r/EhA&HW5 LJjs =#Z>Hb`[NĎG"bwh7d A$*n.L;QD1Zb_DS3 G!2FQN= lɸxc÷1I) z[0,0vO?녢J1`ˆuxjEhouqqQ,EPwqg;wGVE/FtoGYDnT(?w@Wqzo^ {@GAX.7Gtڠ m#p2=@x#w8b>O9AnrB/ZKja(,$VVN-)/)j4gIiiy9*ĊӫWu_icħbxT5'yma_ kjNQik ' O]YҿO,_YҿeIʒ%+KW,_YҿeIʒKaǿ\_hM |I]\'<+\REb*./Ke!o3HCQvq.'|ߡfsm`'#7`^0*b}B`69 S_.*>q*8Er\/u%j \.#S$זW6X\mJ~*^);E̔7yDH!C`}m$S T`ǞZVccb#n'vV agGLֲײ_#_O(=^0''`T}{e3{ f5`Nہl0 z l3{7ٛPW+ʎqXy2`ϐ[j(ܣ#b ׈f5`zz ]`3Fq^8C3`~ uR f 0d3~2Me&v +1{/#p]a/ ܤVX[ JH=Vke'W`<ٍwN V, Y,˛iqZ -;좍1 xX'G^>$dFaC^_]$JH䦆ׯX~H5X긟^_?:Y) DA?VF}/%d'FEaV" t++W,?`H< ^lIh tʮ DHJ , endstream endobj 432 0 obj 29527 endobj 433 0 obj <> endobj 434 0 obj <> stream x]͎@~ 7{?!? { 9quu)PM͸gvߵpim ~{ uOvy֣=}=l=Wc|3iW0u+:'GG647hW7 ^_{?CG~иwٛ7ӓZpz œ_4&֚l֓kO{0{_y_!G= / ᡘ8#v&ىk 5B_aB~q t  :߃!{b{'׸`9+TcG%`'?h/#E?bhX+_pvآ,DG'p 31 A YzT7> endstream endobj 435 0 obj <> endobj 436 0 obj <> endobj 437 0 obj <> /ProcSet[/PDF/Text/ImageC/ImageI/ImageB] >> endobj 1 0 obj <>/Contents 2 0 R>> endobj 6 0 obj <>/Contents 7 0 R>> endobj 9 0 obj <>/Contents 10 0 R>> endobj 12 0 obj <>/Contents 13 0 R>> endobj 15 0 obj <>/Contents 16 0 R>> endobj 18 0 obj <>/Contents 19 0 R>> endobj 21 0 obj <>/Contents 22 0 R>> endobj 24 0 obj <>/Contents 25 0 R>> endobj 27 0 obj <>/Contents 28 0 R>> endobj 30 0 obj <>/Contents 31 0 R>> endobj 33 0 obj <>/Contents 34 0 R>> endobj 36 0 obj <>/Contents 37 0 R>> endobj 39 0 obj <>/Contents 40 0 R>> endobj 42 0 obj <>/Contents 43 0 R>> endobj 45 0 obj <>/Contents 46 0 R>> endobj 48 0 obj <>/Contents 49 0 R>> endobj 51 0 obj <>/Contents 52 0 R>> endobj 54 0 obj <>/Contents 55 0 R>> endobj 57 0 obj <>/Contents 58 0 R>> endobj 60 0 obj <>/Contents 61 0 R>> endobj 63 0 obj <>/Contents 64 0 R>> endobj 66 0 obj <>/Contents 67 0 R>> endobj 69 0 obj <>/Contents 70 0 R>> endobj 72 0 obj <>/Contents 73 0 R>> endobj 75 0 obj <>/Contents 76 0 R>> endobj 78 0 obj <>/Contents 79 0 R>> endobj 81 0 obj <>/Contents 82 0 R>> endobj 84 0 obj <>/Contents 85 0 R>> endobj 87 0 obj <>/Contents 88 0 R>> endobj 90 0 obj <>/Contents 91 0 R>> endobj 93 0 obj <>/Contents 94 0 R>> endobj 96 0 obj <>/Contents 97 0 R>> endobj 99 0 obj <>/Contents 100 0 R>> endobj 102 0 obj <>/Contents 103 0 R>> endobj 105 0 obj <>/Contents 106 0 R>> endobj 108 0 obj <>/Contents 109 0 R>> endobj 111 0 obj <>/Contents 112 0 R>> endobj 114 0 obj <>/Contents 115 0 R>> endobj 117 0 obj <>/Contents 118 0 R>> endobj 120 0 obj <>/Contents 121 0 R>> endobj 123 0 obj <>/Contents 124 0 R>> endobj 126 0 obj <>/Contents 127 0 R>> endobj 129 0 obj <>/Contents 130 0 R>> endobj 132 0 obj <>/Contents 133 0 R>> endobj 135 0 obj <>/Contents 136 0 R>> endobj 138 0 obj <>/Contents 139 0 R>> endobj 141 0 obj <>/Contents 142 0 R>> endobj 144 0 obj <>/Contents 145 0 R>> endobj 147 0 obj <>/Contents 148 0 R>> endobj 150 0 obj <>/Contents 151 0 R>> endobj 153 0 obj <>/Contents 154 0 R>> endobj 156 0 obj <>/Contents 157 0 R>> endobj 159 0 obj <>/Contents 160 0 R>> endobj 162 0 obj <>/Contents 163 0 R>> endobj 165 0 obj <>/Contents 166 0 R>> endobj 168 0 obj <>/Contents 169 0 R>> endobj 171 0 obj <>/Contents 172 0 R>> endobj 174 0 obj <>/Contents 175 0 R>> endobj 177 0 obj <>/Contents 178 0 R>> endobj 180 0 obj <>/Contents 181 0 R>> endobj 183 0 obj <>/Contents 184 0 R>> endobj 186 0 obj <>/Contents 187 0 R>> endobj 189 0 obj <>/Contents 190 0 R>> endobj 194 0 obj <>/Contents 195 0 R>> endobj 197 0 obj <>/Contents 198 0 R>> endobj 200 0 obj <>/Contents 201 0 R>> endobj 203 0 obj <>/Contents 204 0 R>> endobj 208 0 obj <>/Contents 209 0 R>> endobj 211 0 obj <>/Contents 212 0 R>> endobj 214 0 obj <>/Contents 215 0 R>> endobj 217 0 obj <>/Contents 218 0 R>> endobj 220 0 obj <>/Contents 221 0 R>> endobj 223 0 obj <>/Contents 224 0 R>> endobj 228 0 obj <>/Contents 229 0 R>> endobj 233 0 obj <>/Contents 234 0 R>> endobj 236 0 obj <>/Contents 237 0 R>> endobj 239 0 obj <>/Contents 240 0 R>> endobj 242 0 obj <>/Contents 243 0 R>> endobj 245 0 obj <>/Contents 246 0 R>> endobj 248 0 obj <>/Contents 249 0 R>> endobj 251 0 obj <>/Contents 252 0 R>> endobj 258 0 obj <>/Contents 259 0 R>> endobj 263 0 obj <>/Contents 264 0 R>> endobj 266 0 obj <>/Contents 267 0 R>> endobj 269 0 obj <>/Contents 270 0 R>> endobj 272 0 obj <>/Contents 273 0 R>> endobj 279 0 obj <>/Contents 280 0 R>> endobj 290 0 obj <>/Contents 291 0 R>> endobj 293 0 obj <>/Contents 294 0 R>> endobj 298 0 obj <>/Contents 299 0 R>> endobj 303 0 obj <>/Contents 304 0 R>> endobj 306 0 obj <>/Contents 307 0 R>> endobj 309 0 obj <>/Contents 310 0 R>> endobj 314 0 obj <>/Contents 315 0 R>> endobj 317 0 obj <>/Contents 318 0 R>> endobj 320 0 obj <>/Contents 321 0 R>> endobj 323 0 obj <>/Contents 324 0 R>> endobj 326 0 obj <>/Contents 327 0 R>> endobj 329 0 obj <>/Contents 330 0 R>> endobj 332 0 obj <>/Contents 333 0 R>> endobj 335 0 obj <>/Contents 336 0 R>> endobj 340 0 obj <>/Contents 341 0 R>> endobj 345 0 obj <>/Contents 346 0 R>> endobj 350 0 obj <>/Contents 351 0 R>> endobj 355 0 obj <>/Contents 356 0 R>> endobj 358 0 obj <>/Contents 359 0 R>> endobj 361 0 obj <>/Contents 362 0 R>> endobj 366 0 obj <>/Contents 367 0 R>> endobj 369 0 obj <>/Contents 370 0 R>> endobj 372 0 obj <>/Contents 373 0 R>> endobj 377 0 obj <>/Contents 378 0 R>> endobj 380 0 obj <>/Contents 381 0 R>> endobj 383 0 obj <>/Contents 384 0 R>> endobj 386 0 obj <>/Contents 387 0 R>> endobj 389 0 obj <>/Contents 390 0 R>> endobj 392 0 obj <>/Contents 393 0 R>> endobj 395 0 obj <>/Contents 396 0 R>> endobj 398 0 obj <>/Contents 399 0 R>> endobj 401 0 obj <>/Contents 402 0 R>> endobj 406 0 obj <>/Contents 407 0 R>> endobj 409 0 obj <>/Contents 410 0 R>> endobj 412 0 obj <>/Contents 413 0 R>> endobj 415 0 obj <> endobj 438 0 obj <> >> endobj 439 0 obj < /Author /Creator /Producer /CreationDate(D:20080229120943-06'00')>> endobj xref 0 440 0000000000 65535 f 0000636210 00000 n 0000000019 00000 n 0000000427 00000 n 0000079276 00000 n 0000000447 00000 n 0000636356 00000 n 0000095090 00000 n 0000095557 00000 n 0000636502 00000 n 0000095577 00000 n 0000096221 00000 n 0000636649 00000 n 0000096242 00000 n 0000097028 00000 n 0000636797 00000 n 0000097049 00000 n 0000097734 00000 n 0000636945 00000 n 0000097755 00000 n 0000098395 00000 n 0000637093 00000 n 0000098416 00000 n 0000099341 00000 n 0000637241 00000 n 0000099362 00000 n 0000099912 00000 n 0000637389 00000 n 0000099933 00000 n 0000100777 00000 n 0000637537 00000 n 0000100798 00000 n 0000101383 00000 n 0000637685 00000 n 0000101404 00000 n 0000102106 00000 n 0000637833 00000 n 0000102127 00000 n 0000102810 00000 n 0000637981 00000 n 0000102831 00000 n 0000103590 00000 n 0000638129 00000 n 0000103611 00000 n 0000104406 00000 n 0000638277 00000 n 0000104427 00000 n 0000105085 00000 n 0000638425 00000 n 0000105106 00000 n 0000105850 00000 n 0000638573 00000 n 0000105871 00000 n 0000106473 00000 n 0000638721 00000 n 0000106494 00000 n 0000107018 00000 n 0000638869 00000 n 0000107039 00000 n 0000108281 00000 n 0000639017 00000 n 0000108303 00000 n 0000109544 00000 n 0000639165 00000 n 0000109566 00000 n 0000110388 00000 n 0000639313 00000 n 0000110409 00000 n 0000111536 00000 n 0000639461 00000 n 0000111558 00000 n 0000112488 00000 n 0000639609 00000 n 0000112509 00000 n 0000113828 00000 n 0000639757 00000 n 0000113850 00000 n 0000114898 00000 n 0000639905 00000 n 0000114919 00000 n 0000116428 00000 n 0000640053 00000 n 0000116450 00000 n 0000117741 00000 n 0000640201 00000 n 0000117763 00000 n 0000119097 00000 n 0000640349 00000 n 0000119119 00000 n 0000120042 00000 n 0000640497 00000 n 0000120063 00000 n 0000120622 00000 n 0000640645 00000 n 0000120643 00000 n 0000121493 00000 n 0000640793 00000 n 0000121514 00000 n 0000123149 00000 n 0000640941 00000 n 0000123171 00000 n 0000124597 00000 n 0000641090 00000 n 0000124620 00000 n 0000126075 00000 n 0000641240 00000 n 0000126098 00000 n 0000127161 00000 n 0000641390 00000 n 0000127183 00000 n 0000128547 00000 n 0000641540 00000 n 0000128570 00000 n 0000129459 00000 n 0000641690 00000 n 0000129481 00000 n 0000130150 00000 n 0000641840 00000 n 0000130172 00000 n 0000131075 00000 n 0000641990 00000 n 0000131097 00000 n 0000132093 00000 n 0000642140 00000 n 0000132115 00000 n 0000133168 00000 n 0000642290 00000 n 0000133190 00000 n 0000134407 00000 n 0000642440 00000 n 0000134430 00000 n 0000135259 00000 n 0000642590 00000 n 0000135281 00000 n 0000136024 00000 n 0000642740 00000 n 0000136046 00000 n 0000137151 00000 n 0000642890 00000 n 0000137174 00000 n 0000139312 00000 n 0000643040 00000 n 0000139335 00000 n 0000140571 00000 n 0000643190 00000 n 0000140594 00000 n 0000141449 00000 n 0000643340 00000 n 0000141471 00000 n 0000142313 00000 n 0000643490 00000 n 0000142335 00000 n 0000143214 00000 n 0000643640 00000 n 0000143236 00000 n 0000144196 00000 n 0000643790 00000 n 0000144218 00000 n 0000145147 00000 n 0000643940 00000 n 0000145169 00000 n 0000145779 00000 n 0000644090 00000 n 0000145801 00000 n 0000146961 00000 n 0000644240 00000 n 0000146984 00000 n 0000148063 00000 n 0000644390 00000 n 0000148086 00000 n 0000149485 00000 n 0000644540 00000 n 0000149508 00000 n 0000150904 00000 n 0000644690 00000 n 0000150927 00000 n 0000157201 00000 n 0000644840 00000 n 0000157224 00000 n 0000157990 00000 n 0000644990 00000 n 0000158012 00000 n 0000159022 00000 n 0000645140 00000 n 0000159044 00000 n 0000160018 00000 n 0000645290 00000 n 0000160040 00000 n 0000161135 00000 n 0000645440 00000 n 0000161158 00000 n 0000161626 00000 n 0000161648 00000 n 0000172042 00000 n 0000645590 00000 n 0000172066 00000 n 0000174141 00000 n 0000645740 00000 n 0000174164 00000 n 0000174964 00000 n 0000645890 00000 n 0000174986 00000 n 0000176047 00000 n 0000646040 00000 n 0000176069 00000 n 0000176958 00000 n 0000176980 00000 n 0000186814 00000 n 0000646190 00000 n 0000186837 00000 n 0000187672 00000 n 0000646340 00000 n 0000187694 00000 n 0000188563 00000 n 0000646490 00000 n 0000188585 00000 n 0000189529 00000 n 0000646640 00000 n 0000189551 00000 n 0000190799 00000 n 0000646790 00000 n 0000190822 00000 n 0000192126 00000 n 0000646940 00000 n 0000192149 00000 n 0000192867 00000 n 0000192889 00000 n 0000204601 00000 n 0000647090 00000 n 0000204625 00000 n 0000205455 00000 n 0000205477 00000 n 0000214931 00000 n 0000647240 00000 n 0000214954 00000 n 0000216201 00000 n 0000647390 00000 n 0000216224 00000 n 0000217674 00000 n 0000647540 00000 n 0000217697 00000 n 0000218992 00000 n 0000647690 00000 n 0000219015 00000 n 0000220437 00000 n 0000647840 00000 n 0000220460 00000 n 0000221270 00000 n 0000647990 00000 n 0000221292 00000 n 0000222324 00000 n 0000648140 00000 n 0000222346 00000 n 0000223719 00000 n 0000230588 00000 n 0000223742 00000 n 0000230565 00000 n 0000238510 00000 n 0000648290 00000 n 0000238533 00000 n 0000239740 00000 n 0000239763 00000 n 0000248441 00000 n 0000648440 00000 n 0000248464 00000 n 0000249517 00000 n 0000648590 00000 n 0000249539 00000 n 0000251032 00000 n 0000648740 00000 n 0000251055 00000 n 0000251964 00000 n 0000648890 00000 n 0000251986 00000 n 0000253029 00000 n 0000259869 00000 n 0000253051 00000 n 0000259846 00000 n 0000266670 00000 n 0000649040 00000 n 0000266693 00000 n 0000268693 00000 n 0000290987 00000 n 0000284912 00000 n 0000276925 00000 n 0000268716 00000 n 0000276902 00000 n 0000284889 00000 n 0000290964 00000 n 0000298772 00000 n 0000649190 00000 n 0000298795 00000 n 0000300642 00000 n 0000649340 00000 n 0000300665 00000 n 0000301048 00000 n 0000301070 00000 n 0000336517 00000 n 0000649490 00000 n 0000336541 00000 n 0000337916 00000 n 0000337939 00000 n 0000346611 00000 n 0000649640 00000 n 0000346634 00000 n 0000347534 00000 n 0000649790 00000 n 0000347556 00000 n 0000349071 00000 n 0000649940 00000 n 0000349094 00000 n 0000349507 00000 n 0000349529 00000 n 0000374288 00000 n 0000650090 00000 n 0000374312 00000 n 0000375787 00000 n 0000650240 00000 n 0000375810 00000 n 0000377716 00000 n 0000650390 00000 n 0000377739 00000 n 0000379058 00000 n 0000650540 00000 n 0000379081 00000 n 0000380629 00000 n 0000650690 00000 n 0000380652 00000 n 0000381542 00000 n 0000650840 00000 n 0000381564 00000 n 0000382549 00000 n 0000650990 00000 n 0000382571 00000 n 0000384007 00000 n 0000651140 00000 n 0000384030 00000 n 0000384916 00000 n 0000384938 00000 n 0000391284 00000 n 0000651290 00000 n 0000391307 00000 n 0000392156 00000 n 0000392178 00000 n 0000402098 00000 n 0000651440 00000 n 0000402121 00000 n 0000402943 00000 n 0000402965 00000 n 0000412832 00000 n 0000651590 00000 n 0000412855 00000 n 0000413919 00000 n 0000413941 00000 n 0000441964 00000 n 0000651740 00000 n 0000441988 00000 n 0000443096 00000 n 0000651890 00000 n 0000443119 00000 n 0000445096 00000 n 0000652040 00000 n 0000445119 00000 n 0000445529 00000 n 0000445551 00000 n 0000459899 00000 n 0000652190 00000 n 0000459923 00000 n 0000460935 00000 n 0000652340 00000 n 0000460957 00000 n 0000462216 00000 n 0000652490 00000 n 0000462239 00000 n 0000462709 00000 n 0000462731 00000 n 0000521523 00000 n 0000652640 00000 n 0000521547 00000 n 0000522619 00000 n 0000652790 00000 n 0000522641 00000 n 0000524101 00000 n 0000652940 00000 n 0000524124 00000 n 0000525325 00000 n 0000653090 00000 n 0000525348 00000 n 0000526543 00000 n 0000653240 00000 n 0000526566 00000 n 0000528209 00000 n 0000653390 00000 n 0000528232 00000 n 0000529247 00000 n 0000653540 00000 n 0000529269 00000 n 0000530570 00000 n 0000653690 00000 n 0000530593 00000 n 0000531388 00000 n 0000653840 00000 n 0000531410 00000 n 0000531794 00000 n 0000531816 00000 n 0000547783 00000 n 0000653990 00000 n 0000547807 00000 n 0000548712 00000 n 0000654140 00000 n 0000548734 00000 n 0000549915 00000 n 0000654290 00000 n 0000549938 00000 n 0000551038 00000 n 0000654440 00000 n 0000551061 00000 n 0000566973 00000 n 0000566997 00000 n 0000567202 00000 n 0000567621 00000 n 0000567902 00000 n 0000589099 00000 n 0000589123 00000 n 0000589319 00000 n 0000589881 00000 n 0000590288 00000 n 0000603713 00000 n 0000603737 00000 n 0000603936 00000 n 0000604378 00000 n 0000604675 00000 n 0000634291 00000 n 0000634315 00000 n 0000634506 00000 n 0000635186 00000 n 0000635706 00000 n 0000635774 00000 n 0000655478 00000 n 0000655630 00000 n trailer < ] /DocChecksum /1693DFC9B750B3F896CF468A1AF48A0B >> startxref 655953 %%EOF traitsui-4.1.0/docs/Makefile0000644000175100001440000001077211674463545016757 0ustar ischnellusers00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = build # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " text to make text files" @echo " man to make manual pages" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: -rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/traitsui.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/traitsui.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/traitsui" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/traitsui" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." make -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." traitsui-4.1.0/docs/traits_ui.ppt0000644000175100001440000721600011674463545020046 0ustar ischnellusers00000000000000ࡱ>    {F؛ Rz 8ݎJFIF``ExifMM*bj(1r2i``Adobe Photoshop 7.02004:08:31 17:31:47jS(&HHJFIFHH Adobe_CMAdobed            `"?   3!1AQa"q2B#$Rb34rC%Scs5&DTdE£t6UeuF'Vfv7GWgw5!1AQaq"2B#R3$brCScs4%&5DTdEU6teuFVfv'7GWgw ?o _yE/k~b+ؒRca|w߭_mW$?{0;o _yE/k~b+ؒKߟv_g/"?Ňֱw^?x=};b([}h% #b-_*o9#Q?IzH'شffi?vO^?}_oܰXGlt%!?d_}TI%)$IJI$RI$I%)$IJI$RI$TI%)$IJI$RI$I%)$IJI$RI$TI%)$IJI$RI$I%)$IJI$RI$TI%)$IJI$RI$I%)$IJI$RI$T?=x2.}7DIy}|2.?s{2C?7eЇr}#$o(ޔ߻dW}s>s5ޕ6>|nC؟}}^G֏mIvR^>Kqitײuc:l-k63{l~Neme6Xv}5Kr,czP/$~ϒFH9`4I n6Q$~!>a Photoshop 3.08BIM8BIM%F &Vڰw8BIM``8BIM&?8BIM 8BIM8BIM 8BIM 8BIM' 8BIMH/fflff/ff2Z5-8BIMp8BIM8BIM8BIM@@8BIM8BIMYSjblue_blue_gradientjSnullboundsObjcRct1Top longLeftlongBtomlongSRghtlongjslicesVlLsObjcslicesliceIDlonggroupIDlongoriginenum ESliceOrigin autoGeneratedTypeenum ESliceTypeImg boundsObjcRct1Top longLeftlongBtomlongSRghtlongjurlTEXTnullTEXTMsgeTEXTaltTagTEXTcellTextIsHTMLboolcellTextTEXT horzAlignenumESliceHorzAligndefault vertAlignenumESliceVertAligndefault bgColorTypeenumESliceBGColorTypeNone topOutsetlong leftOutsetlong bottomOutsetlong rightOutsetlong8BIM8BIM8BIM `JFIFHH Adobe_CMAdobed            `"?   3!1AQa"q2B#$Rb34rC%Scs5&DTdE£t6UeuF'Vfv7GWgw5!1AQaq"2B#R3$brCScs4%&5DTdEU6teuFVfv'7GWgw ?o _yE/k~b+ؒRca|w߭_mW$?{0;o _yE/k~b+ؒKߟv_g/"?Ňֱw^?x=};b([}h% #b-_*o9#Q?IzH'شffi?vO^?}_oܰXGlt%!?d_}TI%)$IJI$RI$I%)$IJI$RI$TI%)$IJI$RI$I%)$IJI$RI$TI%)$IJI$RI$I%)$IJI$RI$TI%)$IJI$RI$I%)$IJI$RI$T?=x2.}7DIy}|2.?s{2C?7eЇr}#$o(ޔ߻dW}s>s5ޕ6>|nC؟}}^G֏mIvR^>Kqitײuc:l-k63{l~Neme6Xv}5Kr,czP/$~ϒFH9`4I n6Q$~!>a8BIM!UAdobe PhotoshopAdobe Photoshop 7.08BIMHhttp://ns.adobe.com/xap/1.0/ adobe:docid:photoshop:7ede65d5-fb9d-11d8-b5b7-f5f4d0bff19a Adobed@Sj     u!"1A2# QBa$3Rqb%C&4r 5'S6DTsEF7Gc(UVWdte)8fu*9:HIJXYZghijvwxyzm!1"AQ2aqB#Rb3 $Cr4%ScD&5T6Ed' sFtUeuV7)(GWf8vgwHXhx9IYiy*:JZjz ?eu{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ]~s=s{z~?d5}OY}}:?؟ݺAǻ~^]e⟏{>}T笋#ݺYGk=|YGu u_uvy(=k:̿ꇬ>:0}}u_N/k݇T=eSz?[Gê/?Cꇬ:2}=uCeOY=PΨzο_v:3ePaP:e}zοYk}=ھ~}PӬz:aMuo:q}}pꆹ2{q:a:ο[Mu~::wPOT=g_Osu}M׏_wT=H_w6zο゚?vP~{}~u}wBǻCua}Gxyoqg׬:8{uzξ:l=fQ˪u~?T>H_vꧬ-|:_Ce{oY_qꇬo>z̿~T>}f_ϻuC_>T=g?U=e_uC}}۪p*Ӫ=۪/3AuS}ꦝe?ᄒNz?݇T }OqQ_OuSAh }g=Sb{Z=uSA??zYS~kuW\Oݺ\ueu{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ]~rO_{]kY>:?ȇ^׏{Ӭ)z?Ͻz?}1o?zʿTovX=e_OvT"}?O{0ažGYcU8YT*}nP-ֽTq}Pz?^:z̿}>z̿ϻz̿6}ϻy|0}ǗU>}fê/OӪYΨzξ:eaYqN:οv6z̿zο[Tx{t:aYOYE:lǻzο݇T4:}ߦzοO˪<:̿{ꇩ Ϭ:ꇩ #qY}ǻ:covuCuqOY~?ߦBqg?ꇬ_U>H_o{6|οnz̶`zY}ǻCu?q>:lgQS݇T>2|:[T9:mw]Pf_3ͽuCe}a:uva _x<ꧬ{#ݺ0}?޹q Ϭ?_݇T'=fw}PG_vTxnNg'/ϻzovu[|9a^e_~]T~=uSE>: }ݺ([qaOꧬz?MOv1֏Y˪1m]dcU?ˮc{Z뗽eu{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ]!G߇z?=u_Yu^ aG?uR8_aOY[v/V<ּʿ{z(6oaOϬz̿w{aYGﯻz?_uC^/OxuqYWqOYGǻzΣ${NoYݽ=z:?{T=f_vꇬǻ|:?e_ovum~γ˪o݇MN+Ywꇩ/ꇎzο/T=f_wz:[m݇Mԅ}'{{]P:݇T=g_kzο~>Ba"{ꇬqzο[݇MY{}P#ǷT>}g_ſ}a:η}!6_ǗT?>(xfg[??ORqgm>:e?zlumcêYn=fSczu=ߦY?qYuCu:̿::agU5U?޽ߪOagϬz?\݇T=f_aOY:YGêlut yoNqUogU?> vꧬ}=Píu}?Sc7תeYG}u^#_ݺ?[ݺu}>_゙kS1O۞ꧮb}kreu{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ]r>O\kS_}|}uSAa֏YݳOY׻PyS?{U }W*|??T=d힪z?=uSEa=۪oϻuOZu?:YGlm?pu~~1Y)}z2?vSe^>?Ǫ{vP?އS\텯uCa.z-P׬U=f_Ev6YSYuCeo)uquCua[݅=z:ǻ Cuc6z̿￯)Nv::ǻiu?O݇T8<:̿?PxooCuo:Y{nuÇ{]TӬ{5SPuovPQꧬßyYk݇T9zʿ}ϻc꧇Y$T>}e_OYGߏwS)cR:?s~{z*aYG{u${kb{ꇇYG]dz?{Yn=۪WcǻuY=T.}:?{Zeu{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ]߽1|?s}kcUz爵dnz?U#1oϽӪ}>: #]WYGu^s_{U#YW)Sa?:Y݇T4f8CQ݇Z*{.-sP㬣aƝPҝf_quSe=uCeaY:2^=|U=g_tWYvU52ߟAϻSeya::>qgYê/T=g_v˪M޽pꇬ{ꇬcP~:ou#PG޽SCqꇬ=uCu}eꇩ :ο?wS^xCq^˩ ϻ2ۃ˦x!x|~݆zYzοæYǻzΧ=z@z}=zl>::+_>ov6YT=g_P:e~~=H_}uCe__vT:?=e[::ο_vSfO}Ps݇T=e_~zο8OvꇬuCU_wCe}nz?~?:*'ݩ0?OU=e_?wT[#YݫOYW?}uSa펩E}ov}T=dA?sEa݆~ޫ0}=s}=nAv>z/I o=}??}G`[ݺ]wo}>׺ԡm_3x_I[??>^|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/׿%n߿|G/׿|F/cj1?J'X{_/ V7_Ck1?J'X{_/ V@=s[WAd?Yx.Z/0^ k1qr T݇2r<_Zs[[yxO{˿]h1l_l1ooK=˿~]T1?{8%z?c_{r?e9c~pK@-+x SIgo/.e9g?韾skq8OIg/.gx.YOgYb4'b}˟Yx.ycc>yS?雿y¿f/}oO,Gae}T47<YGa?2;a<MEAO47<YGa_2[v_cOvD_UO3[@uG?{r8oW+Iae}T53<Yt0oOL=Gkoi,?/S.Y?o/́ݟ;#ݿ|M&e}T5Uɦ:̿˯_L]?Io_+KD?U<nM7U] [7vvr4CAC<Lde˷~~ d=sg*ȗo>yC?ow0L}so*ML?U<Ϳ4i/x3n<{UQ?Ldf_܍|ÿ+/tovʟS'w2ە?o |gWn?i)꧓#Sy:ʿ0}s)OL?T<\4Yx;I? 9ۿSyMg:ο?{'eۿL?Mʿ?e^>_4?ߝ9Kalg8),YGx?I o(SL?Uy+e_=?]ePm>y+GsY/?I>]6/a9˔?I?dw?%+|O'ves'WTT<·ug}g_wr?ϛ6*ꇒ9 g}e__xwUlꇑ9.?_YOΏ?Nw]/ʠTy3v\־/?,?{w_Wl꧐?_YoQexÞ9+ P<k* ?LW;v@v_mWo[:zo#}g_8 VoSs$epΨy|xk^;wǻz;epΪy[~6WnT?93#gMo?_YoOǞCÞ#-gU>1־7~|y{l+P}ϹFdwÏ#-a|Mevo?_YoGm׾Gi??~ '*?ow?Wo[:?|xwIs}s#g]lx+U3`ܞ|}}eo9mȮ_YW͏ߔ}~9k=nˑ"}f_5?R?vb^~_m6,Tw0\־ߚ'lK݇?r&kelۿp|y+aw@G?;`ßϝv,Tu0\֮4~Q^9??uS׸?o?EsZ̿i a!mel۟pu| x~?o?m,Ts0{\֮/?CN=>?}-gU[p =ȮWY?'k'Yo[:{Ld7?/ o!;em zAw/Oݿ?uSo_CsZ>F; ڿ{ uSo_CsZȿ f#'j?T>xuSzAg?ɿ= ڿ{?uSCuZ>|H9?{ ?u_ nWY__R~MnP[Ǹ|Met ֮?2Wɯn5}{[m[:o`7!]d d%| ;Wnv-Ti?0֮2??Lx |~nvo-hi?0֮1L?}q=[7Ϊ} nW\Ϙ&|_^G[7δ}?!]s >c&_ݿno-Wl?/!]s ~b&VW߿no-kl j]7hGiO5q}fo֏~>?u|.x_ҽmoZ>{|/Kb'|?{}MeO ]ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^ӹ "/y_coan]q?;ܟ|d9u|c:u‰r}o?|c9u‰/B>ocoo o_n]q?ܞ|b:rf G޿Nˮ"/Bco{ ?_n]p6!'f?wg 1:ك_(f?wg 3'zG1ηs?.Q'?0/?ܺF8م_)f_Շ/?ܺG67ن_*f_׿yg ;ɿ7zS2s?.QMa{ }ٗ.? a{ ̿wϮ'oOA߿W̿ﭏs?>R-Lb?uc2s>>R=Lb ?}ٗ >>RULb{ _}ٗ >>RmL?b_-f_տn}p?ܗf/O^`”r_#ޏw2?}n}p?kܖ/{cc_K,ٌ/f ϿϮo@޿a]۟\)z%1/=t/=NS Jc{fՇ޳ ?=NSJ/@'go]o 0:L'ِ _2fտӮoo@7go]o 1?:M%ّ_3fՇޛ O=NSI/%Oݢٟu{np?+ܑjgo]X}:7ۧX)$_e)޿kE7ۧX)$?2[ <NSH?eu?4ynp?o@~?=GۯX*#2_io=X}+:OۯX*#3_io=l}:Oۯ\*$W_9Sw4?ynp?܍w4_ync?܌x٧o%*_ۯ\*J#3_io=[ _2zRٛ{_Oy'_zS ܋_.s޿xÿ#gۯ\*r"3^~?w٧o$?uO3>ko=oΛg3 =ǽ?n_y_ݺT\ǽwVxΝg ȇo[/ ;nUeCh?]_yDg w ݽ`?_xDg3 g`;gV :nUBGG?;?:Wu:nUͿBh]= O:hu®rI _[x*Σg_3 G/޿6_unp?/oW#_WV_4X٦r>?uٷuOο߮o_WuX:: ?:~VUA?j?\}boxۿX+6 5Ϳ~whX*VzX:?:g? ӷ [coՇW߮oVzX9UwlW_!?~kFٷwۿ\O+~OVzY/9_߬googo]g?î'ow_8/~=c\+OVzYo9c\O+OV~Yo9o9p?>kZo]gîo͇Wo]gîo͇Oo]gî'o͏Go]gîٲhÏV^6uz{Ǐoy f՟߿s/7{y f՟޿{/7l{_u¿mtٳgËnnpi_?nnp[i_AP{x k_APox f՗߿և]gǮ?7 f՗CPox??{;՗֋]U\0wͷ'Cu{?;m8Ãnogk¿]6p{ \zٷdÃno׿0wͿ'Cu{A໿mY=hۯ_ +oGP{wǯa_.VO~Z?8?vW={ w{T?^]7qW fՓ߿֏]U^¿]6p׿{ \zٷdÃno׿0wͿ'Cu{A໿mY=hۯ_ +oGP{wǯa_.VO~Z?8?vW={ w{T?^]7qW fՓ߿֏]U^¿]6p׿{ \zٷdÃno׿0wͿ'Cu{A໿mY=hۯ_ +oGP{wǯa_.VO~Z?8?vW={ w{T?^]7qW fՓ߿֏]U^¿]6p׿{ \zٷdÃno׿0wͿ'Cu{E *LҢ7l|e+abY7C^XGCǻϗ=e*?}ip^Lˣ ?%5=wraFGx7 4K<ԟ5Feo$xv!,wd }۶։/^CE ٸ|^w%yFiR1V+)4ytT¿k~Vzϔ+K[C]K#CUE[IQ:JYH$n`R2*EAHݯ ?.af=b*?}ip^L˯`oDξG8?^]|׿0|wJ_~ZFׯ>?r>;[Qs#׿u?u zҨ߿֑?u뺿ϟ\|VTAH_g]{޾+ uo?]z3s.A_U:7{wW9^*?}ip^L˯`oDξG8?^]|׿0|wJ_~ZFׯ>?r>;[Qs#׿u?u zҨ߿֑?u뺿ϟ\|VTAH_g]{޾+ uo?]z3s.A_U:7{wW9^*?}ip^L˯`oDξG8?^]|׿0|wJ_~ZFׯ>?r޿k[ʎ?OW?֝8i~m\(gc'?~Oz?oVޱ8<ՇXuìg}}nz6?﾿zX>zoX3ՇX߽}XcMӫub?lz ^:zXO{uqìGGۏu=Xu\yzu}yOu4Wak[5{Vao_q}ǺVao`?_Ϻ?X[5Nz }ӃuSՀ }>G`s^:[Wxu_OW~}Ǻ>ްqS Ӄuq}ot=\u޿9zȿl}Ӭ }\uaXg}}qCӃ Ou=Yz[ X[a u"m\u[:puG9ˬ-zqӟWՇQ۟ Suq?aoN Waoďu=О#1GQ7gW3_#OVbks.1a•Xaպo|Wc?Oz=l|)unzX׏Ϻaz=Xp}|=:돽u{{^׺u{{^׺u{{^׺u{{^׺u{{^׺u{{^׺u{{^R鞐=ꮉM.qKd37 Z GR -=mdR@(o{딊xzOK,vti&nA?q=nG?+ivPaSk\~+fN?rZeb&IOMGBb`=Ķ![?LaO/鎮O?gWzpͽ.)Ar]]ecw/1 sh̴8 txڪ69yb^hUr1TTzɇkGܵ>%h$LhQ9G?A^{{^׺u{{^׺u{{^׺u{{^׺u{a(gc-zx=~~=׫>վ}p?޿u3?Sպ}u{Vb?[ޏVcn/[g?&ìG޺Ni?ՇX:{'޸u&>uq[Wa?>u=X|_ϫXSX[WWaouˬ-EyCX[ou=\7t=8Xz{_9SQ׺zSӃuN}n1?Ў1_uzpp8XC_ zmXOϫ>y?s">zpzX[{C }qN7CӋvCX[D}Qx{W`o<﾿q?A\zu'OW;}?ߺ=8:>}[-l}mX{Waot=\WaoO˫u>ì \u}{aou?>:ߟ5uq}?OtVaoǎ=.:xo'u>Xt=XuW=b?~z iX5׫0}#zߏuXǽua6}ޱՇXXu{Vy[kX[_ޫՇucpî/z=[Ӯu~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ^׽u~{ߺ[sx>L yogp4۳]hq Z(7T)kh Yfvws>]1DX6,8T!v`Lo]uS$ ƀ@$U?w(ʜFrrnt« t%8 >E(0qҿ'@@v@e 5ŭytp7[n,lOZ+:O{q|Tkߚu񛨷_jn9'כPĴ[Kl\ߙ)6ڀ5jIb$FU#=x6h vGL~J'o@e7;}c@?2=8K?ʶp|ﯖ9nCoTM/.`o+H3ޢG bJ@A`l,,vv.t梤;r'XVܡ1MT9'99tn΍3]ÐnNL,)CvrW lujΒm^^L^R`F|a~Uoe*fn$"V:?E@a֊y\Fc)AVW![c!h|]=&3A 54Q`$j T"h2I8'$OP[wg T3:o7_Jw_se~G˚퓹?1}AEW9 "dmYY",y%/kasG5I̛˳ŷm4frHu xANy\rѼn_:F)k!jJl^ݤ)gxGx7IdIz#T.j,tIuTu$gl$bEjHJtB8M̠8 Pժz18?.^Lw{utj; 5]MeQmuJijY3$_oݢH7"I!%QQ=FFQ Ӑ?.m1c[H8`:BTO[߹7jcz1U[Cg>Kt͵%:T*׭5I)\u6 X^sx2AP1e'~8a^PqLP+v`v@i~uf󬪢mGƫ#-(ή.^awkmv2Jֵ:{N:|6s%E F5M?)<( Z}(rzg5fޓi㲸-E&lg5Q<4s"kܱ.ѵl7 nnUHtQ/;maqrPڴIMe& *̀+=wG}!z{"so;hdpb6ܸ[ev/sXx:HQl0El7IuT Հ8 '͋'7M ݃2$ ЎʲO?5~Z?# wiwlro,e7m肆4A"}Ϛ?vlUٶw;AKQA>PH9VֿSmvn$(@ N :_>ѐiuzwt~I 619\G?|}d*bwN~ͪKE8ټEQC@ts7.ivN@1P`+릞g͋y-Yӷnnu[6͏6~Y; B*%1D{.s҈# @M*X2O;G($sjK)~t_l%h7%sn|%}^#A墥O54,l8#/eS4P3kBUI7{ 2̈HhA?궗L|r ԟ:lbp5-͹[M1vG0tP #f1S<<-9_o/`ypXң[4 PTT:Sv[9AGҋM8 :A_|^~j-FRdy֔QCp Ijl|TL55b{E,XvJqէW˥ ;!<0kLt5=ˋl|{7 to^n޶힕?f>8 j`ܙZ>tKQ,h +ȿypv}pK4y$:V$UX 軗onݷokז wtxu*Iqdžz/˳K;:^vGEAvz]Ż6fSobl*KA*2T l.gKRKjpO=wTfZE q8Q}__1z[jڵ]=o~GGIⶮzL]lɘI{5L۩EE Hll˛ea5&FeFU`zwZ6,{n'4{=+Džd|s$G. [ϣcK(j=sV.r~ƷV[xw%TPThj+O8uE'O"c7q@u(gc(oϿuǮ{}p#޺ϬGOzߟXu8c7c6Xqc?½b?s]Xu??zì,>sX.z Qu?z t4}a>zȿ~ou~}׫}u'7~z[kuq}8>ް_u=o-"C uza^゙zsoϫ ]\u_׺:7^ t=Xu>iӞ|:3Ǭ-?Gnt>}8>}aoW}q\Ot=\|?q>7q8:zXӃ p>7{:=q?v{ՇX}sq:pyu?_t=\uǺN8?t=\|Ot=8Xt=Xu=aaOW`o߁N7/u=[-ÏN ?~z?.C^>ΰ8Sӝ`?zX[CXxWXaaoᄒ~ޮ::[gս:z\oG}=ua3{V:މ}u]o{^׺u{{^׺u{{^׺u{{^׺u{{^׺u{{^׺u{{^׺O92oO}Tx?eʵy=V]=u#!/>uob /L{OvԷ[`:{xAZX>ǒ]IzxNìj̾þ^}}N-?R k/CZ].6Syj,F2O[?|cyژ}X+ާmt_[Ozoۻ+j V5ŒTyI>(:E(,H8EI$bN hzvs_1ۻ {RY|Ybkc QYi*W4u {rG*,8h`i#'hB tfn>o]%ˡ#{dߔڒj(jw6f|-^<29Ȧ,=[jw;*_XFPRyq9dW9~g+OJօQ<j3owЧh>I|sek#r,衆 |T*DePmvG˗%G((ZԒp4=G[/ ~~b)5X-JF}*::"~dcW);wwZu퍡cw&X%TPJi1opQT"܇x%HJ9ݹ&)-7.e Y6Uhj L2:s8E6wi:++`ji_EHd_ݻЛ66ػқEGfv3-JFB& R$!*u,M滍⽖x%JVVd<37w;4x2e`8"C>=Nyr&Sv6;w?.;o+^n WG5^o 'LSLʓ%D iu05~~.ͪٸ.-J|,OoFAvU d -jF@=(:=~=qhNd6s~][xl|;I68 boe{o kW}jj !t$AuMRi,*ڐ5``ytc:Ӵ.-+Phq_#ѧ.ssvmgmZ%Zb*E2j+Ϡ/nSz> jJf}d'/ 5eX>6ʻoHlRSfٷך}v' u:ɯU=`; ܿ$'|݁08\u>v 4W ͭWQSh7wgrdR Ƣ`qP|ܡY]-4Y#ÓTQBz;:7|€~wL.ۻ{vb,ٻ7{o,n;)+fD;b2Qu>ػ+ylqB$ 3kʤӀᨏJ-9nym^FUtV4B}ƤcdV%Y5#}4sE1rARI:h<̎=[lmk-YyȲ)#i!B( #ʾag?_g>۟#:c7(+tuΨl®SQUdV)S'Yt)ܹ_q<mod.4 iLV6MK˴,U[dž(lG}t\uoʯ);sv>'ݹ=;sm1zݽAf&;ngr_Řr4NL?]*71eT0R `25EF+Ї`^_i4gA#1u.x4x@5S2OO6oZuFPo^z.ƃ. ISU;&!AC,wQFuQ;<˻T-]P*]5 <ӿ1n]$Vh6rQ LƜEj:-0ay=n]˞~qQ읹S- Ic,C&\ ǸOm,wQKJ溅hq_#g-umnԱ "iy6w;k5;gp|qa2Lo|~;3K5C_C* DNKV*A7#-jT+*"A w#}ݥDRA 0AV θcwTٛ>COn>CÚVW㤬L@`\rp[Sx,M cЗ+kIb(¾`9aA :(gc'\?q^2>޺}{ׯV{ou}c?[mziZunOz:[z?~=coϺ:uVuoޏWao^X[SՇXW ~u=Xu~}קX'u=\|XWao=a}:zpS-{ ?.mXu׿aoOt=\qXZ~}_Q{`o_CQE=qq${Ӄ z? cXC:X[ot?.`o{zQA{GoCǕ8y}ONvzϺӫaa?_t=\p}Ϻq}ot^=aNk+\uz{}OV}o{XZotVb?{u#yOu:}uq">\u`?gXn=뭏X}9C}=nǺ>:߽uoX|O|,uxS׺:}}u׽u{{^׺u{{^׺u{{^׺u{{^׺u{{^׺u{{^׺u{{^?Gwv'J淆/ y~IS)Uv|oͽ}M}fG3ZV5U\YSwG)I1ijMSFapUD EJ?4{W,Ov%.hk?c1n;pdٍp9<~|nFRAPZZ7^UiwkoݕKl 1#^KKw /^'OJ1՛l.H=0zRXjg`xLSp^O۹,D=,R(&>Z[5-*$MH5Ş[lSTP5Lր EA)N9Wmm1u{wG\F`k2ݍ*h2;tE nGnMj4\#.V*1M$4 .6.]t7]ll~;Onl}ֲֲ H/;w0Yeh,QFi41ۣ^ŋRPž) ?zӓG4,TMIS_ kG=o[Wv+dsQU*GQ*+ :tBB$Vg2g2=~#ZOA@<''ĎSZ ,Ԟ$Мc{Ue0I ȭ|fg('}Z,isYQcgrmoUuSϻ)Qҡ}1-cMZhBjz^u7Al-_^+&\5vs٘|&a1xdIQUF@S%Pίqk8[!(I V cUkshmuիLb1 Uԙ>Ѩy=]ڑ[>3 dSpg+;YII'R9ilnRB]D` PR㑚}n߭quTX&9 1T-]IC"A#sQHՂ)GKT, jucRN hxQ,5_bct{7pnlnOᴘ-'ͿsjqjXjmrKH$nup]@R+8T]Mx9y /;3}IVקktIJ*w䨦KSQ2Kf2 ;w/ՍֵH]YzDh2 Z#JX__j>(gc/Xo~=o}cǺ:]Xp}ގ:[c>ՇX}׫??'޾έu?zX͏x~=X>iՇX[ՇXcou<:t?>:ou}:}{'ŭq }oOV?CXz s~?~ySXo{W:~=ӧˏX[>z:}?Oo.7ak}?SQWant8or}qӃ?N=zߟ>z>z;u\zuqW`o:{v[E \uq?ao7CӃ}ksXOuqz??>x~7Ƚqz?7n?u=8:{>}aot=XS-X?ӫ=ak_\ӫpzz[Ϭ-}qaﯺq0oVb?|_z<:=a?OSǫ.^8u}*u?ӁXu?ՇX뫎=׫GV:Ou}?îyunz\?޺z£ua?q|m}Y'o:M׭[׺u{{^׺u{{^׺u{{^׺u{{^׺u{{^׺u{{^׺u+etettb 2:0 ߽A z:qG#v]ӬtH;mRƑ cUl XdN)kϚ%J׻{A[M?EϝT|ORw,{>o` gрeox:c)Wesy1KYڵmC-eS==bɍ1"T =tK]Ph2ZSX U[]C^ݗ n w9˷C{M. @pbԟ2z$!׺u{{^׺u{{^׺u{{^׺u{{^׺Y(g}눣OǺ.^_ga]o׬g{zߧXxoNպOOOuìG?._OVc?_][ma=ϫ?O~cGsV:Շ_ՇX[|NaVao|}׫a?ᄋq}a[ޏV:￧}xq}^8a?zX| }W}O=zXO~~8?~tˬ'SՇX[?#C9v?Ǻ=\yu?}uaì=ӧ=:?6CՇߏu9}SXGoW;xaou=8:Om=\qo\yu~}-}?}uaì}gϧw??>׬/W)ot>}]z??u=9W`o:OWQOVaW`?~:}q?O ğ~:ߟ{ì'"`oCX[+?[nSպ?SӞaoߟ>&}}uo>Ϻu~O:O{ՇX}otì\N=q#?~?[=À[g'+7Xu?>:ߟ_N8u?"3돯t=Yx?~{c~?[Vƿ=ìMޏV.G|ȿ.w~LVE;,?E'U,j|Ѧ٧wſ< K?o{ߠ_ӟ˻_ˢӭƵ~g!7>/{Y.׿wKu>CVox}_˯vG]{?ϯ՛^~ݿ}{w^?fׇ߻o^!7>/׻Y.׿wKu>CVox}_˯vG]{?ϯ՛^~ݿ}{w^?fׇ߻o^!7>/׻Y.׿wKu>iC_Fɾ.|n@= y]vƈPNG  IHDRsRGB pHYs+@IDATx^|ՙܛ$H"ڵZd-fmXk)nOv?~bޥR_E/v֪ljVZ+ $X Hrsϙ\ȝΝtL=97}̌q730CXo _#4æꋨ@@Ĭ_FE3l!?P>Ud)fo@}O!Ko M *dM6eUntcGRU.VcHmPoQm'v<ߔ_|)puXh7R;ýomUGkPTE ƌ+ ;HK-ܣ[dh/r` A؋-ǾjSJh0-xK=GUNZ_y5LO]f|(,0(,(,1͠삀)ۣ -N{|fXɟ>1a!Xr@Ȑ2GiU q,lL#Rp$T`J0,JGk݌ſs.(@& I1u}U 1TNO@HADEZ>/)O8l܃ p2DGČ(ӧH8"N(h/eL]L)ԑnkcK֫8E+*pvG X_ً퐵)g{s?pr8o !6 ׯ(O:㸱o>~B{+tTiRmY&6A7oKe$F찝O&,@h^ӚebI̢Ɇ+_Gr<$k\^'`.ucG̞lSoOX+--'Ee)^L̃ti_ #$z4-_j38bq݁u VU~`*ǚ[4qm`'f}'z3ˏ="<Zp_/߰w6ϝ.{ } Z;aVq1݈Le ]{g3$ˢ]nQalX蒧{D[cޢO, `WȄ5O}]p|~ZTx KIpuEKMdl1Ԥߪ&1cԩEX_<ɔqhg?W~l|R3=?߶LZsc%žNISc$l= wQMO>:ikJ*^V{,s]~G 3n_˵=|sRs1 K# @`$QyaEϟ+ K+Lel?Ɋ&jLFzF  nSeMSt-!u:F,J-3sFۿ;tNo4 nIK{Ι\G>W M;7][t.}W+|g]]-|"_]r̸7oh_;:$_][3:~.|?m< ?Vc?XΣ]߽\Bߌw [1֑OA+[~uD(&x7| H^ӏt.fBp[)?C"$O*. H\St)uvgKծ)GMYRkkiBsǬ2˺|즣W޹lm.uUh*>f݆o:e_q}^R딚ŇSWQ]Lօ?N쭘ϱi2fn)Zw^z/y%Irg\$F)ZktlJ:;"wD²JZ5kIOi z)'1"VnXӲ{XKg1~>T<##lX=BU9JG n;xɩ,4lfaL4crih`w<dB A0[VT[7=J-93bfC2?{Cd#­D@<֖tLΖ%0ʲ}ȫ\#단JJ@l4c\d*(w VYls6&O1_nʿ&z> O J"U\yѹ.zWߊR*'k |`QՏt"l+ߝt[gX}AXD VCT[mn+G7zۯ/oLјO0f@"TJbD^ ss⚽ ؒmgH$ʔ[Ʉ=E;n+s"ԇu5Fߪ_ҷ_hz5{/PbX*!_u/mW~7X-V;.65?- ~0|)QF-)?8o|E/TV[N O4z}ERX}毤YxM~Z@sc3@ 3\\`Tlik].JxM%q;Q._:I"Qr+L했~%e]ro<_wcFRk[eʶ4CGu֩j\P#R(?׊^Xg??^Owz?SYt/\iom]崪ު{<#ƇV2p?FqÌWSrR;m/q#z{?u&VIqU{/w!fuQ@bcm4>E?O'r*!jI~=cDRm C}C"ێ?uGTO wU<"6 [#~7\&dH>h”Ns3hqW  pb[_b{:}ҡc:x[7jST(I 'YWQܿ $_,)#.;3?%MSb kzVԩcu^[- ZR&yr2x@خ+=Yr@84Y(A@4+{d= }vߏn7(\&#-ڒ!ځn=$z5wz{(]W߂9E) @^QyXPtOS2̒^6dZ<$v7Q]L~Δ."ӡEr t[%=` ՖOUCkƾ) S%LKHq-;IˠzȐ!0B~I==/BKrFDO薏Id]hq_nMRL IFRJ$H-)^|rO-|Ad ɓ/4uO9$ƨ'\Zҹ@˪8݆ J[Tgtg 0]6 &@w@9" W@C&4'@  l>/bm[%ZTp:.A'j.VsW;50C^^x.P@@NpMW]3Xۊkku^P~$&=`>Am< uFqttodKkwrX^9l[jQ+Pw9-;kO:~LO`}nsľX"9;Ҙ=ìKR;1Ĩ[al]JY n_8 d@#%f fi H@#@a^{+|IiĥNrK 10o/ \!` Q+ >0܅݇|Fـ. P 3 w!<'j@!@}6` 9T;]@ y~}@gPm ByNC>#jlpsvtTg@@>0܅݇|Fـ. P 3 w!<'j@!@}6` 9T;]@ *ߛ0kb-BChim=|b#C @ILZ2@ڠ:Pc*}sg5W-&C#!oqWm^f/o^|lGekl]Qmwyb  ;S/SzƄ’ O?E 7fT;/ : 4> Ga#R3!cê/` w{B.OAyA7'lR[^fOH pG^.T]X pr 5K†@n3i +!A$6#*h-KsMcxݳXtK{ѵ FbOqL@ D"f8,e6|0d=ḃV}/ ِuSY1oC]4? #bwY L= ː|ܭ=amFX\o{YԴtzMݲD$Y2ς^cDkݩ+`eȖr)r'~YT jժeKej[S;YѴY?h4m?U`^7tkgXd훫Ivl*nk-ZRo^ ^0jD,,F[sLzqʭ/?y̦>N ` ۶+VjC,ޓ T;9Cb(.rbjܯ#E@|CJ6ުVϵ3%ޱ;ٚ.VNq> +zd#49кjzbj4>r@4u⻣m w\MÔR/K"=sv$>ZնdV[؁|B@:Z0wTa".w)mG+8{FӒz;rvbIt[w\O6u>t^[UϿjguqy\04)Ezb*?էd35\Fj'SJabw?1un?K.vd:RzU0aif>SnZW#o"kޓujB$ * 'Xwa!L)Yaw} K}?_Kid6 hv[ .D}}Dpuځ pk*B^C2[BM72ϾŽ na @.#(iy\5D/61{M< g7jH >9@бp'װpoA7]pvHkv ym7rdɿ<@]}YMp:vw\@tSmF:Ki@@O@4 o u@xQPmo: gPmg( @[i33^ -T[@T/JC-Z !xK?CpFvƋ%j{˟!8#j;Ei@@O@4 o u@xQPmo: g /2t^ЧM@pږԳ@K L}.@NuGN|8SeeHxo{G)@ {EW2FU7aZVҬڦW1ӤE1@) aN.+ONBkڟj @-qv!qy@@fP̸Q 7Pmo* ڙq opU@@3F-@@N2#jgƍZ!j{ÝV!dFΌ xC;BȌ7jA wZ T;3nԂ T @ 3vfܨ@g/,IZ S%b Dh+ Tc~-| js @TO\U7#%k24] k#%+TckmTFC\SVf00;9mkqqb M;[5kM%ezD+UV}lnX 蒑va`@0+?kb-BizڦT"rVyT]XBZYuVPw/Vve+{Y{KD-]D+[̚jm:SxVmR4rKkkS @n0 Ü\3d~ڹApڢ@ҒH\ EvQKae4=^f@awQj[SI Zu!;r ɞ@ 8X;SFz֙+ @ _ O, DWpIS6&hqB%Eymnޢ#V݁m˔3vo 1)͑v4r@3LO`:&576o2fVݢ,iVW## . ,cJnuXj\ȳ>@'`=,-I4S0\( <&fct@Np! q@@v8 K/ !%jq@Pm_NCyKۡ/ ھ6򖀨6w!q@W,&՘, P?Y@ yTWÅ@sT؞w>2$#GƏ7dT`c/miy{.xi겧n:J}D߽zv̿.UA#[y6gi/]>ax}c{,[ufhO',i_쀼.37˗ߺ~YĤ,4xOfgY i康<0wSi~+® X;5a?|ed\ɩ7~_yO KnxQ"`3,"sU`iYIZ: pʼtY%ݯ&6Ka@SmT;u_ =Uw_^$eUn~Q-S]lgtL ϫ.2 ʶ++ϻn̛XX2O5aj]LP2j>/+9ex#Zs^ɝ+E8RW.kߴU+KziI=$HL>oҪaՈ7 <_ڲx-؟n2Gs:蔹N@ɵxO@?ib&j>>}A׶$?qr޹ Ə/ݴOQ+nÝkbI*+h:GPo/,v쯵 `όOiPm5W-'=NG/B^~ Ζ[n~NM~8]Sh* z!(%$7CEۮyٯq-vbĖ Jx#~I5v=k9 QVyT-\.lѿͣ+g7/_uW#-ye"YNrW.$uK$O:p.͕O(XDQ: mxU$?1"$-Drp/:L0}˖OިMrecż uIQOrlojΔ鵛[Tu<{.QšE''ϭseG<"K0?wP~z;b0̝{vDjKfyOϾa;4eBJmސO]_vkmdZ23+;j/`?t=LZ| v .l;o<&]-JKNT`UL=nV׾^'ZwoUʙDwĭ%GǛQ'b+zĺkn?nG=>dipDZp9 3G @`ȮjQ3*Ξt[)gŌ,YwwT A`n̓cb_~Lu/zU:3m[WjFC'UjV*aif oQ6F]m§y!Hjd @9 !dyls~x})+ۃ^^0; ާcgN#@^C6靄;}wleh!`Pw>g qV CzĝOOn*s䅿;y'd2u 'vr>Mm=dG<Գtd̙˓ 'sYYrf Uvj܎ߧHil^Uc'N +w޾^k=#jqT;5/KdHmv_|ʣҎf԰<GWzO/f'qFw3g.k_7rzDO/aeӺlj_kdN|k~>e]owuz:4~ ک:}JUxy_19zF<, ($]6ާ#gNpz =Đɭ2X& \&W!vvχ|97Pm@~"Tkit1@OPm?B@9 Sv~bNá:Sm}@뾏r&T{rYY$ޑWX, Au_G8+ȸQ\Y;hYJfKkRf)@aN.+ONkDlb j;ː<-ZYПEͫ ̖~X=f|Xk;7&}e[殰[KKkk.Q aN.Pޗ/P6Ǫ-JN*-I\U[Kٔ(d4Z ޼6RYuS B'CyF}p(kqv!SKb9nn*=+R(X :LMSM*Vƌfʚ+37LP i 0rO<#9NǜF ct@=O2XnNۋ#9Ut\  D@aG$L8r@a^;oq@9Bi$G @yJӁO >8܆O!@}:p )T;OnC>%jtpSv<݆|J6 P<x Ӂm@ O y:t))>(nC5u!#jݐa@Pm_CyGλ! ھ>wCN!_@}=|8T;C&jzp;v 9|M< wPr: y@ y7t5TÇ@0+?kb-BC!=k.@C_8'3ijIMڹQuGS Ν@_kT wCN!_@}=|8T;C&jzp;U_jJ$օ 7B357<یo8MY@~!^]tK{ѵ T.6krͣ;u4 #T{=+m൛GvD.Aݴ!a'-(X~O=KTN[t$ vsVY0L{ih=xg@#%Q1MK}Y֞K[*{C|vEvؾdkVhPfڢկ+5K`SF’k->Nʤ`u ;f!<$j'gHE҅[H+VmU)*:.޽UkfJcw5] [ݝ| bW\Q]:nG)C$s9ZնdؓG ]#jۇ~Yr_'kn#=Oh[;_zfms dWYbW6g4-S);0`'f\dAuǕt?nSCh߻HSng(|@Evr^;V_))f+qN#_ZyyNW_tA4#;I; wMk4cdW.^|a^uRdlgm?L:sz$Q8@ O !St@V YMcI&@C*F{#z[o C`@p_2$9<@`T~-| js @TOPm@~"ji1@OPm?B@9 W@6 ?@4Z @ 'F _!Dh+ Tc~-| js @TOPm@~"ji1@O+ '`8Ug-y8@Z}3vړ"K@9Lu_G8+GrYgv?в*f͖64 S R0 Ü\V&sڟj @-qv!qy@@fP̸Q 7Pmo* ڙq opU@@3F-@@N2#jgƍZ!j{ÝV!dFΌ xC;BȌ7jA wZ T;3nԂ T @ 3vfܨ@7i@fP̸Q 7Pmo* ڙq opU@@3F-@%nF3q ڢ  O 5Kkݵ>5̆k֚ pMTccYWőnɮ|UE>xv+6 pOJm]bXH/lGҬ\=pG"Ө[aWf+P kߌ1jñf-}mC `Wn?ZVQKkRdYRQteoFJU[HycٲS-`7#0:*W8Xw2W3*v[wmQF̸]\\Kkkݤ I0 srtsXEI%:)KĖo( SJw@'LH<ÿ@U:UYdO[[ ,ٺ=;¨ڡvۏ'uۖl|Qub7%ӲCOnn>Q-94޸( )%`#/iIO@ii[ZvD٪7Uͱ[͓9'aXxZH|.YTX;3liYk;:( d@34LӲ~q`MZí+b3e.vi`QYi]EYQX-Z'vEu`,e/OWCԘ;՘[9TtP' ѰY^[i`9fĵP7b I"f>INhv' hSr IN8}'f/dHA!0T{8, @ ڹ?Fx@ Ah 'F _!Dh+ Tc~-| js @TOPm@~"ji1@OPm?B@9 W@6 ?@4Z @ 'F _!Dh+ Tc~-| js @TOPm@~"ji1@OPm?BpMkJ$օ eL 6m dkni#\R1'{ոG}Y@ Y1oC]4? #bwY L= ː|ܭ=amFX\o{YԴtzMݲD$Yg&7GG ]r{mfTLdEӒ?gEkԯhJMy*+zTdmaϭ2pP͝A@ ;GQtʊUCZU=GJwoU瀙D؝l-9Z;@,Zu:쏤Sڏ̉&ɣㄮBB=vG:N,3lGK{>?Js@^ȮjQӯm:ފg4-S);0`'f\dAuǕt?nSǙ2AB'!"j'SJabw?1un?KV1zŽC'UjV &,T5R6QF)@`mgٹ@˪АZZ[*/ @ MijIMڹQuw/NAA0ÀGU@#`(S7jg9-A>T{ @ {P챦%@'j! d=ִ@`P3 @ǚ  =|X =vX @ GkZ 0|b@cMKO>C,@T;{i  g@#jg5-A>T{ @ {P챦%@'j! d=ִ@`P3 @ǚ dN4kڙ3& pږԳ@K L}.@NuGN|8SeeHxo{G)@ {EW2+uf-BilimSL0 @ 0ei)_vmT]3Q4۠ E 2$n5@Ȍ7jA wZ T;3nԂ T @ 3vfܨ@7ic) xJXS4@!T!0C)~ !xJ?CpHP[ƌ9VwܐzzF Y n0gUqeZާS|;K-d&aH4kٗC/Jg4Hǥ4 +D:c*-4sRGB pHYs+5IDATx^ T՝﫪7Abh8Wfdp3F'$'193Ęhx㎇Q"5ę1dEGQ{},۶UJeY^aKnT/*WEjyvVxGX| qR>BZj}I|ZBUiȣ}z-HqȵSa[گ~'cZeRLTK!i)M4x)Tv'zfXPpWw.+F#ZNdz=s8֪;[~kr]:W^)VU볁%H]N24O&&9 @pH z"*X[Z9xMmZЭoU3Jy)Ce8x|ǧ"_/h^[}[ޗXZݝ(; \:EJsU f%Z0VGjZaU4 lаWE%b9o-Qķ}eT[  9q@j*Ц"RSv"OлxDD\$tmY"K?e^HeIEEH zT1ĞrGzOcy}h1;T̃q\f Wv-|@QGc9>xףZ(Jc9R˧GLVNl/R:_5jdQʆ7 kҨ61C=$wH$Rt\-ݯC HCD\Q掚'-X1Z"'s dn{>ǫ<2?+1:y<nj(օN꘎mm큶Vc-myӪBͭ?:>x*kWz.m`7yqs9⏵6ہh֖L56}miբI AE' F[΁J\:t{:SF-ݷˉsD*r淸{= >M%GYE^=^.y+q_w~tS7;mϕǛ BiWuYZH4SO 붙F@~lyD׎b1 j7=яF:|ҳ]B=O|Kg4QT;%}IzxD,=W"KlUmsnNwg=ᜏʮ<[0xo2ڰ62CyF=ηlŘ3aQ&&nƱo;E/ǽ dлhG뽶s]4˸SUyRJ}oG;~y7MԞ߷ WOCKKwUi鿘;$% fTrDZv9GS}oݝrwO(+mVCcuQ)_}E=N;}g]RfpT?n_RKji"['l| 赛d%EYE׍۷lnZR\TE ܿ626wf1ZVۏ,ֹ۔,Sj z.ʪԓHzȒ-pnP=@U^&?y_NuFWZ5]a\s]:r'{^rԝWW^3w&8~uvue_X{( oҵ̻nīT}p3W޾}₡~)JG?wRnNJkF5"OEMK@FΦ;tnwc"2\ܒ$Ƣ'|˽:"czG&bWE" ]n,*rI~u5bdƊBui 懟*meR1D5_n\rѠْ)Nw06mn@rG6;璺חߩ/'vܥ#'WQM /ԅ/?$uXK?ZfvrMM{(wTW p3^:<ŐE P%W+u[B1&eGyŤ y 1K]]3ƷI!)S\ouEO\ON&VdĀ=6}Y7bʧ&&*C KYQ'w"TG|JGacj't-UfMo{c:ux@oslg_yve+-:z8ތD XA؞Jxl6+5CW\<\mrN{ &%q7-=(Է]*vLVyW^{fH y#tȤsIʻrbk\$#˳{lG<K7MHA(ܴj(!"-cuxe~%wR9l:(R_uY2Q`o+'/sr>N(KR{ {/,*~mEI5m'c" @XV31љ(ǢW=//]sVOd܉;)#3"֩Xt_y 6Ke;nYM-r}ou_xS_vUX|/GY;ce򺢉Onrܺ^K^ x.|<|Ͱ'c|ooo_pٷZgI4٥amS]x/P?^ ջG[=7crG@؜3VK7* oG{}߳ %zbhLwxUs7"#cY3J疚E).%J%%*8ʻLr:3npUL g"=ƷvkbB=Ó}/]ر_f7;{S$E5EmZɣ-]Vڥi oqCԐ2UU%>+n#5ܙztw$. k<`<[bdԙ.ˡ돲>{1_y]h갘Q=2zWGK7>pVEbe?o (t']ZkmJBv| oىNɟkش7cϿ=3$kt44omNB Ր\/(2#5ؤ5u_;[3*G9˚ΤqlWЃ"z5P"-^-+̦~OW5i+ViD%~ '-Lr; EΔ{mYIIA?KĐi<<@x:nʻ5jOKDve,=%QGI EO鎠.P$njmkQ}϶>ݢVw޿u"o]]/bzc&ʴuI)S-MnN:e}1 OZOonMرcZmMбpS[=EN)4B+yAr,A&ӎ7#,*0z?C@;2g~yw__hzqDEdGZsjzd~|d <ʍ\K ]\!:.]y!1/w'˞Lhr`j[&~= YgFF4D fIR_>?tNϞGw2V/N[:n r j$ω7i5\>X+rB!CN[@e !yD[Fä⒌C3Ef@"w֪Sƌ:z69^6niwxKgTUmճG7UzyEFX @;Yl߾~G"b-/6aƤ ^@`hA踸#sux坲Í߸ :S2tB.H kz S> "3tE5 >'H=}` 0 =4@Y&j8@@gEN@>C OAO9! jv >=}V 0 =4@Y&j8@@gEN@>C OAO9! jv >=}V 0 =4@Y&j8@8O%A@3B[p@ @@ q$f@@ !H̀  BA7đ@A@0n#1dž 5MԹz^C  BA7đ@A@0n#1N `Gb >@! @:}!xH! @ ˸0B/>Yt5@@ EA7˟X0Yt5@@ EA7˟X0Yt5@AwM %9#u - ЉN `Gb >@! @:}!tCt C 83 xln@oqgnt: C 83  @@ q$f@@ !H̀  BA7đ@A@0DzmCL @J . GA7ϧX(@yt|E@@ GA7ϧX(@yt|E@@ G@Ss+AHz!z!# F B$ױ0n[1 (Dz!z!# F B$ױ0n[1 (Dz!z!# F B$C E@/1B7ʭ2Qt܉1@!@ EA7ʝ2Qt܉1@!@ EA7ʝ2QD $@w݃@NW `Gb >@! @:}!tCt C 83  @@ q$f@@ !H̀  BA7đ@A@0n#1N `Gb >@! @:}!tCt C 83  @@ q$f@@ !H̀  BA7đ@A@0n#1N `Gb >@! @:}!tCt C 83  @@ q$f@@ !H̀  BA7đ@A@0n#1N `Gb >@ X& H@ NA+@0n#1N `Gb >@! @:}!tCt C 83 %`#0nC1(\z! 9s %0nC1(\z! 9s %0nC1(\Q$@{ޅ@% BA7đ@A@0n#1N `Gb >@! @:}@<'ݍ@#t: C 83  @@ q$f@@ !H̀  BA7đ@A@0n#1 e**W )+)-,.(..J|b<"[Lϟ^t6==X ^oQ ilС=<[ߵF-l˨N=#\d _P KJKJʜ򲲪JJK+JK嵹Y ̨2=#\d _h$ىdD[v{k`A/m CZcQ+|L mY:(3j#p@ 8ji$.%:"dT.2C [5W;wJ/QezF @`K\ͷm* WW7I@&p@ =O;t{O^w~-q% @~H\(ߎt: |' u=I! t@@ q$f@@ !H̀ X4Fc h\P6!&_bA.Y]x=^" zܿnu;voJed 8uh'p_Qq6?q0t/lnUUCn]8E㝈K-^۵EBm /=__NiΗ׆n5l|N%oX>so41H:@dDH%0DϿw?RFk'F' RSZǨ~'hUy1t;b@n 4zU4| X^ELRzcG%Ssju%m4JN)6Z-ydon' YC!@텋7/YkR?2ݳ^9ݼ#_ԏ;ʯ]՛j-PqS-[Qw6Ƨ-ڙ7ц;QRh:-C K?$ZrZ3T}{9½W29&nQ>(; @c???E?z}K&@|L߃@s,f";ȳpC4N֑N;@=(&^p[/p'F z{k97? 1K6NȆ@%E;{6=h7Aϝtm=A@{kOͦG׷깷eA5y.~ux=)i+s%N%x{{n$@,J_ێF#ɝ=q mx@ g6m17T@= )` DI Bۇ@Ng `Gb >@! @:}!ҏm=BpU 3  >uNUj=!OL. @=z3t, `g-=B(jk(8"㎔sQ\tS=]@@  J*9{['E.cN h,">P0wKļE%^7F)wg}jUȑX,S:YxeEȑÏW#/rQhkx:I.f3&Omy|ru=KŘyENj anNk9- >:Ѷϒlh#.O7A^e 9Q8\A] D#^XcoHǿ:b ĬaKsȧ ޓ܄xCN() x`朐C/;R>!.jexO?T|{q٘!o kW5G.|vٿ.&l ُJfǷuY6V7;5>+朐FoIKgddޗڑˊO|_gԪu3>k%G^657U%.p}U*L7E{}] vTK?J˅ݛӥkv9!ƃCН7#78mN^z5c$XUSF-ab60op _njz{ӏ՟QΞgn}X?-g^wEg`p4m8g;{Bkf3ș7Ñ-M3do/6V͘Q[=[KcOpHcUY?u-)[?rwmh^^Na=n^|śʥ`G{7>aƤn'eO5777< ˷]if1=!Sy'W?,mP?ƛG8aI\NGT j.mU_4l:ּ9أ?ڢV_2s !voU?lvͫow8̽dF^ZBo?A3B_IÍ/"&$z.& :8AMM7h7AϝtWT=aĶ;?l\{hje؛+R Aq_+.h4V=l3院p]Z?HF؛@-=(r@n XG^{;goG6gD)h(#OK{Q35ۿzvS@H :\N@v IiNb@%g'A8i,5'UF7ڡ>Һ`䤵!@ @auAorc:UT&N8 13,{5ftg8S#K'>TED;V9O#QT,iVNi4>"k)Ѩ. ̒aͮf&-UejRl#E @0)F߹IENDB`n`?DUMi$rNy$PNG  IHDRsRGB pHYs+>IDATx^} xյȓ$#! Ei U(TDi^{+VJ}W'VUkADxի `ȋG `㜜g<̙ǚoΙk߬fIH!,HpBfVA0#δWZ%D|"XQ7x$tH&O2iJ_1xfd02XH#>Z@6VFqKu_ !p-/&fȲdfj@Y$dlIUfQL$ oY yط FtϢ>o'pAz^飹 \(on9=yp\=-?v" @PE[K9NJnم뻕>O9I[.u) )(&V0NIʭb 6-IV63$?o'GC0x @=!xurMB!I0B !$X6 k%v?X; }SJUfo,DKXG:O\!+)P,6`9$'xh$PP " )")$I۳-= &`HFy5x^iiN&%D"YyrL;}8g.da+A%n#x$xNCu@~.?47׏0_9?ǿ5ikbGA!e 0;#q8/EAH W 4 "@\gs]oꘋ7t⹳!]+y=t扏qXC9Df<.7̔{1ϝ$ _AvW<3 s͔*a?p,]RhJP$*!-BD|c'V9'y<0; /$>\N\W {W~RB?"ˢ(>LQڗ]қ5;o|O޸sE;Q%%gS$TE4.%yHo*$bǜjS22`` 6Sh]>J,0? 1 eu,6{o c2ȎtB:{g^r:_u:\}y¯Nw^AH߱(3ҡW,Ʌ@}7PaD  ȖP/;K[t-$KrI}N+Ts/]PGr t+{lLjZuѥg^sʼn ;|꽭ş#ddRemvL&$beR+nBDeyM=4re Yz膱w:J9aعq`5Q2lhxMOT+'t{8sbՕ4'^7 {=?vqzgC v="y4 gdr+Ltw^PڒO掿]v^ճy~3QJ-ɐVXD` $B` EEx 'ͯд@~_͗̈́3N5O]Wkz+*S tR !|K"Ny鍼JNE?({g42\ #@!=Gr( 01%ހymr:CS?sQ`!cINAl3Y/1}Vom.'1ivjV}#O|U22mˣ+-U\g?t nSs) m50[ʏ['PɼUP':E0j󐏚wvPLE8jn19鰰ȞrQk"\wc3P*M!o۶#i%S] ☑a?,\@<9?8f:?rV~BF.JmVyWIe߻q7ɴ&y|řjeGc |Ɂ/ez&M QI EBaq?^=g CTXD LbːL𖆿!t.“OeB&%G$J2mO-5L <{ X Oq~6uҡӷ^VM]pghz9 /rͪ}ee`x圽TN|oqIBӝBwه$>iþ mk7mN+=2}<@2b3QuV%!lHV7Uǎԕq1ւB!{l 9٤qxIW 't7:ͦqIvHW)K^ LFsB2!NV6lĸ[esZ> Z, 8L9TBr1*`X"@mXuCXG[Cڅ|YtJ"0CvvztysIlp&{ ""L[ê.? . B~Ț%~ L[֋\KwNë1tr)$#si 70jڙKs3Jy7QfUm?8[ 孏]xj>pBp'ٌӣ/y|{aA֢٣3 2G#3 NBcAR r9tv_9sԩf(MPN7q{+AEh0l$?dY:͍D(2pÙHqH .Cd7! 94FݲrpS(.^a-/8K4gg6EE3XPܺXkJm9ht(`GyN?N ?i+ubcDE8|TVFvGy]uv#f\Nz/fwCM8ht(L \EI?J%4&{|w1$~GBӨB@aUq霻7i漂~P` w3iqSQxzy~?b(E]mHL Eix\)k-Z(>H_bD3a xZ¢eUyzAW+--^F.$tc=D``T8A_MvҀ oqxhr:Z1 +ױ⭥Qg"ά /mYdEYrnTtM^iTJWWD jǎ6<$?T  <FB rЀ_@.,R^/kH]D$Ӕ<HSmV*"ZWV FMrWݣ"xt )ABRI~<")ȑca (kDϸzG)g H%@XE0挕_<8<>QRc =40hkk5a´˕2U} L8#?ȑuLP=xuG.{l\| <\pWxƠGit ]}K`9!7pBf~&|+:=A{Eq ~W})oO>+)'$2צڈ%y^Z$=6?ٖFDFw^i/ >.JX;2/l(;w,8p` -e ';,Vx٬Oxs GMи/X4e,;}qEr!r n1sX8 bwl-kt-݂! }Ы+  oBOClΧ‚{E?ف4LJf*R1!@!f"@"c!@!f"@"SwlѲ!A Ej#Eko6mΦ-v '@Zɂ@ } \叜n.( ! ec\թ::AD 5@BOqE@tMR'UBBOD;`yݕn.aXǛUʌQzݵVքG`¥}sc7W86.~fne4=DHnn̼g߮yY^sڦ)2u>䜣ǒ&϶̙,U8bT,۟{ip CZ79MscM1٣bxx%Mz^4z]/XHd 9jiႣ̛{K摷?_R6C+K2WTPH"rd^uV/6O:tݥNyȶ6UCmrmGwZ!zpS鏄}&"0)03}&zy @I4,_rJC9wQbsg{ݳo?֒{8_QQT6ȶ%/6Ƴ Iޯ&Qx߇rnxpv,+'8A"k"@\%c(CTӲ;צ9}.е uD`|}{QKBc0;WB * @<1"$&H9."@]FNWTGA.u7EB7L  @ł0AJ[#[ΨW\.R2KM~=1t  ]`;DHJW,2?\EWZ l&5ԠZHAD ]Tt)9[ff.m\" 669miORB.K،Ll i@Ѧ'CY%YScjDsD@7tlZ!:qu6DtDr)*IwXNH8FBO+mFY.ʱR^8x/:u Y.t"+z5\t6CD @BOA}D  D#KB ɹ0;WB* NC 6CD @BOA}DЉN" z@Z h_W-T$#RXĠC #*>UBHͣ[m`MM  9YcX5|+K ރ3L)$xxh>ڱiS[QJwJt-(VՒn [DQM[ꉑ{"sd"PSl"g&Ru4^͂7Y,i nsC͚%LT55 :^4mQ5¢+H}yr:WC]?Hfb= >Rk#[b3NRxٲsi8>e;Vl6S}pgP_ǮQdrR`\q Q"045)"5UxD~MӖ)ݰ{^"ᢦ:UiFya*KJ[;$A!Bgf~/Bv4ܳD+ {shzރw聠>FMs#<"01 G~ѡf3C*%nC*uF2|]1Ǭ H&gX*0zOl{z~.D84d Aa=~[cbvJJM3#Q"0 l޼ZI>A\ , ]5A ,+(yFy4M/i!ǫGXM{`A*r??p4Xa ylwPlAv[&۠"oi+"Xᄼu/crt l{향SE>x'Rsm#'=}hPӊ~`#{V@D 9@BOqB-D$A! "$H1N%" ">(DX@@ =9 DD`P+  @P:V$b]LcU;jX2FI$5&Pw rȮXFG ʂ+Yj,ު~+"% Ç@H:VX4IDHmYAw-%cXVtZskh{&H9GҗPV q $5@B7D c-Ja!%L@L)X“rYNl)O%Փ7Rɉ%-pQ%DMU M$ƴ .zL=VFR{)c{ߔ WеYךE&--iEjCSM:OrH+i$d:@6O"š@#BDj"juz *h6`=t7riJwZ:vL eNUWAat$tdf%OrbIѻ}vSKi Y6򣊎z})QD@/<Ï F歐 pb“m;&%օ%'9δtFƥ߶Hq"C@H:JWbMfVmŰDd 0Kf,ռ]:Fї8δD9 6sQh_皁"Hc0}n~|M#"`%GuCD@ h5$t-`aD@$$$T@- kA " ' "hA ] JXHHcl:-3FM*$՞l-*;1@iocP'R@VP*|V *BB;"/c]#&r GՂ@wJRh"5Dp9`V8tU4/ȉ/-pD\i5 *<R,a3D UbavoiҼSq[o\Na93ռ.xZ`,WoZ56Z=tb{D`PӱRU6!͎l@9=,VMU؄,*"9mUdX倣6k-uGwZ~K +#k +" T-{h<8=aVC1UrGӖE5U1VI ;Y&ͪn(ӱ+'&IVC)=ysX0cĈd14+!"Í@d:ֺj=sY3QpаׇZli#M  I@d:VJTN[Ejύi t>Qg9hGGWZd&d^x`cΖ{n|jXH0}n[C6Ҳ8:02c!"/,ED`@BbD ;7?7tœܑ9YY#22s32lL-b/">JK QLBBO@=r9tv={̙cmN5Cioorvn3y-E$ T/9x%fsG@ʁ==СfrZ&!HI8hr!DQ+ ^S v#'%FƐГ~$рD@[fpx=( NQD =%jxwՕ"Z9/m@BOFCy?>ԣ*N] ]@BOבGME[d6?t"-`3_~@@ԞQ"@ Dc3frY_|=z:LyXjB_($t6P緜wތ`NlzG7?![%ȥJHy`~@/ DTOB˧|"cltD@HxQ  6`+ 5H]Xբt)x q@=8"#P( >q=,`222x@B"F!/oԄ Ə/WT52q#G>) 6<)${M% 54ᇯ߿^ٻ};?l=EnHPt@mݲtʠվ+Z +*#'=}hP~`#Ǚ }PX@ G)iuR8zJF!":ГzQyD@ Հ @ "f @#5$4tDH-Sk<DHcxtDH-Sk<DHcxtDH-,3ADjzZ= z**ڄ iuc;:捴DFD ڛyGI;y&@}MMbPuD@(~l7]@DHb~`E"EIl  @:#S\Wڎ )rI!ED ]@BOבGD =E 掅iP4 ~'u>|wedr;,՞iX{D{?H-Za#-{#6B?s!b\J#rsƍ+Gw("}7.bl=GGC/slaoO폿] C?8!t`7"XG.a"v>N$QQah 0NG{V_y_KOݳ3o"CG{MK:$Қ |Tbs,:Bhp]f;oߺeuI)c~|s{۬H dǗ 1<HKAB{"aw"-}T`@7D:ڛ~b aZb׈Cgy ~.n]&4HJKJRkSMw& 0ho"e|c WotwV;T|TP[$0dPBORK5w%Bc'/0gwȥ!%K1?*{.k[m;D?Ym4C3_XA?r{+[jyE~y}58S0*gꪑ^ݣSRx3ao:azqsE"@(s˞Lg{SyGLNZ+(PG#`⶧H T~: v7iWק> xvЯ J^xzSioP>*5zַ^ (j|>eչ\,=.~~㝻: nb00j<썢MtBjЖ|AɮO'27vփ1?O rƃ3Wڷ? =-]Twf͚r߭ڤ%tLpP%$03lff}rZX2'zH3_uWO6CioKo* MaGOO'-w(9q+[?HۯZ*;5/y^*թl ԴY#Fe֭WE7*0 g/AzO`rK=-:W25i4~-e? ?^-6R2qJ1:nǏuU_,l&Py+WEM?ɑttNp럖AcQjG~v)Slʴ4\QзGǾǛ̾7BTl#z#̺Yx K/Bc* 0W"a=a;[UD :S?$?48avE7܉\Bl Áy"iR7^z4\8m28V _yoziai_lwT,|1䱚rԐ ǜʐJ4$ː:8]Ǖ=[ W;FpϽvz`O#ow}>x#Xʡ|o s\`D|{#P]zCț22K/z`U4{FBօђhkWf*%|HUބJD_>8v~M{dXIi|^X*ߟ{>/hPkn'?Kfxo^]KˋG 0lgޛȉsۍOv,B{S{|ՐK ~-#;}СIhQU`|ݮc{좩QJ.IgS'ڰjql hor hB>pͤ,@yCZmoJ=E8oj9zN_hosASI) P`m}l, i9Y,֐-QZ`g 9^_JB.^( @DTBY.BD~Ї PD@LA Q" Ïj )dY99e#lِEDI}֓۝iJ(@D(rBƾ@2-Q!L3G$iᤥGGВJ(-e'Yy8 -Ѣ´C3-j%owAPM(kJ T2 hnYaK E'RJEo2l(@Gj:8bӉ;IENDB`n'6pl;P8M;PNG  IHDRaа?&sRGB pHYs+'CIDATx^} xTEY !a $3n|85*8c8"8>1(u!58* tBLIw{nw:kO}E[߭sN-WXf qkE I4 7bh1_`*E"zr_(ZD@p#8~|Vw+1eƧ[$QFFd%6M!FH$έ囕刵_ͦc{Ĉ14Z,pB LbH,ВSdeZa4E"R&+j*kݚH:GAIqI1$i"> @x\r @.= s&cSɥ z|'a]Ԛ@A9b'7dbp Hh2 &4Fh!MASM{V@IcPw&$(d`LJbR@Ľ@GH4#;uÂ) N&5ӷ{8"@{W (D ` N JC5"\TBJ4A$**\@0r7}pA7GˣK"uNb)[sa\ IL'6&hz-W9AU5*Gi?FM6f{DMA}Z|77X^R9N8GK⣴8 Gx' )x9uCCk+ T|PˊȢq#~#u1 k$%WS%TzW*2PL?SͳR *D[E=c"-!;5Ax#**!*ZPh01i9B&A4f$ `e$sgt&sHC muu6G]r9vjns8 Zی+*U7Xqnf//q0AhZΪjAF\Ԝalu*,V+5?+u5G \Yܠ&L.8AHT̿/ LF&sM/l"jvC|T~;KkZF#!;g ;VS #h[ȍfʹ?I$*5E$U!o}VWu0$Ś9˅k#v;8M}#AE$%Ib5i;dV3U7ݻ"o95և#N>FUV0O NGj۫ ܡ[8k;r3q,SJIIߪyfg\ !S% Iʆa<vhpNLxC@ ր`!xKޫq?wĜiZtwCX H60 mRlbb[GU5ɥ\ <u#\O9 DFbyY6pA"Qrx@I ]la09oDQoOϽs4mSOr؛;v׸b>unY# L)Oz湥񈃷:!o/+f D3}P-=C8+bЄ&gk'^~Nz P<,1!:L^>[6&ݛ ޚU _!GUxg)yz'R_{ Xa3_ќy*/]G|CX nb:Q<=e]Nzn.uRȧ8O-Dk^ aE(; [24wySLR/0'0 fi߲ M *$rnƗw[GrS+ڃJ+Hh0ؖTelCǰmGҖL[1j7UMRi"cst!W7'yc&\xRprCXQ++bi)+rzx::3x\.Tқ؋ {\ٿM7ٽҕy^w^4~G4OC-b?#!"@1J:%5%Bä9݃)A/zyi;у_(MplP$AeG!x6>8wm0o4? &~28#V#٧/͸˙`$TBʾ?\~ a:>jt" _im5mdh) # /~֗P뱘6L>6"_8kTyA'O)a \ۏܘ_KH$iCa ?`ƀ{:~YGJ#@TMnûK& n+Gb!,w}[9-}448BذhV;Q0hF }%޼,ᷗ/DMKU˂Ec,ɡs O$NXOzqܚϿY_c zlT1:Gk=Jҍͩ(}+w"Pƥn9NX|*ӏ:p:<tIo2BY rDEg kɸ @UkԈRL۬aj2 t.Mir)\|Q]?~ZH9`7fڔI\[Ag3x6fJgcV\F[%󾥗6V7T{DPUZدt ܘ; tS_gA9Ap]߰;&1\v$äF4=:uYr5E PmԟT8>wB~*~uȴpر(OplegnYj)ʍ=aS >y:W~ꅪ1[nǫ̒G9GY߃ _( ~]o#k:߉2yB3y6:wOpcڞm \i} mB@=M)"0_d bW0z1=!nM?7yZv ;ApqoX],;%].Qr*B6."uB þ%Cz^$@T*/o L@*pӘBW~y{xo P8+c/~5Z/;x擔ΚPSSO.i'>Ӑ~̈́'Y}aky]nh|mHvP PG\Z/\løf) IBl8v ` s 8nw;5[vvV]R$bY`}$!&, 8p0 ,F^ϗ+^YQog-#da uC =z GDHmVt^t&%48vpHn-8:rpKdR# " T:ڴ}-Q#l1dD4U;݋H!! M|^BS$sBm۲?[n{,HN8&#@hVmyJC Qm~ 898.smTDBh2<0  =J^>p<,dBF\úY GsE" u4jbTKШ↗5 Y>ѥf}Dy\]d Rs@h .& T†3LM]ϥ:K%9pVQFhsL"21y !zܱ}NonSm9A.@9"95V߻ۊ @@|~4dg?X Sa!@'D~+f9N\Q@5)wnx(0.?A+bx̯ {V h@8IcAV}9 ʞBHJzʏ9\l>Y)s=n@:1@\ܧgnQ|ťuYgk.GPbR eb\D@`0L;#2*saAΖ] ->J K Gt"#6>-#eѫbG*G_պ#ܺ9/Λ02"С G:64B>;)X,"t @gFKEA9C`B.rDyTXQDC,;v,xxV]g䈎kD<[<2G@d;!"f=@ZC9" G`@`"  Йu "D#E!񨱕@Pl#"QcC@ 6LD h No"PD5U.EKzHvyys`0DDf$eN]{[rpaرO˝FStX3z~O7D]V's/3iڕ°c9Rvd؀Gg>;,=~R_rkG}K;?w_Om'~to A<;qint7zXr'(9f4Bm; VWЫ |^I4M3:gxOu"xRc2t(ʵ#@DX|{"r.UAx,H&ɚ"A(DV =ApvNqn"I#ڳGcF-] /0O$b. p&PSdEx #Iayq$@k7ZYV =D3gn-U[RAC:#l#-^EUqjˡ,d:=2:PNY B-`.9@ [f%VLBoMC-.?۰@J_D ?$xGnΤS>t뾔 JZ=0竣σ#x7U!a<=a=, _)5m濪D` U9`g1"K}f60"Sm; b#*Yw]?@~Owyc'9֫z£iJ /n-\_z?ٙC&߰(2d_U[[U{x J9MC)ZRzdz_ƒEﳐ35 mmO0qU4Aԍ#YL) Bǭ2O͔o[,;q({TjM$V3:LO?s,gYkuhɞ;DlW^zxCxp,nwN[P0\#tiK'BtjdVPL~IQ\#'xS|ij7%nJHJ?fIQ1д D).6Ix8 yUt{0u⤹Z5#_1 OGzuw 9 52q#P|?%udy6"mS\^ؒ'{ fnCfmRtoGYl+= !!Òw-;!ᖍ@ ö́xҪ i]2:vG|"VgW>U[>mī5ԻB1].m^-tCT\RF͇Vl!j+8{RCSlǯx*&JBڠ|9߼doeM {,/.OIˠͧ\P#i :AˢwRSnUhki% /Y Q@| ƯlGU\}6Nbrpb|?'A+07f9@z*kR]9vAS)#Gdn*F@KOfdN`h˙4a2 aHh$SŻɳyՊ)-\1ILxtڦ!^֤={x&O7+R+啻g?=oJ˔@j(|7}?ʼMms]taXk :HJ2|^pN@e }C=*îaNKFd b;re.nyGhk="HF0tep/ K`⓯ 1I$Ӧ"Hجp;rnWoy2#SRM\ލVhn!e3T%Yf.#"b#/-W$"^så[^qH"8N;jlUj{]W5[-3 !sI?N^K"8};Zv'>.c[ߜ7SҮIO NvվUYu='lgvBAD E s}g_iw:i#zhtv0 51cM Xj [Uq8ju+!]}o3S删"юa(f rD⏥# " 4P9Dh'rkw..ECE["]m\cT4Oȿ8( SLA]y{lu*LEv(}xw:<:wRڻl4586ڋHk/G9"xHmBck)+r.F#t"#G4N"91 %nv;ÍsD`1mon ;x@Nx.ڋ{qԇGm I*:sֲ=E{Dcsxyqq ʳ"ʷ͚U'$zc PVm?V&xUCMۚsdl  K^]9jlYyl+˲mVybJ9 GBIިBÒ sjL%ܚo/N5E2i 6_zZa̻'^7r}jz"FR!,FbsD\fUci|С@߯)̦9*]n}CZ5v5LjZM'6ӆeHhiޔm+%BsS@]u"e!8)=4`lbDsދ 2oWW#3uSR~h2̥3חݐy={x&ϟOzPe7+h!zsUiOvv>Ѯ#e [{Rk®zx"K9Η<(KtQEZ{5 =?B5:p'%Sv{z 09mhF`stujɒ,]C3nxhc9"K4Wkt!ى]tyYrUSaP5+ى*LPg?9~(Kϡ:u/ G;x\Nڷ9So]qSù?8{JFEZ{9m]swTE6}<ۧ| V/^5:jurh8h1Q-ihhpmx2*nO1W*70#c"n- @`+p3\pb>@D9{>Wl".#…$tO2丸XصZj˥{"B/ zEEbz2>;XZTA%jVrk 淲IT-ʮܛC>4AJZy%ْ ">S?SA@vD &L "$_IENDB`n"pjDb5xSPNG  IHDRTsRGB pHYs+"yIDATx^ tB$@ GD>9( HEEBUEQ?hE*F@xyRi HHd}ޙ汛d{sg#,]xxX p@qA2&@ ER[&HDBd-7|0 uU(zTTM qI 'Hbqͤbdĥե[t?:($'ʼnq4ZtPBeq/0/$( tDy"W$YP}Bsƀh'zg8RQ~&;MՕբ8ۥtMdzUNnҽ߫/nK~wDp-N 7. $D{A5/FE8)#/ǭm':lF %J %RnDZg7VGo`jj NƼ>lE(n'|حnKmuMS}R|J$u6ē0}QӜܫ6gMjzu|ZUl*%tCI"du#@>BN W*BL 5<2}UBLI0ŒxH't 0mYhzwa3,zb6b6[~Zlvedge}x]jd$[X@ PMdEwV3˖ZMMYK SRR] Q404m`*1kSxILze.I$1}}WdALQdjH5_LtY#h#W6.2dGLY7,Iwثy˩eƯlzhZ}zʹCe]ljJ@+/H=$3cIJ7)[`y#MOo(_%/oRw|?`}fdK9O+-zSXȡ%ŧ'[oSh4nSqyo^yv t>vA?^-ֹ3%xERՍ%&6;>pHZ?(ue m+`%v.)]Abe|.4X+l ~-H*yRxY7{c+eƀ(p =f/>a|RxIчAF%Gsr{P􏠃^-|&Z@$KBjZ9|gM+1mb &=*3@#E;ԟ s}d6\]0G(Ok| "A=-v$!t!qF^ly @%gއ$tZ$ *e]x5IX3z6]t~ y.8=j7f5'/ߓ×76u 4e~W}ke%GXu%sƼtYRNl^i)x[E ? $<<*>6w4kg&]FR0 ]*4 AECW%VotVJ$ukI޲EXb2h5ԉgC~ ۡAʦԵ)rը[<6ZWɗ-Z/.J篗~(}YC-e)?7_o|5ӇqrMx _x))*>2~n}>} U^93'QԞ4__q;V潦Rd΂Ǩ/g&Q3DvwaJH B6{ a#,MšeM' -ʕ+HP1QEWtm ֕IL ȇ.e{ ~`(MMlHVtRw7'w mtt tq,7M-|ﴗ~Tgc]mrz'N>θ}{硸OX=\|ɸ|tff+L4¾3t漑i^f%uS% >nD肔aLF`g#kvt[ SK.Af~&E:!D&OJ Ux"h%%>2kǁwºl$l2ut Q7r`1AMDi.ѹ U\~.i\Sr g\JM!qOL㉣`N/;4ػhybߞoMZl[+S02e .qҮ":4 D Xѳ(? PHhqZ={?Cg(מ E < t*@n,&0Kۣ#9 hΔ]U? | bӀ 5/rem}>zÈy Og^L?\e)6Bz OڥEV.Ҵ/T s>&-de 0+?DeY0!=I^˼0'FK{>.>1/$(+v6:=D8skQI܅^bbo=3h7)6vx־kv.rNK$XLAl~yRqD Ct%]IME|+]\{ܙ Ff2moĞJ Eҏ~p"uKes`7&&ͱ'V10HX)W&:AIvfLK& g izv &Dc^htAϑǙK&CeS"mHGְlm!Öm9  iʟbΏnHI%\2t~ptDҵќvt;fTRL-D*.b}ߒKGa^12H!.z%`!eϙğǰoP.C>mim"HOq2 vR`HpaQp z)al6G>5=!xl'CH+!2 4貉¡-n5lC > SC%2Bn1? m`$|ԽP8BɁ!K>H{DOӸv6ߣk;yBO^B_ɱ/w{*uebGIfVu@h)@K mH#rUD/$ '@Hi(xu $$:@H>F7] $@^$AH  }{!$h6@H `C$@ qtսc>]z} $@ 0^yM7{Q=:D.}`H D9KdAb}Q~H 4G 2$R]  $Z!e!$T(x) $$@HYeF!il2M_rbH hͤЖsCH &1w$C 3th 9 '@_]@Tem,@M@ċ $дDc+ $PH0@k $rE@I?8'jj EHЋl!0@4@F[h!'FGH H#:[4 j#8&6X~ph: _Ma-fCr-$r7;jc]h͉5v)@]"/2@ h$GcH HAa4$Jd4:ڌ@P"ѐF nGHm)N4r@^/Ӣ4_XSa i79kNʃ Kd9iu}2otz&%#v5~Y&:$7mI{Gz D~y1]c,$7,+*ʻ<ґ%k N&t<@d$!uq>&_[V/ܵjk*%gX1=;%8X ^ jA"n ceˎUșg𾷟{f&:Y?Wj𮋌r 8{tR"a ʟU2MQtf ^G]~ {D쬾=~;}Q0>kxZ@4Θ%ou=B%TY=,/+&L^aeXS-Z΃F7w#!g.@%RdZˀ<>|d;ڲy-"0z1E_&O}{*.n sU7ӅҢ1r&v'`&d,iʯ(n cf/+΅j%[U=G u7_ C)?H/0ZV5:׸]j&O>1 vF DBֱgԦY!9d>tMSLw9*'2;95Kx.Zx3C>;X"=5~ɴ(|v#R 虗{9q.Cڍ J?%]Fu7_+YUY7\`]$tZ k*@t-)p)vUŷv޼5 cgM1FE(F+Fj]sg:MsmdNqŊΟ6Nj6{uľȰcqnmnQ1L k')?tJdߧXM[+̂ 6IHd٫_U(0H'`c'aw:|Ƨ^HC@'uKnnlKھ?B MmQّz.L\pս˦saC;2nE,eG%wQu |fQ)_|5[݆LYAƋچRs (rEe5甥BÞ>e]*xʤyul)6 Q NըʮL4KR#? KA\mEz`sU?Tj*uo)ҏsnޞ[YA֓Ps[koޭݣrϫttݴM[u9{I7/q}zMKߣ~qSa@o̦,=rbxo0tًԷ+?p-~V[Zm d=s֖*}>tޚT/1?›\_:YZvρ5?dζ5ݙnIhc/X k}m{Էn~~zGpd}kXɩɰ=vM|cY H{`x~2l=gJ";m,4vvf{AS' .ć?1uWjМ@.ۆFA:smzl4xѧϽCL|W|hى7\#l0 $ p{*SS>7|-oԻ'sr?.vCˌy-Ca𱬨pd689k>zB⤟Vx G rd|bjn)t!;oG3kkn 43/ mjꓓUM&͜a ɓ>|d)TFkܚKbhx# 7}g/)=6wC{UEDCٛ6HJz숿р`]srysmtZx:5EVq]"{G: 3.5 p:!L h$nlhwM)7'Ɋ pum1R<{o|yn\dKԽpXD³nKt;R#Vo־3Y7xۨh#8\7?,$m0Otw-We{!Bý@yvWVgo5Ekhr}N˝!ʀTU&%p%z(,Ti2I=>JGR K:I]6ɤ"fr1ͭonFx;bS375-::b,#mqբ,LZunZL:'*\mIy>I]eŻp 4G1xG7%(z"+Ui8+$^N3ԭWb˙ZLb3?-okeȗ*;3˸Է$Uڍ52\}ق@4{t銋iFI>EGQe0F;YUv|23%@)/$$NH8EtuH"~"P'y˩+VҡKCJ.% U_=Hg ?Y}J)d%5AOLǝԓb kN{ }N3hPKޜXpaWv?zo޻$Iu8djfM IL|mvHθ5T~JA_,v>Dub@*PRQ16* JB-:U,VB+@iL0&aQe tp/&0z̉zCH*&]wrքDj& .[n?`NXbŇA@@AHI%CR5UoTIxiԠ57vNۤzDNPc_}}_T'šH/ϰBL~%#V8V|AWL-/6QS\ J{1=k[)/3^th.;siR}ϚvSZ^ub{a;XV$L&E{a`cSustTکgG{ETtdsyoԎ]$1S=Yԓ풦E;ZRN'&ɆU&nVnu"גwJQ9nRQHOiDJ1='tUjYf8K@-;__dalk*mS tF34U()UCsGRLQFi<i ].4j+7jbemÍΕzs ~["$20#L:̫P' y=WD+4(?t 5x=K:w]Mc뤧x4Ӆ¨?b0KIaX=o7RNzڮH_??P7/֋:ܣ]WrkW) LGB^b'V%a\!D0";){Oֻģ^?`X㹅 Τh&Z>N4@6- 㔞kͧ[]n3iE* hU( 1O-|u&~4nWE<5 ƒ=%qRfh2JLlث|{BbJNE$zXS)\bɵV 򽍞\;VYJR-m>[f4*챂I+(MFYyk R3h_BwFvީKyƪ_x~ H·/wuNvsBhFf«wBz,F]j#@r(z~TSCIͦ/kkSJ![N*vtLW5[mF0̒캕>Iuʲ93y>'i vr>zAYBM5Ӵnx:]| 9OOk(*ٕsŒ},f/~R:z4\pǦk7jygg7jJg١`eXd)Hp+)i^{>6 @1yM@32;es'Ioʓ>I*'ЊRsJ`4uϗ* ISzʉd^rڍv#W*1+&Sn3(ϕnA9v+_<濽<럳?CysP,ڪQoW?pGO国Ҵ˵:_[f,I[yu7G4L]s]ԥ.2ζ84L_U)7oe\B@1=^*z7OoN<=<`)5MIHt"VRFFm.u^=*9u<ĚN} w6?,BbVKG4Oqu"iI( MZޤ2Oߚ惎qWjxW!jR[ꥤW_OvܓKjJRI vdO ,[Ma*;H<{]iCO"<ۦt(H%KSseE"xH!%'h"E\ۄ33(iQ;J,&2_ѥIL|=ӳFrgs'k`g:l̕RLD>;WTc!ɤpݤN:@&y=913p=i%n?Ҩ-5[VaoDXIghTh3)z3$z?ץA зR\4ׯ\.kI[M{LNLM6zLo͝Xs*mNpf{ @OWup4ϟ⫷zT<i,^?$9"YKC$d.5p{?D"% <-0RI@;89f&u.pǃkVPtnW;U{ dp0D;4.yWmAqy%IcBhSʥVҕjt?]h#- G7k*zE/RG N `.f9K z qxjԁ jϬw?&w)@ e5P{7ń BH4@Lq @$@P]Ҹl~T@  &@4.6T(yj{Jpxxu@ dPݬbSK愌L$TiN$R x)3@0f^2i{&(h@  2elGƯ(͡zҁC&,X,g dwH㌈ @ XbU%lq޶Jgݻbuk㒗 7t.w}Ji~ioe_EvirjF4CA@@PŔ {`IRLFN*5> (*LqD )cS -Ϛbbu/kN-_T'& IJxPP6|רi.ԞYp6v򧍰k?$`U5_ e`@4* 4Hk@ * @LPhH#'2ET%4(XP-ة=74fbn~ 4(  }(@ @# }Obm>@ N*"@@7?VZS>ŏAb4VZS>ŏAbS1  :({6vE]3Jx6: Nw'xm?Wj^[/  ab4z%o#eJ=mm`k-?ėP* 7 J?++seu`FK O3ӓNTCL:q4N:ƫi.*w;]32!(fLWՓb˫#p85vUq ϝ۝ũj:7a/ G*^t+ѬE*3J v nU}_2qԆِ޺`Ȅ/|GQ#6lR~t+NL*N*4a&?%d}5Ks&B|EQ ~n-IRr.Wh(?-36 9cf?YֹnEe~TǟcO?Z:*L\Nw?keR1[矒09i ?hRu[L$''3uid =Њw/=zDOczʔ5rRYkn2&1K'tձ罄#O1yf+(vgP|o`W?vPu ~㼿OW7y"0i@hŴy Zm)N=/3j`X4qxi^,E iOP6"Zí^t/;22k3V win.JL@ Oʧ>Z4OjKz Ex? ]d0BN?'5?uQN(t"*Pa)BZݭ,fB a%G6˥]jVw^6>lTyĮQY.Z˴˺)tԑ쉒FI(eJ+.'IOuQr1?i?lsM!554Oz&bJ;wɧ }]˴kcZӦ;[Uu}t(ҫ0Ή#-1XT)@L#P 3?OM35SqyrpnH }-A3I <8;lIkK*wTiL* (mD@ gCp~de"H@ @L㫽Q[,/jo@ D !dA@<_Q[&CLcQ;0 4mn_@ L al@b4)x6?L @e-z4@jˢ^ a% wO7mPÅ3aͼWE{2zU]DrÚ/D>dN"' T񇁈)q !&1 1`$  Ψ%@ @LC Ƀi|3j  biC& ~泼tf:@@ Hӂ)\!BL@@ . $%M-,M+#Cp h]GZ t4\;KF.2..震sI" <|ڢ5G,JFl_+{4W{GD@Bo-æmꦚ]t4B*]St=YLȚf"E3@HLM_Ec_.0W誴U|&Y|  -t%K3{H ̑7:L3E  UË庨4v>g_!R0pQEj _;W\ @vBIABIF./ '16F A@b@ DT7 j ymIi_F  ꡛK@@bH@ @@  A$@@bk@@bH@ (L絇54x,@q #1 K  q:@Dޫ O7Zk)BZ?|U*O-? ً0h) 4E+x)~rF0)i "  b*+=pY{ 2X VS=bwȂgyo T0iBk馽{'BP CL7/Jj\ɚYA )e9S$-ƹm ιy:lvU3fa9g7/+˿nȄ/p^h_ʭ'q|fS 2gaJ"%w력@RWw셵)pƍVy+\.pX%eCQ/Z[]tȖ{.zdK!`ʘPq.! λ-gݻAv#.nx{`9%+p \ )\\|ake-y)o͞$1ecG,>ktMxd+1F5i>mNc{U䲺 !&?:'R={.zQ_tcplPÇCL'~2̥%sH;Wј ksEٝ΄aִ sh;ILvK!Kg+uCHFK*;s11۹xQ4=]O[]e$ #t䤲 趷%퐴Vаl//!i ܁!r,duLV;cuNִsg[Ë)&2BiZzb״ eR o{\22D-?OKe6&dO1mPÅ3 IHZ '^g~CK -EFJ;EVU+0&vNb-aY ƧS!$@,1)BL=EʵrD0<yYby|P"E@ 0{@M@Qb9_@b{?pRPaBRhе1URLG  :bn~8#e8"1FUABGb:H@ (ƻJ qب"@ @LC9i42 z3F q@b*4@,'Xnd @ l aC@b4[uiP##X&1E@F%@@Wtx>4)3x;{v*%D#pPnkSĴqVLϬw6M#ww[GABAb H@ p1?8^|@W䫞3 QE%jfW5."ڹeaIH+™5)l2{oz*_i= b2ֿwdRf-\Ś]x/46.i" 47;=o:5O8>3'wL㭾b(!QĨ&@6Cyodž8jCyybvnx|6OG݊G.ROѺ ƀWUC^Nbou_y|@iއ(Y J2+i 8a969ա⭾Շ *D:F=U Ku.=+Q@L#>Db&>>N)4qxӽcU_i ܤB1y))Xɳzc޼7d^;N|u 26;M5R(,hQΨ&iʍy=\{>4y*hȫy9^>\g-Sl{2STJ+5*U_)uf` 5ןx6>9!@MGC58{/w>bZFw*uвmKr8z[ߪOa/U\n|Wn;55C7R vol|R []Oa {חSh(,nD.fCʬ1v?ŒG&uhk(ԇeVm1iL[kWwqagYWmk8X[t''r(w#@ts>b@'{Lpk?1r@e-Fu.p՛y߾U?) 6j-|]>?`nQ}dǎc2~ A 0Y'xWyq#lY ?'#.rRڻl;Wҩ|3w:xRH:;!Hny 7|!lާb !{9ֱ?*#W-}~ݡܼ7o[E.+Z 3OUe%;؆Y5+W_Nw|'X`*D 8= xJ&g\}.{;G JIXNɵn۹xJ;4רԕs٭3=v YGOݖ,t#Cs%+c׌:1VzF7Ab?oh_'fX4 5d大ImURw͚/2 A@#k!4zWEU\*㭾Vp9 G.+z=Uᰓ)ZL㭾B7?72gM}t{Ufk>wZ">*UI+>=AV_n>4d5mv9cD_ڗO?7ccXKA⭾hQ!.w'GcP߻y31,͍_y7Fb5" %Œd$z&s: hWh\R]b0kݬ"ސ@SQã #1 [  G qب*@@LC)c*eL%3BH|8ƒe4_`uU{fsLضϥZ} φ>߶},(]nkiw\|@)L'1?{Wbj;iw}#\}ŜY_L7t~y8h%kQwX| ğ㳠(4|ӟ+Ч<U_}R.}*?|Ờ~'QGL}'O9|l“bOBPÙB+pm +7A@.GR'jWsIENDB`n!i%/!ɷ!PNG  IHDR1gzsRGB pHYs+!yIDATx^] x3oF!H";!_0m"ZR+(ZD@>HC$ՊJeI1[{g-I^^^^fs~sɲL<7[3YNQb49AeI-7Hs _]&ٳp-z`w@8]Lوψ @Eiqib#d, c=6|T4&DX($P 4@]AҐF)h mDC[WKm/@RU):%CX"%v6ƹL):0E5@ TP,0)[]}+E$UFȡ%CXmb%%g*ܽ_bsᑬv7dx#LF!Ղ:Cİ Bd9HN/;f*"VœM3D%(1`"85(ׂ}7D6]qԎm8c750p,sGA\C. kUHHDd΅D n!v,9'$Ud:Rm'EK92sҕp$:^e OaӟX`I d` @e'=i^]챵 ɥE,+)9K!!3Qx]ZqndPsY8,<`D3!МvNQ1HOdGkT^*Y-.Yp1L줎XeU㥵s?{% n%. )HIۮ5aBE>25 !G<B/T\C.(UWUANC(`v@ 償de*hݯr;Kc-G!^7ӈt*hf+~|q_|f 3@uA GLLz mCu (iX*Ϭm5)hoT.uhGA /V WY!&EBZ/ɳv#nΏQ,?sibD?s\4bٳ~۝yshKmo)oHr+&r4\+ +#ËݱSGdRB)PI>:gӗYdDHѬDE@p\ >t5,8!@Jp,P3z4Gϕbks~}أXd!j;|Q`| -cy&1Cݰ-K:jIFi#+Dƶfza/p#17N-TVx0Q.k~R=3,P<:njFVpkZ3ՔF"Lf6}#c`cy̔Ek_=HfMkf(Iǡ9֩9s,t@FJt.DAZ]1 =YԮr2\Tb66qG0TzlGV\ XR[Î_$gh`&z&'$T(%鼂wfZ4;l=NcS{v ?/G%d 5Sv'?>\/RS.Q}NobOV΋ioO>j/xe/:Sk2u]~^*T $U/T+8r.%< 1=24VN~s~n?EfMo̵MSBipaD~9&o00 ai߶;KOEgM<ڸHڀ.b *5?nHoLp.[r'&n|TEᣑ_N" |,HLuLȩmҞsr'1g=4:ᧁ·iҕm lgP);;pyEpi^B0̎ )=8j+h=_R)vc/w+e;320XDg2;6<2 /qytr.\ wepVZUS"o`IObࢣa0av6.jNǬL7$hA.e5uzعPw 'J0iǴ5OXb@-#L0Afr 6D5=X ڂTy|;1M+n?yȅ*Ȭ6~ljIy3Ђz}'ҾKVVYUQYY^YYV^YV;*˫˫+*jgE*lb]p{Krxi\)7@(QS:4[k!T\fȭhz! 7Ʀ!$Ӷ_| :LFTD[&ªx<n%'8)=:??][C"CBo93-3 =3yMi7sJEmLl s5MeKŅ-s64QL x;Lo_9 e`V{* 4O}8! e0"{z90 `~)9YpF怟?VR*waw3Xor|Yzp`xޱ^k|z-=5;IzyTbX *obn/{5rjؤEGQj}ZrgV?5#[@eP|4gQ6?Q?~"Vr06̫!U$!0?YjSZG @[ 08o7/E8gXL|Ǻ>Mnx'' 胎ݞ#_j`}p56LwOAH} $Cj:vLJj^;)RxPJ7->zi0s*Yb%#oepbixȣEমaʇspIC/^wOM"2^YJM0 F /ASՀN}꺡LwDpZPa$_Zm@age p02n(ִhBK/HBG7D 䅞pcJHM> /z9Rk BOšZP`mSy4_?QzCw梤YdV6ImC OY+ 3Sp4r֫kЇ-Y:@f`zKRvd鄑6z55D U逈)!HL=U野/:7LC6:N?t,LuB7p^*(>ARɲ"ӏUT" oh ;S#cO:tfj?{)< z@AD'kgs ɲlzOɣ0ܠ Ud0Aנ~5b@Z!k|@9} 3VN5#G'f5GQV=7W#mֳspI]? Jf  鵟cR%A}HmV`Q9gsRlڈVɍT{9ϡh[ t`zR9MS1$kXY[OSUOGtaHF)jv\b];t)+%ƛ߮mA?Dw髝$ "xC.((m Ɯl*P'FO\ VP)5 xba.mF"e& -Nur,NE_wc}rl>3D>D}w݇~}9 팴-tArD^.Φ@!r*RpN"rZhjGX: "L`MMpX:0C嵲0urC8~G݀mQz1ǁZq~y)Ǜ}q(F&",u@DBN{ߩĭZv(ߌ .#Q,{sStg{UڛG яiaZy_G{OPt gcse,|tTj4=nmm0 ՟>u9}ܰ{nAf,zD7GCjhܡoMW^TM{O koZ>Xᷦ xgN. Z[{ x Dtڙw㻴6, & EZ[{dz7@aÉuQmfmclnJ4`{Ƶ(k8u檪2;O_k=/ٓ}C\n(y'}RU}/?,rd3!5z4k $j#w+=œp |={$xCn|bO->:gw>#̚p/Bgjz QQ@~ц[VVVG2BHą`wVx0lE qg+V?,l{Nc82&w}Iu7/ ^ڨ ``;3F`8nE㟨M#z{Z)ZO[-Yp"-cؙ:±&$%`Cv\2(-̸m(̚#&(QI3SYϜ?]'n_(Ɗ7쯅ۄqCbyg">0VOg'xGNI%E3UisZhmsDB-9=8YlE v%KpEnf8 ڋt".|s)gQ75Wj;)"߿SJOZ[{qxTpm ժdߑ ~z7?=~lRB[[{݀𻝢2o='n=⩿0FKUO@jNedVd4Ffܨ\ kkh UKD훅 4٬C DhE8v4tztzakF^q8"\zt@DE&G:NMocL)Up(@f)/G [H4ly֑Ouy's OEYwwzQ}u'dlP9h?D`4nH[Dj&dն8?`[1QfIENDB`nr"(6<0`:PNG  IHDR1gzsRGB pHYs+"IDATx^] |տ3oN@%vĸ`@DPZ m?J?O"ڀEMdS+*Y 1[wν3-{]¼;w=?{3,#p|qHL6pMs"^'@\" YK"G/pZ=עWL.bوiąQSi6F"qI.  {=p)I|B"fK$d$$>hmAҐEϵE, p:Fj|QXH}nF™&C 2#/ua,qH EH[KFaF$ȹ0g9A EI00D~nl$V Hu q&H69a9Xt K.@Do &$* $Y"2BJ?1t;MD TC@줼LX[?%= WKӔ &-buNd& V5~Q6qң̋~}]~&'o~X%, VSyBzb Ƞ tY8$$N3!Д>G =jvJZd]v D߅k 2lI,NnkХ oK{cE n%. nȀIaBE>@35ˊ EW<B/vzik`j NL! `Bv9l,5Li7EϟQc'|;4P)9& SmI=եuOV)&):sVet&%#UC`Ztctpкa1P4h9sg6238# M!dEo < KFSå=']I^H(}z}\ĩ8k)/ej6 3'@3_n'ANVyxb ChLR S˒K龄~FFNhSxZ^ڬD3WS}֙hƀcZ&^ǚhЈ.7&bP9MG}ۤ(j?a=d%>C* SH΢"h [6S<'Q?x:9G=>mզDT纽`/o@"BP=cLJ5xtm)@ysF ̆yP__Ŷn_ss93g_BXšKRƯLV}KMktrQʔ$dLl%.%^闢eN}d=J~R'gzvlҵϟ!ZڌLqd T5&<4f#5%' a(HpK !dxq*1Q&)So~#1A%3kS'o$Z _ҘLR %uHA kJ)ҬpcܟaQAkem<4^&bԔnɆOȀ?ܝXB]?9hiM%'h-{bk:ϰ:}yulHo|injjSVyh<uD"I F (Au@s=~;Xts` oCSx'i~ Xˎ|~AkǙK@uҎ 6>O ʎiB;:LHlh=P%.dyp 2}Amȶ ) 4 '9[48NE2W3@Rr`iJ97<367(\@L6d^Tnzp|1{>B d/McѦ(c@c4DG9p9z".Vpעf9o?g%t-6/ŊCMdEc}/a 2倘e/\w!R#/9|Wyww~y2cdD!n[X\| ޽\<"JO|%',d~hޒ]hϞq]˗5#~_-Y d ?i0 6˴Yad]u뱝 &杂 ^b9|~ڑH ꥓.||bGU/Ja_\b"$@|ao:[1Y j>i.x BG෰[*)شXx aFxݽx0IkP)\n@i/ܒ_>_ M|G^>x6d"٤[1?$lٞD7S YtixqY~ 4%"bai\ `FXsRF.'乔ODXtb3/4" \R+`$o}ӓH[:GNx%0{Hw;A,ZK , `٩` V"#z74Ԍɋ-@fѥ#SFibV(B֠-D˂MZɱ(:{ucZ}]u9 팷#taRD/LeִI%h aOF`5Lo# B#ʈ_"=^TG׬;VJ^?{d֡[!.=:&"Fʊ 'Sư7`$ صs.(wvQZdZQa-U#C҉]K)q\vS><\2H_ЫKհ[\-9#ˉGT(ch`ٹW gH~bmsC`XG^Xy#p1se]\(u/"o @[%xR "oz꼛m2*Txu6(άtAcAI|!zN%UsFDOU{.uoѓn7Z=?m |08D'Kr[!WjΔ34`V8%L UBauw!ف$kN?cUK/~Vd VKkN5e]ƃ7 w)־]Cf_M8e&<3%hƲxÓG/=c9}oek_,U_ӓowhP_sg/+bpğ1cC-#"JV=, opS`k oʀC@N(!+VsD[]h֘F#2ptڡ,&C`<[韧y^{|>S1-ƁVPw>T"n@d '7!uLz?|@]~+ow5CoE>VDņ 6T=h0Fm "!}ܣ :{s-. gcqҹdeg35񧏽Bz  sf CPSA6˯|;qJ\@2Ʋ3kڻwN8켺urvʎ^Ӷn[p!e_54%1.2,暚+,,{"IF{k("P3Sݖ.2fH f^Z'Gkl@)ΠXg!{ UA*ko BN:D(uyC[ ~ =H#}SI֐iZHPrT`BVXGkEsv=~r_iw<7hnyT_+u?F@Ss] %[y`:/JDt{-G2^'r}$`(Q-IENDB`n(.Q cyyPNG  IHDR[sRGB pHYs+(IDATx^] tU>M c,(K&ڨ:6RQD+C?v)X&"U 0VTeH 1߽{{I^^<޳ΰgˉH\7[BhOd-'}iH$-iV+"qD!B|@8[b-g V 20lbaq`SQA:YG"+nri)ݒ5Iɘ-LRdBiAAFy恞PP }xCYO4S5IK3o;p4ߎg8@׳.5͡ &$)jY8! ȉqAdJ*Do qZ/HIq/ IF?pW$QnuVQԊt8D Kd)y8slm0tUcQ1 sN%̙y.rZ;yAv-0Epz:HQ NCD1Y$c@G44[JZqc0O4VXtG'AEmg00,L 9T`۱_>twHЪ`4IԜMH,5tp(&<~#ND& `GϋzNmWW u+WԼq` n86[W|2V\o^ <-r4.d@;U=zjd 9Sh v+v[߾fu\#.o  jC ƒ/ 2AI=j N2F N8,Xwo$idDf.YhqezwR g.wivL8>vVo,v6w8P4R84ȓe=i my#He`I:njh`°309{)EK49uыϟ5\>s]׃b:.{gm'̅njS NXXb˘a'T뿤7u! ǘ.RR.5I:E`sqUb1~2VmY0V̇'|tж[=N҂r>Uۭjf\2WfxNJqW'Tކ0͓m+kpT|m#ؒ :X24 EKlJ釭?һR:P| !iJn͙ҳFXgΗ(.O$_Sy$%xf0Q68 a#ᘧ4OsSC1P{城|h&<J$IDg$ ?XQC+W8xkEpAI`nBؠ*!TŽQ9=x78d! eq}tr~Mv61)-Q ?UC%H%d݌3*tL'SP"mJ-1"($!i]Jww5s莭-,/)6iMvO&YDaQdH5  Bp'W`Vw׸/ tp46 hh9lW3i8?mnYG "Hΰ$=?j&%1ЃZ4Ix'GQ8Vߛ[=E Їtcu- jD<2 h ,!~T w,4סNSw!uM93 K#KثneT3 M(}?8n7)xآ !㟎H  2d up6I<(TՉDd/DǍ͐( 'w  V_>\^r;D͠+F!&GW>X7| 4?.^%ONn]hz?.4^3@Ne`p Q:0b>gXFz" -m܎ K\[~} K,'5 lʀ tIƭY*p" t-t_³΄5܏igm 4*#1ԧ-BNWe \j[턏rc Q:- G[K²UuyA|zK}ه}q!?1B\Dl*uv)+/"9GPUYENȹߢ;JkyֱmJ to`6 SlBXD:M?NsMCg\M`<ڸt|6~tKNPqR؊'=؃H!Z0sp%Yxyi8ඃ*)|[./O.`~*Bhk %c_Iľ|lKZ}r:cli…}XO[!;p2D9?S a Jg-:-)=4Xj{6Bh:4}ɳ-0L_&8(f7XDw 'zk3zr)*,ycX^'hV#4fm6l⏴wFiT! $@3@hu vEeA+! Ee t\"؋lCDԯ=%gW h2[CsccKcckSjk4ڛL&3d\%Xh<)k@(US:[j F.ȵ8!b芴 Ud~_ΛtAZ6#a+S@A\éX#%|l`T|K*rT5_1@$=ІokHi)N=p s5L-Fi*A;Jwn6U-p0e[a/5ȓs+ 4hlqC\aDKo`*`0R >b `iҵ  !{| zz*sԂ*v%LGS]ְ7]2fʗރ @ n`U'-caOuK)܋9c'a%?DBp~jP&[Gz-=I*Kw4K W&V́irv?i+ b* bIZaUDKM%iVa`r,5f+ĚĢT Xrﲷ* dQbePX\ʸ1SC_9\Ȝ#Kn >P3L.y{LLC\?*rܿvbOVG4DPS+*#{ЎAWǍґS] q7^)8wwHm1sKqU@GФߴNQ9")䍣R6*!uA}nZ3aǜNп Lv͈鈭A;3DI\]<~mb>𻋠˝=o _wggIl j31f遖\sJ)T9~c{՞yӊ O_h5F@>QBxHPƕ}|,Xi 'z-Mz``R qT E<}g7f%z1uH(T@! a{৙A+oڥ kYE];S )j vi|OzԊ3я}dExK{8c|a{ӥSd!h<`ֵ@jf/1^ "* `]B$ld"a97W7 NGT@qSKLqpv+tl `Epo èbR&(#8QW['W$&AxSϭXk5\E8 /o|odkyo,ټ-K˿K{2V!aBr΃&^x!.>*083<h>ܲ^.Xy吲b_/[ QV1CN݊1,|ɺŲ1{gV,9S枌!+\90X1fJ?BRыOߕO* 9HR-ӷ̉EHH,EӋ/!^[!y|_Lz :Й[19!.9zl;gu,=>?2ӱNIqH]"*?^?7:^M^,`ǐF$3AS&4 O_]{!FW(]݊>!C> ‘9![3BVOՠ#'|+h.ExE)4)ja97Bq0HaRXU[< zߎl_mfY Pl)͙42pr$v/‚n2q8wj'҂jCԲUyoC$ Z;kdKiTE }UF(8uuP>ʫဪ!DvSJ|* Dv}HRy+Iv:OCc^3TcADN|DPhR+Z7|!T"jeT@DQ۪ MdSDQ۪!V4!LDdZD0{Զ"jET@DQ۪ MdSGm* V4!LDdZD0{Զ"jET@DQ۪ MdSGmbO+-@]qRa.m A!Ɓ|WgOiɚQc+%7o%!%eKS-Z1 PO8߽5&p rg( k+]9T'T0xp@TK3olG&i+붩G?[ZypxX]+q(Ǡu)8 ƥJ(S{R^3!/}:N+<̿76c+AclV>}.V,VOxKGDŠ}U@h* T@pU*:T bsBEG4冴 >RvCIqPԇԬ82 Qe)K:o1TUmԅruYR6RLMb<  >joKgxi焅x1|3=-{ƕǃP"xy$8d3v,RKz璞Y!2`?2xK'g +Hp5 OKg Ҳl4)1u{v$kcVŤ3@BHEt}aBg.y{ @d"x $صc\+8k(Ba7].공 s3,!~@HQF\f pj|J-]" l?>G̏ 7@_.1E GUtaRy[h!-%=ީ )crjUǁ#_m)Plx}* b\&_D9:\qU`"΄BsZ.yUƔ ƛTM㼐, Kx'> }Uo^gIqJ X9ԝh\x{,o'hJiɽsɎfni_|L tA$]ϡ8oa^o@B uᄆ]DXrt#)tEN<\9}!Nޘ0ueAMgR !!4p 5~x5RmΛ] .}"X^"&OgJ>,. dNד=x9D".ם⤫s* Z̾wN<* ZwN<* ZwN<p* S~J߬ς* S~J߬ς* S~J߬ςzoJ *Cn8 *!bdk@^mWYȜgB]e$,w(VX@"M2"(mߧRgx  upجkBgHbs4h8>9IѺhUz ɤhVxǎi Yss=4\N e'Ǐ͝6d ~Ii!Nǥ{tãnvF hwih `F% f[E>"7 tDW/(à qxbYuNC$Z}+ZA"w2Ô8/P".M=aʔ πvGctn&j7MYHfwەAG(%[PIFv!E[?1S7/Tͦ?=\^[*QTj!):T.~Ϛ@m 0P֨T8Amgݣd[;lfSѨ>K:>tV/5-siii4N=m KHÞg<4QƉobg@Oے5'~\*!w;KyaK(р4y0mMŶtq--- ?=wly#?c)kڍwO?)- ncO"?mX'ϑ;ݫG=ے%Hp=!޹b"qFqtd L>ed120/o5P&4pֲnLQOةU?L:k i^O^5uc'9d0p֫0Ώށ[z\oЬ5}5]58smɺ9츇D/=[B: !ޘ˃]D݁~7& ͆pإ#v#tfBP8DYsRGB pHYs+IDATx^ `$T6mI#j姤Z5(PEm@ֿUB Lm@ %g cfgNv7n}ݙx;;^6MӘ)Ff% ّN:XrsՖ50蹸g푀=uI@3?LDߑ:`g9Sf"r2sj;lt__l]:wd؉GLRKL:†$ƂphKhB|;%T56nNkcN8RP-;zvII7m$vqS:uځ>: Br>@@@@9꒔A%U/.EWn9^Oxgƥ튏YYR蔦F{J͞l))qW[]m\ɓ }ыw"/8m'``֑K#i;95[gFRəRAjKCԸx=a4-δdvN ZKu'Cv.RXة4nK#'sH<.svG#A=i6G~f @oyEr~hAc5<; ;fSxz!%$4Hǣ#kӥ]7?* ~ $F7teFo8SKLj5p‘SȥQPrLÜL[w9֍a6(ֵ@":j9̫ ۷ƤgZ}é81$!nΆ~,'?;l; Dڑ rN8%`%WN4TZZ5o|iQ/51 n ~w[֮ ^b[B6  Sˀ-ƿLC=t2bMimc6JK e_bsRw*#3]c|oo$ƒ^ Ne̾2elPwҦ͝X lt ::?2?b[f !@LvhMXd~V.XgˏƺC#c*3M73zTֳD;ڵOmȶcҤ;^Z~:LRZ7f{hwvZȬQo]py>ݮT?J"Br>`z{hŽcۊѼ.A%\ ̯ ZDdDz7鑓K^8i;>R~).m]uRĕHu^YMgTVb43% [`Ziz3ŧ@@@ n8hyRRNKcI$h2!nξ5{Z!6Ǟtɶ8 cfk`Giv֡+R[sSHn~\hyͣnRZ>AȎ-̝ycn^Qd!6K/~v_d^'lSw<9VcK;Փ"xgg QџL [N[G {-7!7  C&ƞ|i}K=B;Szd}sӏuFnin梃RSHb ݷÔ~ւUXRAd*X?؋u#whLV7S9c/(/O:?& '!?z2"P҉d.d^0~#w^w%pM)qT{p]O{~֐f8HsƮp'|zv$7aN3ǹ]E>l @WhXGAJJqEC<4,ql}Qtio;WoI7&yX6ѝ@9wAK傎O-I _UL%xaKI:{$xz<~@}~طuS/ֻ_Bz!xVQDv!:jx_"r <2t;IlT*@Rsާ,~9ܣc5os>t8s\Ck)}ϻs?Iэ/(7cK%n?tvӋdorҩܣ8bnFȒ͹ *dePδkotɖ@8@qyP#HBn|]%JhZ_.( -DWoEjK[F.{GG6 P8< 3\n<p!FI7y3tM֐Dz8*#!{$1y2PzCJ"fFP~=NQN/#$^+_:~_ϾekgEeN1֑ۘXafoo[ʺ{L񴁥n]^q433Oo@$ฒE@h+B绉# J~[U6&)=Ľn^p)ЁD#'9lL>lBr\"٥CKXʟJ^˱,xr)٬~Zذ}=IY6%?u0QoAߒ|ma(<9#㛽K7Q6SIwYl\/#Wz9+vr>XwMԅTݢ_yR%O?觙;—l4knfc ;;V|dccgd=;n|2I7;aQz5< UӉ^6fbM$meӲܹ5t9ų g# 1ONe짿m΋[}9;wެKH<@EV?aNo4'!7e.l+$i`q^_J3d-mi2 Y7vRNCΩIU-L52dUon:U+l[kܔ(@BS@]p?wvjRl;v|kx%aӤt'hs3}0uo=|v1yNvןXͬ)R:uQk$@K\44*rU><_KyxE٪r6]Tn=ʺ^!˚A@@@ ,?`^IzI֑: ^szҍw6Oxc7|qƵv/.~WURo~7Iv;a1@7֍:Lun:Z Z֡%[]Ёvj 4ÔǺ5Qj;A@@@tkM nm-Q6Oҭ7qWc)z%wd7On}`$Hk2    ~ `im9y<:SN^EA   {ƛgB%h&fֳD2@+J]VJfD%p tt;$j`7 {*#tq-h-Jl3Ban]X  hOҸnO>ip1no rOyTqI`4jpMg>h{bJNJA+rHr& A︇շO <9lc/f)vo 9ћHfKqhvwiO.YO!BHi:)*qdHãFz03k-VH%7cRQH2Y֛IQW2BME%#΅WK/JHEAXxS"1III"ݦyMd7wMyKn񥰚͚tJ!RcBFI)b_.f1frߕF|%1:GR2EthC4u񯞷Q'e*[JTg@hJ؊d"Ou ,t7?swxo_#a)wP= x|4&bbz4\/+y/6 -?>X%>,q{477tVEtj"ogb2(Ⓖ Jy(/}x"COf)zy\UeGf#͒qeyZTӈ"3d<**sS"TۙL!6o͎O>slz퇎MUkVnعݻwuhpA '*?ܼK(~jg%/}otgs1?yf7.W|L\ FR^t0+SǢ1]Re+żGH9?Sϸ7.dtu$1t“'齢Vr豣J1c^‚,GnyS"m#?72_9g\1$W I?eQ辉&SRT>#cpЙEke'7ǯJ}xb`yO3#D)?yj30? bH\6)}[yG(-gNRCL)>t]J7/dW[:bMrx,S vNm%;1oH ԍz=<]}~?nSc׸`#bc3_\y ˥QX.{GUv*EG TC(%ʳ!,թ9(rJJ+ 8a)Zђ>E4B8[!e*Hr0,aZ"A8SgfpH79m57`UVZzޱXә;?h{~IJ'2_gd )7ХVftæECE=V8Y%;I{-Ǔ-vMs8]D2 /G^^M(3̴{ժ(Ǘh9i4v컏[K\xwynjј"*(ʋ?Ls,UBǽdPQʵR^T=m$.*1K[һasE'J##PϋjP eKXHQC[KaZZĒ׺JTI,n]1Ko_"#YcUu]UVbh~AHۄS:݋ axJ4SY\-ɮѡ&(諫ҌjjٕLg4{( BNIGϓƑ<+>swϽ^|W<:3Q.OGry~˵sQ7"Lɜ9۷3~w1yM7:|ܒ+a~k#4M{u>˩bD3pŖĺOLHQZnmPAI34MA>Ԋkk-DB_Zym~s?h/,Vt]z_Wrg?w{_X9 ?G!2c*#M,z焝^@g'\wMY4*4Yцl68bGW8<{9@  hC*IjT.٤1sU8 R(T(_Lhկ*R˲R@T.sa]G7i^ʡ7Y2o~JY쐕:"O.BCim)" u9 ){X|0'zJ4tҬA;5<|1|Zzv+9h bqw#(U|[\fr7[#>ܔsRh%\Zgs)A§)XF$STD㡤"H:\3']?f87ŝk+87.\OV}˿8޸ZQ?Rxcio>2g#m9\7!%R:jQC8|s*a^״0II޻iM]o)%=|ƭ?zb'dgH 2Mdʣv5mOOwWSorGLQ.(cR}LseM][M{w#y,|lHDb+%ݦi"-aqGAwbbl.k<wnጌt=Lk1zv|-DLZUWW" D.57*bI-i5_8FTſ+Dey%K˫G7[I(JY$ov5P֫2M1`ٗnSBX7 gq9 a=ؓO <3"o __;!q-v|)$CzGi-oGPCBK $Tz 'Uݐ,9 &(1wHɧxu|6W_]ʟ*E9Z=,0Sa:?<̖nQzʊmM:dz76f&[kZUVVRŷ৽n9IE^8sYe.E1̤L}j2I+]ɒ?Pӯb4ll~zIukh5 1.2T/6;x<%J構s8ȯAZBEyiz o-b0t۲e&M:"}W$Mw' ؙ9HGXfp&eԒ 4Fٷjt Af}SU`eN)hD*>Cc+htTwY b/ {X=HsuPOx9\un s ~//t[zu  L_Ѻn;ݰ]c•|`a].ۭzOt>husܱOn'5huoꏽiޜ"2ܒjި|A~sQ$"NO[P̱Rd<8>vzntÇ:ྯjQ/-/)=̆}SnQzݦF t68vۃzʊԳVq唯\NVOcKuoƽnBQڨUJ6ҼjIQroN&igx˸3OuPŠf)EwQ<΄L|* YQ̺v/^7R _p4Mz@@@@ b ݾ'g7{wWA>ndOpqpn=}wUm\i-K~O>LzزK*T6+&fDn4-s”,pbe&ŧuF+%0͡TйQ/:fF   m@"[meQߍ}9vx1sGv=t5b7&)A#C,JLS0*%Wq D0@@@Z鶞S8'?NҫG瓻w<{:|ucZU͊UnrB eYε ? W    кVbesmn'es5Ks;錍JslmIMP/n;"N(H=˙| gj][P:pOJG"&Zw'.vb)"vEpE6{J'[0@Mk Q&9hA߽·vX@ƪQ}3060Zڗ}Zqpw@@@Q(4&fE9 ղMtZm^Mr}ew,:՚A<֣CM_̞ )m0ۂ&˜aPeD}YQrYrDN   Њ|R&D6u|V)yΛa6zTZ,[nvyhJ8;q1KZ? I~v'e^p^?ڳCC헌 4k`٩&Oׅj-Ǎ;p.z##b{Fv.P8nd[Ѻ;LhhpB9 fϦkSuB{Q7z#_-XJ&y>Azy;> h:0Ag'9g<}y>7_n]M+J&e)pb~V^e/ͯ%swm{_9Ez9N'acXl D uŗG4~,Ϛr9)wg-gSe培\5brnU~52I9u  /2UR,Wl W y(c)ݚu#g[]:wJGjj=OmhuY_=Zҡoiߤc¯V<vWdAƶy;L 90ܳ]$!WWz<KK+~ 'iI ڨbegݹYEܱʒ_ e]rxϰAum @@ gPRiRQMi<\btkv:of][]N$qj>z:.ى=ķ;VGo~^7I+[Adq`@D_BXlM龴&ݖ4BBrRo4#nZ0ŰwuLQhXJzݎܷ]ٹzspǎ,xjW[8sbu߲:m v9T=XŹ2]9V/-G«$bG0q/~B:/^MzY+.I._\X*o#ճ*u1Gwj   M&vCԺ.8< L[q)=9۾޻z7Ro1tZro>YAv\6PN}WyڂucXM͜B{N=Y~4oAKh1h*_l9*f=7_ߜ83c[L/ /ӳ +J1p[b   b8HZ$ H4i=>AfWm!Y3ۂr9ce5Vʢ>uGsbf?[9^{j`7>ۄA o? NSGSl}#挄  I@n?'N!9Ih2\.|nIkw |zV?uK,n!tХ7I׺>_W}>pSt[|޾ @@-A]N&'-FN6c^ZD.k9R5ua9wQQZ&2DRz-p&@ZR wɝ fb)ݚu3hR/h7?< <@ ; 94 8`!`w;NO}u3ؤAr1IhbF@Ic"I@@@8--n!~i%t 򵁿78ߨ&ж|6iSl YѨV?S ~Gg(mjs&\V45h$"@}n jR[a*6Jffn4G'8ݴlOr<+ҍ+R 5zbV k“ڭzl?WKL(N}VLEf   ZZ-G^Cy?Y5P7ݖ3$c擯{7/56<7Ñ?M8?q{0+͵8HsO hD2Ғn!Q{Fn#z)?XXGe ;zQq0@@@ rК;aaZbnuC qHM_+7rSQ`Bf)YʼnY|i@N;bdUT|DEt Ji֠ٝlfl6ٙq%G-Srɠ&x?z BGc^} Y'n<]w^x~8_>aӇNvQZLCvug\⎢An>%hN"UgBBp7-f540.m84.mQ   wkq( j%nłMnilF @@@eiқJtk|m 9f'a%nr8$a݇>A͝fWőg4wBnS&{ԙ [5DhDntc7^   1'p茰yrv|@+֊`nr7Zэo_DnlZՋrHY$"6BZ[,iق4y]`.c,~ȱ~ 3\Xn\K\j`tlNs')͚rc|H N5bi+r& vc @@@Bt[F>3Ǧ~(Xf冝?ݽ{W6cKWs[<|q8p@ R5,M*s3.8/cC/μ|pC2~ՐtnjQ*6ݼKTeYT>MnW U(I @@ 4XJYl]3o)捃I{k,;ŕ@WXږ90:V-ZhM#OOfLoT5KkZcg T+Z҄bxp7f179LL}L%  /b)ݢt5:1ô4z%QGBvQYV~ 3)Xu@bL9vV8ly aQB.5فtZi~娐S.[[5Jie|^2 *qk Ab 6t2I5@@XJIi֠ٝl%4fgvƕ mؽ%Ϙ_y"S: ֬UwKrŽuQG/,lp.JsQinhHX ڹ-+nCj'L{kO-VW#tTZ'p$NZ  ОRŭ-%;}Ѭ_XdђYKSmCCu1ׄq9ag]5hjr\0\(:[nqux 3oau~Ot7 fAo5)VѷNƺiKEy[r^L(%$|C  1!K^B&H -o]TpOfmN_IJo9N16kVL6mf$Wcx7,9$M;EM  lNw>} je53nVsmv \bX=3;v9Թ|8 }ci9Ųe/'(`@l̆^Xz^X)g9>Q-kG tӠpDI@1@,;L[~ۦmkl^)OHTX A@@@QnM򺽻w/3y^?Q>u }`[ƪ;&MwlΒFdoœ -bE"K$ۇ[v>y:Z3zth>~±ucCedT|TRd4W"_6HOSxz@^7mVMD5gCWג $$ҽ:6 j_ҩKn:2Ow{:t9g=\>wyAIIR'GZ|*-b[8r"#8sSV1hzLI?>G'46F@@yb_ci YzV/ҭIHM-pE;Q9N;|pA[Yz֪=cIZ=-ՙQӛ](%Q\ўjKy40]3 D%FYDr;9ě͙7 J[(ҭF=@@8teiƺcչsΝґڵGS${գ%FV<vWdAƶCcRCe]#宔VB̭$DG zov:of][]yIfe~]5Xgv[V7{X~R~n:;TbpK4iN&6#DA ҭ^#n׾ov#9 }UV.ΜXݷtDMbx;%H96O;llVvQQ,IZZ?,a%^ˋ FhM܊BS)ŎA@@,[>(qY,^mj.ܬ)7~sg66vGATM޻Or->Z.H\eOGQŸ4Nhdm~ֆnaT@@,EX +Ԥ?72_9g\1$W I'o;O_y^j5>@J"@uRC /(v^7҈DάK9kLڰܜ?!qqآ3w2K{kO-z觚~1[R&Վ"cݤn8pCC-S^K6BFzod1[d*Nȼ=\n @@b-ݚ ~YbWt5ɮѡ&(i \Dgn4Zz1ٓJ*Hr)jf Bm vIZ9eJĠ]J"LqLuDcy蟟U+s GDQV."o m%=W< 2&ԳLKm"FXh ^,<.xǨ8}Eiu.2mDkl @@@bL -nn))f=AfW7CȲm{Fgu 578c7v`G  _߇c~)R95zF^3mqY!@Ju@@Fլg1nW(sJA _k}sΣ7E9H醶 nBn*SfݣcxjtsK6    @b)ZDZ(qZz7@@@ QR S|\JlEa;~oi0Wے_//٬K e4M@@@ REn ~Vr57Sܒ܂ 8&">0/D @@@,t[mUJ0>3Ǧ~(Xf冝?ݽ{WA܃V>??+/OF8{MxOr򑅅xZ@@@@ KfCM*s3.8/cC/μ|pC2~Րt|)=Ks[ɤv6We"?[_9:fi/ JrsK5mŤA*ieź/@;!KZ^7YnctIPvS՚MUv|qǪU+UXSr}MM=8~OW:h6:dK[qa/ȫ=K2I2qqg8gDђ<$Ƿ8:)/p˘zUɠc36*7Cȯ0t&|ƍ|k9^2Θ/Qa$ =!r-2{\oa6|Fz4x􇇮yJC~μjXF0#K|EFMiHu\wSTùx+ =O3b5t WV~Ԓ[7(;Oў)~?ksn;FE ##٥EX bw?ZbӨ>AH7%Ϗa<+l?oT@@ ڝ-[Xna!X'/:IqɩGzRk_>X%Z= !V^՞ɠ   `-|v`V#nY:zb%ݬ*qfʕ5ZMbR.4tk@ۮ;j  1!ҭ}`K$6k9ݻμLL#@ԁ   =An\vS[ys@nvc+yI9 r6   SK)Q0`{G'[FF<%-q|"bW. qIV@yRh4;otF~%!a~B3 Ao0VЖK{pO s8_nquoD@K̚rc|H (ZTVT@F}$ _+. _E,.T +S)a&3 42LZGw*BJR?/ފY%TNW3 }'K9QUR2.SJ>#AXoK6 {O cac;Ξ-$FA>3Ǧ~(Xf冝?ݽ{W7m:6f/t+nB,ߋׅ5uVX3&HOh]4)G)]c&Q# J;|TPr5:C6M K7GQAX nVxJ)pnu6Jak7UTUiwZ_r]Պ5+RLYd޸K~ImJ_;Di@|'4D6fkH$EսU!(.(e) At,da*YHyˑQ`sLh=saJ EK5k)^/WB|)t+K3^O~+fRR\e\ nV7i= <%#|tk-,W$WtKkt ݐm3Պͱ"wPf"|pU gPu v;z\O^%%rP/)H^7t$27!ьSFjYUJF sz^/ /ZM'˧vajtWck_lE2&יH Y;G6QvW/=oƻ%l!ZpۻAXϘX>%@C?s[{,J %ՙr8(yQBeW^??k.nSrM9"~Qu=7o}&X6M)"8IM풪֊aϯrFtuOEPݎcƼ0tLxŕqE~3y,|R O[35bǎ;62UEO+<|m}W&)5wkD5SSSE>ޢ 5'.i C1",[*zFn>FZ"l[$7~1=~0J9.-$ZfQԉ.Vfn:xgeǴ4l0{PFh>ٔYLhc”,OI,V-DIrr^ő#?R>#>FuZFyzOEcZKsDu:bKorD,@QJ<|_N9GW[9tAȞb YwILѮފg;`-g! W(@MT &kȼL%:)4QZaaMxªُt_ wgR1m sc-v,w%ЙGzjwUwg~7mu=(#TikbY=[Rq,&呩%ݽjYdTGwX+vZ= 5$Ү'{iUn4C/q" YG)E$~pXjڗ>{X!`2A5 x#%xjPuD*ܕ^}z>lN:Qi8C}rQcоm&ݖC cxVRz<dyR;G(?_'"#YcUu]u_ȍMӽToE MP@O 0n!^uđ>!>|p\b."!!+/۪=kɶ{k߹ddzb̻wϽQon~S|gjwەyOߛy~Ds9p }F$}27ϒKk4Y{|9RYRrd>7ӝ kgC{b4i"ϐѾbҹ ڻR5~uP )Ln|/![s.Bar9*FJd?Rdp[ BNPx?R !@IU?] &tПMJ5I?P(X#oR)[Dd2?)6440[ڦs>eړAU.BUV#;^yYAg͌Aq:=E5?W O l<[Hŭ-%;}Ѭ_XdђYK[JуuɌo.,ǚ/ؼp䲲Ut:g}ŭ}I*R:5'2v ˙sbW2s䛴9tɡr*Z0DXG)򱐦cV}A.H>^>&g\6hR~yRxmVc.((qIƞKf2$9sn篗+=./TAVGX# e+5T>F/Hy&u-R䉮LɈCM(}U:d{/R҇w5s:TU}тH"*V T ¸I?|?0{<0s:~?a'I:?7T-FP+N[ؒ=04Wγ|w{ ׊tk8k?ݞ=}2'[n ė"T%R6U/El *+wɊ? mVOa~_[xΈcOCf?KSG/U€’mN6xD,6kz\y`)GL 'B]KWO+Oe[.A)T| YzҔQ,+:zwAXCIXvʘre;3ac&h^MUC {a՛1A>Lm q+<<%opeC{@A1$7n^7}S߾ig=p.u2\_ ڡ<,{e}/5M =l;hMGgH=% N l2 潲#KA!3J+6(*l:LfBL 'R7ͣH rT%x:52X W/dta&l$U+J(%,UEȫJ )٦j&JI =㭁XWm*K<%o/!Xga9T˺IFJc jJˁaxJX~JPi^OVퟏxP, Vϡ?xq_/"7[_v?ͻsyv귞Ai wӛ ']"R.(UF* T\U]*IhJI~{JaՆz '33T9Ue.2RI t*K9ʔnu:`]{U:VDo ,[ݸAWm2QV}pooc}6w:s!;04s8##}JY^}f=Kf79֡ɴ1nDGS D-ݪD"t1gj-/Omɍ QE"!ldPb|[lD.HrU"@f^eFK*2Yr#} Dؔ]' =1xJTy;o\mG\u[U{`KѽLkp~0o??H=gn͠BdZm۶EuJanFwF/(T(zZ!hQɍnGWQHC('VIzMuwB RfU^Tա` RjޟS!d-SW:*Tja)q) ƚxJsg٘t S7_Iv֝8?jt~v'e^p^?ڳCC헌 $F{R6 WgT,4̓P^h!ͯG g׽y5?ϘBӧyd 5¾j;NVULQj#}>\-/KMj a=OԲ}&>*^W eIr[t}\,Pg$ 䋙)R嚲2 {O 6Pk%s8nts:DG".mm ԓz~Zv>ģRdH(C*'zIȼgc*7[55M\yUQIiɺ񔐷^4Dw<}~ibJ3Lϫ}nA+ S_\^[{دy/z:yWoi>jgk֎>{׿Gkڛy@>j%4-|喔8@8ߨys(( SV qpƱp "eS' B<̶\s @@bDۯ.L=v䠫A`@-))yyUƤ';ws~džkx4ٵ79;v4Z!$]FDx%WW!+X4LSV(QK&B6!o   Eʢ>uGsbf?[9^{j`7>ݯ{S}a3gy&nQ!kˣ  B -2ӃTD1nx&:fD&ƺaZd-<[,i"/vO, jaseo6EMqeA`ۣ((`]JY7?<'FȌ@*H(&̔  Ƃ@uS;̱:69VmYavwri3Z6D-+{#8 J`]mtK lPBYI?72_9g\1$W I'D5zUZI2TP?>O)(^cˋ FeSd꼥!±΅Ҋ߼긅-fnD*/U1BdX,@@@e ąt^ЯAu[jͦM;>ظcV^ &3WW]#,/X;C3+KVt +0|XsW@, ąt8֭N0wz7pӡiJykǴ40{Pȶ,urbeinLJ;*`B,o<.%5˹cեW~{3rJ=Z !,[H(   BYIi֠ٝl%4fgvƕ L(Jq]f)(*ZaMޤpmцaE4X;M$9)ݒ#W9>GIm岨BZC?O8"}oȹ߼\وcB Y4?볹靻}d98wY͌۱MxF[)ϷD=@@Z@c v_"yZJ$X/cּt<6]:~%n    fq)sʝL{,OM:?}{P@ZHq!,z@iaZ hQnλ-!n8     nn%w24GVlEa;TUZXn`*/٬K e4M4@@@&H3Lg>U&%hCtkp;܋̙LHxц b.<)T1YhQA ӶWw@@"&p茠i{q!fts>nv¢5xXE#.I/<>!tcS2\nT,A//},/+?LC[P6Q] (oִ("@@tS+h͸༌d8W ɸzhUC ,_X8dw2~-ͯE/xf*(韟-aprY.rK&e7߸9ر+QiV +@@@ MzBREIv5AALSr!0͞T Fʌt[yUPM@@@@ ąt8wj7!\:5ƜOc;V/CCi#[#q1M"g6g-E"hM7Vw#=YO2 E3BSJ<<4P W14dMSH|ظcV^P\GϚIZߟ˵lQsӭ~ii#vDI .~rE$F )pf{Z\V0 4ߐ[RVRcc-^7C KZwO_+r9=6^5f*'PgD<#AY&+&8 mUy)$[4g.;wYM4BZH E_nMZ԰ZY|) Hhꇟl(L3l-K'P$|m[VlRonFk9=y9zOD(2Sȩ(^1bH*YMJųtqMR@J[7>%լu&Cmٸӗ2lx#Fv?YYrժh*tEK'+-.:L-04SC6FqHo:."Ϙ_y"SmC |{[6Tԕ6ڕ(8wݲ}co,d&^.<4 t]db޸ng*]x~8_>aӇNvQZ|+Ff%fŋ!8=NtjP?=ZbK=<4\uAt:Lߛ7 ԩ)[8nu {ZMm߽{w TUU-Eg }AdjkIdXeu[x!/-; '%l.k"hn8)9/I8O B_VnwK.qIw\q1ڟv'''/j׮\!u܉e:_*&ӏPWVZiW[[w}.O?fCѨIOL{.ue'=mᗚrr." 05ڹgO\w֫Ә%Fd -mEyŅt8mK+5o9yߦ#QA#`MmO̻ә%V^ȧ 6%Ǝ*+lzwK;)鶩qDZR#'}Ou;~٧il:t=t8(Ikƒ={6lT.ȳyCcH7?K$ ҂4gKjllHQܺmʝL{,OMpbn2l-cYkӻ,wyoskr i#k`&s18́ Cx47ry=Qnh+6͝7ϸ2̙yO~:>}§7DEiIw6w{V?^Lylg ,Ɏ[P8v٘sۯGҍs WNu99A;Kbt#ޚЉ_^lcƚvhw]Ƥƨ(%9<,]msBeu}\h=;jcDӟxm_HO2 ι⦙B^W7-Q?/-#*.ɿw$HYg5 9ekn*)~{h].Vl"6}{}ȵ}tφJ;zaɟ?`1Tk`L0!mhô}~}|ڟ}s*F9VN2R@Knm3t_^=opjLątu?72_9g\1$W IZ90KCҴbw\eaYe)$-p"^u0=:D L1Bڰ\[h<G#Y릲ɜ0]k9V/--mL-C4HMKЯ & x=Nu1:\4GS\b0W(ۮ_a rV?ýLy\xUC^ Ls{'3Dן֧&|/S{bhVizWw|3򷃖XVuw<8o㫯ּ/tߋ/`*/ѳ7?~y]_޽?i=wuvcݺu!2WowO)x_/e dժ+*>z-[ތI_& ]zBR9x57`UVZz.3ѯ7Sg*cS*v_k$Q7aR~♟r\D -!2m&@C D">)1of$ x?ȅFrV irC Aow1MA$ߩZ$ HY r.}hmcyGd׍kF;f-=c1g7.>4'i.o gJ_ʇ`"_~Uo3__0}3U~]8/;g8S z';{f͜t2cd#oWZen1,E?|m/>ě2һ ^kZr͕<9Ao%&_9"3,#O/}⡼~'zkrd|y?7[c5qhr+#/ͫ5kFM-h `֟8[$wqHk26DIkc#,\BM-K:$n 4>8}K>i!60;)Sbz) ~4R7I>  DntP{7zieM 4@\tZV'fֻX==OLHB!WOc*aj1z/ {l+Lk="4ZLxG|Opu{ܤ՜.ML3zQ:;-D;r$5 ЪBYa*I ݩWvA/VG8/o^"xoJK/HMYUIHf:y7>6nHv7γӣ]MD@- fv_x~8_>aӇNvQZoӖuIgt]}qW㠏ʃƷu<3mq1MnVݏi2C &]qrG>` Qxa$DO~`<{T04k6Jsdҭ9*<[@JVdA 7՛9 @683Qg!J   -I ƺ~i%-91utu%),hq!,0% Sfݣcxjtsk\(@!ʼnZvl76~"u#I7Hr7Zэo_yv؄qXƺp8Lf%@ޭai g>bzW%F+$݌:y`X sKFVJ vJﳚ$d  I !E3o}^nnF 58GxwLFsbtH   ^$ Saf'96}\CG&Ǫ5+7\ݻi? $6r'' Ǒ DФQ矛qy/zq3qyݪ,o/X81?LqUU`bz9J4rQP<[=4$v!"#M0 Jk7UTUiwZ_r]Պ5+ׄ}޿S-Updb96Ѳ;*rK&eD#rsa٫4;n"8.zMktlx&:S8uy…V]"tV~r#fP@iq=Sï0x4=gHO.7ࡼ6{P6q"[ *_=HkS*2([DM1ROO#OSK㑢?W?(HQ(4sA`*C_K.r BkE |q&d%(-bzH Вڲt8O-Z;[7 J 2Vyy|y_Hų!%TkH!!@Khtn&(}tm.JݬuX@H$閒hӯ u,yh,y%IG@$tx 3oau~Ot7 fAob@H$`(Hō"$$7MϼQ5g2a>ng 5?=2bH   ȣENaɄYU4c5>}/̽i|)$Z-@@X͝NO>#~=jf~uلE3:èEJ^^-hN}Vq[@G|KPpsɑ@Z [V}}̱-,.Dx!/-;@@@@ ,H@@@[ "Bn@@@ a!B D8(nr1H! `q  A@%D&HC:ّ>бbG#o7D6bUB1iῈ89@8wkز[XDVx 6xZbxh7"Ax!uۆ5ooMx`-gGA@@80m %nm5.|G&Q?nJ,y4Su=as.Hi&YX  `HҊJ))z|x'#]v;.cX2Q3zU6ɸ R2YV _q܏_0fNӡT`BE^Rdž])k$5|`ĭ&vbE[<ϕ(:J^g"F5$h `+@[\6 jc-NZvYY.r#B]>踌)ePȋefF]LW3A}‡ e)g)y_5ua%:dof|#[ QRS?=1/ rlY- b@btKj^;q-qWWqvakoIU/+!6c<(yk%pX7sfό PҬi+,$Q#T+U_%0m<AwF~(~d$o$,h 6ڬV [#D#` % 5;Up&#ryb32w[Z3&wסIrבw(5}jg ytNg< kRڂӬH  Ќ ݚ.&r1}]K׍N_ {KyҺ\`]Ը~H AO\e\햞Y֬]^$ޞʣ4/M_`¯ :2֢>ikS̑DA+mhV+!HhX%`*noC6N'yƒf7J/Cj) nAOlCjunǫQhO]V;U:ɟ1So:4O9sYvhYpגƖ CL rǛc>U0vmoVK @fhcF`jPڈ}I;eA .Ƌ[Q<eϪ׳uAD;Lw9+A@t} <^}~05Xl\A@-tk˭@xv`ҺtG6E<-n+a͛?\,R:q1-R#NnCB&n- Ņ'< ##@=?[RǓAkقWcorlEڃ$z ])ϊ:Riꀄ6>⻢}:b\H ЊJ}f V(@@@H3L A@@@@{    M$D`   Gҭأ@#m }.9i/+ FQFrl#:d|i):jD F*zK Rp0g@:t}m"fj  V@l;-^nnˋ AZQń֣9*K Bu+&dJSQR-ΕeWj>KXD]cY<C]ǣ2V0E:%9MF͍›H%\q@ H6Ӕm"Yyy;F}HO+"QL#,L5n0&e&"6H| s ʬH(o"u"0,A G8"-]k7F0i(N)R@# EW{sdGoXS'gD5w+|by"FiN!܊ISeR*0TT{aC ˰25rB9dE   eڳ]&&IH,`ųU/di1s]}`^KW44\@!/xQAL׋AQfv6>4^(s^ZjT)5 ٤6#O/RFݥy]AO2fp@[bW;֫#]F  EcyBjڔJ}XEcXil]/焚Ƣ fֶ*g 5WeHyu*=fQ;X(GWiAOܬ@tKk-@Q}g9&GNɰ}Z3YxǺP81laIݒd武p4M\F(d,Ii~3Mz2Z-69@|t5җ.]]N|gn3:ļ |\55 uKzǷY-'ze3B#|5#i@+fg!lRUSu}8=i);DFҭh[9Jsߌ>Kj Y̜0@hϷڭ)*.fx͟WTSEֱp"ͳ6š,TMwJezJn m[[l6Q'1-`.Cm2 ^.&uH6XvX Mf"C=)N-VdQhD䯦Bp , s 3pFX`yB,KMdy\^fD|HIUF4hkl控r} Zjf~u[:lf,zFIOfSѫf Z)j6sb5odYą񼧻rJsҸuk47H8n ks}X>V^u @""`MQqH [hgZ˗R-oJEҭm'jDϪ}t J-^[v@H7    004a* `iM Ԅ /0ty%t we2g.B G @@@bL-@4HcA@@@  b ف@tk>ȹhK}gtos"tJ _M:4ϤIĈ[@"((ӌPrl#:bwϨoI.i2̦$dNX$@ p?3 fix1l+_^[2)[79s‚Hm[A=Hv 9Qbm{fϙsXyq$r2*aF(Fz3#3pa6LVo'48rH  E4ʆtk@ pQI?lLKPjœbWVgݰ-H( 'JٔFb]{3 I*7Δ + lXῈg C)-o\:A  в^̱[X\ :aQD"#[@y0Tq<%!WhG Qc E䚼i @@ q@%N[RvOҭ   804q*q,`iM /0txdc"tAм   L*aL lMH1"aڀt*A@bH9:LJA@@@@z    M%Tb   FҭУ`h*HC"k 7-Ɏ#m*\)Hf)T"71@@:Hm~Nd>njQ*6Zay՚eY%-Q)x2-4@"Z Q@@8H6mzTdVNάfO[z덼X9k^EE=iK&^8#iřLh9%HllZᴲi6EU*'\tT~FHq stZi~(rk$XUJB$ g _^uI9 1+H_u҉2šLKnq,0**n)Rn rhUgn'Z]$dӨ^YnɤFU(a*A$Psh,LhG KK+9!1@btKvQصs [4Vz.$\N.-=%X^ M3Lͭ@ ӖcJ H7FG|~ƴf    -G@ӘFa[1GI    %H("9Hc@@@@ JnQD%k 7-reڌ0r 6),Wd`{! =/s,-[( @@ N @i,IRZJA&Ê ܖ3b6jr9?S./T)}W9a*S X ٶ    ZP~h96O;ll1+([^rTf $-WQR \u|yq(C戼܊BS)B8  [lٓʪv TgE5{DkMvTPP>Pbdca{RR^$lr8!F(E\b#!/n`m)V"ZWZvWvYf%`e[ 9ҭ~V9#h(weU-/ 6_/#Hf1%e_ n1ʭ ޭDO-zȡu \IA0>D# | ںQ:@+>;޹ǐGz3s̸V&޿gta-qjZ=)_F@/cS5j6+nM    jt    qM@#u&q    `&@@@CN4i7 LS{0@@ '5t}zVҭ?뺽vU;@@@7ay$'ؕ    4*@@@@@ a`7i*    f|M8&@jM(60Fi    K w$ 8HS9Ⱦ0CA@@Dq;((WC}OQfnnKJ1ɞd.՗OSjֳnw!gh!uǏy*Z}-Tj3yTNrJsin|!{hYkb&:6JǞ?󺵷ƺw @ ]]zOSiggzuC\-9)%Y{Aҭy@@@Zi5'=Ө^k Z@@@yp~M@p754Qd̡ҭy7@@Z@Ur\!J @[QEJxv,=z#ptw9@\Eb\|]jj7yY\Ëعd̘%;eYk}z]BPa:^#n(ixuHZZAeZ~,]Yc j_~bX싖9daT\V*uT[6œ),Q^t @@@ 1xU7b_u:{[^`FJ%cu[޾Ub"i}w~76/K f.]zcb!n3=ȭ(ºUq☓6r4H@@@䂡5U_\96۬j޽wmanַUi.=z ?yΤqޭ3<̫5?S9zpe>g2c߹"$Bda4H@@@$}}o QtV d뺝ԍe[x|a"y#3c6g2ɏ]j[Ml ;A@@ (=Aee{h[A:6֙?!U3P-b+EԼzݏG8R 5XM+IQ;B! 6BC;UeM֨+J_nɮXHHY}EӤXiibqgٻT'##뛖=VZPwlhDދna!$ H;K˖ۭg83nۻ?qq*ľÔWjUNͮv?,ysFx˔pƭ?hG }Ǹ?RѢl07CN=roNڣtF%|X]N߯^:.'ַ>vsg77*  i6WΤ&&UhCY_YkH7|A@@p9U7.+qFCC=T!܂KV_yô|]Q LD {xzW!C!qoskv#괷;L!Ɔ   ם{_0D'kjW]bۀ&89KIݠgn^_<=qe[}!ݚ~C    cX$@ ,2Q Ā[ " hn-@ uRwM>3mc5t&$GZ顝8_I޶n) kT{ֺ)QNsE>*&x[Tw]c{YSuQ.w[z.]`,x5`i4!£MQmGmߩm(KX1VcdVtς( S6DKߪG#,=>gYOh>[k?0EGG,.ut)u_(ˏ0>J<گL]JbS,KbhŻ6%M@@@@9 & IENDB`nFS?ƊGPNG  IHDRPDsRGB pHYs+IDATx^] x3 !gxCZH !(i Z~h1TS $Vy$lsd6lv7\.;qι9'2ng'@JdSnZ:A &EAeI _"XKA=po@8B; ӈvD3K&+rk ܮ}"ITHQZ` iȈ|*GAtcwhMqZjxJTi#Vy ȟd8@Ô6ĔDD5P Z, Rf궫 ;wI#PTߡZK*.GPU uJ$Y}xM3&, 2/ua,qHÍ&$`pШz%ՉKEe\1`"835%S Dj3`v^GnVg;IIT  <`MYrsn=-\MHHDd΍D b"v,MMD7 \CIY4q"\ILQ 'bSX(xzF $Lޞ t(9c,کg&F;Wk}<( -rB^{B.'XF4éB(͉}T SlU^*oH6a.Dߍc *lI,N^Wӡkgܑڶ "Zⶑ5t3z/hRT0, TV%*M7F7gJ_/p'n=9$TՕANC(`v d{V]YUuٜrѿv |j<鈲.g0dP I͕HC\ 2ڵu[5 BP4h֛%X`ʙ̜ Ƅf2E/>idrgW V#IOS^P@o1L' c,j# غ]B . ZJjxeGl:VH0`k \[@mpAnj)U\Ѐ@$l[ 걣9 雈0aHBOA=!٬ufm6V#ڬR)U}kG/ps<z+U@iT&3Q6w7wxAl}:rft괩^?$]kmʕ|⩞'.3@'`"BA$(%;YW#;w?m\Np~:1&t/%@˚@t|8,J{eNšnH,;# )狋<^Y1*Cu#i54t8W9]%Vb I+Bߒʅ4a]8w9+0+.M=m0%q>`w]ž[u=?}ѦD0h:+zc o!"d0!LJ5p>һIJ"-$&y4)Ў+:t^yZBe~_~jq.y:.ջYUK 2r9{BѶYվ3 ˲Re ZVV7 AjϬKH5HcO_]sj MkT^lo`%|1% CM0 ^ B9^9sf?.s#NX5x VHۣmOP#<0k}eMQ_W s KXp-®ceE[?*?61}eĵ_!XJG3CO2^e~=CI'wqO~nFX!ۥc+Yl@y 2L椴;+A`u>(s=a:z:`hhPC̔*l$fqN%3U `Q@z}yƭ/2xԃW@0J&~R{ld}A\%߽tYP hz`zC|*`lZI*{}ߞb") y.[6[ ARygXVwvr|Z:])j댰|^հ0Z]&<>sK)QkN#v)H`d V{$peXvѽ8/ nvLA'ڕsNo(Oy r2o.vF` y+ <1 E\ʬsj4+*JZ!8?Y0pL 7 ,">~T#%hλa{e̫h-sNz>naA5:00W-=^x2<ܼ:n짤=l7 1@=P?v hzCA  CBvOJc1n jA@sWU@V!ݼi9\*XKe\"Ԛr4gG >(^LOY.S؜@J<&,Ej?jReˠ. UU1FbXR4؎kw0޿/,ql)_wYb^ dA C zP;TPSh?T.nMg\}/$oOW:axd9Lx춓>>8=ƹJȁ;jdYW.aݾtƗ0q`{Q>PeOWǻ=ei@fy9ݱ|n@ 7 5 2o3o@B+`$5^#C 2n_|Հgf`鴃=0w]٢#-=t ?|a%`ԙ%;H@`tJc˞bw<9+MK_ړ'(|;@.x¤'HZ3{۪ ep"0;EpM6OnGY*j>3ғ3Ǚ 1_uR¾#5FVX"f`s=:]߲UHMڵ'teytrn\ 8nZ+J+rS8Auf@=ȸ0z?0RAp2Ѭ8u J.5 59sla@@Ta!!~о߮=yb&(T8qLr:t _C\nR"/H< XW+$z y6G@xE4vwl4DţBNsZP/+:ݴVWYVJ*`VYj6WUN=RnFB qMҡ:C!UY*arۼ 4Dˋ{"_aCSEܻV;w|ጪ/Y̠ak "$?7]W NEz߱w.+ڇ|("tLFB/qn$:Ty`S ;EZp)r-*fB@F W[b qE&ʌ [j/~ %X lqB\zBYouE|O/S0ԹAx8+fPwp@|MaA`>D= vGBA\%3]Eۡ EAtN+48 pl(Wcؒ%k7LTW1@ mCdl0S)&5M~}4.z v GtD0rhO#nb .3#Xݼ`85i} tʓ'h} ZS ZSQض($)?КmÍ)0p! @hZ\;mmJF~3ke!ף3ސ#+7 Çs4d?0-B 0a\4F3!]v NJe9oH3ޫ dk1@AY8hq'zTlӥ` VPs^>SE%>BK!j$ \~6]%*Vܲڐ`\>Y~,9K s5$$@@2z`5h}^>ӳse?[@eP^BskYQrH̘M@f#DCmZ ÇXP0 dĊi,ߞSCXʒ<~b YV_v- j'eDE+tB9D.%ה(Ic!`Wc-#8v|ؖI\sg"ߛu* B,:}H@dk '0a! Z/n> 'OQi}"FeG8O͜ܢ' cavhZ0!`Itx i][R݄qJC#aW$.¦$x!=S7<,Ci9'ϕ_"qBh[rrNK-<9`/ @jq.;*u8ly V B!^Q紲W'Jϝs#!)b3fn jToNP'&>ttQ7XC,`R `One)"87gx^![>QHtA.h/2ɭ58`!@oa?ulu/7åT$127sr(] h+cy0@4Û'L F/7N[-%Ѩ=$F[!2lU5~:Q 6 " dVǶ-alU`"hc(u*wn fmuae~:# ÇR RoEVr[j"p@DJ'I?Ӗ5hZh[?)phx˟X n$7 |CV)x#uP@hlZ&B;-՟ʢZ-MQߑ2On-k4m*Zvʦ{}Z9/]AHȽs؉^?hⳠP }WΉsSYb-2d\J;O ߹}r{=k 5*Htɭ,\)zOn+9x?,GSYxﱬF^[g|'?yCld tn|P0Bxr,]'Olx3\Dqr+i&;BުQaԘ[mL!,VcaKtȮQ"035|zr+:zl;ǚr$`-_6{}G _̖2]c [̖2]0ct-~b(x0Q?&3FzW05ebB]0|ϖ3[-Ȩ!*$`h!DETP(.Cp%b$.̉ /[7~L7Rx!쵵<ϯw={*|ɚ%;Q٢o: {Ν\0uȌEIUؙ>(=a 4D"tcyOyQ3oFn;t$5S$ }co˔e1(w|^7~  kDC ;v]6Ư~&ĀVX@dnh2U yfM4ҤҠus" dX^2l|ɛY[]̷QJ>"1R[@USݍg;n!u(+= [ >Nі6O9Uώ uj}> r^򇇂awg?0@Sؓ#,CgK֒ 6ٙW5[_/odCޣrϳx]V0599Ʃ!pi *O+yh ўь-Shɲ&f;}gKю.Z8{D`mYю}Cy8c{71`aly?b)yOoS&ɻiJ͕~z߲"rw, lxآЌ{og ?ULY?׋T<NM07o楤@:R?( /j % 9$j ~=_Bp߾3eBS~.ElpF};@j\Ʉ}p' a`>l93#c𵼨pGʕvHme]JFvwON)9c.yU! {StFazzL;5Ia$1<>l1cs١d{K/DGdԩoU(H؆7g;U<Ŝf\նpe.z]vp[ /рtZr)lOj `qdE 5xv)..wۍP84xEɨܹh;OO^% a[0F B\m[K[s꟎wg6,u=ggtZ3: }x쩼/ D-vciOO Z5^7٪" 9Lɂ454HSa<ǺNf0 B%Fm& 2 PJ.Hc.1ЉdD(uqlj~Megƕá> |IvTcΑnI"[߫V&r DW!_TγHA hS5$!/'}bf'\Sg2V v;' ,6bnk mK}냟cGrQco=­_Hq@)r$CܜS X9܎^^hu\[3۬f:vp;l֦ ]ƀh MQaD4y[9[bԾ{iJhLHoSW5/*,q@XZhchpV@ $rؖFƐ etzFkB=h^i`}i $Fox_/FV$8ZMWmmFsn5[LƖ/Mm&b6 I']?m % h51 ADXB v7V3[ͼ[̼8jhibaۚ!oj@mrAK}4Z)|Gݻ2$~qACx|oa4 &m}>J `aDB@|4n.Jqzm;n9./vom|kH8Y<@-sQd26@9t;ۍӐ.%$=eBv{kZڕ ٭x`e[^wuƷٹ Н!s' :a 2AJ=d_6:@0bYT)}x͟J<܎խ̉f<=\܃wgB;3or0?J{}а' C '0eʒ=i On)-H]6V$Ku8YMi=z _}@t jl#r-wd4< >yp&GtݰSoBz&{y2 0GMNYk8Xu=ARLZ;'#hy/o+x}Um Aލ v4?h~:{E;V{>R]S Q=8nW|Q>[HG7E%=PW$ϾL[{Wp׮xB)Rnϟ̙ܳ&OI/?UpTNQ{`F> .*[!$FLhf+،1/ǝ#e0x i( ĉLAGlL黻j83=D3Jqm^|jÖD&Mj6㵖arzP`6RѬXcv5C@!wC-5k+{uo[3ajdbhC'V"t_Wy)tylUbTZm` aw#Dt! [<ԁ#ɣ{\cbICk%30dUQ '#z|Xu ӈCTO'=dIա]B?^bl9&Ł. EtK\>tccjP0)Eo5*r !UmG)ۖOɣ5\봃.`穆w{k+B9zL̺ w2V s<'}W_u[/@dp46 hH9lWSi qs`!G B#Pΐ(5j&%0Z4p-MۭPvۋ}4Cp{^ Ej~wThFC|+' \M o⑱ pt%#$KثؾnT_=^y3jra`P,lQ!?y#q0nN8 TXG<3 ~zu<"ڏ*'-( O: @K" Ăp_>կ] "͠+?ՠ􉅰;>%%.1'}EeuZx5t ;$slΛc+_4LCΛc6cʯ_+UJu"7¤Q b >Xys=ÿMXww 3y}mJ .tl ؄6${~5 : GPWS][X:xz5+rߣGJ&:T樂ǃ~ʤft-g&Ww:tXR+2v!]*K>p 3ߖ?2f.FƿC^OE|$E:jܱ:-_{R/l47644646CKSSkSS[sfk2ڛMf3lL߁.TI`(U>S'tH3nqQCP=Pr0C-fuO9a329,HylM޽Ͼq%>}{T8Ԅ^ʧ b(:G @L˪ EЏ8=vb/]`eP[6R 1fIEřZH̞u.; Ϸ .E"@@ |s#dLH@_RnaLy!/ˎP ^3=Q%%Nʴ6E EDz|+1J #]83Ғг"uKHM2p+qc{E/  i1 rv%^sgSk7x5dD/% D+ _a$V;2(oDC!n@={R .] X=w?dgX;nGQz2 k;Z'|֕cx^;pK*-F2ѭG nbޟօyyÂdta |" U%r q<|Ǜar>aZ-į^7>?l}ؽفVrv_;q+F*ɰV枩􃖵غΝ\dx:K"Jdn _v؜ SnX) `9EGG(]n15JN?Ӷ[݇mRuɿ;H,[2o?iM ؈_ 萡fV ds?TgeLLv"ci _UbQ%H!kJt,iDL08_vؒHۍHW#PdG[* MbAWDmի6^o7Ku:tt |]WNǼmg]}N.)D@hR+X`oDCsQxSGl* "V4!,aު!b] B!b= XPȰXϮ"%* 2,ֳu +  * b] B!b= XPȰXϮ"%* 2,ֳu +  ~b:O+?]f85seI5_qsB[Үg pa YڡlZS:|^PAo]\bKFnűMwW3Ιp|~˪;r ~o[к aXCۭ.)Km!;{BAks }fmgq?H))rhM^(osΆO~kw|b Y%N`ˉ0b:$y?W^1'1`V4ꕇ:#bX`MK4ZߴJnJJ⣟ZVp=0 +Gg<|*lU {VLU<߿a :92N /=TNz;׬P3bPq* T@~U*:T bcBEG41}P!ݵxW¥jaR5g rMC}YvV@X4JKU*,,@ $Н#]Rw>c-"F|F%S/VQg'φ;z$#As+Ȩ! B6n%U(TZ1R,((CJg `R5T_y:@,?˫-@}S仝 }9]s恊ܒLic/ˑ_SCD>*@P&V`9"T@Dg&txũ"zE ; JJ;/RǧН1Ӑ֗~MK*p+#7l\,bOr~ y1ͥesPޤ 8S靑OX+ߢβ%Xj.C+=t;Q9Rl1%n׊˝y-s?%b &j(S7/p=x[z"6 "9H۞ j2Mђծ;9T{ؑ?=ɘG5ާ9?-e#`:"26T@ٰ ȔKبR6Gf* "S.aJDXa I>Par 79* -k_D $䨀"}&p"5nJ *C8 *nstv2;a@pL^{Ĺ58gJ6 J.@B]{}ɽ?j_J ڗ}oAkW=-B* M#Uk>tT3<8q/UsXuƩ))i$N=nMIH¾<$ȋH2z乻`P )X 4rj$.7  z[SmA@=cKkk#>y')OBRZݺ﹑E~(62ÿ9"˛O#w֌xwg'Ma1i׾S3=Q8|ѤW@8x9UlGb =SVC\3o5aBgPtv+@JtդKݷe bh) 杢kwJxD|MZy q);~+.&j4:k5zwkj/51(WVPX.tS@YҩQ0d]RqබlqqB~[{F)'H2g|x쾲Qii8&eZv͓ CG`f#C& J̧|ȉ6)=4dxu)+{=MY՛׷!߀lx1t1Up(εo6xa{R ڛ']x݁y7& P6p؅#z#tfB8xD"q^|ll|n}q<lB @#,ԅ?szVKx4dx ż]nA7"{$Oy<}Պw _ŀ`YV{uq"l*{S[/oU 0N".Q3`C50pMԀe fS$3QǾo; MUFtuRi\DD,Kׇi\A}$INM' ~RZo cj߀+Gp)2DI:|TQiDO\ɪv3?$S':#;6:2dS~RC;+?t- x{rr(zIENDB`n+ˆGDƣ#PNG  IHDR[sRGB pHYs++CIDATx^} xU^&Bd7|* a@gGȨ"0|.N`P;2`TpDt!"Yb^U?ުN]KݯշzsR8Q*pӾ8#Dd6räO6x"/@ b DKqls\]&QA=~AE(3d8IYivhbqXq@~/L?`(-ŐR)$ I! FZ` (Ȉ |3Z }6.d򷣞ڜO(,w>BZoƱDϔ2攌nI&d*)j ?Y8!ˑ)ތ0 J"DJ*glm`%}(*܏&}]Dy&`"d6QD`2p!bX$ApBApxtՐAb2BSN$FbAEpf%n2Dv0Q=bH\)"H2pw  GptDŹTp XV!PM 9T`۱74]*X20 [NgsIk$)Rd3PL`~ 鑁>b5ND& . ͜I+~qEGl ypM>s,@94T.=ILN6Ps#E^Dkp0R@1"8:8G t%qNYq}C,o+:n؆kY?3WBќy}.# !fzf#]Jf#` @G !{ȭs5h ``'j30 X2wT -5{$fx!{M[SF:/WF8o] AA /V ʐYq2J]R +i-XztuybqϾ$[V wL'X>{32J X~MŔqJbxܑSL<cyvJ8b5i;-aG}24nQ"Ĕ$]'0hΣuS+m BptE1 !}(B`58! a,i0\S.!U]Gknb``"$JoAzO~鑬ʡ dMXKưPc_dJf٤̞ݾܶoNzkQ%rNꆹOpWoe=' ], dD+.A\(vwvg׸. T_EB~EdZsՌ[`EІP|4":C2A W ݨJ^L/5 xrJcYJƈqx8>_}~V4S UÀ.@OepAumJ jLjƾIN;j3̗0GtbIV-^Z}~$xxaލԴ};j7<,QOG$$ 12x upa'L%T5D>RŭZ Rf<nrFV\9\^ R'D,ɴPM&̀鏩~siaB*t3\3P=Ys/ܲn)Zb2Tx b$D>յ)aT$|Tݣr2kb{q_aHmɨD@%~k^|?6XRkXd8i`h`*F&'2H .=\#xߧpi ^O 5A32[3oP3!WX}ox rJ6DUeڗzr?4@KYQgbWHxl Z N{6c7[)6ȏT*3q^dZlGev6'|(A?`VTT'ZMGhu5F !!pldBBfyNۡXܲޮx`ej\'Ƅ=;/jxF3b=ߟM2THXxuKvoyylpK zhCȧ:57qEC{Hg1ǒvǣdW&kԄf " Gb\rO *;,o_5 zdۘ$+RԙK^(N5*" w@s0qiЦTr@>&M:7a+0 x܃ 8 \0]QR "$ DY.UNGSY. zaɘE+a S&AP OJ% ~i n|zC9:6ڶޓ4,23onTf]'"^MȞe ZX!ץKK܊@[u@DȱTXVڪ"D*"z%HXm7.!~{/+rcgJiE=JG9*"{T#1 Ͻ-Pr$xoF@$o@ N02tBǂt@H@Tm2ec@(Bl<y>#~Dڭw߳6l Oٓr;!< sGX%(Pd UU<㦔 KCn,c%SRH˔M8wzy /ZogIb J+nnhxN)\+wEU|\>C EEEq炑픷T8T 9n!u>e~q~9(ϧq'E$!KȜ˹xmR~|9wݬՊJ4T\< F.`١$\!C@a 5!: 2gn"`|aѭ0'PAaPsl$j 2g{J]v@DɊO懄©  ` !bxpJRqUXx-S x`*Znw:4rNTBlXtiQIVz\Ǘ311 fvr._^5; @S G=\^[uO'u+*XsZ.W4FQla^0Vndəh1Tbv hSEŏ.o.gAt5@Dt[FeS-5*1G,#mξDN'Kʈ~fE: "JLD(-QrGe: Gm! m[w u U-Ҷd*9{:%="\ /@taKmyT"c ; aml";Ic@b'zC=7]BFƸ˭"XZb|)ayȄvlug]N ?i0 _Z 0j&)zCļ3ۏߵ(__pB ""|Ǜ2]|zj>m_^O/;ȋݾ]&{nŨg1("oa{R9eBR48 Q ~ϢࠞͅHF~V=, N1,׭[ 1PL t"%S(+>XЭ:bYUH=wv3*/?枌! *^>?Au0:t8\PFC^5^ƿ?$i)Զ܊A ^mYx<d,Fӱ %Cr}cw~YjJʙ.jW"Ku*Tb@D=.츔?r\:DWj-  *c> A ξpNU}nIp?;w!!23vi'ڏN4مe)>:##d;Ur5!-1a> X@q)*7ܣ_sxCyYv@IJQ}bT2 TB ѩpIe'2{;8ieGmq [:(blsK7?q B3}Qx1{Bg+=pgFˀ #&[?EDT/Ο=!CYHrC$@%Ӏ`@P`R~8 IH3]Nun^t{ӿPyWMXDqW/";!u@h:bM'M_39BM7 ր[!S6殡^ɤS 6uc/k&{> Ĺ$iP,$@MJ q?C]Ӷ*>kG=C);zNJ-AzH|UQX] WpM}8^q{pZq/=e;½)~S!Z" 22Gb0CzY8jS{Ee%zJO3lZ uAȄ=wX3߶̡umMQBm.ѯ1>Jy;!  OU% ֲYB !wJ.@ Y>`ۗ3htR*aCT79UW? 9BnX}. fkvh}ʃ̔&!d/r7, .g}nc0nVjÇN1J܊qv]~&礷ZO6ѫ[7'S7F zӒG|pl{PK֘Tc']PƫJ[p@p'ScŠ;,t޷kW֏13MjR;#} h$ ^fDIH mc}I@=Ӳ=B%7x7(bƯIXGW~ \Z %o:H)UD덦0?*6g[6`Cjwړ)Vz|c{n&BM݌<, p5׍CK)k|eZ(M智siREǶF-$蘖؇9'm3}֝*ǐ3^XI2@~H4d6$ue'Y6p`ꊢ Q"! )<PeY{aY7eUP~$^Q'} QEpЌ;PAK'zxx{-

    c}X;b{ӭ=*N)`BzL=hU,* p0V_ 0.\_5:K\ѣ12%%(gr,a,(!\d*`]%z=y2u!Bc+^:pmCܺ9iw jFM,I{|׎f?Q7 \{ @7~|kWLY*\~=Wm鋶ف9U\,=:?=\ IyFzč1+\c{l?U^5.ΐU fђ QD63ЇH(N=À 0ab;1 G_R`nґpd=g9 ߱bKWWUءqˀv|K=Խu[Rur1K=$KvyqDo3ŋY*!. y藊bl!I\i}GtX绸aа.hQa;rME7>gTkc{R2{"s|v/c GsNh2yZIh8NEӜ Y][;fv(5 +zM)}>w^Q~׵raٻnQӾUʰ&5~sښ5WQpvso@ck[/P Nxr/ FOЪTzq~\okŚ)h;[Y0zت?0C(otA;oF7PWQ*!0žXP5# pdgm$JcAؙS+q,9 jx{WVUpZEcNԯ?x >I"J*l EfM!-]]:#@@3Qz~iM ƬgӧN}jå$=^,@o\6'bBՈ^ȝ&ᅺT(# ؂"I+oX-fd&'Flmtf)[ږiw]jS(pidgx>_\Ȃ,$@-0u8trfJuN^.=a*>|)V#Q@B~Y `# (\pVI/AF5Q?.w+Bv|^"n؄IA/l؄C^3 V b(/TSĨXZ|x0;D;2mx|`5cX6)=޶Q4:I*N3gSE$"]?xʘe9,?i T3Ebx8 &P D1ҌٴDOtD^m `F}D}*!"{%uccj?}VOV82ru7b+<>Jܷf @@s  43#s81o{a;:XvuIW=5կW^ݯad)VY%ͭ/dͺϷWp\xEP=g(:pőA86hť1ym6׮LxU*ƫdBѻI/Loap g<+''s E P_Vuz^p4 Ül?\1o qXH &OMMErejTt@4SDڎz846:b[Osfnr쬴uŽśplS%%9UP~'5U0mFfU_Kg}&q+iƎ Dt #SԫE&ME*EVoF^Bu]RiB z %aIx܍)}K45yRƕ8&''g$8OÞd q6p(Q)©phYdC2:D rnf]9yF]a$W1壳=rxA'n"\|URtW.o xxٯ!~3 L}S_@:J [UPŝ3T@vC$CLbpAl>y9XauAi85ͣ]j7([P;áQoO0. 0'; - #K:p8A\-+Eᨖe.;T`;q%  r?J,z񸲤T)x[|hg3uͼdcۜcYaso39M{58lLJ|c5mU->tĨD3 #2ީ8# u'TU*L _VH*_UԯVPGe@nJL2]ONԇګuUtZ|SuWq;k x-6DN:-Nq{>7'Fbx&aUiZV&g#cH@ȝjN"ڤ Xd"nI܄J{R'b+Y^5;IJy_S#HŦ,xפHcqI$)[> YvbM]/[ i!6Hj(6Èا⿱̾}S7=sv}.2VΩqƦ{pN2>7oJՅs@Wڮ938ʙp ݱ ڧ 8(6ބ,Mjf*pWq*ah~//B/j2;!qY.10/21o50j%x%KЙ5XTS,+ hUgp+B 9sa݅'TQ%5$44zku#Or5́Q`E5pv8SgB_#o48 (RR uV;!,(aE }K¹<ܴ9u_qefԙ;<\<vcVN7t"Ԭ/*-~ sEkm,o3Ife [XLoMՋ&o(DW'é&i9Ux`eqSMVҸ/ $%^]l[xPƶ"ukBg#RW"Ld}93 ;s)qK.qDr']\⒗T%;@i^s:5͟M?ԪKN[ZrJg29z6[(JMZ+oXBV"v}{Ҭ_q%?OFf4/]7/Oޓ~@N|zF7&G ge&WKh544OjdY)2Σ!WHd,^\w:&%%Dja8(Cypޥ9s?J uL[4JmG59 o!%S}Q!9۴u\?WBK\R(p\~oGJ}d0h:y2/gS0n{@w~DՄ5,<q&&yf IjO,'ی㪘I4 JR9UWɁSx֢5jA$ I:tA s6taXml_VgXUc fv)aشLH)\"ON2m &r64i`5ѤԿakF HߍDmSC o )%^딺Tif"xZFf88jM9MAj׻]*ړ1ɌOT10ȣ7P8:2h:䬺*m#7Lb ZkT0i"Fq#qe< Ltd g5K4RC: "+_yaOw7>iȝk?{]m|7X{׿ifS/|پڎpv7U/o߄ It# + zA#z0(8葓T 0J4x7U;ýUw& &uFlJrܜHEgUTUe4y4("c8Ob'(n-y.z!LcOPeWKFxBnc8ndNDao$bFN-gZj/1F()ɥ\r_r@2 )$PEI4U S֩j#P$QGj\~s072Ca#F@A}DKcI=)6pVYqzm.pL4:"Q牦:ti=;˪5~3pr4T{oc*o=ˤǪ_+x_`KyjQ#t &"MI?\.`lrPq_cߢ+D'.ӣwѻZy5,#TqwűU|~͝i)O?JwozKL"^Dӧ Y?|ʨBį& 30~ljJe={Ͳv.8U06C}a[jcli &UΆ/9oԾYryڏե>SzM-.Yɠ=v[J)j+K֓:+t?=11O.ث+t2<aah;@?+I īR Ui5-Ims<[x{^=4T|'wzΝ=n륗ZhS+7>{ve3{`֍w9=@Ǥ/IAn,|Km>nˇ6X4V~k'oްasMAdwpx| Ixc s*\t$h  sJPX~$~TC6A< L?8X0f(OG\af)ll1T¸yaq**MYJW&kLcG߳p5cOlƹ{nw1dެؙ CP9^`lvÜ2#Qk\g봯kl%EGV L-x$m  1(D+ BS IfFO*WTS I#ųރ=TQ cJze ^IB>lL뱜2?ϛ#:yDewp!@!Nh8>'v 5NiZsW-PSDAvދ)c0;z`A0P WMbH3t;Fd9H΂XH)3l}2N3ayK$Vn#€KVRmѥ0;D HzϿ[Y%:H.>^~GIOB:‘*u,_2`3Xlps2N';yŽ[T=qS|%Y-$NjRZ B;q6|@J?^Oֺ; V`{[Ӭ15:f2(M1T1g:;chN ,B: Xf5 V(.禛ݚնNzj\듿0Wpb/˼yOֻ޺•WW*ƨXuR =%$þ{瞾 0.p&Z-K{'H+ ˇT{KR"p */KPQ| Mߔ =NѷP% Z.x?E)t::BW>@oU. o{#*Z_%vFנ *C߅B/у=L_װbrfyf7ނ4ob_>c\w:Y*N)ZUFAj~!noZhzy:z&J=vrn{z}k/ß̎>{>~wD !nXJw+ Df?KdA ֢FB ֱ?#U(m%sZ2R#f#OaOQXIv HK0ԑeCY2 udI0ԑ udyY,`#Y'%Z‡:UN :r"PG`# I|bX ) v WQ8HaZ`/BqRJYCaNvn#CqQ8DQP8EZO馤`1 _Xh%ځAzlB .dSx4;>g/c- 2N+Wï5QNrPC|0y!x~-Hi&(X 8J|%)Q _FbnӴA!ZZ/qp;h90o"f+RYBYKc.|^sᷘD:^K$~_ TJ JyGYn|;Q{\TjC;(UKio%C4G|OŜGy"K{,Lcɖ9j)-~;A>JRۗLIV(K@<^M%yZS+'+G%D,RS#[‡isQ)j(JK5Rܹ+.M,YӶ7DkDxٴT~ Pi%u!D4AJ^* ?V/P0OްRZ~>.VSnR,˳l~{gNn(ߛK˳2R3*^؞H" u|lqow>Wm*+p@wي+'LO?mȂB1|w6_774P r@(qns>3eǧrÙ|([,e]B){!BzS./8ɗ? h,ߓ w=?/LBپl7d|';o4$8[|?hn K1%3=|/F/7Н,BdW bCU 4',XHFRephJ-f 亇EJbqpFmp_"];_W_gk Er d 5, d\`~<s.Y1|sԩu[z h2 0 B= 1EvHv%C=@#Ъ@"}@lgi~5ےٞs KjO j,|Oo*o)TB19KQs"\mwPl(PPNYg2 ۅBX:_5З-hi)LR#lw&KJiLOO/ <I❧g(r&#VY2$A[BҁDrgvpǂM e 4FR R)raKnZ0KO& #x2B b8QǤ`)כf$l)""{3U+:kmj-:EYW_vKc 2yzt2##yG!LrtAd ;*[A;a2EQ94)O>YLd1 }b'i,}b'i,}bڤYS{0I!q9u}+9/W-s`Oe m3D߂XDL KX3왑QpfPXUaq5:ꎨ;:k3ha0gph=;%C|g0gC|N)9>E}=1AOst8݃u^r[풻32ӧTQ=$Z(@ct!W!W!W!W! Lǥ$`&ЩfWW4ǮkثG|;7WAԇ}]IN^JN (p;$صzbИ}B.c0KᙸK]Χw]Σ O3qF|u1 ,bb ~svBXV_fM;ඃ-mm) 666`fTF 02' ᒐ$dS(qې\^r}NZfA0Fd&}n-`փ `C|#h],e96Njj] <20,d9YCQKO>0 Ns`@(# B(ŒSad S[ O b&1}lLCsZzZ;(F=#x d5aH#7>0ؓ/ Ï ڻ~ema98`7w6k>|t& Al6&i`8_}yj Զ ~VwZ]kuꖬ[]{BnZBל5&tӈWkgSj{5#:zSS|oG9X+=" GLТGZFˏ&Q-[(_^ OG[G1Zj[GLsVD'oիIUG9wjd02N5A+!9*$xܽhŪ#OxVi g" ~L+3mnI8WTbZ.']]']'8y&xIxGs%v>gdgÊ8 +OqW.~ 8ΞB!XD /ιan68wCpn̆#{oqٵO9lؽ(E0udN?K^:nrlBa`kCR)5)"ːjHZMy=uu5_OӢ\lDWY+xۿz08rLS!Mbmp*ՙ$WUୗ^9>;>^s{P_(+C`.uN-| l6*BauQpQB$"&"/CC3.LRW@ C*@b "bAG endstream endobj 1028 0 obj 29138 endobj 1029 0 obj <> endobj 1030 0 obj <> stream x]ͮ0y,oWcp%GbJBX͙3m.@kfеpim ~{ uOviV__>M}LCw-wgnn)}4%9NkƼVIUViSɿgrѵ#J}kҽ4T%eˢX~ooYr:?aJuSjQv5iQ]hzH=~.y^PozN=P[2D@+TG9.G~]%xK0;G'>8#,/Zk'PMP+E` .!B~~%V5N~߄9z/ݽǓ?hzGp75xG|/O~z> endobj 1032 0 obj <> stream xԼy`յ?~Ͻ#iF>Z}$[%ey:d8qBB&a!&4] iCWp-Ҿ}4o }mKcN}]gtg|ru6"=ڋo_7 ]>Bx6\&u͵7mj\xI6, tfZGsݼ'|^]c:H-BGhݾ}ݍ#wiשh Z^nO7Bj e#;7ow $E 5+c©^lr{>M  Gx"YJg곹|(5-m/^DCȓȅ!?bψLMMoOHo!t[H]9>Hsߙ>Rn#Ol!#1>t}~+j&NO{EbG)a'+яqy"h}CDУtD!Ԋ~sځxRzwtZJ\7D]Om/ 80>6Z_/ҶFz݀jx}e"ފ/}bL:+KWzJ7_@!T"ib "3RJ;ZըޤzAtƩi_WR@HX`sRole2Tm2qDnZ&A F:IWޭɾHO[$zCK~U]ˤ*=l&+O jR}$-{'D0be(bw}=eӽ2N &.aS"[ OjZܻxeDW{lN0k93XZδ̞>2o8/%5؜UċWUrKXNuRL<ۧ,9|-2iNOW -[xRu+`YLJrViySu"w/>!KV|LKW~ Zu"JVRLųd%4Q04y_ګrJR^ RZ WJwp>\RmGyQiJh4&zL4M ujM ϼ5M1ItN';4IM. (B!v {$dnN>4_+ll@zTh[\~a4ם.2{Rۙq]O'Z`^wg_k/aiԿe/je 5nR-n(' ˅75PYR%8W6Ŝr e5sF/]߰쵵ɀjU= ^u=S2 H%\X- kuXI^kރ2A5FvЀvl0KvCEѵQr2Lg)R ՉCl1Ib8S ~"[NMJ6Jd1[bI1uЏ@g^vyh9Bug^j8N#Kޕ]fȒϦ-욡4 fֻtg=7 |5C نJb/j5aw%HL)VSJL4IF%!tݾu^dMkVls73O/c%p*m!vM_?v7V5E^-o?k+U?>48| <դLKGb`}@s}`CS8څ`knR݅ϺՍM=ȷÇc e0-nb:p̳̃>. h #ؘ)͟Lf_[v`}sojw]]M9.p\z=={!#A6; `{{콽=="=nwloϤ6imkwlۈHֆz #@\@X.hB-Ӟ4DJhbN&jeO8 w8{|쟕yJ)PlDV!FzC[)=2b١zW6K0:44ZͣQJsc<-XSU`w/]L{Ph;5 aӫrC2)U6Fl7HJ*` a.Mқ$]4P6TZsrNc;n7-^ollަ93|?}~ nuo[?_+i]tӼ@[ⓡdROy̫,kkuP )^Px|f]9ZՈC#dBI˖Q zr2 ";%P;Akj emv6FdA/II_7oFڶaYm﷩*=~aMzMg#|aB}!MpN1 Iư&:}YU+pm jSSl hPNւV0jjjz ȂVjj `BVX+<-PP0"+Ah<5 )4},`~M c;ӌ3ֻ(nYsZ+d̥ftCڝ*݇J+DtLԨ:p bNb6aa ue$bmJү~<`pN](ui9+$Q{-W4;26[gWXۼ'_w4FVJ֔y/m ~SQ51.A(>a6P+?P``薾aOP"%8Gð*p`y׺vrnٍ:'ܰ<}ZZjG(\$ -g-Y`ނ-s_irXG">-\1WmQ:AFhm xx^59!@NH鋾͔sf=:KN41F7yUz(ߦ ,Qeh+0 1:ʘht:Ąd-bcJ0ZaFQqܭגU/'(ar&-~Y!㜺i*J>_x"z Fn8lh6h4,` OrtN(b6wm:K2*"*X.OWqSE,b\" GiUh.mq5b@Uj=%7?SvБo{Ku>p= Lu?+>Nh[uխHqqn@oͲjHͩw.A߯ :pт8,q4Q4i'b+X!8fLyWxƗKMx௟IbH[խo›SSSx`#ox|󞁗/ 8+#C%p\A!4 ܟ[R 6[$OӛDmPiI_Y0뽨1 [$p/T p.i L8,߅Ui.K2dߥGt-֪m8d%<}ziE1X3Ty /X)1LeH_tу@*L70bikA[ꪆAPuZ׭踾gG\GJw> m[N߷e-ߟI~ն~Rt=l6Oէ5F|e).->Hq d` tHHT74 o7!KS֚Wҕvp$CݸJ˿H<$p:"Bҝ Wy.J/O9үϦ?;sWg䷔l\:Ȼ.pp;/; _XH8w+q\cɴ=L;Үd>.SrmrGrOtRe#dal3OnDd:^J fBฏ-3rBc7 &50AP9qZ2c gu57LBEgHU\ =,Pǐr8_QGgjU0JS014Ch$ BQ`5ުQȍR[SEΨ56;Ng#٩ZrT#ݗpIUZX\JHr> W/jhڹeģ6x k:6u)&c>=j&$Asoc?]SL9fMӤ4ZSJ S)@)QyjZFM\ 8As گ1z0ZfX3٫ԜѼ5l:;]59yK,&٣!2i@U5vD{3a ΝS=eʇZo,×iٱQ* JG9ׇ TQXMA*v" YT1:_r<RS5 _&ҕΩ疥$s>ZGCpP~AUǞ!h>SV jտRvKW: ^JsO( uxP]:Bkx=nlvarP0Ȟz8L1J@f+s@A@ԥQrS .p8aa Ԯ. GJ k>VgQnDht'htLt#Ŝά{K3*+ΜZ%iA'>@H(AT2i?I&?NW;.QQYq5Z]ũ5}Ril5lWK̺WbD&C,o(F0Ŗ>L,l94VTPpfU뭉DQ3Uc*b3:eMj+IQx& Gu$Ⲁ?N}VCmжFWBS_[_c:F~%Rc#>Y P> 1W.>e535-]p0$ղC;H`b6\>e1g3&8n7`U?#͂*aG.{6G MEx\ΞüeFmړNIIwN6J"iD 7"oy$yDC!s ᚽ5opj\xG!Br,*O!&|Dv=Cb"H$gkZZzbe*RyQWYE1fF´F(I"ҭ* bT L EziJMyA @A+D=) Gf RL Uh+mխQw˪sj;nkpb΢^sֵ=tl!>6[cf{ӕ#9 4WMTi:*4US.Ҍgay=֟'u'0`$mdތ?$8(?J#= 9"a{3 'a$Eja!N.Ι,[t{2+] !׸ ﲃdvxv|.ט=c3Zs\F]uqݸyj{pO -`7zEtzX^.쾌E_؋ 2 e3T )3I,Q*w ʝNHa93Jp|yi1LB2| Zd۝fu*Ffgfs;;ghc|EŚ1^n.kk ]lTSzZ_Fm:}FGU :-TecL;.K5f,嵶U43ȕZRTשּqeX `4hi\~wzn|=#F:Ss /ExK8o5;ዸƤ^oj;l Ҿv"[n4<- rbӿ!oNrד>=h(xk3 o6@<"0%׽0 ZVaDTSL;$(xz3Ze/;oQm= pñmmJaT$"m*r)#ZWx':IK";AkSR`,%S)R*_L"O$>NH<*~  mv&Šl i0( J$iwJA6T"W^ֳ]zluv#;|:A:TJϣbSm⑓\Lt4v(ңb#4XzYUxB$Qub*/eqUf-X as"*kf~t RCC R֨g̐UJj40cTA%5r%;ۺ˧M:-z&k~&)-_ku>\+;lh_h 9x'S6i+So_V=7LD,<75i_Wܐ{VBͅ/6xwR*ξ滩~|F EQzB.Q^7>U V3zU‘f>Ԝ6vQN{9s8h/c)HBmmdC,ΞIFfu Z"6S;΍Rp.YŋMʾhjbAoLixNEajl'Om3z-DxC|⚕)_hkakuO|tT6(x_u]~b-<{䱩?N0gG~LQsCn.$c)}O@0GL sjO5 pLh*WeҤ$7 |}*R !J$!x\|NF"(TB1jRQUV9UTNw?܆T/fMD#bnO<,)7t`A )Ojnjujkj"_ߪ'Z'^ qB5.kQ4;b %!CegRP 9- jjkI@ &ZZN ڢv +?w~͞<;@ `75L``yyvM"ZUL!'pزlevϑrUR4 ( vuZNf}(?kyga[mW'VΎ+ n//-vpxuGbrtmЯF?z%3'*!%h<&Oփ#S#a0sHpx2hiRTaQROIe%!mPZNKZjO-ja;XZjk Lr}NL#Spw:d=,$GVjclb!j̄t1dF!Qzƴآ+ s({~~(k+@g4xZ({wFD6QQ`e0"q 6# 95Tﯘm\.! X=7WtWQF*vҁb7&\F<JtA0#|$HOO(tB>\ q|#e|e&jA&S % Di)mG3&>%~]T7"e r4 l ~5JNnjj6_ y Q2ך Úq8O`JiTgIl Ɣ_?tp-qPf]"@N:qMQݠzP(f|o̓O%-<X+11h0}44yCPSSP!|0jс3ku=*B9?'ZA3N Pi@cktvF7`0O/MtW 4gU_1J*<镐>sz}T(BƆ#A(97La]VOtlkƄ;pZSuYe; 74zܪDT{Pd3hb gUŴQ^W.ei2Xl<*EUg*'C5*1VF+9^@3'mF5N om($1^*"6 M5Bm5;3k4:3WQލ=_ F)}F~RќpJum29߿1Uv](>8{8$z,XT|m!Bu>^i9=ƪ'jR?.Aφ :+UTRy^cce8ӕMyFFnM&|~Ig7teq!^w[x:@(( ȁ3* kBQ)љ꘵]݇:5ZQM]A]%d&D $%DrxD/#^k~߄6pU=c"ﳻv6Ub,JjnISXך)d!+SmXOY{UE;i~.S0_ڡo(Nn`7Cቐo<0şfXي]iPjLY3 ޾hRug(00!%PC 6vhnrc e|m'HIdPoC͗۞/N-ȫ 4,)}]LGp~(^MGީ۷M ?ck~)dm~|Er +ME;Z9SkfO٪@SJ攈^bX,󅼞T*B-J\)C Q FBHB!O+,z,Oq{Bh{i }rIJI΅iA]r^./cmM~ on]+Ѥ ն<8'\gW$J^Em1@uuB 9BY IuIWJo K#j# }*1tCh!w`0mk9c18P#18L g9>pFpDyFdwm\֊ f|R GTr)ZH xCLKʦ-zAǁ7n~Ta)09́tQh瀉8ôʃ*8 D+P˙'y7`^6AN'Ng-rk zXVk?jfJCdNa)EGb׷X%>O2Y.W,}S#QjT\E=2ֲ'lQ@WFibU&V\159'STp$ 1oLxT6Eю((sDI!9]j?rIݬI?s1b(VM3>}q(sפ >:c 5Gv?ZVQŔB>?Ta3"U(9cFĪ2e#-qg/P^Q&xRu4OY 7>ӶG^+Snpsl _aROh#<Jyw>3?\jM>npRupEu[sú:f}POP2%lI`4!N,3CZC8r,@k׹ xy֞#ҚZQrmNh FdGQdM\6xv[^Y" _ATʤY >vq_EؿPE@Rܪ?Yu Y9[/_Wh];J.59h#}6FziS_~|L0lWUL"rC,^2.0ue"7plu ؠ-KnTbҠvzd:JJ}KrTJZ@˕ hIL"5+^,TX#&MiiN 9򗰪8X.a2mM4Ɛ1V@䒢1a 5ƟU1z3_[@n=<^~rЗ]yx`\9g<LƱP E,vK9e_.7C H3/Qt㡧CZ::z?4ҘH3TˑZ)%ƵC1/;eq i`TY^g)R9J'Kq??'3'ѡIdT8vrVy`G}JPhŕvy쟌TB.z.o(mEgר]z9W*0Mhː[ˬ[y5[3Ŕ2NP9U<:fԽKVݷQИRgwݩG4/@d&%V0-Imua3v,9 sb|B"譟6i1IYQbP}_qFo?q+ <=My6_WYokXV7 F}$p 46=vXa>aVx FcP(oȓOak>'-ye\VՓoUZվLkxcZp#&Zj~/W2{l+ 03^f >(7K?ZO9x=9nګ1Y9k>vWb4{Mk^kθ\O9W7}N~WݥY3w<@7Tڻ]{{Vݫz4nSkZ$$kk|P@a C-I)OJG 1i` RI0$ ֣z D16R}'9lSN/ iގɦE]T bBhyԂS Zjߴu'ґ԰Pƚ DCDHCXobH̱wOqTLϿ9Gf|iŀF~o}z6Z٭DgP+[.31=V,ӣ?%.1ll0'+ʆfj$vd%)/I0EkT&^L[*alGx|yɎ ~Ym^́vNHib]Ԝ^dfIZ-n| Mƈm3^Z%K7ْزly^IBLrlH,ldRа&j__1@Q Jx- .{}QeG>ՄQ曄&\hbU\C'AQ}ۆa{|C6mnvJfmƬW*[c包Y˰6efƇMceUoLLLT@ZT4WegJX)3EVj2Zn9T%ΑRO۰ռ6u*]ծ}h+n8g nzgѭ VϞmלhGoDc+T5sǓHCȑ !㯄K UAK!zK`:ҧ{+g&_iavhYr{G8llKtUE꺙*zν }9Dh9~Lh?y"|Ls+sV桎':^X<ߊw+޿AW`T+ R{Um:;I_{V<؀]2ٜco:3fbl6|%gqv&p>{@(J6 K(V26-܀H e&KZ8jA#/d1FblLg'Xk~VyZ `-'NdUŻKaL 7JGtd Z:UIoP.tބ0nɐ!DPا_);> NPxIc6{2|tXDf;hdR.Ӌ+SaѨ)c?dkAX\;;>6ޯcޑ[P=Ś;V;9iUw7q[=gj^hwm_UQqBJ4￁:[ڮ`%gs[3 ə}Cs!{*!➊`8d ЎնrȈZ|:VU*^+kň*YDMN]6Ah-z=bJ9c  Z\T\RYl/*۬'!6Ύv0::z!"!؉l6+ r:VSD2{A]e^g0g!p՞Ҩ:l/*'r: o:vQJ;izI!h$tC b:=#ZߞAXϤ5oP߱ԃݜ摁b+d>DtdBuL~rӫ< 5Ae_wPV;<4[wv=նre;yûՃ^/1~O;X5t[esFYP'@=y_ck ]+D̔ &4#xF TrAxxvk^xd}sUtY{sۚL#^w]ǭ{>z{O8|)G:uGod[Pk~OQENN sY4XCAK (Ae1 d%yꃤ!y> ٽIMKsᐵj8ZbEq(%}ОloMkV*vYcZ+3]U-JS6}fPx/([o=9iwc`.gkNQ S1''.bDE=>҈1׀ʺJVz]W`i.0a}Wekڂ|l0I[q5ޚs1('G_b-'X((hTuz,dɼXfǹ(02Gڼĸ.PrvdʓE}D!f5dIZd,ݖ͖ĢNmJKNh)֮2 2*ED5 nR1YĊ;O~1wSl/&]EF_05+`Aq > 5GHCѱttBy726cc̷t 4ˮ.zDVK'rfAՙVCFN\1gb/Y*^Xg^Y(fȱvTei/s.<2rUӶRqm rVʹ# ={SKvv@)g=lZ[foOߪ3V7_?кS'h%xU$EQ{w6>T*p.\k#F.",h9^^ߤgF|###;cX_rwƪM;Îsr8`µBC.p\ J Mf3֛ft6a Z2'\x~rKU P8*>JXldو˦"ƭTDqwlVN ^E'{ .dDlԶ:CI''y@5d,P)7'% {vfli(遇luhgvrKs-GW^qƓW6 nj*u/l6pk-+'Yqr݊!~❛WPe?-݋ qi.Ր(>1sclj 4(ɔ@,$}OpU`YyFW 8 +3v =^bO>j`gElmf='NGN {ogs ۖvm.dۖ|4 tȶ|7 $,r++]/Ͼ{'oq.LyGnnÚ_gwaS_/suV*FCrCƆ>Pe'P3~HhԵ6le28&`o ̇o.,QZBhj/cɯUP[](!ƼyE"`yXMN +ly7 3 m2,E#w84iŻCͬ;[hn-8ߙ_<UeJ@c+l@ YeF+/nnd3OaӶ緶9K+s&Szd$L*駈 A!}c'Cꮴr4smɧ9^+|G}mu]'Pj t-VS,t,9Nm%!r&6Vs}%pv|hBt@cE5_ߟ{W6-J%Z}s6qske'ҟ'd(Ttd;;6;sǾ(mѳ/LcL87|}'L5<箹 F%( ϵ2+fm\f'#w[.>TgQ3o=MYnNnQ.Ku `OS(b(gJ 6*bE4 &("QHp MO*H(%j~Eb*"Ix_̌[q_>j6s-ܝ@fœJ Wߍs+R8.ZfΉޯA%VRM6[n+:%/*8;N|q:ELM .G@W'rT0)YRbt!t[ [\]rK S[ryuS܂-',-Z,S+&k,f -{?/m! ^XVȪLr\hc,G1SGEX?h$d` 5"UYYdTxZ;M钕i`ĸIYV_\O,C>!8$K2zP8 cN:˃2ohR[Rp:w%Qp`>eGQF"dLE;IbJICmPe Ytn-t Z_9r 䤖z2SaN0)ĕb2o $1 3 /owzuZ=m2F޺!Gm-[^&4xyZM{HA?'eL'fߛݿlObgۆgH[&֦j8*:?[.fXbw?:^so(S#\9 Ź .f{Δ-umδ j5jX5 2:mY=Jư&e3:jYZAʵ8UN,aXFŜC,ñXt2Xv,t1X8er:&AE,8XAtCGd<<6_` 2FU:V =g" .lE]atBbL@ tG][Q^tRө u|ĂLZ#rXprzV}dbec'h oE IQX]=alL65t=O>|VF?,#tuVE I %w))t䢉!'7Ƥ0˷TrRlP9ME +vp1{*6UK*4nVU\11TZ}9m}XzaFUnoR*=Giv!zsד-TB&F]NU 6s&IcŁP.wvw]^6jC5o5CRߠ:k.VS/sqnDZT r z-(CUU(~h"ru,N*t[GGMm)?a5bD{.aǂ3qwnp|m6+1M{?BzJ b,!=QIv ^ qa.\*Hi]Rx|yCei ɦo2,d;l~2>W'w}wT>eJ5{jo9V5trB(U]Xwt}${J ?_Yk\mBEMn͚W]Wq7^) +*[Z/|U, Iô54MxӦu)_U9}jbB<O(0o\Wm^Uy|**Y;Wvkfժ a'ۦ.[>5uީ>R}Tt?`/]KT<]XZ4@Y:}>n?sc~9z,E%_Ymp/ G3F@Xj͈Gu#yv9W\Yu}<%*YUחle |KOhgk SWe=đwSe ɂL8b+0){svޭ8HRҨҏdycyHk,b\|}ڪOy7J kؐ<n7d,Yad72H E"1RecAdϨOcUoehVz\JFrY.WQ-QyZ&WV,X{ʂCLi]j%-햓cʄ+V9aman#\cHGa&ta MEV3m"oKCxz fN'-a8 ]鶈;sU)YX0@27"бiS'tcI fŽs҉`U[_١v1{\aevgU w8,j_wJZrs܋b,_/gRȩ,S߇'g~9+3{,3 JI4i4i?H$;p;n?bVMi}?1:i󓯥>T؋Mj58In\gC\9*W§Ց.,z .,#wD_uNgipat(KK}75ớ_>Tgnj+-Tp pA P:u::۶vƩX:V^gcTܺ:+޺H~\6Țη\MdTT&RsLԶbbZ'#Nz&٢/dI2^h n4(Ģ7 ii:\x%AIl'膥+k m@~yv$ฆ6i(K /ٯ-֛t2jӌ ǔ 򼱻_(+ۄ ,oX-T]ś>}fZ0G"k76m/0"nmy3{_3O5-fO~|]KdOJD_+_DҏXtRe?@ RPxfd2  Cbŭso"։On *&so/Bxg#1mx6sh'7VAJp.,cHI|w~ekQ>یG#W= 8; \'J? me(vL]ǠB!aHcV4 8v=! Y.hOC5!Vۊ)_SSYkeg+w9~rY? %2o!z}ǂB=/T,\:CB^_K+e = SEؽ!X/ xXZr fQV9b 2dc/r`ߒ`z3J B6] VˮeՠbEc%/T^QHsF-Z$Ar$EƿH0l&ː`9Z$X66HMI ?'j!+A&. ֢jg$8[g#wJ0G PQXFL ) RXA.I +o%Ha)_GC`JJ0 oK0 VK0F|ݿ`(_>[|LPE%ʷhR| q O%x?Da K0jߣHx9#)  搿\̻/^M6Q'%@a3U%S8D%(l%<% >(ʆVH06RM$y)$xSLp(\N4AL !|+t֊$t\B`(ПhYDP ~Diģ0KP%&Pl/Q'~-pM>rQ\'PF4!mF&Q2Np'xõ\opᙄ4.#X W4Ssi]'ahԗн/(.\"u>bROvPn' &R;F}$!V/ E8GkƤb08Lɑ>1i;E)MK ͥ(mICQ KmF/ y"e6!iOH| +#Tc&%޴J-ȼ~B%sP*'QNT"I-~w3-@s<2-b")y8!4%6ȏGiMK t$e(#a$m )](Ibzd{VD8--u/'R 2=b'{1|PZi:U3rO߰$be~,>4!RM t#A PǨ P.jV< |P I-E5 <C tFq7COu$[A%xPj󒴕[T/@;kBER E7P;I쭒ČJ=^iRQ*$b}穔oE`j>BOQ|D-!)Eк"P;tX2[hZT *9md|Ii!G.YI$*e%aZ;.K՚ q-ŴP䨟j^ʓAk|Z֒owmCc?p4@|: w/nc,\EeB_˔ yԇK_\ F1gR[L]"gD .4F~ohT?yI𔪅zErGEOо^j륜^{qaFRy/h(WjK?RO\z*#"eyO(Mοy%N]TwC Vk"+5u0͇c5rT c1 jP|dK<5R}ã}Cc1<2S$|*>Om5q:~~F[F|b"=B<{ӽ@"'S|Pٕ8M+һ!!p|bPPoj(>24ݲ_>4HClIvnmX_N+*~31e",Pblp/ZNYb/O D*H "9w<{GXb.`PE޼7'SC#V8LJP&L&HR_^֡t<lLG{Sß19늕k6tw/_:){S ɓ ~JBWw  Cc}qJD||h?Uq~K/1 2H:;q~41w'3;@t҃@D E~;CBM?ջc!Ro7\&8LtzǶRF'RDL)Ht*^I47PG<[A41&y%#ħRp_ H&^J¥m #bM##4dCH.` lNN@~.A&RbM_,"G@bĀ)u1n%O(46Dn"#Ƞ$!k/P$ e0@iqPC$d=BJ)@+$dm0cǎ@|hz A#5՛e;8x=HdrW/Ѣ_P䲃ZޘhQZ L@<-CbM{w2緂ԍ;zw!H?ъT!D/I !A cpOoHT!OCAf O$A,v Kn^l/6NB)?rV q慢Ʉ<ꏧ{ܑJ Sw_/j&w佑Xi4\]QXxH`z;RFI] JD \O 1 `ā+4(Kgeo"MCC|j^B!a~Mō ˓ ʧX@'J f@FwJ^~;~Bu*SSVĹO4#40}^/. Ϟf~}}}]UOW>]%tUOW>]%tUOW>]%tUOW>]%tUnsPT&x :Rp<)ië)fŠ -c,p$ GhKcsi.B#oJr$gZ9kjO{Ieph^n?I 'p/ՒcgKcў->I1:Oz"4!"i؉.Z`t?_!2\20;󅶝ap}!.ƄKb vOLm/)n$\܉D0JMDBq|ߏo9c=1,QSN 5-HN n3$8@͐!#7}psHW7 &p(ߣ{|f aBf/ o"9R )wC!f%\7K88` Xv݂E =#<̉g;4cr3!1g<%T ijmjahw)p;e]R NMNjcr& UpU U U Up2@Yɉ&AZ?rP<.E!p B=}ۓ)!@cgVxz8ȇ!|H qÃ><;a}Cz܍ !+ݐnl~ zZti?}i,nzn?Bn!Mb;{MPo"dahZ΁{8Eԍ9Ă5w꣇?:qO-69c=snm=.;R)ϼ3p`)\ka3/oKp ynr{ prC3*7} [.i_{/SGcݷ#w ccG7Cla<&Cד/(a܀A|cر{=x9sn6=o6nn:Gt}p9DŽÞ@i8slќc$GWQs69%:o̧t˝ͻu!`nrȚN[oX?2顸p7 Yp2Jr.}V(b3L ;=+3o|0# Q3ə3'fN(7AuIREn$k84^y[7hYZZ+Z9[F'-6dyӛyjp,K.MMaN44+,nbO/s,&&:ցY6=KUs,#gβŖ3nb3ܸ$+܎: *ܨ]ZX &~ڳꖂ•;Q7գv>i6/?OekZM[+}WNWM7ni榳n:zgq.y} ezs+p¹o|b_ G^#i߲V]={ڧs7mh et^˃^N,\2h&.Ɯ!zb"=.4!R;R@q|\D]J M)K?E)b"J}GzqGTtBW,rٴ{㴽^(> endobj 1035 0 obj <> stream x]ˎ@E|E/',$?ƒy(|i I,l2|{a;E6C_1FC+-zj?iO'%˿އa_c>_"ksګϥx%6?f\ktSosЎQw,96ĭ:n- kFV ;JKڀ+ B~.x-Yvt7/{ Gĺe5U`We8ow胦 OMRr_I+KӿB?M߃_"$$$п=>& N/ϥZJ~?b?2--mzo^Yȴ/_J-hfLZsK'ϥ)wmz62x`~!đ!YÔ ?0O3~ endstream endobj 1036 0 obj <> endobj 1037 0 obj <> stream xܼy|Օ/~oUuuUEݭ^ݒo-lnۀ 6``c0K !@!˄3 !y'Lᅀ[ުjY̛~~juթխ{={νջ.߽(>@nֱRb@+v]7~oPR-{v\ys7[󁓶l߀[t߰uU_ز}.]o:voIt!voۺzxj|]ߪ |*^t&7J5ARZʰ2BRk:h2[6{r{>  Gx}"jHIAU KV# Nt6t Mlz?~pF7y~?%f`󿩺 !xSW5`L@RMӟO'鍳JM-໨=k|o1XZ =^I?'PVmF%FxاEYo̽fJ3=v!w s6DMg> M9s,x>΅4gSpt;Ї` 4McD,S 9 )h@}\75|k6Q\3zq?F>>`HA$۳rY}>䈔# ? Z O]`htwi;<_$˷Z ۧ})p}6[ӀU1ߚCSY@:7,\Mwts?`;7k\v}ٰvKu<}h}JΝST7*}{vPe_:4:1hv-:}nMm_x]1ڷj ^cքsH31VK5pw7G>tx-DݹqE$`1lsaA>_㙲pC:q֠ E;?S"ȍu Ibe<_0Ԏ7ar&eTLA L[_/jaʽڍmćF~<=t:4zh}|nC㝣n~B[4` q Q<] c<&Z "FSOhH]X`'!$ЫyHVX@ƅ |15p9BS n1ĈQr-ǸT!/ l<$8ۇH;1,PĔ,KӔ9h"Cuߔ&6%iz4h[럿lQdp<4#B.BLKrj;7?.za=͋" >6|֏w#;ŧ3ʍ@?ҧϲ?ϥzsiL- BOö`PJ%`ˈŃKps|Zog?s V3U~d``5QF[7n78ȢJUfͭfGT*7T9FRǥgӠ`uyM07 F5ZhvUJWф;+ 뷛~5,sb2%Ŕ͢ypa5m}$.*&~}UӼ Zڢ\ Zc1!RpzR`!_4>/m4`$!tyC\>/I >o.兌\6DrZ1I6p^6$*TYN)RTih)IAѠ(HY@i FK I)5D^&d&ݞf7H)gi'&K\NvBeS ӧ̱u^K7΃/T;V[}{6 ͒Tl`dPݺvMJ0Z&ߒb`*P+򬼗&䘫. Ɛ㨂 ZÜHbqޒW eKGA 2g,IWA|6,4~VhE4+,ɑ8/\!de WsN#UӈEEaH'H,@LJ$ZLd. hdgɼD}}p~8ޘuiuKrVcx8åꅷB7+7կ=-!_[]3?=y[d$s7 JZm4!I,Ahtj7MS f2n i25҆i5T֐ɰj֝)d܃Z ,MPYJTZQ83'~&Dϕ M<):<[{5RIӄJ$u3G]1ӐB/T*i%|4ӈ ҠG qB>Y, Kд4jXef9RH]gXe ?/ dESSʸVM"-.|.ٴ-0xV~A3̉XD#oFOt+% aU$"Duc{R IgtiڔAZ6Hp.vKh IzhVilG%9\fHR,xHPޚ`Qg bREHUH)P |A/0W`^:cwPZy+pGב񈇳N%Ŝ]ؘ ?镋:*kʇqSk1r oW~hg)R,uh69jCk|6uKvbcyngk%y.pn.|Mf2#?? [̻Ghnnp74YXXpHip A qh]Cf1U?3aa°\[RԶop7|Iyd^úށpCh'zk_Z᫷}+ky^9@M Bc. ); t{:BH 9C4#C\pp2Eሣ] uO" {hDܬg8&jEţ5la\K~q]nz$sLpPlBfD ̞N q7[͞Ejima#~yCs&m7~cM,/q(<ˉψU7 ^~]u-n]{^ݹlNl4CCMVMlJCD&[ȟ4>--ciah1,'GfQj JFlN&"DhHO6Ն\&hUeLH"v#@KpX>9]蠬˻4%6RR)t@q'B<FSuyA=/h>yRSj,F:"XD EW*{#8Q0 ?1( aO bk(x%C@KڅHcZ'.78+[ZbbeMnڜ_G én`4Q n,s6]lM[ÍL_iVry:ypJpOŖRpo,[t/1x6GidSim ObY ͠`#: 'ID1MjbyrkV[J-:cF׳܆n]-I$)d[_ @ƽ*֌"#-V/K"'u Ez Fݕn5> U۾l/pmTr{r. }R zq[=-˿(k h/_yķc2CXcL 1e()=ds7v 0{h\w'2^%ޕ:Bʞiu. U"S7w[O^}[6roo'PqsofTQ786f[ī|Di`.{8cVm0Kh!fe:@0|eh49o^W[l.4 iLg֥ cQ^?###b\4ɯb;f]_g,JŨR][Bwf'5,-D(Ap(G)Fbw7Ļ\'hSk_Pl'Qnkד::2t?QF+-I9;K)OnWŒC[,w=\?,[mfdX`òj4[)=Rl [fUZuU^Gv!'ˮ^6)IQ&`f3"ۗtq((?^ez)װLjlgh/^.^0uH@2#ީ3ץT 2@l{R&`q=80g'wjNȀ! Cd{(@\k 3h4˥CRaa;gX]nnڱ0(Uy^i'd,(#t@ H!j1p⭭#LciҠF@6!NMpQ\==1)amWᙀ}FB XJ FF @Y~fMt+ȻT W7xy'A_+dD*aƖI Tp8T5>еEeEiڦ7}J}ou#SO|ÿItj_JTa9:av&FQAׄDb) Q.!1L,Iђ_8 :0o0(-"t96MYy`k?K틆윮Q6Jv3@T>bhDvNiFΐH ȄP$Sa$"):!^D IJ%'jHd=%|NyPCh. .Z178uqX]03J|?a 4_v >XwzR/hs۪?[MjӼ=;F}JVӟ_dnߨy٪zͻ]ݐutywzCƒak>_O;f"2z*"D^J:tdm8JjXG=ʅLA7(٬.ʨC&d*~ì%/9KH_ѷh{Dn:g5< z{C!, ./ e'zNl;T ҹHi1{nr(yWd(,%PO7: W(4dTu{w1S,KH3qD2& nkw fO'%.ũrE ꇓ:1q69#~ 䔉04dxCb"oid%qd Ҋ/I,]m,务\xK7U kz' a <*!-KL@hp˞"Y˕p@nJrj,s/#}.c .0\ga6&+BgxP?x]~\sPC(gc9$ˇ &0#zRXG^ISCbo1-:X&cR_NB 6%aȏk >!Q?LDZ? #b+Jh憕:<=\9:uZ.v!ѯ_}춬u`ϭzm+dkA>3X]Чj> \o]~Ǧ5\hmՅ}gzY6PbdתK9w!{c<Ymf@t?ڏQ"$^ A^s{;I[P:?dIJ|s/cӉe6 9ZBliOCt7r {`'nO2"v$e~U Ij `v:nϢ{f(j1.1b3>~lj>~}<8/F/˭_؂LXK15A朇$M/Z|W hAP?۴gxKhݥ0zsU] KD\e@w1mR_T2r-T=U:21[ |~{߯1GFe {ZZ?xVw鷹kN0"Y$n12T,65M3,sOC?j~v(ج>}fGgL5֒T=cp=]7_H"0MQ9+MNÃ]T"%)"蜥hk0?>&If:/$b昝T4HO@ {!9Lڡ&dX&M&`3uΒl`r7$3$B!a f{\K2<1ɖf-,jI-CӪI}Tɦ2iݧ}dP`G+M|yǗDrdNwb]m){Ÿ^gD'JE`1RW}4RL b)2_ |场pC9arߩ)fu]2Zg<9D%ehȫG670hdXIB{ԚϞ&b!)&ҙ C)M߹i6hQF oLRKyq^Ta[!/:lK;QʧAB8gE{\pBEO5:ľXljJVhU"T{1xbt 3熠͙?1BJ3ݾH,vCSTr__(HFqA>FL܍{*D` * ktrM{{6ii3tgbѧc2I&{`H?mr6&-lx:̊p^% W#إ"dr^ Ce(kQfۇ,Z yx Ԕ `EY ^HONA9x )- ͋[ )+{ؗ@v[S^¾]J ;._P1ϢʮH\{=tFɱQ*?nbDLQnx w^XQ?Ek.|T*`2,70 t >@AG3(]xf'q+|y0!L Wq.ɱAAu%Y!i? a-!yNWSby F.4Ru(\2ʫX```c4%c0XȀ!pW/|-\J-Kl zh CTh:NxN`ٌQgڲ~x5N`l͚H۝:`:c2f!rzԑݖ+t[V^~`[`.V՚ϥVgQBrTLȨt?@2l8ބTaS?3>2xgBhsH>WD35ʩJ!4ہ*% Bd݂! ,^3PZAӲab۪ϙt^2Odꢦ2Y]ԗ_C|^3!}N}6[~0&VUɅ0O'{_IZ^-Խ=2q>y6YU޶Wot{Ԡ>P##}x`@,tCLuw}畛DK?\(s7WoỷUZ6y'D+B KAAg?ׅY8I&p6W+5HEK(+0S񩴾_| ;ؐ_\ qKy9yaW-H(ȋoz΅vOfuO-ٳp7ηuyW득غoYv=";:ܲ~dm> mxND"'A 4{eMF[Ozt'$JK=~~Fn`GN˃rŸf9DH3AEI0i"iLԂ_Yajyf7&E Zt,X䱅GJgr9rn~o(r(]Th[;Li@`}Τ %L EItz W#n!q-ɛB=3k= fXItO +pj%)") -b,/y!7pà 5uo=VIgھJǎ _9ޏuvn-z0 ǸD-Woi8ܞEbE:'d<Ury߭c;lli65m"]vBc8`pL4 &Ѽٔf، /ސ5JUrd]T^H ^=CK`393CdC$nv(_N Pp`Dm kR&|A>Z,jvh3h1vD͵ZzD`o w;>x42"\L\]$bN 3|ZfR%9㬝|lA.[@0SJ\O$vK]'%a-]S:JM.ԙ:ƫ wEmeWgp̙ׅ"&RĈg^PH:Ӑ(Ln]5 ɲbp(ͫ~.߱vy|lYV䶉64fH,Y dC;3H9޿T*-y! ) Ta.暰!di4M70}CBGs2eWUzz^ɉ,HNe2Pt;(J*ސhiBf 7 #Mi[5RƀH }t`)HUCHϰ)}ذ*wezS7"chilEj {xA}) qSQy>=ZWdx7Ԉ44: Iku0/(!v$oA ܇b7W}G}FpC\Bgo.o\Έz5u3Ⱦ`4:]eux{k~~J _CPS^5ד:5so\}.#a qr^ rRj?Bǣ֝,GB)p{YoJ4'IPA1>#1uHb%l [t%t1_h`XNkuj&lFsi Co :( B. -bԽ#u:vٚw/7T9,jœ8&} &$qf%=3/|1 5%&|#1Q 󩸒&PFWJ Wr%&IZNRQFd!WR+5lRyzOϧnpV3ְZXo*^]gS;#J+f%w{`HeQӼӥc"  //J~ ܄˶F.vkmm6Z-͖& BElD&ʬ\fml^fsr4bm^@q`ךPCQ Ӆ7Rv~ު柱)?3k$ڙoqيTIq^|%"6R;p `;g0krsGGimGzXHkf7dFF[27hLO}Nܡfcț-za/g 4:u^+*)eQ}{kWїS~݇oqQ:ufɻw-)s%-&BjRfGB\Ǿ^*}KG$jDoiY2d.G"1Ѥ445)[M Gv\:ɚymyELolr%R- 3pc߽Rv̚f997'J/J2~765oe~|2={=N=db}>!%%2 AR&-Y60j(&A9y5Pr$y,(ʘ0} ϐe/%ex~J>OcNBc<Y+ ]'&5 C0'`Td=hh<^q'J[zrdDodH #镠wyc]zkCN&u=4ÑtzW$#@/ZUszsZյϮ(=0vg*5 >-S-X2XD:íӞ@KiׄFMMc%lBqo\Kb aёY?|3/ -x֧ė!_l#GQ8"+ҳnBZCzrY!\dyV-qɍUTzfg^]MZmz mxOy .ռ3pUY3Z? 0j2>o8"K17a9Ԟ ;IMSL 9Ǚ\*___FA 9ʨ74I#I =|g6ogbX/7^fm_ˤ5$8k-!^yRYe%*-dhllYHRf Ṯ:V"S ~%:3/]QۄfoXhRZimn!+ϣѮ#MX'R֔2 B_4J9Jތc Mǔ9E)4 S9ne ܊JWZQfVVREM #RtdN˥,wEN{KV.-Imm|t.׳gjgI4jR'Q[f̉a=*Dmn S+>Ps}}+VU|q8_76oiSZ*#o2]"< /{hh2HB3#?|V>2@gdpWGyf o$𜸟l"I!O!^P>MeYi4,K!<x%rDPt8w'c^3{5Pt9!|p vTo?/|x4 .Sg!©M2+fEzNKflm1sl˙9[,{ c;UjG8`H{㱀F{ADrx8Z{;_ɈOa;7N1 y~;7D Qyr_xZT&mR)xXi$j.hZ5\H$ҖLʎ轢t(ץãŇ"1S\0FgeM^l淐l?d!:T$b'' MNdsM^ 7jŲX,Ke!ʒrLڊ\r1k*쁢7PGި=IrSLX;_<\, ӿWx{T{ ž`4]'1zqe'᪛~2!Ra(1_g[`|k鉅6 Qci\to]MKa$h|a:;FNx2\",EUXhۜ[ 'n^;YdD7Ҍ!)( /wk@躀~_@m9` Ρ2"="Ҩ|ZhYj4Ï '+iIbZi~;O|DseڑV{`#X6] و""1UݠEmA-`:^G7@`5 1QPm(wm {VOvWks:K.Bkٍqٍ_{JíFO/yBc(g r nk%pn ֡<[OKGi^,BwG:>k^V=)bZBn]I1܉BǍx#Gc|fBW}a;q8e*[%QoV^FBtNf_&C>|ϼoe7M[s|]1ugd//ʩ ɏ(I;_{?ʹ2[\"s &#űiCyzEy=w<̚g[?Nq /g=xyˠ U]]V^~6*'г` :ѳ%yeG=F|*|xqqVϦ+c[k#n,m$ݨ_ j~ px^7yg_g+?v95a}{F^KM5&ϏQ^uNCf /eWϺ g+vgn^ֈ< Z׾.񾸏Q[JR6leKn{xhYxpqτy[ԱKz.EW라^uE.-3Vcibf x=@\ŋ㰹ym!2I6@#< 3g,PaBФM҇J})R+ɋ(*VO!}R<4C٠򶆹_fyN.NuQO-cAzX=v\_dv+Tu/jEƑL=+J%ޯyH3 emKEG,\^=,n|.s6y/oW..OfS|sY\ Xf+ ?,23']xLL د׆8ɟT7vOC[^#u^Eˆ]BϷ> K D9_QYQey>Y=鄭d萇آXzx zNy#)i8z(Y{&]TZb+ߍzڢ*U%Rjkh^R>#&w{w}sx92ǀU ~UY%]dnЫaUqV}4c O,:ji͢\Ls(cIY.F10gZd k꒑5ͺ5xJ{1Օ%˱Sl{V݈x,R̓j8H sXU[S/7{SHMaTg[/ ? Mr:55 zf㧽ؕoA7w?4Ɵ!UJňsQ][˸}QylN6JU\Ir3n:O'iul5:oxEz<\drF՘rK85=2ɭI2U]|wդoF$<ŃpnMQi)&gBQy)=ţ9 3J&3$Gehi=dpQaU6UYCF2&6L=cH-JVN+VIZ, ! b2ֳaZ& ph$le2>D4Šp3mf(NlC(>BMٲ<؏<crԋӶ(k(N&%fL{\O[zq4tSfC\v5wBW ~ Hp]'5Lr:yŴ`y< q&AU9bQM2JQ6 ͩ~ޣz٣S:ri.gg(YJf)%jl$ܥ5ikMr.]iݎwwٿ ,H@z:_Ao:=EHhGqt}p|mgB%woJ$wS7oڥk PZ;4ֳN]g6}y%O$gb[%3[w>SSрSR}VjURuhPA. m(hgm1@dvҬ}Ѿj#t [(?N %fC*Q'tOpe1  g4K.DH'gcd8D0\UD!t]J 8дJ良ʉm[ͧƷ(Ñ|}P. nKvs7S7goù7]!n'w4'OzB og@+E[}e Wf_./^/}S79DoR "-8RE"E~y"E^}Y;;+F~tvMlE\! \\ARETnTVP򗊔> endobj 1040 0 obj <> stream x]͎0<ۀ"L2HYG8)RcCyC[Ds%0.8Go=^e je,OmC8OMOk%>vNScc_}XΚF _ϥ0qy<압J? 6w]lu6md> U%s)jRTh[agp]KW\[ e-2FyOw֊CLZjoq{Y70e_ͮ2,+j# n?8X_K7U1|H1<ͨoc endstream endobj 1041 0 obj <> endobj 1042 0 obj <> stream xԼy`չ7|fFҌͲdɒ-ɶ,'ޝ}q'Q  [R +ak˒@iIX{q-B{{- P꒶4lwH.YΙM~r-+.[5 вbo;՛\V}?k.ݾ?ikW-[yz|/z5dwMdxeo甇kz.ݸbك+~-۶R=d?ae^q. @u|͗oq~}ڿip&oHɇ&GfXN`4IbN-EPq8RR+TZohԬNnimkc_,fe` |o7QTBwi@@Eg~^{=9Ѣg>oo&ߋV_=^:`,%pw0U 5܁߃g`v rߒȃw`|p \G'ȑo/s#M>ȗA#Yp`.l Zg) $O:>_m i3\}:萍N)*a5+;'9o!W l_KrWA4JΜ NM@%@h!b|Noȇt`m deޢ琳Tp}>_?&h!ßB`a 20YdR}o`C5Z"8G~v<9#Ws:2s?#y w=][`_c?8;~<24Xhk y C112Lʾ ٟk"2\DtD:%JV&*hI$\ aY-fd4zu!Z4,ӽ!&LCS*($[^6i]XTBaMeC,^͵tY jI\[sݓ~/+ׇWrPǹ(?Bsl39`c j1Fh8yv]?O6BmHtq MlYs[uC!pc౲gtR㆕˖,3<p}mPYH2 Бktk>=,CmtԾr~:?Fօ{YȺ}$u^ow "$"=DF.־%?9vc,0sDF\P"2d'I/}}`_x藞H#g/Zؾ6N %8sqz${^S!y!G[memiH):ga+=emܯҟo! iC Cʹ!rh-]WjcU Y.߿#߿C9SojhBI7z:nzB4?sw.ˉPs;=_uD@OJŋry иM[ΞK<{柟QTg[E(xR s{8~D}9s!Թ%/f%P(/ɭ 涐S Mham@ d͵ 1֞rL텾Q--ُpE OYxAX1[x*@t֊.ҽS)Gz{J`h hm6VD6Yk8ľ>l ʉe&w1>QU)YlTm"ښ؝8 5Skж{S`g;'9QjⒸ"v0MF;:Cy:^z`hoza2onPtAMIFhFNvޭLk@V \nuJ:f)&Z[n(n=˽}Y,ˠR g2ç_CKpܮK>Cv=N-g2t+CN獀Dq$3@67>h&ߌ-d`&3ǡMDž%JuU( )5T:І*T]U8-TJHICPns3#(z"t/(tNa_OUVv\ں-M,z9*dl5L2_H7mnWOܶG3kRQrWW©삇[۫_| ߂ir8'͚]ۺbH~ڱlٲKyzrv'E,'${r}GsSj[g9 &HZ-B6"rD쌜8ҬFvjBmVQ !bp`ُfxF屳eGAXd/Y 9 JGB!n9 ]NBWRMD>i]] -7@$4,g=YZVR^X-X#>pPxNGCPfx;f#Qá=.V6c?ڏ"˕յHtA?^*H_sjY"DZX}asX:%GbU4Q`⾓*1`(&p8Hd ^o=qjd(7#{YPC;@e?lΏUUΏx䱑Ҍ9 -:wR\g#|~e$Dx8S pv" $HuF3mߩӤ {us& u(MnRAwڐN S:Phg /55}]N'L/XZb'=fǿŸ>e$ ?@ZfYd򛐁5be1`v|a;"L cI5D 61:K1&Y<v311au'ᵄzǽzN]T#.1MƓؒ|U~+l>kej J!e?ީ8٣^+9av uuRmmsħ[Dr{C>_T'*(Tޒ Hޖq@$_a Y+wEXL-Pbǯbp؁{)Hd@1XCl-L Uq~%HptdQG-9jd(]vxx'~8`O$A <Q k_; ${h}9L(W1mGG%{ёG#2@JN!mT*yPV(TI*R%߃ZK3}lAq$탄*TGf2ޔhTB[ntp:F,|wQhqsB߉/YOF9;lxڲhg _d}] o7=-&c)#BT_XCǫWyY1wI@t$Tw@!qa$KIDb %I$Cj} +e}ƗSUhG4`kքOc~"er@ ~W8fzQE=U9h/?;+Q%I\]iӰ&4]HtvP°|a"pp<%wx~q( EQ&'J8:q{RIAgv'd;whOznP՛)NA6eOUV_ jHMMݓbNSRo)%IK²$ ɩ{$x,%əɾ$`Sɸ|;vov՛J *oRvTW`WYo{yQX 3J@|ZCg/Y߲~hQ@ A3>Ll:UZ3 \ir );} y4k!D2Qu%:@>M'S n5=~< 4KT ;\co YI% U7gEjrdnaʛ(`uU{ժ-UOTWagjA R: ח_YT5pk!|a߈|PWnw^tJ Y~LO~fb.WA ~m >@%єZ_BM((MW:wjȑ gi8(@N8(|ap^lE%x" ^)AJ'%z$ꢆk bv\pwuY;;u֢;<f7ߧYK:ƺ) mE\J0Y2ٱw~35L$n2ĢJ!'ANeWm6_0/T$E]v:R5f.6sU3x=f?+Oz6([^Q, zs ,X>,YEhmY/xh F.ta_fw{h~g᜞!׿kC>=OlbAX*?dSeY*<~auԃjqDI$"#dJnء4]3D?j74N)hJpTX?>l&44_+ʼsa^.nW#s~,!$( PW*Š;7:w8'Kt۪7P `utmw^:nVez`/J -J)ۡ?GoBn&4ZQnY*R{4 ]vI}ݠ8QQc?3NTF/`%GTn3D4hq{)L"TjjM ]!f$ox;ܼ7ʾo?uWf?ۦOQ4[״Vd@oY9x4vE-㧹.nP *n9"/ 63t^ BXWĤГ&2vZk]"];'y®:s8i;y.h-@B:\W}4.55R-"j\*b][$}YtlAm}i.ۡJ Hl/q!LfLfT cH4gF5!VL])xu^壣.) VRT04u_ ,0G %Xס.ɦϞޝm{N@}3FAϕ!=MW~x!ܻ)(ezhk-pɳ Ceᛂ`+G|?k;\a'B$}?F$pT*ި@WU{b;m 0S"BV6YxF(jC7)|")̧\n{ f8q7ehD##e1.=.WA#jɬT"~#yFL#9D5J~xn"1S>a'O~ 9AP(/ T |@A{5a\T.ߨFfE EH$Q%FGF@o=LR/tBnfQ?ٜq_5DIŠBRvR osot|`eO[n$yvF16 ;@$uޗ?)gsC?zgWd(ʜį'@$&8j`JN bquGԊG+M'wv[n)%Q])l1o?wbXԺ46E-@VEba:<6|Z3A<3*SoitĿ'Zb/F? 'AfN u,CKʌKa,STB|u:5W+?Ȏ53q*Khb.A|Ex]dHA7vAEtuEתꄫ[~ronw|;MkvM;D+\G,uqkf|F3 7ˍ?2Fh3 1Udh?ͣyxr" ة=,ð,ZB(8q8EmuBy_zGp)hjhUs/(\}6 *$#I#ސ=_#+N_.[%g=а =6hK[֙Dwni0Dk;f`=ħḠN'F8j*'*`mG#nbQ쵗Q&'}n益SvwJȻ"C&wM^"˻Ʈ{^z_Ɯ2'&"dBq"-zx`|iU,8YC۱0O9[KJM(sW ;g`o2x>OmZe~N:q.z@4Bkm" l@V0D} Vee~nv`Q:NqCD  0 '|Xu'hNQ" E8E{EG^^ox0bd34f*Ó9x9n%w9wcksh1( D2AK* YҖ.-" taD =3L%N믑iBۀ+Ax|",t!1P.N/z8Qp5u>xgX){*`cl \Zt>]ǎVW@偯=/21B@zrUhFT %XxLȔQwMA7\Ko( :.e2i- TD74ׄLPC^؟@l<ռ،#&o4@P,.>W1_d*Yګt:$%+{ &!2L&cYld3ͦXYylFfӗ%1)ś "$H GP}m,!FzAFg!QSLJFWN~b@ ǰpW$M rk%ꬄ7UBO%Ě)p'* 8irFխDPo& O8sNLYa2l*+3 )?W  ]Ryq3]͓ףBp L6N1]Ҕ eT1(̰8hi)=hAL>{qQ#eAbR/bݣ梍 Mz&$AΥqgቲC7ay""j0_8`o`OF*JD^u&Djw0FX#yU-Ee$ _bC_.I^vK`o-2 ق8DqF۷zD]xE=+/~L9V|./IXlFGihlƎ$VhIͩ1A쉨B&UηÎ#9j#h{\Ue@P r@P0[zrjJNWkՠ-e0Cxo|]UllrSeڴijZoa:=KRtԇ;߻7P8Gx"7~,ƥrX#,[C]`#2w/A.{z43AGj|<LM]%ld͗SDͣlYEA])k%)p>s 'A炊u-3ෲNfOųϕ蔛uŸ| P`H,߆Pb Wp[,7u?[e8ڥ[CO00GM " P.L!.U+bt.}K0gF-x(b"ЈX! l9@xz3`S|`EKV.u d_dkɓ%#%l̋"urc63M-킷C%B`Vn nkVE׈LX3}zb-% -%j*p6MB*O5hZOe GCwzUg{3DSmSΦp{ *G Ea4v;.z\Sݲ7ת a5XUC vݰ]Qlq[rts}娟&]uXdX@U!EUE T:\H`X3Y_Jr=DO#L!сL* @C]]O%@s%9:F&ܦ9o"LT8\PzfYrupsZýZ@Ch|9v8 ,5?fJ(FIX ;_ j_[/n-k}yխ t%,="jw X`գ8?sSwR"0Șh/ٟm>v&aRP - ,VR [ʿWb]%{Puq 9_Q^6݉,5w!,0A aVZFj >QcVRVQZJE㏗/sě`deTgCYHq0HDmUCZIȈ'Wʛߙ>/R=LXk2-|d %ٟ|GK򠓨*90-AyK"TiZow n.1Jƿ>xs|W}^7y N-{w_Ӝ8~t ((s9}T;"aMQ : ^O w; =Y) p~ p/h y_B700mo#) (&j\(-Ed?~!̑tX-qf(Bern~^Y 37<3E{rK 1`lCb!`Z51bdvצ?N fayfkd 9=CP :cԯ5)NB])OB;RpkzwlI~&;1>чG$>Q-]+mj#x:d!NW[,5Q[8͆cx?C1x/ "|>OY^Xn|0DWc TY?G2(e/U²!\`BCPQx/MCP8(،Fo a#QuΉ%A] Vɗ"z9t䯜rIRS80g[ /)믾9X1,^~~{7V33ƾpJK|MzqPxoau4"y!7U̜A0"nnKV+oru:tvP璜39,<L`̴e5V 0Ye»6 ByIMsC #{ J߿t ]&fݪX3;ܬЅK|#tN'; _/{?4kH-F7 VSe]I'tw SrYǪ}} fxg.2fʞȲS \"7z(V'p:"0xt ^p3{&S@ӽMl+jjT&@'UTvTa\y.2ݷ 1wz]4*gK-,iKBH.g2gF7-Q= SU ݭl@ G<<6|65:F`NC6#7;.Uffa,/WzHu/g&_bYbB pn'w7{aq Ko@V XT%7V3ju~d"2渎e/]љ*8!;ѝ@y/v?)F GMnS-ob{?ZR2pZ9Ze[v}t*NY{sBaYP.xxa>fAy3 g4_f8] P(uh^9K1̔{O 3c#$. }O~Etn]~|X99Č @sD^^Bm^AnW5>f4"Vg?ك! MK'Hұϣ>=S uy=̴9Ox"םEA?PT4PZV` ~^UANCʧPp79Aa$%WwL7À6hD$J`H1# Zíq(z^OqϰGNXa<RkZ3wƺJM:(+k㣪:;ȼ2L2'@$LIHyE H2̄)^+X[~Ƥ"h-SVת}_|[VO2|ks&+I`>kZk8{Q1)J2F'>Pq(gPKb,, \[}LNђ-~F=CU9O틟RC}≽8[%N>BQ@o9[A^mf_s]uWB 6< ,ȃ]FynGdYUpˋ Z)bKqn,) vX))V[Xǭ\bU RdXe⌜$GN)pc̊j.xUS/#cRS]E*IzsJdߗ_@LQJJ^cʚjř`Jv "d)@PRM9r5k}Bvkk\gqWPA)s8\ɍl@w't9:k5Րg5ޚͬα5x/^nx2EegkG/%uJ{LSsv5{=9F ]t!\щK۩]QKa:B2U*]fjhdrup՜jڐycjMޥWk? 7~-9tQ/n/Lzs*sĴ$>s@qIk`O-f K>h}fPi蛝lLO Z!Y{lJ=4-h-Io2MMM7f[}u{66v6^aT㺟l=l.߷'׃Jيngl~~NG=ۤqu9&Ss4 -hq.>gs|awxMZm12s&6& Glw w1.PY_rV Kuщ{w2`V\HHz}#kd =)dC4BU:\v^>36&ߦAK*Nt{zl^-MMjk3}p蓹[x"!xu_럄9lŗ5k}s l0 v͌=F NFYSݲuN3 AQhjօaAl%$fO8bXp#DM`'L޵|&#ca|5ù9,Q9P J-n՝qAn}Vřx"fէUiN>a?:ړz~QnlUX]bѱ`D?X/n_Pdmb=(lN?99uLv.V< Wɹj9xɔ_%0+`&'Z_V^ƃnlz/NS^fS]t{zV SI6X쭫Jؿ=`<}NpQ:~_>1E+tWyV&c]fa ~=jjPE-'@͆£tĆY`l*5? ,窜sx 7;L|鶣iӎsڣ;TQ۾qJbF=ϭ>Ɓ;8X[Ǽ-i׸KO0]Q  Mքy_;{Uq۾rU[[=]W#4z6?~vqzFr}R!C/YmAR|p}sF[!;v:Xat;8ّtpf;:td^p 9:qܡ8x.r926vdVoqef-9d)o))#F@MaqTS6@f^q"W&|`!MLHf٥+Fcm`-##:?kx@5XFj5ה([se2j?C'Mdm&[yMqZqa1TM|R]T1[#d@N=1dU&d 3¡r6E11H(`-Ď󵴥`deoYWZ6Ul/+մnF (~~W"mz[<%MYZ64|{*R5mD,́֞k<;=/^0מ~t&q2r.T-HcH}=T~{ | {̰Y 8J1պ]:ךlLQkwU|@#pra@ ?`ؕ,H&C*Amsw& x8tKإdd(NzBFC+ W-\S.`9L7$;Q0!Y(B>x&o/l#oWo:{<~+d<)H=pIx6^Čv t`̛֧۬COgq2Qpz#cV=ɐ:aI{ZM1  \NJƔԭe?;g g$KgO\=;b2&ؽ뮆Z]z.bUZE~)Q`'oݚx?M7q[Vy# L9q CW&y|11X8 ^"Ve?P;+>`cI`K=)dž36P[YN_z,:!ʆfI*u8kF]Ao&gS1"BSB)ӻFqbtd=cRs՚Gm͔ϫZ^LӺ^>bv%Qk~ZVbA^{J+>w` ݪF%ϫ5r9c8SRSz[63< *o[>skn(@}IINv;m2V&[ xr|5(ՠz St=Ŋb䴣fpոo.6CHÁjEK xa ǽ4ŤC/]e关 +*R<W<` С3 )pŸMw+NRz7~f g f7Ns+;lՙx:#k=q,6V%~g'./Ofr|5q4%Yz C"t$$ôS;nMC^?n.^u$ȌtY5#)8^_'ƢfkXUo=_oj(TV ⇝w߲oiP_vkF h$;3NLڄZ n{lƶn0Mhm%z\/dBB–]ȯ|k1ʔj vЛ*}Y{۲}HJ!4ɵKT9:7'uG7q+rJ+zQ[A2 oꄊ]ߩv 0UE*vDU2SZz XF-ŋ;\C.=1Z_IttK39ɛEurn%0].-.>GU0Z6i8Gbjt"$Y"+_7NTL=IsZӅ 'e 瞬EȒIlX5oDʷێ_5k)sP@&}:3`CsqrܞyO#+?~%]u⇌Y𥳐{P^Ull)٩*${*t[J`i0݅FwOfN'nM?M3,vJRCS{°Οa0t:Zбk6WtR+J] G54#Ds_zk|-`+*WyLS[Zw绶OKb g W]|I ?oi&3h"j[k㟝e+w>xO nܤ%%o7VP̥|2y\8[vL4bfd0J6_9:9xw<- >-NI(|JQ@LNKhTZ9ðwTLH2:xVyg2䫙%A2~E-d' WZjn5nA]4z[}8v`dexN)|.A ۂt'i^/Gf*|&fw#{s8g7hߌ$q&w6-5t5soseq1oANf05iJ,Jaسj\͹RVK$Qo(M--%gRʮ.*+%Ap4+-ѲQ>9l]:+.xٓP\7YzY;$8>=#.%N_uMF)˚ZgnOȇ)O5M; ?tt4vo_A)2ʾBm_;!9NҠVU:Zm¹\ҺrGx*Ywh!xdܛ|2#g~YxV9p^.gx39AS=dl5< '6rPcrcerUKWlCx z ?"6QK֧L&V1aGOH N%6R2?@H ס۠ 8rҁE?㳙&a_r+S0=񍗲3L.rm.wBy_RVWMJ aNϪ1~NhLr!߰p_. smf lc3˘(^ziQdr)_ЂK{sYAߦ/{ǭ%gdw"a/ V׻?P{?W)wO1S^W|&%⪐CSH[ rJfΔ ӁJ3kI1rgW.C6Sa+y7^1`ZeV`5x&EG^]2*ҙ21,`G2IE}l#knB-zJޛY°C(l `b qQy㓝X&>[z 5ϓL eWò|[(W}~I{O4hYZ~g;z>Qc/ d<랬Ϲ9P59BOсߗJ㺿eXVqYc˳sVnM!(³&_ytE**ӍE]3H]'Hq Zy H9|0$y^fBO FzůI0[ ~I#~X~*/K0 Q8@q F(eN)yW?RI] F|9D\K$us \{$㺃Ťp=)|VROHgr`L/%I!K0Io0K -c1!&̌0&lbF Lvb `R=3# hXFF#Xf>CL7`L>ħYȔk?fPwraC1;iZD\?=inU;('~ (0 1)Ԃ`m´DE'5P/}ORMꦔD%*ӹôf1JwK׸H2y]AQ̷ 嗟rY$q#K_sTļs~jLa ?L?%3%TF2JJ2.,K!՛(%Q;6}\P=U{ZoK>2l{ >?D_P)ފOڲ NFS xvp i brD R1͉Zo4uPҗ*p%Ѫ JH>-%F$$GД]dHilLR6BQD(UjrMղaZAg Tz$rwuJiLz/1$qh-Em#v9H)&~j㧹ODd6$ʢYTiSoU Rlt2O~c:F}D= Q]mydֳjT7S|JG3uGlDn[ԣѷuöb}=X)[cĚ7 烒D2F$m I9LgюDui-hR$/~dbe=Ja7dޓ21I؛٭,A&E%eHQhpbiʦv&!"i8 ұNjI, FFZ>Z~Q 9EPJ*T]kࢾDKyKZ>wͲbvN% 9L5O´w/5H@S-h"o܄E78k$5*f IM Hi9OkŴ]HlmQAz TIePGQAbd8=)"rOLIq&(y#m .^?-uxV %-z6!|2i0ZFMC%Y҈`NsVhڠnɞu饺3pIehZ$|VsaYKnAzC$:%acEu~WGE̅c~҂v̡Tc)x_A2^"٭^v%$H@4 myƉ=QE%.z"cD-h]NsTF/ R5ݮHHj_!: QCǮm &4?,{ںM@~"3)KR'u$+1g"exxJSONxgבڮXm G"M}1SSVQE=Ee=5Bk l D-hw_p00(4-,ZHTȶ@O`?"C=aO3"ǿ? b$ z9Q?bH>Bp B_AqaA0:1 #@cX=8GF`LXрPV$*ʅf8$, D#%BG( ƒ{b%H( Bp('("疋[\i\(T) S!]ae  e% Br/ٱ)" kO`ry콈%틖.\ݱuA{;bR kދzXp[@ $) _ `w v(=hpӠZ{J>T aI=áHO~TEc0܈0D+з5&ևJ$MNPT$tDBhqE5=084==A"fX?@ 1TjR݈p%?E%٩V^G¨C1\aǶAl NРw #aE8$4v$ro!qjpi됿?(60raQ:~ eD0!2Vn("eLPz`XR"ҌcDF CIb_P2BBkME!u {юC=n5eZ7ЦhI_,uKzDKz3+B:B"p߈KAoj3@I%eAfr8 `~Jh6)7()*  MȔ S%ʐD=(sajݠ!j1bA!?yC#J8MbHhaas5+߽e(ffKji]ՈJ"8{#KhTjhXQO cB Q -BAgRxhnv jի%9_@ #ӌFDEhGGTnh` å+!{"CA"/{( wKgXשQz a7U7*@/N SU#]2F ɍ_؆vPIH+d,Ki9 sĘ!"w*/'"-L\N ==͝7 g+|g+|g+|g+|gKڐ8gV9'HGSŹJmrr'p[w W,Lyh1*\+)t9yEV./߅9Wz?rY\*L^^g|_| 6s9\2_?:9r|1&3&3mLNd-.W(/Z<#0KۼL'@=p(E@򉴴&3C>$?9 *r}Úx5ޚv;z?_m 1aeКزs-|y ep4b?ppt -M1 b3pl'}Ѿ}}G>CB430 偾ԨuǼ IXs sZ$N[lRͤ1Nf'MO-p3QNĿy2Pe  vb؏a1r&10p=ƥ0l.u O0&2iINBքy&y[h’900Dɴt)}^1/0:#<96L6t!LAQ2ax 'cQ^ хzB0aP„59L/"#e'$K-SJ'O,fƫ&[[⵩Y64׺:hSBW!%U b\aXOS>4}_d2n6L 4i;pBp/d~G&~C&HaMW7C.'&rLtvb=ƻ:߸y]Λv:w߼+y]ޅzy1Il+?Fra`auLp!JHs~ ,Ύ|Xן"9&2ʐcwOdc@QEU܋0X:16InD[U%5S ,`|@ҞmqЎ 48S h(1>Bul2ӁŎ1:cV{Fx_Vnh&rL|h")1a؀0#d47jjjVմ&u;Pw 0-,T`ZZA@H/< rdҸ Kم`2B.(Hu M(u*@P A$`<℩;҄ɂDwȲ~ F Sx옘Ӽ|@hJ5X5X| Ao_5ۇ"7Zlc:~wwOһ Np݇1wSbǛ:7͛3G6a9rxNBO9s@Zwr H-|dO{rݜܻ'Ϲ7:ouٝ:waFG?e]ccǸ14|c$OAփ҃&Qyv`b*d}g'v@6b0އ0q <|Csƶ{l]oL6^W^ok)man/D n@ڀzqO0JߩE /'tK׍@ӅdicGRTgXAɬ}nQ=cS+ѝ.V2 ;1pȣu ɝV#:ԧue\ZX,J’TnQYeaJ,y|B}Q>+[p^oHNJTjM\LsYNؤvb#a8eI/swcC~=Z®UN!Ek-$߲v,zÏ !$,(wNB ^L'a^0g.wՕ;NSdjʝLDJ2Ƴڛ}ܷ|#jaIsGXh0nlc:Mm'a¶qUU|c5{wdbfJ="öŒmWX53}x9vv)Ech\q[[ǪS d§4Nq 5|f-?^`YEҲW fwPX8^7D!BLFŌL*G|LnQt &:Kk_h>Rllhh"Nvު@9$1i4 ><"bX6]6X;nƛgƍ7Iͅw endstream endobj 1043 0 obj 30951 endobj 1044 0 obj <> endobj 1045 0 obj <> stream x]O0| c`W"eC~N"o_yn+a~3fo/yla1~ps)\!t}'o͔1-zjmiӍ)˿]b~lx_zmpy>7ӗrz>tq_11p6p ٪(f߯0t)tn6sh-үvk-+ _Kz_Q t/YBa]z e]ѣU3{Զ:e/ԓЉy,5ZW//+h`_ MJ=ޠ/Œ{_v7ЉuQ#_4'=rp:{%Oٹ.~! ߣF!SM~~;ߣ^IGz.8GIGBR_F!YKC~~O~ălQ͓F=E<k].?cm<ǑKDgS=3 endstream endobj 1046 0 obj <> endobj 1047 0 obj <> stream x}y|Tٷ7̛Lɾ 0A5MB2(dVuAqZok-Ze.*VkVkmKմVMw}oX{Ͻs=Gؘ@zH׳5#->n8V\Is׮uQ6BU~]çj'GPֺ CX9{;ڟ|~iSF /oH5t1A(wpg#.HP0|GS(UjV7MbNۓp@e@c BV~b+ۈ@h> %Y U,5 4c|ӈDEV!A)7t@_\#pjߕ^[S/XdH_3ZdBȌ a,>s߅Q_ζK}+Ry8zk=xԌ.hE!3h q3=:Ԇ橉+R"s`Ǹ6J=el\nDw?OBX t-z~lÛL?&;̾Ⱦ#7Fv0gh|S¬dvqn1WߜQԃߣz݆DXx.3l PIUsW}MuKao~  q|ԫH MP%΅C-z &" 3Q0 ̝MArfN@_s`5SFݍ's07+\@F܊}~;v%C'Os= *A8jBvt9݇Fu h1~5ߎ_? NGOMﰏ/:SR!6\ ޯ@7Н/1EE^qX50ZFmkq _'_?Q2/5~ 32A&d3lf>S,bf5$K712ece3y,Uv6l[.`Mb[]A\'s{Sq{J^Oe zM)~㛁A\Lz?FfO0c%>Q ?/T8͔#C57a^)Dxb!.$RpbP ~ m{ЃRԁ"( 2_CeQ+5mçO%jT7३-b@QhsǶG ڒ5I mM)fi)Nbb^BUB}HHXF5|C]YHQx)l1@&Bk]mB}aӺmu߈N[Mh ЈV371g 0'TWtl3@ k;Bk(T4E( $IF&A #Gv^?ʣ5m}g$L0G`ܺs T:6^wu $s!yyMk$nn>-nhC_O*铥HJIIBR yqlggSǑ^ $3Bu#6snQpϬ),5G&: Qt-Y1INLfZ l:IS2Dhgl@O3VN؆m'?IE ;?Bf%0" aI4D/T04_YXiN MЬyN1< zݨ@&&)/5XiN2mHƾlOL6o >Bs{R=3k9ITdehy4 ;d.igOPZf02d8Idi'0;GUj`EZ$߶Hl4T3y933„lfI;wjgN 000 q``TWE)0V5̈́|Ջ^hD>%uMI ᤆsn蟯R&|CzX򦶌frdȏTRHiWF:ORpx5C:Rٴfc~‚@BBv~PBIh9;#hMڈ8l f`(2f p۲KpEQL dp )45LdήUM/elUx~vU$' 9aqZDcuC *Ew`nG粕bHSFG_)g3<!#Q/,ry L\c'">fbX$V/6.v-XT߁6eehvM_dĎ:Q2[+MV+kMA(fWC!m0 D5U*b|ŢQme5h%UŋW/^Р[_'(ٲl4|NtЗG|s<)+FMlr5%5*Sp:x~U]jriGs4uD0kbż XR3Sp899(s4Z>A|/oMtTDuNgYT{W#W$WE"e[To?xHX5$c1~|j(r9̎"WDMRFApTͳĊ][3hFI˗*: WWFLmcAS*PHnoT]$ (B Փ~qYmMBx)A9͗J9T -"$-:~[0$SY-/s8$T,M5ZY _X̮[ec|o=g ^[0p \,ixa-znnNa 6?[if`C}C}b5o͕2s֎foYŌ.)km> ~Ġ7Ss0Lśczrʯ4XW&Lu;[502?{}ёXg6EfIy[Wp][2~n}6Ӑ(8R\gue'\gT*KZii_*'g_gs2ұej```%I%0?B)L\[ :5~QK?2%nEM12v辗]{鮉wnzg;FÁ_{6}w]3qzwK7ݎ^Ww@F X̤Vքtvl oDǐZg :{1i+s[] w:۴WߥgA_%TtkZU9;{f=8:l8l|"p(3e[Vj:CV0 ?_06Y6'lgQ lrh4>l#@?}ebs/z{vMkfhZnb?4VSiiiIar`'.br@1'q`O0H-7Z"`)l8SHb`:8z[llqGitCW/F]UZi{\[d4F2~ Ƀu۟ξL{00.]>2};n G~|~z˓mw[8i iQ) ")1I$# ^3[Ϲ/f, ^EH#jNVxf`sm+뽛t}198g)V]V C%Qq_+}q_ou)l hu`I0~'NQ!0nWUl}|$d 4D S)`7qmzn4-N8{}0(ՁĀ-Mfzr8Ҍ[8-/Β%G>C9i4Xn};/n/n?y&—ޣ.w* ;V? tg@Wq[DC"3M3Nn1t 7xBN-50s:GD'>8nɻ?2Jb Ť- H!  }CEb|;'Ifvrq=qpvw3ļ_be\ T KCS()-g AT* B:/Th GOW2ʺh$ BGhnaڑw1.ϬܣY] =++jtxHSX 2ftQ1P[ 2[jBPT;0#; |ɡIqOH1O鉴"ʟ?XD5,*2y.Z(FɫJ?$/HM9ը5x'f+:Z9i0ZmZ]TTF+ǮAX*tJe[ brB~ erg; P8dbw=GJ%b6:rp$?'+o9*~̿(0)d2[,`kUS&΄;@ԺH[ݥeA`?/#,)^y`"pTNj#1CEe<6um mU'S^4s1euoPS -ܠj]}ξV [om\mur?Y}qk7vb5h -qQ`i2Fw,7whfjt 3i풻lc궩TA 8_^<.b,w-{z%xvw}y]Q#ˏ]I?-gLX8ga}mПQg/_*@.:kEMX |28iIpkP\mkڑ?Tsj Oڜ#s-ϋU\,ݱը /-s75(ιJ!rōQAGm~9ON:'_bvQ! r614# E6JyZ6D+%5JWN\1\thT.ʩ 52/:}$Z$b~>(rڇr'Yw i9A&gRJY.ʊ"xryJ{O㒅Pnn;WuWfʆ򥜻g6֜嫯b#^U1KoVYѠoϹ,Oo4C>ՠb؍ ً#y RƏq_!-i8FcQW;}}xv*Tn:w^s=\[rٟu_} śG:7?}/2/Z>l> ĸVF>zqyϼjjשK_3MF|>f013JEW <>j4s`anM8 ~In9~1(2mD; S?AIcIvy"-3lJQ92/pl\nla-KVILRNQ6 i03 q]Qb#K/rCs3z:zn,Uu|gyЄXFfn~,VvMޝ_w < D, 0g@WBǵ&-WC0j S VfuN<5gWEgvfpP1_ċ[w/ݳ66MgPD-=B޴{j%rC)oKyK7)ȊfEZT~/D3A]SyAdxݖW^MFm[,q_o5tf=>QiTJk?blf~Nwr[K v`)ְkPDVM'I’'.%$V)rb9ދπ;K.˼vit].Cˤhf ѫD#H_7FЯZe wҳ/gr` #$xl8Hfz>%g'魰<x{-bffE%nec,C[K>q. &PNm3~[U*vL*0T<ͣ2@KZ8TԻ#@=q1O\jt^wOzZPE Vl|dʖ'yv3;vv pi\lM9;T -mP\0Tܭ퐥]^}[q cbVC ۅf/4\6fޠըeid56Z |cCȃGZgfs 7Tqx&kJTv=]9ƅZcV&jry8jA]B'AyH!qOze$oP2nZ5r<[HJ>~<?2鎝҄? 팽 ՃWq*nY_ R_OC=,d1D`wKG,`}&jqt;iYY(zU^},>$AȄM`XJku -K,_7l\gyN&e[F?ʒ5rIkS.FpV(}-Ya2*j #ʲvY|SxF6T q^TX)D,[9CZ><Ġr#m34oUoT$?{lsc4zZ~-y~b@]՛2]:77dڄ %y^mEm[5X*Ň,Gx0n[njAVsYHAA47_*N%C'sׂ_-PtRApGQO`;Z'k걆Qǐ%zC^YNAt/4_8jaz'Yv!/RjXZ⑔N39i1u/If@Té#@#(z/D@TH&e?OӼ)\9faH#@ #& TA$2((|Y]e k!֫;)abZ )/穇W6`Umhel, )O_YDre (B3}a% ,3\#gO'6r⯙6QM|LWwf2z;NRuEd=JEJ.m9t2tp&}[N8Q|DZdڈgKVZEBTnfN>DpFgRe22*=_դ=:ꖚ*.B"щ g۠[+YHSd(#SY\dƳ!0a>Þֹٖ:8+䅜V܋9G{An7~ꖧO@"H{c.MLn5yWW-eSyvZ"ُkӮD& kQ``δ6{՗QW2VLdR]KM,GO83"1C}zTiډ.x'RXܠ0rk=|w1:Ϻe̟YCxu3x/aF ú),!/sR9X>oCnw=a|.Ű.7"opZy`F<mq2n+aG WxDw%m4s}j,z+1\5Isb'ְW`7$$hBP(v+Q$j!2PW#uN78䒪m Gf7{\R=}Anu\Oz^\5V}ԉ4NVߨCQߢ-j"YxJ/KX Rq=ЏZiO0 I?AGp $~NM t@DBE<AvDnysMAMKE/ dL$rhtDH<dhL۵4y[Qt!'ZṕZ*3O=始Pay\CK8Թ{/&ɥ[!3't۪9e_17'r?a0*ϊ}ZX^a;w$~RX§Ԡ<^X ¢s}wMJtCo[5wED>{4w~/曓wU dw3>I8A/[^%" _Tgz}a,9;Atz˴yJڦbTTSn@q Oyyjo׻ͻ˻ǫ y^wˏ⪑z5KDIH5! QVl nyFz(I@QaP']mcVKmiGl! SQb^>\#̨jC:KBZM N BadgI^a  s |ZKb2kh<ˁq? / I)0OU1jcwHO;y,:EX6T p?gl49O'|Voa`.}5aV݅~uOJi~תf2gYe2JM } lQ! |!q!mIA)JHd cзٿWFuf*hM閜- o}į.=RH eJ_("xy ėENaD^n)t.b6E]y Ob^]{a65}[&v׾M׶>Rk/|wm:y~X [jB)1ȿGZEoc\h^ImBסJt1k@}Boh{;fe?W(Tf Noݸ; Qakn|G<ה#8RSE,-m /g,m9Ea s( _# 0N~(J8%Ȱ }E(E5(9$ZVuh=wJK&#ge؈.o6oe#a 3HihaUdCÝ2@zeXQVeXFA5h,a-6ȰEM'Pj6ʰY0 dC`XA70)JB^[NI[VrFf-&ðY2 2 koahk ߒa_ :rd :N0$ðBu!ð (%4 dhRX@ s z+dCoQ2!!4y2LXO^J>OdKyd}EO~̧Qڭe:C PCHi]-yHb|Hm] bJrU4wuM;0 71me(gd1bCqz(Y 1᥅ Ổ6"@N}73nt$INu˲y#Lx4Y(=6P|i&K/Ao-[K{ILrfyu%hk&TNQnyfiyP)]/IgIɠڕb% ֯Vt]74(H &6%:k{7t'eC;}ϙV#HUs6%PeE!wiw@`oPޙOÔkrByFq3} ' $v%BwБj'iƞ!jh!Pw@{ߺ͋z:%`h>( ux:(z5K jm !tk6 :{ZJj LOt: ) , ww/: tahoO,c8ACh׷]tt$UPذq}Pb{7m3H 5~zd:{;6nH QS\<<<\A&]QGuCo"Ժx`kDp4A,7.nX\qq|o]\[le` Zq] ] / >o&9K ܼq0AvhsFҲw咍=@#j ]KzځDHhf7%5gL8QBHtCgBglB@y& MPaj |;нft $[?mA9ILbq7aM7YL Mo]$Y5ɇ]Kttwwr3ݳm&||2@eD)N CgR[: 1$34 Z@(rgWf.,()hV-’Ҋ gfE+c1, #ӣ̪Sgsĺ涠/l3i=|q gɗ>=dGΆ?+Wï_9r~8q+Wï_9vGtKr/cqMNk^«An^G!>A܄?Y?_8FN'ŬXHGc0ai: (P6pjՆՆ٫ e ̸7CRiM H3oؿ["yZ${GÏO.|%E޵H&R"WUh*4v?(rbT_S펩vR.RSQVv *ڢF^UJ5fHM!/ڔ> endobj 1050 0 obj <> stream x]Mn0Ft7BJHXG=R1! n_'m.@|qZ5ƚ9}jaf4޼v L5G%iȶ4~,$} k:I5xclQaޜ̲,>Թn4֍f^!W8`"9Q:WH,+YQeV["^}v>Pe ,k yKCWydk$sG=| Α Ww'9"rM|3br''%f9GdeL/24>a׌{F|ª endstream endobj 1051 0 obj <> endobj 1052 0 obj <> stream xܽw`8<^o5IWt'Nݺum ,w *0-0@l)!$@\@́`%{fvOÛigy<{Z GEⲳk+W–e />S"be荒uui4p^5\vBtK͈Њ5GPq/Pgnˆ/0_5=˖t=w LK>kKʁK^є6M BG{{YEmz_kPa@%)3,PNo0xj;.[R`(Wde _>&.E> y{~!mhO>JA|oC*즵7 m@ХE)=*G'-JW;@ir%L)G E}-}<|)==64]~N~HDgэnl;Hp}8 _%pIh- ĕ\7G+ =?\:,00Ep *A(NCHO\H!6?&CO]oDAi .@y\^)TqO3N5_H\h\}ZVԏ#0/qg4f\<]VR$ 5cXijIaGG K(;P<&XA#V| ߃LD%24 zk킫?;a58w9ssa;Sً})ܯ W-`糏Ooopn6 0+'_c>rgW PRQx\߀r(x9hbfVa>RqGl| f*!G|^[: 2Q&#>Y\<<vE7/Y;Z5xZTZG!rXq*Ur2en_V:t|ۇOE2Zi@h=Q 7pm@gs*t2F]֡D?e^ y=GeҀ緢axPc ^ tkOgq+URp"z8Ͼfu7fwUXS6+t873df zVu}eJ*+)f)*U p+L -%gu@ӳ^[ 8Yr7ߘϘb3{K1 ^,Q(L*|hwo8?w<8}/pnaQ@oͅI&xzͰ.]NdfbQ4 3߅;u\X(P26^XX+ H &!tH#{6J,0@ ZOG;Α;n*R>*fgr';c\ˤƆl*L&ⱊh$ qj1&Aj*c݁h  ͜$X2{0U' tf-Eh;-E8fԜLZC}B!ą0-l sQZ0@A@iAh~tک+ڦh݆-qՠ'4uF0FZ,8qa4 t&xA2h&h*͠rꠊ&<.-wCZ&2{td])>yVZIMAMhJ茍gvÂx6y=qW 6_sPi%lh vŀ{dbofs$zx`9 5ot:1Q `0,#Y'ɊzqY=4O'2L7zr"‡"Xk5D`<>PM1r68opYgc \Ȫ^7$P8qTHL;nrfo}93P<3zyww'5\蟉wX[hĎ BN\0к[Y'dh:u!ed,`iIa~b!PA{vj?hp\Ea6'&' OsQfE7j'}N|PD+ A#x`bMI 1,ͮé̓@+I/M S{dqaXsäaL!7T#f ;"f23e4% :nd|9# cH X%ȟ"`᠒N@ب<_Fz I?$}6d"P ?!H2lΡBpU:Lw$@No04xRp m(ٸqz(0}c%CڸuE"*;8N3p#0 MלMלh.5n]}jma8pW!2 %4 $lgw= Z^6S0Z6Hu=h0ݰ|Aǣ*ޥF1!͌ںƦfn]ODMԈZQ'EhM"/5uEf7s'mUb/W&(5T+M\J5fR$KM-NLRT* I;Ce&;Ydces.WjuAtr q%<-0H*hZŸvx3L,,[0102[R]xy8}]qׅJXJ& +Q+T;5FjQ UJ%T8jtjkĦκZ}K-*ʒ ɰ5{]p"q͞oX\iYuڷe߽+s*Ki:2PYـ+õk}UO0]-uē<(qlc~zim+E:8pSLk!4kݾ6Am1Y<!1=d$;Ҁ$Ei͝F.*괺CݭU+74[SDs !-tBܱ!]L#. \n0]ŸbHMLp…u wVQ DgX1&B @8_vꋃ m6$E Hx'Z@ 2S^CA, 2Ԙe`/uI|!~:tš5W* _:pۄJoӟ`oi1k-ןz|b'/c˽z3ύYT]gܧx@sMJ Y3-JWyN1 D-B< מd8OazլzԔy PN|ȤA&g!}ݐo\:܅HB0CΡʔT]tE~ k ] f,uvS|e_p5}~ɲz@>;bP4Zsc\]:0=>5)(QMJ<=PĠAtv&ZEhK,KE~"Eyvb[HBwG\MO̽Ma&=zRΗl`JUGClX[ma4L,.hmLD6 1fP1Q5"%r#fď `uT"(2E[fךeָ)CuGwlٺls|[_V5Bn;gi>AaF.#Q7c1:564"3/ZtL"hs۽V3d!hݘ}_SI4_&o*|J ,N T'٘+Qr\bRlF"`lQ?|)Zh 6_ٚW2z` G^ۡeD퀖 xn'61YOU=p:), X48ND1WTire冉2brL'(ȬuAA뗨4Ј u9s;ͷK }/B4:@c$f̈́Auf(HQDZ2 9)fwpӮ zcn87$K{Oi-]Q虗VU64UzNoS~)z\K-Bc5An8C1YR0V>~A_z5Чcǔ!LC=a7->W,Fhlw:@)D"CAMrA!OWSTu*|L(zo6$PHD#xqPmu`Gu\f(>=37zՏi|S  q21uyGrhN՗2]$ 6C g)%D.6lm}zqfLgg5O<'nqxײ _6nWagXEn(} Ù@(C!y9PV,g~|[߶Sۧ0GV9CXVV_zпܺRY>&Dk̨fԯàacP>rT ,E߀þ!HrH(65zЀ'B! C Jvt9ϊ g rfke#mk$! wb7>Bf,Q? c>-3찕K9 ! ͷy؈@$e7LMZgΟ$4Txs;T}Cp(@F vj*UcO~~]s|˛οs_򇚙GWq{ޱ֘(/LŎWcšOX~SNYQl2 /jz\D$BânL:LI]), $g LQ3J5{Xį!ad#J-Yאt(?Lzug!Fe"S~((J(菌B:XI `du _A m~=(+Em" LxUtq.jg;Kz?K_[$GD0BhʁO3.'4j5 @ID,(.-(\rOfsē",dT;@ ͠ h7{y6@ YQX~:;4BhXz*|@)qD hi8,se?]PgȄʀAY‡_4Ÿ?*7n7\u}ycTRG?_|nӾ \ 8T3p̳bVcQfGvem_T|-͛ڷ>|RuDuʬ*J-OצfTLOÄ{ɄY"VPKtLPPg~a$rӉk \{k{"p{<O{Ykۖ{KpzX855]vѫT:[J~xGTGy𗬬LMQwJ2"~o|_HvC|bGAf yޤu:@=|LBCj԰& x|OGce@ S8宝|iF]E<9⃡9}0 3",b$h]*=P/u[ꯞSfW{er8uuV?kϥ]stoM+FWLu0IM߄"X[an=-y;VR9^J}mrDV~Dz=GB9U5Nf-,Ȅ'Am rY'kd".v .iF,{8>Ul<{C &c93Λ!yz:D]lr}P7B""ywH[t%E.7eVLp/%җ,8F/]r6n&u̞q'xUT=)9G`egʲ=Gqp,Сd,ϟ?pQ*Z-䘹 fN{h06X W@zjmaNَsdLv{uX 4un,)Zaea1xxE#6sM=Bt`¢ʔ,Nd8].x"#XC)AAL`L-2N_[= dGKGyk.2Gz IiDeF@W*wDfDpo<'"`D.nt388G-ʛ+ys\iVwyOk*̼&lxϙg>$\8kze?llg4UF܌uDXo췼m+WS'#66;"Eu/AA{|@ "  )ɢO&zV8ԛ8cs;ڍLsZvKe 99`o#K}+"ĘH1#Or\n~yU FF DQ71#ڄkxZd|.6X_rP`w%Yݘ1>y' gH%5Y]XƼl7wŰpd;kn/!_^$b!wD;lv8P4:ļ#j6(X'-fbAFN=Y,p2eV fȂlԆ<VFcgWZjHaֱywEAD :#لfP"T^]ZdC%My rvueKEJ\cB1$jJ% vȉKnKp9`ن //gJ$ B H3rXr q 躨o$7nCr:05gsZX.{,rn9ԐK:29nU.X-rnΰRܦ..,.K[rP5X6VT!?H}C}O{.;:Nps϶j|_6 7 OU/ dC ܡW" U<&mU~Ix!c!]Wo$<[ٖkCr3H-`k~&{G{ŔV6*#u~?=ދQHX ИdS2)%^J|z8ask^vXoԪRkh֯B^1=1<~~.{M+m}UJ_8@uBeFK2#$asЏqOɿYcWN;l=R68kw|ffѿU ~rBD8&.O qyZ^hj[3n"Nu{Kb|O2'#xddG^:V h '5qP,U$'8YOUM(elĪO&Ʋg78]lii. F ӫĜ-UD"qy>K*թݚ_&*#ɩ,!vsG vZEāP|K ucۖzFOƬS KRوtmжvvئ塒T 6wr781)RTo.sC |(G`iemC1t6cU ~%UTKDC $5"!EyEDTlQ >JIdWgj6^#cgשO)>v%^$IxA՛G2O$DV^X&lBv8(PU]xl 'eЉ,"=IIRAH"MȼmT2DɝFd傢U${P o#), #FQ r-ͫ^זki-3~(ɿ4B)٘#-;(2rW<5*2 )}$dj$k&̐B2eM_X,l 愹P< (Hc ut"%R1Wx䝧*HyJ4y~y"]c;T1>LdlT2(푚'![C752]qPAaD )4.|ZEw,a}=hMzH@wۭW+nn??2;+Zb/7wX}K]5OKsNg.Lv[^[kK,^^;w\wVAlu0_1a{;Ngm?+mHiBLeye}ezN-me? n, zPZ^kx/aag]X޿vBJ3E tArN^A{:Ŕ?gR_oO [9Ge^#;;2FcDFhڔv1lHCSd H~X2l=1R}1]D秏7f\YrJ|;TXU8unLȍ98E|dQMkoѷ UjbݑiI3%.r;Qj\f"A5iPrB*]iV`IΪjurGƓq3UpW'eeD5<;KCʦKY3vL!XWߐ\6r-C#.vwmϻtî TrZ6^+T.Ťȶbӗ$9A *q1&AL\Tu&qJk$M&7L]C|R l"F?B" G56+?usȑCT}?XzJ);2(EE:/-q1c7Aj"s.\ siDՍND*A$$.Y;J䔞ڥO AB[L䤉4+]O'#mb,)EZˆpTTA|u[>jg1U[.6lz1TQtd s&hzű>Ffa0H2yBO1ä k\k ^_e}"]3a 57ZԢKo)=zg;`Cr"5h;EI$vѩN 69mVEqf3gb!6b0hb3h2Ѕ-f54y?U$9@udY/n~i-XU)+>@tdYP(@mwE!0`>gqy\ޒs-L:1 LEY+RTXsi͟6ә ;Y8pShsdjODVs_{o5ZnI#¨QHȡMBޏ.cŒ}bXb4NE,yiiN>-$Zj=kBO{E)}ޮLAGeϺ\lN isp6vwٖ ŕݬ]5a> v;Pm ~LMaD4WnjxQ#IӪA{&D%-}ZH8*^ %594-F=3!Hb!},(AY>ItjD/ٍ"d/`&dޑ;Rr J~n0o(4o8 hlX0U#BRSH~a3$Im0`"yeXj[ -%UZPh`ZGJǼUoѝQ&M#`ME{y"‡X[87ÿ@wk-"LOםC/H}8I5&XD%3̊ l7s:c4EgapapؠDA49 oD[GIoѰ<щ$E a$הrŇZWpW<{gds̕qvV8{Ŋ/rTKC=Ϸ$眎 <A(zS<5k 䲬xIRG~r6NoLJp3RI˟lr[n_&,"uWLM(lsن z^VԾ:ڸި8cw~~7ԯ\b&ݣ=:NgݙIȊEkuzuЪZ NTT8p8NFWX<~icHdi)WKI#|/چ.:|[Kc#IM2wƟLj|>JRoB2YoNNθ*1?ٸ?9(x&2~f^4x[ܛl7NIl2=#˫ᘚ0Bƫgeql丠j]8ꟕ`43<7X%Iox3 zבyԳGIukRHi5>u__;57_1/k{0׸Rq3F-ZS@gԌ ~٨A;dw;E$ԕ&qd|䤳nB$u4;YvOR-ퟀPd /@Jpv}uYXkDSd겚MIhR-h5ER"OBDuTU]E^!)M븱߾/~"{ehxQnMD-SEFGFDTH@.BA.0:_*a %Ť&հ!VVle$qFQ%.c4Pk;jkyp$mִ ɲ%R7o}nuDZp q!vI8PW uU!97" ,o&8p@"C (7,?4%MkIZҴ4%MG .%WPZނ\%J9WP-GZI#I)@*'*9W9B#${ u"9Hg,oatqv94m =T??^HHYLIRh,C]K)eV$&><lj6_K:L҄BD;!~/(J&bJѲA֜(ʛr4v\ 5vQoFNEl5̬R\a=cE ;X]`\Fd_'NCT/ mh(Z18pSnrTlx–Eo<{>6?7o嬥t/SވC?[x(A&$Emm^Q:3OϜL'"e rCYָ7‹o"dǤ 8"ƈ%*u88.Q q^3AQQ) ˰Pm'KW*"Ze'o_}w+yzfiM7l=k%'d)QUE<+NH8()R\/'Ao=֞^Ŭ6tK\mܽ!~em lpkbD-Td~dfsAfq}oIBb& 1z &j#HE4WXM 2WD<Έv\|FM'hгW!تȁ^'B <^$uGBuuC0 sr͠. R x6hi[b`&D< '1y/fDiqMLY~$I wNueBfNB2VLh>4kb5  uhrxonV57˿CxџE6XPM01,+E^c%ycu5e`L9O3ķtV\{Uݏ/F0Bَo˟o2uZ?=/G ?# NH;s*|/@t2dJe9*Bՠ[`£C_G)5X/|Eԏhnh'Z mT鸛Y|>PT+(7Wߪ>Qk~a]'fEk/k=kٱQp^x˽Uiiֿ2J.8%)KsKR-Y0x@ȅa%!V2FQf kP K2>֡5!֣6(w*a#:M]A1ZeACYTm/ Wɰ ɰdXN2<&jd5eXF kX!:TkO952l`a#| #uB9QXZk s(h]Ea%+0|MVuJa-QX zdCa֐)d0cw0]a~ aX_2 kHa}0Qu"ðd׽@a}O0oZ2WWd*u 2̡`<$0~a*e2̡r .&Hi%s.-0Ÿ)l#aOPCa;ۂ)P"(A{dn2L?Aa/G2 8p)O$0[ 0Mp@h ΢pOh P8I8A 抰( B0z>a')L%| }çԋVh Zy=|tgurJO/M@j"5kJ%{J,N3kйm΁6ȥUQRi-k ׬1W̓΁r:sB17@~Gih[ c3=MNf*9n't=l/ِJ0ut4df(NS|(ɈB4sy=+c/=d̤Yn|ўJト7b;y W"5Fw/O/c:>Rrz F5Wq/g̡ ^c'-Pl^ z {, ,>?yGgHq5H:k^:n+ǭ_puvz %t.cx^I?9tX8ut΀,VળZGO+Ӓ;7WIA[9nVg=ZgC)HA%WR:-1ksV^Χ"]1.s\66 HCzo %DC[+|gȀ Tb$A^ s|(ϨwlV˼\EEjKΥJxTWgH8Jne(fv?qTxf[G+( GOq5_F9*~|C9X/}~RJSҨ+VV>ęXqWr(Ku<+)XK۟C{ีi$8:^:)7\y@ŵ+}4\NgZ?7$F[[ۙ";[c| cI3>_Ge"maLrx,Tl(h|"7Lf` nR1Xșc92,3[ ␾J^ӈ)FIsZ7bc~]..Fs4<فxi:Dly^F ^ n?9>-mG#m yaL1lP"%o3 j)~рsIaO|ܬT.6B٬a.]{)#(0&`xv̈';9,dz'zn -/&J&Τ8߲EGg,7JfGJ=K56)'na |Z\,=_Y3I#ySpvDR $xx2+i$WZ17?F37X,fg=<-~ ][{߿˷[N_}=(=qo{ K-K|](SɩnX}bBĐ )n++E+?hY)vIM՛7Wo\ zp&M՛7Wo 8+HJQÖv On~GvгIvsxw~ޖ/=gRZN=]<+gI88hq<8::+\6+߅/D\Z;匨_)n!vQA y׿-G=JgeeڧM ׃OUS4a@׺.b!N֔&eig/v7xh€l}% P\I(>)>'OG{GeMI(7lsض߳훶MvĶl!mml[o۝-oy 2u\@ \ւcbئ}L wwO Uvv#*>@.^$^U5jvj܁հawXD^ܴv,/zwڕ+*({!|L&&ֶ)m궭aW^47hOi[Σm}vm=!%5 T0.L ŽpaG\G.L u.{@/^š{k=vw2OYs@(;Wlv8sM3k,9v^ɫy-XS[QYQ]Q[Q6LXEea\β_ LYyM,P*E>gbaWi+_qv*}[my+-s KS;W,pدi,eqzO/1 _!>'\Q}?T U` f6~RG4}\Wr T3;lJgk$:f9` *I@+ix4 !!!!HC@C@C@C    AG| ^ q`D0H)~y"@ V^A::::tttt####Hg:]a }1`8Ah +ϒ :4tСCCN:4thIC :iСCC' J4,hXаH iXаaA" 4,hXaA Kj?eo)3q6qF.$pfdt4p.v|TĩplC4σU3d6rFsGȴ7!sۅ2+TGTNP<TOvt-].w{k"3ԔϦߛrrr)w):WKmB|?9lS]m*EA~wݢwoԟ*^xԟf 3TÄ_y}ϼ5ތ_G<om+z.Pccx$J%"=?*yjKMk7Ϫtμϙquvw8g)受ו;YRY~^eҔ8^dJrQApp+l:Yg$vƕA^]jV]šZةtj[: [#ȋ'fNGak7]^m/q8vS);WɸjiJqW$n:tPLҘ13mhM/x7(bY aVlZP/)ݪ5s`ͨjV@'#[ g9P- 1cVV>=p{a\6wW(m=}3n_ 7`NnyxaI,©eS9,RR+%0i%)WB-'K"{lv}t?D!:[]v(;c5WUdӮ஠lMýn2uT#УˤG̵[ڒPט5Y|pb%k;l }r+ZvhQ/f Uw= j* _,"g> endobj 1055 0 obj <> stream x]MO@= hҐhk@aZIBμ6̻ntYm|?ah<}Z6;>>dfLػ&>n~X,-;MbaI:?6q#dI]1#u~ĖȆtmƦ',bݿwBn~6!Xe#8Ε]%+.˵pp[ ߡ^VK欔#ra\HͰW. Qe) NXWi_Y,K' B9YWZ3k&I}4!2 NB2 !/%;ٗNk+r''Owr.9աGKglM{!~$:2hF7rq endstream endobj 1056 0 obj <> endobj 1057 0 obj <> endobj 1058 0 obj <> endobj 1059 0 obj <> endobj 1060 0 obj <> /ProcSet[/PDF/Text/ImageC/ImageI/ImageB] >> endobj 1 0 obj <>/Contents 2 0 R>> endobj 6 0 obj <>/Contents 7 0 R>> endobj 9 0 obj <>/Contents 10 0 R>> endobj 12 0 obj <>/Contents 13 0 R>> endobj 19 0 obj <>/Contents 20 0 R>> endobj 22 0 obj <>/Contents 23 0 R>> endobj 25 0 obj <>/Contents 26 0 R>> endobj 28 0 obj <>/Contents 29 0 R>> endobj 31 0 obj <>/Contents 32 0 R>> endobj 34 0 obj <>/Contents 35 0 R>> endobj 37 0 obj <>/Contents 38 0 R>> endobj 40 0 obj <>/Contents 41 0 R>> endobj 45 0 obj <>/Contents 46 0 R>> endobj 50 0 obj <>/Contents 51 0 R>> endobj 53 0 obj <>/Contents 54 0 R>> endobj 56 0 obj <>/Contents 57 0 R>> endobj 59 0 obj <>/Contents 60 0 R>> endobj 64 0 obj <>/Contents 65 0 R>> endobj 67 0 obj <>/Contents 68 0 R>> endobj 70 0 obj <>/Contents 71 0 R>> endobj 73 0 obj <>/Contents 74 0 R>> endobj 76 0 obj <>/Contents 77 0 R>> endobj 79 0 obj <>/Contents 80 0 R>> endobj 82 0 obj <>/Contents 83 0 R>> endobj 85 0 obj <>/Contents 86 0 R>> endobj 90 0 obj <>/Contents 91 0 R>> endobj 93 0 obj <>/Contents 94 0 R>> endobj 96 0 obj <>/Contents 97 0 R>> endobj 99 0 obj <>/Contents 100 0 R>> endobj 104 0 obj <>/Contents 105 0 R>> endobj 107 0 obj <>/Contents 108 0 R>> endobj 110 0 obj <>/Contents 111 0 R>> endobj 113 0 obj <>/Contents 114 0 R>> endobj 116 0 obj <>/Contents 117 0 R>> endobj 119 0 obj <>/Contents 120 0 R>> endobj 124 0 obj <>/Contents 125 0 R>> endobj 127 0 obj <>/Contents 128 0 R>> endobj 130 0 obj <>/Contents 131 0 R>> endobj 133 0 obj <>/Contents 134 0 R>> endobj 136 0 obj <>/Contents 137 0 R>> endobj 139 0 obj <>/Contents 140 0 R>> endobj 142 0 obj <>/Contents 143 0 R>> endobj 145 0 obj <>/Contents 146 0 R>> endobj 148 0 obj <>/Contents 149 0 R>> endobj 151 0 obj <>/Contents 152 0 R>> endobj 154 0 obj <>/Contents 155 0 R>> endobj 161 0 obj <>/Contents 162 0 R>> endobj 164 0 obj <>/Contents 165 0 R>> endobj 167 0 obj <>/Contents 168 0 R>> endobj 174 0 obj <>/Contents 175 0 R>> endobj 190 0 obj <>/Contents 191 0 R>> endobj 193 0 obj <>/Contents 194 0 R>> endobj 196 0 obj <>/Contents 197 0 R>> endobj 199 0 obj <>/Contents 200 0 R>> endobj 202 0 obj <>/Contents 203 0 R>> endobj 207 0 obj <>/Contents 208 0 R>> endobj 210 0 obj <>/Contents 211 0 R>> endobj 217 0 obj <>/Contents 218 0 R>> endobj 220 0 obj <>/Contents 221 0 R>> endobj 225 0 obj <>/Contents 226 0 R>> endobj 230 0 obj <>/Contents 231 0 R>> endobj 234 0 obj <>/Contents 235 0 R>> endobj 237 0 obj <>/Contents 238 0 R>> endobj 242 0 obj <>/Contents 243 0 R>> endobj 245 0 obj <>/Contents 246 0 R>> endobj 250 0 obj <>/Contents 251 0 R>> endobj 253 0 obj <>/Contents 254 0 R>> endobj 258 0 obj <>/Contents 259 0 R>> endobj 263 0 obj <>/Contents 264 0 R>> endobj 268 0 obj <>/Contents 269 0 R>> endobj 273 0 obj <>/Contents 274 0 R>> endobj 278 0 obj <>/Contents 279 0 R>> endobj 282 0 obj <>/Contents 283 0 R>> endobj 287 0 obj <>/Contents 288 0 R>> endobj 292 0 obj <>/Contents 293 0 R>> endobj 297 0 obj <>/Contents 298 0 R>> endobj 300 0 obj <>/Contents 301 0 R>> endobj 305 0 obj <>/Contents 306 0 R>> endobj 310 0 obj <>/Contents 311 0 R>> endobj 314 0 obj <>/Contents 315 0 R>> endobj 319 0 obj <>/Contents 320 0 R>> endobj 322 0 obj <>/Contents 323 0 R>> endobj 326 0 obj <>/Contents 327 0 R>> endobj 329 0 obj <>/Contents 330 0 R>> endobj 334 0 obj <>/Contents 335 0 R>> endobj 337 0 obj <>/Contents 338 0 R>> endobj 342 0 obj <>/Contents 343 0 R>> endobj 346 0 obj <>/Contents 347 0 R>> endobj 351 0 obj <>/Contents 352 0 R>> endobj 356 0 obj <>/Contents 357 0 R>> endobj 361 0 obj <>/Contents 362 0 R>> endobj 366 0 obj <>/Contents 367 0 R>> endobj 369 0 obj <>/Contents 370 0 R>> endobj 374 0 obj <>/Contents 375 0 R>> endobj 381 0 obj <>/Contents 382 0 R>> endobj 388 0 obj <>/Contents 389 0 R>> endobj 393 0 obj <>/Contents 394 0 R>> endobj 398 0 obj <>/Contents 399 0 R>> endobj 401 0 obj <>/Contents 402 0 R>> endobj 404 0 obj <>/Contents 405 0 R>> endobj 409 0 obj <>/Contents 410 0 R>> endobj 412 0 obj <>/Contents 413 0 R>> endobj 417 0 obj <>/Contents 418 0 R>> endobj 422 0 obj <>/Contents 423 0 R>> endobj 435 0 obj <>/Contents 436 0 R>> endobj 442 0 obj <>/Contents 443 0 R>> endobj 449 0 obj <>/Contents 450 0 R>> endobj 452 0 obj <>/Contents 453 0 R>> endobj 461 0 obj <>/Contents 462 0 R>> endobj 464 0 obj <>/Contents 465 0 R>> endobj 467 0 obj <>/Contents 468 0 R>> endobj 470 0 obj <>/Contents 471 0 R>> endobj 473 0 obj <>/Contents 474 0 R>> endobj 478 0 obj <>/Contents 479 0 R>> endobj 481 0 obj <>/Contents 482 0 R>> endobj 486 0 obj <>/Contents 487 0 R>> endobj 489 0 obj <>/Contents 490 0 R>> endobj 492 0 obj <>/Contents 493 0 R>> endobj 495 0 obj <>/Contents 496 0 R>> endobj 498 0 obj <>/Contents 499 0 R>> endobj 501 0 obj <>/Contents 502 0 R>> endobj 504 0 obj <>/Contents 505 0 R>> endobj 507 0 obj <>/Contents 508 0 R>> endobj 510 0 obj <>/Contents 511 0 R>> endobj 513 0 obj <>/Contents 514 0 R>> endobj 516 0 obj <>/Contents 517 0 R>> endobj 521 0 obj <>/Contents 522 0 R>> endobj 524 0 obj <>/Contents 525 0 R>> endobj 529 0 obj <>/Contents 530 0 R>> endobj 534 0 obj <>/Contents 535 0 R>> endobj 543 0 obj <>/Contents 544 0 R>> endobj 550 0 obj <>/Contents 551 0 R>> endobj 557 0 obj <>/Contents 558 0 R>> endobj 560 0 obj <>/Contents 561 0 R>> endobj 563 0 obj <>/Contents 564 0 R>> endobj 566 0 obj <>/Contents 567 0 R>> endobj 569 0 obj <>/Contents 570 0 R>> endobj 572 0 obj <>/Contents 573 0 R>> endobj 575 0 obj <>/Contents 576 0 R>> endobj 578 0 obj <>/Contents 579 0 R>> endobj 581 0 obj <>/Contents 582 0 R>> endobj 1061 0 obj <> endobj 1062 0 obj < /Dest[25 0 R/XYZ 165 720 0]/Parent 1061 0 R/Next 1069 0 R>> endobj 1063 0 obj < /Dest[25 0 R/XYZ 180 494.6 0]/Parent 1062 0 R/Next 1067 0 R>> endobj 1064 0 obj < /Dest[28 0 R/XYZ 156 720 0]/Parent 1063 0 R/Next 1065 0 R>> endobj 1065 0 obj < /Dest[28 0 R/XYZ 156 559.4 0]/Parent 1063 0 R/Prev 1064 0 R/Next 1066 0 R>> endobj 1066 0 obj < /Dest[28 0 R/XYZ 156 340.1 0]/Parent 1063 0 R/Prev 1065 0 R>> endobj 1067 0 obj < /Dest[31 0 R/XYZ 180 639 0]/Parent 1062 0 R/Prev 1063 0 R/Next 1068 0 R>> endobj 1068 0 obj < /Dest[34 0 R/XYZ 144 654 0]/Parent 1062 0 R/Prev 1067 0 R>> endobj 1069 0 obj < /Dest[37 0 R/XYZ 165 720 0]/Parent 1061 0 R/Prev 1062 0 R/Next 1078 0 R>> endobj 1070 0 obj < /Dest[40 0 R/XYZ 144 512.8 0]/Parent 1069 0 R/Next 1071 0 R>> endobj 1071 0 obj < /Dest[45 0 R/XYZ 180 414.5 0]/Parent 1069 0 R/Prev 1070 0 R>> endobj 1072 0 obj < /Dest[45 0 R/XYZ 192 236.1 0]/Parent 1071 0 R/Next 1073 0 R>> endobj 1073 0 obj < /Dest[56 0 R/XYZ 156 720 0]/Parent 1071 0 R/Prev 1072 0 R/Next 1074 0 R>> endobj 1074 0 obj < /Dest[56 0 R/XYZ 156 538.7 0]/Parent 1071 0 R/Prev 1073 0 R/Next 1077 0 R>> endobj 1075 0 obj < /Dest[59 0 R/XYZ 200 500 0]/Parent 1074 0 R/Next 1076 0 R>> endobj 1076 0 obj < /Dest[59 0 R/XYZ 200 373.8 0]/Parent 1074 0 R/Prev 1075 0 R>> endobj 1077 0 obj < /Dest[67 0 R/XYZ 192 328.4 0]/Parent 1071 0 R/Prev 1074 0 R>> endobj 1078 0 obj < /Dest[76 0 R/XYZ 129 720 0]/Parent 1061 0 R/Prev 1069 0 R/Next 1085 0 R>> endobj 1079 0 obj < /Dest[76 0 R/XYZ 144 509.6 0]/Parent 1078 0 R/Next 1083 0 R>> endobj 1080 0 obj < /Dest[76 0 R/XYZ 156 145.9 0]/Parent 1079 0 R/Next 1081 0 R>> endobj 1081 0 obj < /Dest[79 0 R/XYZ 192 339.8 0]/Parent 1079 0 R/Prev 1080 0 R/Next 1082 0 R>> endobj 1082 0 obj < /Dest[79 0 R/XYZ 192 150.5 0]/Parent 1079 0 R/Prev 1081 0 R>> endobj 1083 0 obj < /Dest[82 0 R/XYZ 144 518 0]/Parent 1078 0 R/Prev 1079 0 R/Next 1084 0 R>> endobj 1084 0 obj < /Dest[90 0 R/XYZ 144 477 0]/Parent 1078 0 R/Prev 1083 0 R>> endobj 1085 0 obj < /Dest[96 0 R/XYZ 129 720 0]/Parent 1061 0 R/Prev 1078 0 R/Next 1097 0 R>> endobj 1086 0 obj < /Dest[96 0 R/XYZ 144 321.6 0]/Parent 1085 0 R/Next 1089 0 R>> endobj 1087 0 obj < /Dest[99 0 R/XYZ 192 720 0]/Parent 1086 0 R/Next 1088 0 R>> endobj 1088 0 obj < /Dest[104 0 R/XYZ 156 720 0]/Parent 1086 0 R/Prev 1087 0 R>> endobj 1089 0 obj < /Dest[107 0 R/XYZ 180 530.7 0]/Parent 1085 0 R/Prev 1086 0 R/Next 1090 0 R>> endobj 1090 0 obj < /Dest[110 0 R/XYZ 144 601 0]/Parent 1085 0 R/Prev 1089 0 R/Next 1094 0 R>> endobj 1091 0 obj < /Dest[110 0 R/XYZ 156 445.6 0]/Parent 1090 0 R/Next 1092 0 R>> endobj 1092 0 obj < /Dest[110 0 R/XYZ 156 256.3 0]/Parent 1090 0 R/Prev 1091 0 R/Next 1093 0 R>> endobj 1093 0 obj < /Dest[113 0 R/XYZ 192 720 0]/Parent 1090 0 R/Prev 1092 0 R>> endobj 1094 0 obj < /Dest[113 0 R/XYZ 180 321.7 0]/Parent 1085 0 R/Prev 1090 0 R/Next 1096 0 R>> endobj 1095 0 obj < /Dest[116 0 R/XYZ 156 532 0]/Parent 1094 0 R>> endobj 1096 0 obj < /Dest[124 0 R/XYZ 144 484.7 0]/Parent 1085 0 R/Prev 1094 0 R>> endobj 1097 0 obj < /Dest[130 0 R/XYZ 129 720 0]/Parent 1061 0 R/Prev 1085 0 R/Next 1114 0 R>> endobj 1098 0 obj < /Dest[130 0 R/XYZ 144 243.2 0]/Parent 1097 0 R/Next 1099 0 R>> endobj 1099 0 obj < /Dest[133 0 R/XYZ 180 398 0]/Parent 1097 0 R/Prev 1098 0 R/Next 1103 0 R>> endobj 1100 0 obj < /Dest[136 0 R/XYZ 156 720 0]/Parent 1099 0 R/Next 1101 0 R>> endobj 1101 0 obj < /Dest[136 0 R/XYZ 156 559.4 0]/Parent 1099 0 R/Prev 1100 0 R/Next 1102 0 R>> endobj 1102 0 obj < /Dest[136 0 R/XYZ 156 353.8 0]/Parent 1099 0 R/Prev 1101 0 R>> endobj 1103 0 obj < /Dest[139 0 R/XYZ 180 720 0]/Parent 1097 0 R/Prev 1099 0 R/Next 1106 0 R>> endobj 1104 0 obj < /Dest[139 0 R/XYZ 192 225.6 0]/Parent 1103 0 R/Next 1105 0 R>> endobj 1105 0 obj < /Dest[142 0 R/XYZ 156 578 0]/Parent 1103 0 R/Prev 1104 0 R>> endobj 1106 0 obj < /Dest[142 0 R/XYZ 144 262.7 0]/Parent 1097 0 R/Prev 1103 0 R>> endobj 1107 0 obj < /Dest[142 0 R/XYZ 156 137.3 0]/Parent 1106 0 R/Next 1108 0 R>> endobj 1108 0 obj < /Dest[148 0 R/XYZ 156 330.1 0]/Parent 1106 0 R/Prev 1107 0 R/Next 1109 0 R>> endobj 1109 0 obj < /Dest[154 0 R/XYZ 156 362.9 0]/Parent 1106 0 R/Prev 1108 0 R>> endobj 1110 0 obj < /Dest[154 0 R/XYZ 164 238.4 0]/Parent 1109 0 R/Next 1111 0 R>> endobj 1111 0 obj < /Dest[161 0 R/XYZ 200 582.3 0]/Parent 1109 0 R/Prev 1110 0 R/Next 1112 0 R>> endobj 1112 0 obj < /Dest[161 0 R/XYZ 200 383 0]/Parent 1109 0 R/Prev 1111 0 R/Next 1113 0 R>> endobj 1113 0 obj < /Dest[164 0 R/XYZ 164 720 0]/Parent 1109 0 R/Prev 1112 0 R>> endobj 1114 0 obj < /Dest[167 0 R/XYZ 165 720 0]/Parent 1061 0 R/Prev 1097 0 R/Next 1118 0 R>> endobj 1115 0 obj < /Dest[174 0 R/XYZ 144 474.3 0]/Parent 1114 0 R/Next 1116 0 R>> endobj 1116 0 obj < /Dest[190 0 R/XYZ 180 720 0]/Parent 1114 0 R/Prev 1115 0 R/Next 1117 0 R>> endobj 1117 0 obj < /Dest[193 0 R/XYZ 144 720 0]/Parent 1114 0 R/Prev 1116 0 R>> endobj 1118 0 obj < /Dest[199 0 R/XYZ 129 720 0]/Parent 1061 0 R/Prev 1114 0 R/Next 1127 0 R>> endobj 1119 0 obj < /Dest[202 0 R/XYZ 180 167.5 0]/Parent 1118 0 R/Next 1121 0 R>> endobj 1120 0 obj < /Dest[217 0 R/XYZ 156 360 0]/Parent 1119 0 R>> endobj 1121 0 obj < /Dest[220 0 R/XYZ 180 720 0]/Parent 1118 0 R/Prev 1119 0 R>> endobj 1122 0 obj < /Dest[220 0 R/XYZ 192 504.6 0]/Parent 1121 0 R/Next 1123 0 R>> endobj 1123 0 obj < /Dest[225 0 R/XYZ 156 660 0]/Parent 1121 0 R/Prev 1122 0 R/Next 1124 0 R>> endobj 1124 0 obj < /Dest[225 0 R/XYZ 156 288.3 0]/Parent 1121 0 R/Prev 1123 0 R/Next 1125 0 R>> endobj 1125 0 obj < /Dest[230 0 R/XYZ 192 372 0]/Parent 1121 0 R/Prev 1124 0 R/Next 1126 0 R>> endobj 1126 0 obj < /Dest[230 0 R/XYZ 192 162 0]/Parent 1121 0 R/Prev 1125 0 R>> endobj 1127 0 obj < /Dest[242 0 R/XYZ 129 720 0]/Parent 1061 0 R/Prev 1118 0 R/Next 1203 0 R>> endobj 1128 0 obj < /Dest[242 0 R/XYZ 144 357.2 0]/Parent 1127 0 R/Next 1157 0 R>> endobj 1129 0 obj < /Dest[242 0 R/XYZ 156 231.8 0]/Parent 1128 0 R/Next 1130 0 R>> endobj 1130 0 obj < /Dest[250 0 R/XYZ 156 446.9 0]/Parent 1128 0 R/Prev 1129 0 R/Next 1131 0 R>> endobj 1131 0 obj < /Dest[253 0 R/XYZ 192 454.7 0]/Parent 1128 0 R/Prev 1130 0 R/Next 1132 0 R>> endobj 1132 0 obj < /Dest[258 0 R/XYZ 156 446.8 0]/Parent 1128 0 R/Prev 1131 0 R/Next 1133 0 R>> endobj 1133 0 obj < /Dest[263 0 R/XYZ 192 273.8 0]/Parent 1128 0 R/Prev 1132 0 R/Next 1134 0 R>> endobj 1134 0 obj < /Dest[268 0 R/XYZ 156 246.6 0]/Parent 1128 0 R/Prev 1133 0 R/Next 1135 0 R>> endobj 1135 0 obj < /Dest[282 0 R/XYZ 192 720 0]/Parent 1128 0 R/Prev 1134 0 R/Next 1136 0 R>> endobj 1136 0 obj < /Dest[282 0 R/XYZ 192 216.8 0]/Parent 1128 0 R/Prev 1135 0 R/Next 1137 0 R>> endobj 1137 0 obj < /Dest[292 0 R/XYZ 192 720 0]/Parent 1128 0 R/Prev 1136 0 R/Next 1138 0 R>> endobj 1138 0 obj < /Dest[297 0 R/XYZ 156 388.9 0]/Parent 1128 0 R/Prev 1137 0 R/Next 1139 0 R>> endobj 1139 0 obj < /Dest[305 0 R/XYZ 156 524 0]/Parent 1128 0 R/Prev 1138 0 R/Next 1140 0 R>> endobj 1140 0 obj < /Dest[310 0 R/XYZ 192 267.5 0]/Parent 1128 0 R/Prev 1139 0 R/Next 1141 0 R>> endobj 1141 0 obj < /Dest[319 0 R/XYZ 192 208.1 0]/Parent 1128 0 R/Prev 1140 0 R/Next 1142 0 R>> endobj 1142 0 obj < /Dest[326 0 R/XYZ 192 206 0]/Parent 1128 0 R/Prev 1141 0 R/Next 1146 0 R>> endobj 1143 0 obj < /Dest[329 0 R/XYZ 164 642.8 0]/Parent 1142 0 R/Next 1144 0 R>> endobj 1144 0 obj < /Dest[334 0 R/XYZ 200 720 0]/Parent 1142 0 R/Prev 1143 0 R/Next 1145 0 R>> endobj 1145 0 obj < /Dest[337 0 R/XYZ 164 206.3 0]/Parent 1142 0 R/Prev 1144 0 R>> endobj 1146 0 obj < /Dest[342 0 R/XYZ 192 630 0]/Parent 1128 0 R/Prev 1142 0 R/Next 1147 0 R>> endobj 1147 0 obj < /Dest[351 0 R/XYZ 192 522.4 0]/Parent 1128 0 R/Prev 1146 0 R/Next 1148 0 R>> endobj 1148 0 obj < /Dest[356 0 R/XYZ 156 530.8 0]/Parent 1128 0 R/Prev 1147 0 R/Next 1149 0 R>> endobj 1149 0 obj < /Dest[356 0 R/XYZ 156 344.7 0]/Parent 1128 0 R/Prev 1148 0 R/Next 1150 0 R>> endobj 1150 0 obj < /Dest[366 0 R/XYZ 156 548 0]/Parent 1128 0 R/Prev 1149 0 R/Next 1151 0 R>> endobj 1151 0 obj < /Dest[366 0 R/XYZ 156 376.9 0]/Parent 1128 0 R/Prev 1150 0 R/Next 1152 0 R>> endobj 1152 0 obj < /Dest[369 0 R/XYZ 192 276.3 0]/Parent 1128 0 R/Prev 1151 0 R/Next 1153 0 R>> endobj 1153 0 obj < /Dest[374 0 R/XYZ 156 518.8 0]/Parent 1128 0 R/Prev 1152 0 R/Next 1154 0 R>> endobj 1154 0 obj < /Dest[381 0 R/XYZ 192 207.1 0]/Parent 1128 0 R/Prev 1153 0 R/Next 1155 0 R>> endobj 1155 0 obj < /Dest[388 0 R/XYZ 156 615 0]/Parent 1128 0 R/Prev 1154 0 R/Next 1156 0 R>> endobj 1156 0 obj < /Dest[393 0 R/XYZ 192 645 0]/Parent 1128 0 R/Prev 1155 0 R>> endobj 1157 0 obj < /Dest[393 0 R/XYZ 180 237 0]/Parent 1127 0 R/Prev 1128 0 R/Next 1190 0 R>> endobj 1158 0 obj < /Dest[398 0 R/XYZ 156 720 0]/Parent 1157 0 R/Next 1159 0 R>> endobj 1159 0 obj < /Dest[398 0 R/XYZ 156 360.9 0]/Parent 1157 0 R/Prev 1158 0 R/Next 1160 0 R>> endobj 1160 0 obj < /Dest[401 0 R/XYZ 192 532 0]/Parent 1157 0 R/Prev 1159 0 R/Next 1161 0 R>> endobj 1161 0 obj < /Dest[401 0 R/XYZ 192 207.9 0]/Parent 1157 0 R/Prev 1160 0 R/Next 1162 0 R>> endobj 1162 0 obj < /Dest[412 0 R/XYZ 156 587.9 0]/Parent 1157 0 R/Prev 1161 0 R/Next 1175 0 R>> endobj 1163 0 obj < /Dest[417 0 R/XYZ 200 500 0]/Parent 1162 0 R/Next 1164 0 R>> endobj 1164 0 obj < /Dest[422 0 R/XYZ 164 363.9 0]/Parent 1162 0 R/Prev 1163 0 R/Next 1168 0 R>> endobj 1165 0 obj < /Dest[422 0 R/XYZ 168 285.6 0]/Parent 1164 0 R/Next 1166 0 R>> endobj 1166 0 obj < /Dest[435 0 R/XYZ 204 368 0]/Parent 1164 0 R/Prev 1165 0 R/Next 1167 0 R>> endobj 1167 0 obj < /Dest[442 0 R/XYZ 168 398 0]/Parent 1164 0 R/Prev 1166 0 R>> endobj 1168 0 obj < /Dest[449 0 R/XYZ 200 283 0]/Parent 1162 0 R/Prev 1164 0 R/Next 1172 0 R>> endobj 1169 0 obj < /Dest[449 0 R/XYZ 204 159.7 0]/Parent 1168 0 R/Next 1170 0 R>> endobj 1170 0 obj < /Dest[452 0 R/XYZ 168 526 0]/Parent 1168 0 R/Prev 1169 0 R/Next 1171 0 R>> endobj 1171 0 obj < /Dest[452 0 R/XYZ 168 393 0]/Parent 1168 0 R/Prev 1170 0 R>> endobj 1172 0 obj < /Dest[452 0 R/XYZ 164 174 0]/Parent 1162 0 R/Prev 1168 0 R/Next 1173 0 R>> endobj 1173 0 obj < /Dest[461 0 R/XYZ 200 516 0]/Parent 1162 0 R/Prev 1172 0 R/Next 1174 0 R>> endobj 1174 0 obj < /Dest[461 0 R/XYZ 200 351.8 0]/Parent 1162 0 R/Prev 1173 0 R>> endobj 1175 0 obj < /Dest[464 0 R/XYZ 156 720 0]/Parent 1157 0 R/Prev 1162 0 R/Next 1178 0 R>> endobj 1176 0 obj < /Dest[467 0 R/XYZ 200 486 0]/Parent 1175 0 R/Next 1177 0 R>> endobj 1177 0 obj < /Dest[470 0 R/XYZ 164 301 0]/Parent 1175 0 R/Prev 1176 0 R>> endobj 1178 0 obj < /Dest[478 0 R/XYZ 156 615 0]/Parent 1157 0 R/Prev 1175 0 R>> endobj 1179 0 obj < /Dest[495 0 R/XYZ 200 533.9 0]/Parent 1178 0 R/Next 1183 0 R>> endobj 1180 0 obj < /Dest[495 0 R/XYZ 204 327.6 0]/Parent 1179 0 R/Next 1181 0 R>> endobj 1181 0 obj < /Dest[498 0 R/XYZ 168 720 0]/Parent 1179 0 R/Prev 1180 0 R/Next 1182 0 R>> endobj 1182 0 obj < /Dest[498 0 R/XYZ 168 495.9 0]/Parent 1179 0 R/Prev 1181 0 R>> endobj 1183 0 obj < /Dest[498 0 R/XYZ 164 260.9 0]/Parent 1178 0 R/Prev 1179 0 R/Next 1189 0 R>> endobj 1184 0 obj < /Dest[498 0 R/XYZ 168 182.6 0]/Parent 1183 0 R/Next 1185 0 R>> endobj 1185 0 obj < /Dest[501 0 R/XYZ 204 468 0]/Parent 1183 0 R/Prev 1184 0 R/Next 1186 0 R>> endobj 1186 0 obj < /Dest[504 0 R/XYZ 168 368 0]/Parent 1183 0 R/Prev 1185 0 R/Next 1187 0 R>> endobj 1187 0 obj < /Dest[504 0 R/XYZ 168 159 0]/Parent 1183 0 R/Prev 1186 0 R/Next 1188 0 R>> endobj 1188 0 obj < /Dest[507 0 R/XYZ 204 383 0]/Parent 1183 0 R/Prev 1187 0 R>> endobj 1189 0 obj < /Dest[510 0 R/XYZ 164 443.5 0]/Parent 1178 0 R/Prev 1183 0 R>> endobj 1190 0 obj < /Dest[513 0 R/XYZ 180 587 0]/Parent 1127 0 R/Prev 1157 0 R>> endobj 1191 0 obj < /Dest[513 0 R/XYZ 192 446.6 0]/Parent 1190 0 R/Next 1192 0 R>> endobj 1192 0 obj < /Dest[513 0 R/XYZ 192 275.5 0]/Parent 1190 0 R/Prev 1191 0 R/Next 1193 0 R>> endobj 1193 0 obj < /Dest[516 0 R/XYZ 156 483 0]/Parent 1190 0 R/Prev 1192 0 R/Next 1194 0 R>> endobj 1194 0 obj < /Dest[516 0 R/XYZ 156 266.9 0]/Parent 1190 0 R/Prev 1193 0 R/Next 1195 0 R>> endobj 1195 0 obj < /Dest[521 0 R/XYZ 192 660 0]/Parent 1190 0 R/Prev 1194 0 R/Next 1196 0 R>> endobj 1196 0 obj < /Dest[524 0 R/XYZ 156 720 0]/Parent 1190 0 R/Prev 1195 0 R/Next 1197 0 R>> endobj 1197 0 obj < /Dest[524 0 R/XYZ 156 488.9 0]/Parent 1190 0 R/Prev 1196 0 R/Next 1198 0 R>> endobj 1198 0 obj < /Dest[529 0 R/XYZ 192 720 0]/Parent 1190 0 R/Prev 1197 0 R/Next 1199 0 R>> endobj 1199 0 obj < /Dest[529 0 R/XYZ 192 339 0]/Parent 1190 0 R/Prev 1198 0 R/Next 1200 0 R>> endobj 1200 0 obj < /Dest[534 0 R/XYZ 156 509.2 0]/Parent 1190 0 R/Prev 1199 0 R/Next 1201 0 R>> endobj 1201 0 obj < /Dest[543 0 R/XYZ 192 720 0]/Parent 1190 0 R/Prev 1200 0 R/Next 1202 0 R>> endobj 1202 0 obj < /Dest[543 0 R/XYZ 192 295.7 0]/Parent 1190 0 R/Prev 1201 0 R>> endobj 1203 0 obj < /Dest[557 0 R/XYZ 165 720 0]/Parent 1061 0 R/Prev 1127 0 R>> endobj 1204 0 obj < /Dest[557 0 R/XYZ 180 629.6 0]/Parent 1203 0 R>> endobj 1205 0 obj < /Dest[557 0 R/XYZ 192 475.9 0]/Parent 1204 0 R/Next 1206 0 R>> endobj 1206 0 obj < /Dest[560 0 R/XYZ 156 645 0]/Parent 1204 0 R/Prev 1205 0 R>> endobj 1016 0 obj <> endobj 584 0 obj <> >> endobj 585 0 obj <> endobj 586 0 obj <> endobj 587 0 obj <> endobj 588 0 obj <> endobj 589 0 obj <> endobj 590 0 obj <> endobj 591 0 obj <> endobj 592 0 obj <> endobj 593 0 obj <> endobj 594 0 obj <> endobj 595 0 obj <> endobj 596 0 obj <> endobj 597 0 obj <> endobj 598 0 obj <> endobj 599 0 obj <> endobj 600 0 obj <> endobj 601 0 obj <> endobj 602 0 obj <> endobj 603 0 obj <> endobj 604 0 obj <> endobj 605 0 obj <> endobj 606 0 obj <> endobj 607 0 obj <> endobj 608 0 obj <> endobj 609 0 obj <> endobj 610 0 obj <> endobj 611 0 obj <> endobj 612 0 obj <> endobj 613 0 obj <> endobj 614 0 obj <> endobj 615 0 obj <> endobj 616 0 obj <> endobj 617 0 obj <> endobj 618 0 obj <> endobj 619 0 obj <> endobj 620 0 obj <> endobj 621 0 obj <> endobj 622 0 obj <> endobj 623 0 obj <> endobj 624 0 obj <> endobj 625 0 obj <> endobj 626 0 obj <> endobj 627 0 obj <> endobj 628 0 obj <> endobj 629 0 obj <> endobj 630 0 obj <> endobj 631 0 obj <> endobj 632 0 obj <> endobj 633 0 obj <> endobj 634 0 obj <> endobj 635 0 obj <> endobj 636 0 obj <> endobj 637 0 obj <> endobj 638 0 obj <> endobj 639 0 obj <> endobj 640 0 obj <> endobj 641 0 obj <> endobj 642 0 obj <> endobj 643 0 obj <> endobj 644 0 obj <> endobj 645 0 obj <> endobj 646 0 obj <> endobj 647 0 obj <> endobj 648 0 obj <> endobj 649 0 obj <> endobj 650 0 obj <> endobj 651 0 obj <> endobj 652 0 obj <> endobj 653 0 obj <> endobj 654 0 obj <> endobj 655 0 obj <> endobj 656 0 obj <> endobj 657 0 obj <> endobj 658 0 obj <> endobj 659 0 obj <> endobj 660 0 obj <> endobj 661 0 obj <> endobj 662 0 obj <> endobj 663 0 obj <> endobj 664 0 obj <> endobj 665 0 obj <> endobj 666 0 obj <> endobj 667 0 obj <> endobj 668 0 obj <> endobj 669 0 obj <> endobj 670 0 obj <> endobj 671 0 obj <> endobj 672 0 obj <> endobj 673 0 obj <> endobj 674 0 obj <> endobj 675 0 obj <> endobj 676 0 obj <> endobj 677 0 obj <> endobj 678 0 obj <> endobj 679 0 obj <> endobj 680 0 obj <> endobj 681 0 obj <> endobj 682 0 obj <> endobj 683 0 obj <> endobj 684 0 obj <> endobj 685 0 obj <> endobj 686 0 obj <> endobj 687 0 obj <> endobj 688 0 obj <> endobj 689 0 obj <> endobj 690 0 obj <> endobj 691 0 obj <> endobj 692 0 obj <> endobj 693 0 obj <> endobj 694 0 obj <> endobj 695 0 obj <> endobj 696 0 obj <> endobj 697 0 obj <> endobj 698 0 obj <> endobj 699 0 obj <> endobj 700 0 obj <> endobj 701 0 obj <> endobj 702 0 obj <> endobj 703 0 obj <> endobj 704 0 obj <> endobj 705 0 obj <> endobj 706 0 obj <> endobj 707 0 obj <> endobj 708 0 obj <> endobj 709 0 obj <> endobj 710 0 obj <> endobj 711 0 obj <> endobj 712 0 obj <> endobj 713 0 obj <> endobj 714 0 obj <> endobj 715 0 obj <> endobj 716 0 obj <> endobj 717 0 obj <> endobj 718 0 obj <> endobj 719 0 obj <> endobj 720 0 obj <> endobj 721 0 obj <> endobj 722 0 obj <> endobj 723 0 obj <> endobj 724 0 obj <> endobj 725 0 obj <> endobj 726 0 obj <> endobj 727 0 obj <> endobj 728 0 obj <> endobj 729 0 obj <> endobj 730 0 obj <> >> endobj 731 0 obj <> >> endobj 732 0 obj <> >> endobj 733 0 obj <> >> endobj 734 0 obj <> >> endobj 735 0 obj <> >> endobj 736 0 obj <> >> endobj 737 0 obj <> endobj 738 0 obj <> endobj 739 0 obj <> endobj 740 0 obj <> endobj 741 0 obj <> endobj 742 0 obj <> endobj 743 0 obj <> endobj 744 0 obj <> endobj 745 0 obj <> endobj 746 0 obj <> endobj 747 0 obj <> endobj 748 0 obj <> endobj 749 0 obj <> endobj 750 0 obj <> endobj 751 0 obj <> endobj 752 0 obj <> endobj 753 0 obj <> endobj 754 0 obj <> endobj 755 0 obj <> endobj 756 0 obj <> endobj 757 0 obj <> endobj 758 0 obj <> endobj 759 0 obj <> endobj 760 0 obj <> endobj 761 0 obj <> endobj 762 0 obj <> endobj 763 0 obj <> endobj 764 0 obj <> endobj 765 0 obj <> endobj 766 0 obj <> endobj 767 0 obj <> endobj 768 0 obj <> endobj 769 0 obj <> endobj 770 0 obj <> endobj 771 0 obj <> endobj 772 0 obj <> endobj 773 0 obj <> endobj 774 0 obj <> endobj 775 0 obj <> endobj 776 0 obj <> endobj 777 0 obj <> endobj 778 0 obj <> endobj 779 0 obj <> endobj 780 0 obj <> endobj 781 0 obj <> endobj 782 0 obj <> endobj 783 0 obj <> endobj 784 0 obj <> endobj 785 0 obj <> endobj 786 0 obj <> endobj 787 0 obj <> endobj 788 0 obj <> endobj 789 0 obj <> endobj 790 0 obj <> endobj 791 0 obj <> endobj 792 0 obj <> endobj 793 0 obj <> endobj 794 0 obj <> endobj 795 0 obj <> endobj 796 0 obj <> endobj 797 0 obj <> endobj 798 0 obj <> endobj 799 0 obj <> endobj 800 0 obj <> endobj 801 0 obj <> endobj 802 0 obj <> endobj 803 0 obj <> endobj 804 0 obj <> endobj 805 0 obj <> endobj 806 0 obj <> endobj 807 0 obj <> endobj 808 0 obj <> endobj 809 0 obj <> endobj 810 0 obj <> endobj 811 0 obj <> endobj 812 0 obj <> endobj 813 0 obj <> endobj 814 0 obj <> endobj 815 0 obj <> endobj 816 0 obj <> endobj 817 0 obj <> endobj 818 0 obj <> endobj 819 0 obj <> endobj 820 0 obj <> endobj 821 0 obj <> endobj 822 0 obj <> endobj 823 0 obj <> endobj 824 0 obj <> endobj 825 0 obj <> endobj 826 0 obj <> endobj 827 0 obj <> endobj 828 0 obj <> endobj 829 0 obj <> endobj 830 0 obj <> endobj 831 0 obj <> endobj 832 0 obj <> endobj 833 0 obj <> endobj 834 0 obj <> endobj 835 0 obj <> endobj 836 0 obj <> endobj 837 0 obj <> endobj 838 0 obj <> endobj 839 0 obj <> endobj 840 0 obj <> endobj 841 0 obj <> endobj 842 0 obj <> endobj 843 0 obj <> endobj 844 0 obj <> endobj 845 0 obj <> endobj 846 0 obj <> endobj 847 0 obj <> endobj 848 0 obj <> endobj 849 0 obj <> endobj 850 0 obj <> endobj 851 0 obj <> endobj 852 0 obj <> endobj 853 0 obj <> endobj 854 0 obj <> endobj 855 0 obj <> endobj 856 0 obj <> endobj 857 0 obj <> endobj 858 0 obj <> endobj 859 0 obj <> endobj 860 0 obj <> endobj 861 0 obj <> endobj 862 0 obj <> endobj 863 0 obj <> endobj 864 0 obj <> endobj 865 0 obj <> endobj 866 0 obj <> endobj 867 0 obj <> endobj 868 0 obj <> endobj 869 0 obj <> endobj 870 0 obj <> endobj 871 0 obj <> endobj 872 0 obj <> endobj 873 0 obj <> endobj 874 0 obj <> endobj 875 0 obj <> endobj 876 0 obj <> endobj 877 0 obj <> endobj 878 0 obj <> endobj 879 0 obj <> endobj 880 0 obj <> endobj 881 0 obj <> endobj 882 0 obj <> endobj 883 0 obj <> endobj 884 0 obj <> endobj 885 0 obj <> endobj 886 0 obj <> endobj 887 0 obj <> endobj 888 0 obj <> endobj 889 0 obj <> endobj 890 0 obj <> endobj 891 0 obj <> endobj 892 0 obj <> endobj 893 0 obj <> endobj 894 0 obj <> endobj 895 0 obj <> endobj 896 0 obj <> endobj 897 0 obj <> endobj 898 0 obj <> endobj 899 0 obj <> endobj 900 0 obj <> endobj 901 0 obj <> endobj 902 0 obj <> endobj 903 0 obj <> endobj 904 0 obj <> endobj 905 0 obj <> endobj 906 0 obj <> endobj 907 0 obj <> endobj 908 0 obj <> endobj 909 0 obj <> endobj 910 0 obj <> endobj 911 0 obj <> endobj 912 0 obj <> endobj 913 0 obj <> endobj 914 0 obj <> endobj 915 0 obj <> endobj 916 0 obj <> endobj 917 0 obj <> endobj 918 0 obj <> endobj 919 0 obj <> endobj 920 0 obj <> endobj 921 0 obj <> endobj 922 0 obj <> endobj 923 0 obj <> endobj 924 0 obj <> endobj 925 0 obj <> endobj 926 0 obj <> endobj 927 0 obj <> endobj 928 0 obj <> endobj 929 0 obj <> endobj 930 0 obj <> endobj 931 0 obj <> endobj 932 0 obj <> endobj 933 0 obj <> endobj 934 0 obj <> endobj 935 0 obj <> endobj 936 0 obj <> endobj 937 0 obj <> endobj 938 0 obj <> endobj 939 0 obj <> endobj 940 0 obj <> endobj 941 0 obj <> endobj 942 0 obj <> endobj 943 0 obj <> endobj 944 0 obj <> endobj 945 0 obj <> endobj 946 0 obj <> endobj 947 0 obj <> endobj 948 0 obj <> endobj 949 0 obj <> endobj 950 0 obj <> endobj 951 0 obj <> endobj 952 0 obj <> endobj 953 0 obj <> endobj 954 0 obj <> endobj 955 0 obj <> endobj 956 0 obj <> endobj 957 0 obj <> endobj 958 0 obj <> endobj 959 0 obj <> endobj 960 0 obj <> endobj 961 0 obj <> endobj 962 0 obj <> endobj 963 0 obj <> endobj 964 0 obj <> endobj 965 0 obj <> endobj 966 0 obj <> endobj 967 0 obj <> endobj 968 0 obj <> endobj 969 0 obj <> endobj 970 0 obj <> endobj 971 0 obj <> endobj 972 0 obj <> endobj 973 0 obj <> endobj 974 0 obj <> endobj 975 0 obj <> endobj 976 0 obj <> endobj 977 0 obj <> endobj 978 0 obj <> endobj 979 0 obj <> endobj 980 0 obj <> endobj 981 0 obj <> endobj 982 0 obj <> endobj 983 0 obj <> endobj 984 0 obj <> endobj 985 0 obj <> endobj 986 0 obj <> endobj 987 0 obj <> endobj 988 0 obj <> endobj 989 0 obj <> endobj 990 0 obj <> endobj 991 0 obj <> endobj 992 0 obj <> endobj 993 0 obj <> endobj 994 0 obj <> endobj 995 0 obj <> endobj 996 0 obj <> endobj 997 0 obj <> endobj 998 0 obj <> endobj 999 0 obj <> endobj 1000 0 obj <> endobj 1001 0 obj <> endobj 1002 0 obj <> endobj 1003 0 obj <> endobj 1004 0 obj <> endobj 1005 0 obj <> endobj 1006 0 obj <> endobj 1007 0 obj <> endobj 1008 0 obj <> endobj 1009 0 obj <> endobj 1010 0 obj <> endobj 1011 0 obj <> endobj 1012 0 obj <> endobj 1013 0 obj <> endobj 1014 0 obj <> endobj 1015 0 obj <> endobj 1207 0 obj <> /Outlines 1061 0 R >> endobj 1208 0 obj < /Author /Creator /Producer /CreationDate(D:20080303165138-06'00')>> endobj xref 0 1209 0000000000 65535 f 0000953466 00000 n 0000000019 00000 n 0000000440 00000 n 0000000460 00000 n 0000008715 00000 n 0000953614 00000 n 0000008736 00000 n 0000011069 00000 n 0000953789 00000 n 0000011090 00000 n 0000015235 00000 n 0000954229 00000 n 0000015257 00000 n 0000019747 00000 n 0000019769 00000 n 0000023066 00000 n 0000023088 00000 n 0000023642 00000 n 0000954694 00000 n 0000023663 00000 n 0000027694 00000 n 0000955175 00000 n 0000027716 00000 n 0000031604 00000 n 0000955592 00000 n 0000031626 00000 n 0000034023 00000 n 0000955742 00000 n 0000034045 00000 n 0000036797 00000 n 0000955951 00000 n 0000036819 00000 n 0000039421 00000 n 0000956152 00000 n 0000039443 00000 n 0000041197 00000 n 0000956385 00000 n 0000041219 00000 n 0000043485 00000 n 0000956570 00000 n 0000043507 00000 n 0000045282 00000 n 0000045304 00000 n 0000052069 00000 n 0000956739 00000 n 0000052091 00000 n 0000054395 00000 n 0000054417 00000 n 0000060086 00000 n 0000956964 00000 n 0000060108 00000 n 0000062717 00000 n 0000957133 00000 n 0000062739 00000 n 0000065754 00000 n 0000957318 00000 n 0000065776 00000 n 0000068022 00000 n 0000957487 00000 n 0000068044 00000 n 0000069949 00000 n 0000069971 00000 n 0000075974 00000 n 0000957681 00000 n 0000075996 00000 n 0000078074 00000 n 0000957831 00000 n 0000078096 00000 n 0000080622 00000 n 0000957981 00000 n 0000080644 00000 n 0000082521 00000 n 0000958131 00000 n 0000082543 00000 n 0000083442 00000 n 0000958281 00000 n 0000083463 00000 n 0000085573 00000 n 0000958431 00000 n 0000085595 00000 n 0000088380 00000 n 0000958624 00000 n 0000088402 00000 n 0000091181 00000 n 0000958826 00000 n 0000091203 00000 n 0000093536 00000 n 0000093558 00000 n 0000099588 00000 n 0000958995 00000 n 0000099610 00000 n 0000101856 00000 n 0000959180 00000 n 0000101878 00000 n 0000104654 00000 n 0000959373 00000 n 0000104676 00000 n 0000107174 00000 n 0000959523 00000 n 0000107196 00000 n 0000109227 00000 n 0000109250 00000 n 0000115264 00000 n 0000959709 00000 n 0000115287 00000 n 0000117359 00000 n 0000959861 00000 n 0000117382 00000 n 0000120203 00000 n 0000960073 00000 n 0000120226 00000 n 0000122565 00000 n 0000960253 00000 n 0000122588 00000 n 0000125170 00000 n 0000960441 00000 n 0000125193 00000 n 0000127409 00000 n 0000960593 00000 n 0000127432 00000 n 0000129695 00000 n 0000129718 00000 n 0000137097 00000 n 0000960773 00000 n 0000137120 00000 n 0000139338 00000 n 0000960925 00000 n 0000139361 00000 n 0000140098 00000 n 0000961077 00000 n 0000140120 00000 n 0000142623 00000 n 0000961265 00000 n 0000142646 00000 n 0000145172 00000 n 0000961485 00000 n 0000145195 00000 n 0000147778 00000 n 0000961656 00000 n 0000147801 00000 n 0000150130 00000 n 0000961808 00000 n 0000150153 00000 n 0000152443 00000 n 0000961960 00000 n 0000152466 00000 n 0000155136 00000 n 0000962112 00000 n 0000155159 00000 n 0000158144 00000 n 0000962264 00000 n 0000158167 00000 n 0000160641 00000 n 0000962459 00000 n 0000160664 00000 n 0000162324 00000 n 0000165716 00000 n 0000162347 00000 n 0000165693 00000 n 0000169015 00000 n 0000962611 00000 n 0000169038 00000 n 0000171055 00000 n 0000962790 00000 n 0000171078 00000 n 0000172821 00000 n 0000962969 00000 n 0000172844 00000 n 0000173835 00000 n 0000186031 00000 n 0000173857 00000 n 0000186007 00000 n 0000194827 00000 n 0000963156 00000 n 0000194850 00000 n 0000196212 00000 n 0000200918 00000 n 0000198339 00000 n 0000196951 00000 n 0000196235 00000 n 0000196689 00000 n 0000196711 00000 n 0000196930 00000 n 0000197528 00000 n 0000197550 00000 n 0000198317 00000 n 0000199450 00000 n 0000199472 00000 n 0000200895 00000 n 0000963335 00000 n 0000220745 00000 n 0000223547 00000 n 0000963516 00000 n 0000223570 00000 n 0000225153 00000 n 0000963727 00000 n 0000225176 00000 n 0000227558 00000 n 0000963906 00000 n 0000227581 00000 n 0000229954 00000 n 0000964058 00000 n 0000229977 00000 n 0000231855 00000 n 0000231878 00000 n 0000238457 00000 n 0000964229 00000 n 0000238480 00000 n 0000241084 00000 n 0000965072 00000 n 0000241107 00000 n 0000243637 00000 n 0000245850 00000 n 0000243660 00000 n 0000245828 00000 n 0000248046 00000 n 0000965276 00000 n 0000248068 00000 n 0000250656 00000 n 0000965455 00000 n 0000250679 00000 n 0000253173 00000 n 0000259139 00000 n 0000253196 00000 n 0000965650 00000 n 0000262654 00000 n 0000264906 00000 n 0000268004 00000 n 0000264929 00000 n 0000965802 00000 n 0000272148 00000 n 0000274243 00000 n 0000274266 00000 n 0000966013 00000 n 0000275940 00000 n 0000278006 00000 n 0000966165 00000 n 0000278029 00000 n 0000278478 00000 n 0000278500 00000 n 0000285174 00000 n 0000966336 00000 n 0000285197 00000 n 0000287533 00000 n 0000966523 00000 n 0000287556 00000 n 0000288792 00000 n 0000288815 00000 n 0000293055 00000 n 0000966694 00000 n 0000293078 00000 n 0000295099 00000 n 0000966846 00000 n 0000295122 00000 n 0000297137 00000 n 0000297160 00000 n 0000298280 00000 n 0000967026 00000 n 0000298302 00000 n 0000300581 00000 n 0000300604 00000 n 0000303371 00000 n 0000967206 00000 n 0000303393 00000 n 0000305541 00000 n 0000305564 00000 n 0000308569 00000 n 0000967385 00000 n 0000308592 00000 n 0000310090 00000 n 0000310113 00000 n 0000316865 00000 n 0000967537 00000 n 0000316888 00000 n 0000318671 00000 n 0000318694 00000 n 0000321124 00000 n 0000967716 00000 n 0000321147 00000 n 0000322997 00000 n 0000323020 00000 n 0000967868 00000 n 0000360278 00000 n 0000362089 00000 n 0000362112 00000 n 0000365053 00000 n 0000968039 00000 n 0000365075 00000 n 0000366855 00000 n 0000366878 00000 n 0000371956 00000 n 0000968210 00000 n 0000371979 00000 n 0000374124 00000 n 0000374147 00000 n 0000377250 00000 n 0000968362 00000 n 0000377273 00000 n 0000379045 00000 n 0000968533 00000 n 0000379068 00000 n 0000380993 00000 n 0000381016 00000 n 0000389359 00000 n 0000968712 00000 n 0000389382 00000 n 0000391389 00000 n 0000391412 00000 n 0000394778 00000 n 0000968891 00000 n 0000394801 00000 n 0000396370 00000 n 0000396393 00000 n 0000969043 00000 n 0000428652 00000 n 0000429379 00000 n 0000429401 00000 n 0000438575 00000 n 0000969214 00000 n 0000438598 00000 n 0000440789 00000 n 0000969409 00000 n 0000440812 00000 n 0000442835 00000 n 0000442858 00000 n 0000969588 00000 n 0000453100 00000 n 0000455671 00000 n 0000969740 00000 n 0000455694 00000 n 0000457656 00000 n 0000457679 00000 n 0000462836 00000 n 0000969935 00000 n 0000462859 00000 n 0000464995 00000 n 0000970114 00000 n 0000465018 00000 n 0000466690 00000 n 0000466713 00000 n 0000470747 00000 n 0000970285 00000 n 0000470770 00000 n 0000472833 00000 n 0000472856 00000 n 0000970473 00000 n 0000492822 00000 n 0000494738 00000 n 0000494761 00000 n 0000499425 00000 n 0000970652 00000 n 0000499448 00000 n 0000501261 00000 n 0000501284 00000 n 0000504560 00000 n 0000970804 00000 n 0000504583 00000 n 0000506373 00000 n 0000506396 00000 n 0000508489 00000 n 0000970983 00000 n 0000508512 00000 n 0000510830 00000 n 0000510853 00000 n 0000515792 00000 n 0000971154 00000 n 0000515815 00000 n 0000518000 00000 n 0000971333 00000 n 0000518023 00000 n 0000519684 00000 n 0000519707 00000 n 0000523814 00000 n 0000971485 00000 n 0000523837 00000 n 0000525301 00000 n 0000528364 00000 n 0000525324 00000 n 0000528341 00000 n 0000534133 00000 n 0000971637 00000 n 0000534156 00000 n 0000535678 00000 n 0000538617 00000 n 0000535701 00000 n 0000538595 00000 n 0000541853 00000 n 0000971789 00000 n 0000541876 00000 n 0000543701 00000 n 0000543724 00000 n 0000547236 00000 n 0000971941 00000 n 0000547259 00000 n 0000548942 00000 n 0000548965 00000 n 0000554293 00000 n 0000972120 00000 n 0000554316 00000 n 0000556577 00000 n 0000972291 00000 n 0000556600 00000 n 0000559444 00000 n 0000972443 00000 n 0000559467 00000 n 0000561116 00000 n 0000561139 00000 n 0000566877 00000 n 0000972595 00000 n 0000566900 00000 n 0000568157 00000 n 0000972747 00000 n 0000568180 00000 n 0000569911 00000 n 0000569934 00000 n 0000575290 00000 n 0000972918 00000 n 0000575313 00000 n 0000578055 00000 n 0000578078 00000 n 0000580147 00000 n 0000973153 00000 n 0000580168 00000 n 0000581857 00000 n 0000584121 00000 n 0000583004 00000 n 0000581880 00000 n 0000582656 00000 n 0000582678 00000 n 0000582982 00000 n 0000583774 00000 n 0000583796 00000 n 0000584099 00000 n 0000593936 00000 n 0000973305 00000 n 0000593959 00000 n 0000596634 00000 n 0000596657 00000 n 0000597093 00000 n 0000597115 00000 n 0000597325 00000 n 0000973457 00000 n 0000597346 00000 n 0000599988 00000 n 0000600011 00000 n 0000600852 00000 n 0000600874 00000 n 0000601069 00000 n 0000973609 00000 n 0000601090 00000 n 0000603709 00000 n 0000973761 00000 n 0000603732 00000 n 0000606394 00000 n 0000607012 00000 n 0000606417 00000 n 0000606759 00000 n 0000606781 00000 n 0000606991 00000 n 0000609078 00000 n 0000973913 00000 n 0000609099 00000 n 0000611596 00000 n 0000974065 00000 n 0000611619 00000 n 0000614230 00000 n 0000974217 00000 n 0000614253 00000 n 0000617012 00000 n 0000974369 00000 n 0000617035 00000 n 0000618891 00000 n 0000974540 00000 n 0000618914 00000 n 0000621066 00000 n 0000621089 00000 n 0000633662 00000 n 0000974692 00000 n 0000633686 00000 n 0000635643 00000 n 0000974863 00000 n 0000635666 00000 n 0000636906 00000 n 0000636929 00000 n 0000642048 00000 n 0000975034 00000 n 0000642071 00000 n 0000643081 00000 n 0000975186 00000 n 0000643103 00000 n 0000644377 00000 n 0000975338 00000 n 0000644400 00000 n 0000645477 00000 n 0000975490 00000 n 0000645500 00000 n 0000647559 00000 n 0000975661 00000 n 0000647582 00000 n 0000649861 00000 n 0000975840 00000 n 0000649884 00000 n 0000652337 00000 n 0000976019 00000 n 0000652360 00000 n 0000654928 00000 n 0000976171 00000 n 0000654951 00000 n 0000657672 00000 n 0000976323 00000 n 0000657695 00000 n 0000659773 00000 n 0000976494 00000 n 0000659796 00000 n 0000661723 00000 n 0000976646 00000 n 0000661746 00000 n 0000663418 00000 n 0000663441 00000 n 0000670773 00000 n 0000976798 00000 n 0000670796 00000 n 0000673269 00000 n 0000976969 00000 n 0000673292 00000 n 0000675157 00000 n 0000675180 00000 n 0000677290 00000 n 0000977121 00000 n 0000677312 00000 n 0000678828 00000 n 0000678851 00000 n 0000682235 00000 n 0000977292 00000 n 0000682258 00000 n 0000684228 00000 n 0000688739 00000 n 0000686507 00000 n 0000684251 00000 n 0000686485 00000 n 0000688717 00000 n 0000691153 00000 n 0000977471 00000 n 0000691175 00000 n 0000693259 00000 n 0000696162 00000 n 0000693282 00000 n 0000696140 00000 n 0000699091 00000 n 0000977623 00000 n 0000699113 00000 n 0000699685 00000 n 0000703761 00000 n 0000699707 00000 n 0000703738 00000 n 0000706515 00000 n 0000977775 00000 n 0000706537 00000 n 0000708468 00000 n 0000977954 00000 n 0000708491 00000 n 0000710167 00000 n 0000978106 00000 n 0000710190 00000 n 0000713025 00000 n 0000978278 00000 n 0000713048 00000 n 0000715836 00000 n 0000978450 00000 n 0000715859 00000 n 0000718318 00000 n 0000978602 00000 n 0000718341 00000 n 0000720841 00000 n 0000978754 00000 n 0000720864 00000 n 0000723770 00000 n 0000978906 00000 n 0000723793 00000 n 0000726944 00000 n 0000979058 00000 n 0000726967 00000 n 0000727759 00000 n 0001012449 00000 n 0001012592 00000 n 0001012711 00000 n 0001012832 00000 n 0001012953 00000 n 0001013070 00000 n 0001013191 00000 n 0001013310 00000 n 0001013429 00000 n 0001013546 00000 n 0001013665 00000 n 0001013786 00000 n 0001013905 00000 n 0001014022 00000 n 0001014141 00000 n 0001014260 00000 n 0001014381 00000 n 0001014502 00000 n 0001014619 00000 n 0001014738 00000 n 0001014857 00000 n 0001014976 00000 n 0001015095 00000 n 0001015212 00000 n 0001015331 00000 n 0001015452 00000 n 0001015573 00000 n 0001015692 00000 n 0001015811 00000 n 0001015930 00000 n 0001016049 00000 n 0001016168 00000 n 0001016287 00000 n 0001016404 00000 n 0001016521 00000 n 0001016639 00000 n 0001016758 00000 n 0001016877 00000 n 0001016994 00000 n 0001017113 00000 n 0001017232 00000 n 0001017351 00000 n 0001017470 00000 n 0001017589 00000 n 0001017708 00000 n 0001017827 00000 n 0001017948 00000 n 0001018069 00000 n 0001018186 00000 n 0001018305 00000 n 0001018424 00000 n 0001018543 00000 n 0001018662 00000 n 0001018779 00000 n 0001018898 00000 n 0001019019 00000 n 0001019140 00000 n 0001019261 00000 n 0001019378 00000 n 0001019497 00000 n 0001019618 00000 n 0001019739 00000 n 0001019858 00000 n 0001019977 00000 n 0001020094 00000 n 0001020215 00000 n 0001020334 00000 n 0001020455 00000 n 0001020574 00000 n 0001020691 00000 n 0001020812 00000 n 0001020931 00000 n 0001021052 00000 n 0001021169 00000 n 0001021288 00000 n 0001021408 00000 n 0001021529 00000 n 0001021650 00000 n 0001021771 00000 n 0001021892 00000 n 0001022013 00000 n 0001022132 00000 n 0001022251 00000 n 0001022370 00000 n 0001022491 00000 n 0001022610 00000 n 0001022731 00000 n 0001022850 00000 n 0001022969 00000 n 0001023090 00000 n 0001023209 00000 n 0001023328 00000 n 0001023447 00000 n 0001023566 00000 n 0001023683 00000 n 0001023802 00000 n 0001023919 00000 n 0001024038 00000 n 0001024159 00000 n 0001024280 00000 n 0001024401 00000 n 0001024520 00000 n 0001024639 00000 n 0001024758 00000 n 0001024879 00000 n 0001024998 00000 n 0001025117 00000 n 0001025236 00000 n 0001025355 00000 n 0001025474 00000 n 0001025595 00000 n 0001025712 00000 n 0001025831 00000 n 0001025947 00000 n 0001026066 00000 n 0001026185 00000 n 0001026306 00000 n 0001026427 00000 n 0001026544 00000 n 0001026663 00000 n 0001026782 00000 n 0001026900 00000 n 0001027020 00000 n 0001027136 00000 n 0001027254 00000 n 0001027372 00000 n 0001027492 00000 n 0001027612 00000 n 0001027732 00000 n 0001027852 00000 n 0001027970 00000 n 0001028090 00000 n 0001028210 00000 n 0001028328 00000 n 0001028448 00000 n 0001028566 00000 n 0001028686 00000 n 0001028806 00000 n 0001028926 00000 n 0001029044 00000 n 0001029162 00000 n 0001029280 00000 n 0001029400 00000 n 0001029518 00000 n 0001029634 00000 n 0001029754 00000 n 0001029872 00000 n 0001030059 00000 n 0001030244 00000 n 0001030398 00000 n 0001030561 00000 n 0001030704 00000 n 0001030850 00000 n 0001030995 00000 n 0001031112 00000 n 0001031229 00000 n 0001031346 00000 n 0001031467 00000 n 0001031588 00000 n 0001031709 00000 n 0001031824 00000 n 0001031945 00000 n 0001032066 00000 n 0001032187 00000 n 0001032308 00000 n 0001032427 00000 n 0001032544 00000 n 0001032659 00000 n 0001032774 00000 n 0001032889 00000 n 0001033006 00000 n 0001033121 00000 n 0001033238 00000 n 0001033359 00000 n 0001033480 00000 n 0001033599 00000 n 0001033720 00000 n 0001033839 00000 n 0001033960 00000 n 0001034075 00000 n 0001034196 00000 n 0001034313 00000 n 0001034430 00000 n 0001034547 00000 n 0001034668 00000 n 0001034789 00000 n 0001034910 00000 n 0001035031 00000 n 0001035152 00000 n 0001035267 00000 n 0001035386 00000 n 0001035503 00000 n 0001035620 00000 n 0001035735 00000 n 0001035850 00000 n 0001035971 00000 n 0001036092 00000 n 0001036209 00000 n 0001036330 00000 n 0001036447 00000 n 0001036564 00000 n 0001036679 00000 n 0001036794 00000 n 0001036909 00000 n 0001037024 00000 n 0001037141 00000 n 0001037256 00000 n 0001037373 00000 n 0001037488 00000 n 0001037605 00000 n 0001037720 00000 n 0001037835 00000 n 0001037950 00000 n 0001038067 00000 n 0001038184 00000 n 0001038299 00000 n 0001038416 00000 n 0001038533 00000 n 0001038650 00000 n 0001038765 00000 n 0001038882 00000 n 0001038999 00000 n 0001039116 00000 n 0001039229 00000 n 0001039344 00000 n 0001039461 00000 n 0001039580 00000 n 0001039697 00000 n 0001039816 00000 n 0001039931 00000 n 0001040048 00000 n 0001040165 00000 n 0001040280 00000 n 0001040393 00000 n 0001040508 00000 n 0001040623 00000 n 0001040740 00000 n 0001040857 00000 n 0001040974 00000 n 0001041091 00000 n 0001041212 00000 n 0001041331 00000 n 0001041450 00000 n 0001041571 00000 n 0001041690 00000 n 0001041811 00000 n 0001041932 00000 n 0001042053 00000 n 0001042174 00000 n 0001042295 00000 n 0001042416 00000 n 0001042537 00000 n 0001042658 00000 n 0001042773 00000 n 0001042894 00000 n 0001043009 00000 n 0001043125 00000 n 0001043242 00000 n 0001043363 00000 n 0001043481 00000 n 0001043601 00000 n 0001043721 00000 n 0001043841 00000 n 0001043961 00000 n 0001044077 00000 n 0001044197 00000 n 0001044315 00000 n 0001044429 00000 n 0001044545 00000 n 0001044665 00000 n 0001044783 00000 n 0001044903 00000 n 0001045015 00000 n 0001045135 00000 n 0001045255 00000 n 0001045375 00000 n 0001045495 00000 n 0001045613 00000 n 0001045734 00000 n 0001045853 00000 n 0001045970 00000 n 0001046087 00000 n 0001046206 00000 n 0001046327 00000 n 0001046446 00000 n 0001046565 00000 n 0001046686 00000 n 0001046805 00000 n 0001046926 00000 n 0001047047 00000 n 0001047168 00000 n 0001047289 00000 n 0001047410 00000 n 0001047529 00000 n 0001047645 00000 n 0001047763 00000 n 0001047883 00000 n 0001048003 00000 n 0001048122 00000 n 0001048241 00000 n 0001048361 00000 n 0001048480 00000 n 0001048599 00000 n 0001048720 00000 n 0001048838 00000 n 0001048958 00000 n 0001049074 00000 n 0001049190 00000 n 0001049306 00000 n 0001049422 00000 n 0001049543 00000 n 0001049664 00000 n 0001049783 00000 n 0001049902 00000 n 0001050017 00000 n 0001050132 00000 n 0001050247 00000 n 0001050362 00000 n 0001050479 00000 n 0001050594 00000 n 0001050711 00000 n 0001050826 00000 n 0001050941 00000 n 0001051054 00000 n 0001051171 00000 n 0001051286 00000 n 0001051403 00000 n 0001051518 00000 n 0001051635 00000 n 0001051750 00000 n 0001051863 00000 n 0001051978 00000 n 0001052093 00000 n 0001052210 00000 n 0001052327 00000 n 0001052442 00000 n 0001052559 00000 n 0001052676 00000 n 0001052793 00000 n 0001052908 00000 n 0001053025 00000 n 0001053142 00000 n 0001053259 00000 n 0001053374 00000 n 0001053489 00000 n 0001053606 00000 n 0001053725 00000 n 0001053840 00000 n 0001053959 00000 n 0001054072 00000 n 0001054189 00000 n 0001054306 00000 n 0001054421 00000 n 0001054536 00000 n 0001054651 00000 n 0001054768 00000 n 0001054883 00000 n 0001054998 00000 n 0001055115 00000 n 0001055230 00000 n 0001055347 00000 n 0001055466 00000 n 0001055585 00000 n 0001055706 00000 n 0001055827 00000 n 0001055944 00000 n 0001056061 00000 n 0001056178 00000 n 0001056295 00000 n 0001056412 00000 n 0001056529 00000 n 0001056644 00000 n 0001056760 00000 n 0001056878 00000 n 0001056997 00000 n 0001057110 00000 n 0001057225 00000 n 0001057345 00000 n 0001057465 00000 n 0001057583 00000 n 0001057699 00000 n 0001057817 00000 n 0001057936 00000 n 0001058057 00000 n 0001058178 00000 n 0001058299 00000 n 0001058414 00000 n 0001058529 00000 n 0001058646 00000 n 0001058764 00000 n 0001058878 00000 n 0001058992 00000 n 0001059111 00000 n 0001059233 00000 n 0001059352 00000 n 0001059469 00000 n 0001059588 00000 n 0001059706 00000 n 0001059824 00000 n 0001059939 00000 n 0001060058 00000 n 0001060180 00000 n 0001060302 00000 n 0001060421 00000 n 0001060540 00000 n 0001060657 00000 n 0001060776 00000 n 0001060894 00000 n 0001061010 00000 n 0001061125 00000 n 0001061243 00000 n 0001061359 00000 n 0001061477 00000 n 0001061597 00000 n 0001061716 00000 n 0001061836 00000 n 0001061952 00000 n 0001062072 00000 n 0001062192 00000 n 0001062314 00000 n 0001062431 00000 n 0001062553 00000 n 0001062675 00000 n 0001062796 00000 n 0001062913 00000 n 0001063035 00000 n 0001063156 00000 n 0001063273 00000 n 0001063397 00000 n 0001063521 00000 n 0001063645 00000 n 0001063769 00000 n 0001011253 00000 n 0000727781 00000 n 0000738593 00000 n 0000738618 00000 n 0000738811 00000 n 0000739153 00000 n 0000739358 00000 n 0000788201 00000 n 0000788226 00000 n 0000788435 00000 n 0000789111 00000 n 0000789642 00000 n 0000818871 00000 n 0000818896 00000 n 0000819094 00000 n 0000819755 00000 n 0000820263 00000 n 0000853516 00000 n 0000853541 00000 n 0000853754 00000 n 0000854322 00000 n 0000854751 00000 n 0000876619 00000 n 0000876644 00000 n 0000876861 00000 n 0000877377 00000 n 0000877759 00000 n 0000908801 00000 n 0000908826 00000 n 0000909034 00000 n 0000909639 00000 n 0000910100 00000 n 0000926752 00000 n 0000926777 00000 n 0000926985 00000 n 0000927400 00000 n 0000927683 00000 n 0000950922 00000 n 0000950947 00000 n 0000951150 00000 n 0000951649 00000 n 0000952010 00000 n 0000952102 00000 n 0000952167 00000 n 0000952314 00000 n 0000979210 00000 n 0000979274 00000 n 0000979458 00000 n 0000979788 00000 n 0000980082 00000 n 0000980308 00000 n 0000980616 00000 n 0000980812 00000 n 0000981018 00000 n 0000981296 00000 n 0000981472 00000 n 0000981690 00000 n 0000981874 00000 n 0000982082 00000 n 0000982314 00000 n 0000982516 00000 n 0000982712 00000 n 0000982912 00000 n 0000983134 00000 n 0000983448 00000 n 0000983648 00000 n 0000983814 00000 n 0000984018 00000 n 0000984298 00000 n 0000984496 00000 n 0000984735 00000 n 0000984937 00000 n 0000985151 00000 n 0000985434 00000 n 0000985729 00000 n 0000985956 00000 n 0000986153 00000 n 0000986344 00000 n 0000986483 00000 n 0000986708 00000 n 0000986889 00000 n 0000987066 00000 n 0000987370 00000 n 0000987647 00000 n 0000987914 00000 n 0000988185 00000 n 0000988472 00000 n 0000988757 00000 n 0000988988 00000 n 0000989177 00000 n 0000989360 00000 n 0000989599 00000 n 0000989832 00000 n 0000990071 00000 n 0000990366 00000 n 0000990527 00000 n 0000990762 00000 n 0000990983 00000 n 0000991146 00000 n 0000991361 00000 n 0000991518 00000 n 0000991759 00000 n 0000991958 00000 n 0000992261 00000 n 0000992584 00000 n 0000992773 00000 n 0000993022 00000 n 0000993219 00000 n 0000993428 00000 n 0000993631 00000 n 0000993848 00000 n 0000994047 00000 n 0000994347 00000 n 0000994607 00000 n 0000994784 00000 n 0000994983 00000 n 0000995178 00000 n 0000995385 00000 n 0000995572 00000 n 0000995763 00000 n 0000995964 00000 n 0000996171 00000 n 0000996356 00000 n 0000996551 00000 n 0000996744 00000 n 0000996939 00000 n 0000997150 00000 n 0000997385 00000 n 0000997622 00000 n 0000997847 00000 n 0000998056 00000 n 0000998245 00000 n 0000998448 00000 n 0000998639 00000 n 0000998834 00000 n 0000999039 00000 n 0000999226 00000 n 0000999421 00000 n 0000999612 00000 n 0000999807 00000 n 0001000000 00000 n 0001000179 00000 n 0001000427 00000 n 0001000606 00000 n 0001000793 00000 n 0001000974 00000 n 0001001185 00000 n 0001001407 00000 n 0001001610 00000 n 0001001843 00000 n 0001002048 00000 n 0001002293 00000 n 0001002520 00000 n 0001002763 00000 n 0001002952 00000 n 0001003161 00000 n 0001003360 00000 n 0001003581 00000 n 0001003802 00000 n 0001004027 00000 n 0001004254 00000 n 0001004441 00000 n 0001004704 00000 n 0001004906 00000 n 0001005125 00000 n 0001005378 00000 n 0001005631 00000 n 0001005900 00000 n 0001006189 00000 n 0001006422 00000 n 0001006723 00000 n 0001006944 00000 n 0001007217 00000 n 0001007416 00000 n 0001007625 00000 n 0001007891 00000 n 0001008092 00000 n 0001008299 00000 n 0001008488 00000 n 0001008687 00000 n 0001008880 00000 n 0001009069 00000 n 0001009252 00000 n 0001009469 00000 n 0001009694 00000 n 0001009917 00000 n 0001010130 00000 n 0001010379 00000 n 0001010612 00000 n 0001010905 00000 n 0001011082 00000 n 0001063889 00000 n 0001064064 00000 n trailer < ] /DocChecksum /92971AA71ED2DC095A160B89E26E05B8 >> startxref 1064412 %%EOF traitsui-4.1.0/docs/source/0000755000175100001440000000000011674463545016610 5ustar ischnellusers00000000000000traitsui-4.1.0/docs/source/_static/0000755000175100001440000000000011674463545020236 5ustar ischnellusers00000000000000traitsui-4.1.0/docs/source/_static/e-logo-rev.png0000644000175100001440000000751111674463545022724 0ustar ischnellusers00000000000000PNG  IHDRoi*sRGB pHYs  tIMELIDATx]ktT>z\$m ȥ!TD jV|_CWph PT\"B$$6aIf9qfB%= By}; vo`!4ChVv[12 !HGiyg):QVd8SmsQAj2~~AH3qU:?!4[a6SRu ǎ7H'1"_Qq!JbBwx$I-S^QO>AO~( HAPU)=Ojjm+ v$~ئ"33zviJn[*.\v(/E1U`Ycֿ&y3g>=x$;GS@]d1YÓo"۾X6n8o2 ,c_܊U?y" "cdL5HfFj~}Q]H錩/Oxcq'~lӕ_ ţeW\| &cLMhdȶ9-՗ $ Θڳ9i˗>xa6>#E _h2$}앿"a\l߰0/"ޑҦ.*:UQyٕ~`:oYfxu? b)<̜>җ'rYgԾ6ngeSMkm>uv" Snhj ̌ry_ݚLM01@$(]vƏ{_{#&>4l|c.8~rK05bjԈm;14*:Ο3yK|ީT\> 8nd٤B]j맻]8#&[5TEUlu#u\/kk^6t=Zo`Ӌ-,R'*EP1#EQ DfsnlOYYYҨ!${G2yZ~\pN|olӋnϯBu-\$5˘TYgNR^\8gF{@|4Ņ0ov2֊^:j)D"zM En1]WfN@wǛ뿨k B|c!>8T'JԉaZxubOW~;c%dLynظedNSt~WX\f-pO',9UI21`xĥd  ,{ER"Z G 4PLq@$#15! G}\.-2kEfV=G15Q&ph!9Ce Cvj(# 5#GX:InHJZmڞU__(h݆' H7cHκ})"Db-&`i\eU?*YJ05 D S[GabDěrqEʪ9կm"4LwtGTدr{OPۿhj?:}"i b:/7yA@eK#$t13mj51K &^w !%PSSSֆlr{s^#w4DmQI S#3a@57Q; S#:į v4yR+A&P0j/))-&Z4S.[Z2d^!j8J01-j(T!05Q)"jԌ+@vpd"'4LuyC͉cv,@A1i_qLq|s4bvGz!U !KIQD1E3[1vI $00h6FL̙dnu˞?SScw\LGaʃcf-N]y/4u: c c PM18_h>4~h޽f l%&N^>?2=iC)9v!˜j>hN'N~(aİ}Wx+' u0?1sL _/>_nH ! x9zq@bzlLؘO_6Ac6~t=F&מc2\汋rh3.婓Jx`x^_>_mqKkj+-++Y.zw3TU+qܹ~M\_:pBI" D5 JcTubd!P%+~fz*EP]6R2;/uz] g,'Nd=C^n188D,dZ}W/)~ǎ/z~*0P]g*ݐ[{s]b76 $?`[퍘JTDDKŽ t "((}qqwZΦO11fZ XSXk71E~;{GbN#"k" r@4˗mrN"srLڀ?Vh?݁nw'?0l۶`bF4]2UU ;llgL bkx'ۄ&%QU#c*B{awE|DǶBhZ-f/wIENDB`traitsui-4.1.0/docs/source/_static/default.css0000644000175100001440000003231211674463545022375 0ustar ischnellusers00000000000000/** * Sphinx Doc Design */ body { font-family: 'Verdana', 'Helvetica', 'Arial', sans-serif; font-size: 100%; background-color: #333333; color: #000; margin: 0; padding: 0; } /* :::: LAYOUT :::: */ div.document { background-color: #24326e; } div.documentwrapper { float: left; width: 100%; } div.bodywrapper { margin: 0 0 0 230px; } div.body { background-color: white; padding: 0 20px 30px 20px; } div.sphinxsidebarwrapper { padding: 10px 5px 0 10px; } div.sphinxsidebar { float: left; width: 230px; margin-left: -100%; font-size: 90%; } p.logo { text-align: center; } div.clearer { clear: both; } div.footer { color: #fff; width: 100%; padding: 9px 0 9px 0; text-align: center; font-size: 75%; } div.footer a { color: #fff; text-decoration: underline; } div.related { background-color: #24326e; color: #fff; width: 100%; height: 30px; line-height: 30px; font-size: 90%; } div.related h3 { display: none; } div.related ul { margin: 0; padding: 0 0 0 10px; list-style: none; } div.related li { display: inline; } div.related li.right { float: right; margin-right: 5px; } div.related a { color: white; } /* ::: TOC :::: */ div.sphinxsidebar h3 { font-family: 'Verdana', 'Helvetica', 'Arial', sans-serif; color: #acafb3; font-size: 1.4em; font-weight: normal; margin: 0; padding: 0; } div.sphinxsidebar h4 { font-family: 'Verdana', 'Helvetica', 'Arial', sans-serif; color: #acafb3; font-size: 1.3em; font-weight: normal; margin: 5px 0 0 0; padding: 0; } div.sphinxsidebar p { color: white; } div.sphinxsidebar p.topless { margin: 5px 10px 10px 10px; } div.sphinxsidebar ul { margin: 10px; padding: 0; list-style: none; color: white; } div.sphinxsidebar ul ul, div.sphinxsidebar ul.want-points { margin-left: 20px; list-style: square; } div.sphinxsidebar ul ul { margin-top: 0; margin-bottom: 0; } div.sphinxsidebar a { color: #fff; } div.sphinxsidebar form { margin-top: 10px; } div.sphinxsidebar input { border: 1px solid #9bbde2; font-family: 'Verdana', 'Helvetica', 'Arial', sans-serif; font-size: 1em; } /* :::: MODULE CLOUD :::: */ div.modulecloud { margin: -5px 10px 5px 10px; padding: 10px; line-height: 160%; border: 1px solid #666666; background-color: #dddddd; } div.modulecloud a { padding: 0 5px 0 5px; } /* :::: SEARCH :::: */ ul.search { margin: 10px 0 0 20px; padding: 0; } ul.search li { padding: 5px 0 5px 20px; background-image: url(file.png); background-repeat: no-repeat; background-position: 0 7px; } ul.search li a { font-weight: bold; } ul.search li div.context { color: #666; margin: 2px 0 0 30px; text-align: left; } ul.keywordmatches li.goodmatch a { font-weight: bold; } /* :::: COMMON FORM STYLES :::: */ div.actions { padding: 5px 10px 5px 10px; border-top: 1px solid #598ec0; border-bottom: 1px solid #598ec0; background-color: #9bbde2; } form dl { color: #333; } form dt { clear: both; float: left; min-width: 110px; margin-right: 10px; padding-top: 2px; } input#homepage { display: none; } div.error { margin: 5px 20px 0 0; padding: 5px; border: 1px solid #db7d46; font-weight: bold; } /* :::: INLINE COMMENTS :::: */ div.inlinecomments { position: absolute; right: 20px; } div.inlinecomments a.bubble { display: block; float: right; background-image: url(style/comment.png); background-repeat: no-repeat; width: 25px; height: 25px; text-align: center; padding-top: 3px; font-size: 0.9em; line-height: 14px; font-weight: bold; color: black; } div.inlinecomments a.bubble span { display: none; } div.inlinecomments a.emptybubble { background-image: url(style/nocomment.png); } div.inlinecomments a.bubble:hover { background-image: url(style/hovercomment.png); text-decoration: none; color: #598ec0; } div.inlinecomments div.comments { float: right; margin: 25px 5px 0 0; max-width: 50em; min-width: 30em; border: 1px solid #598ec0; background-color: #9bbde2; z-index: 150; } div#comments { border: 1px solid #598ec0; margin-top: 20px; } div#comments div.nocomments { padding: 10px; font-weight: bold; } div.inlinecomments div.comments h3, div#comments h3 { margin: 0; padding: 0; background-color: #598ec0; color: white; border: none; padding: 3px; } div.inlinecomments div.comments div.actions { padding: 4px; margin: 0; border-top: none; } div#comments div.comment { margin: 10px; border: 1px solid #598ec0; } div.inlinecomments div.comment h4, div.commentwindow div.comment h4, div#comments div.comment h4 { margin: 10px 0 0 0; background-color: #2eabb0; color: white; border: none; padding: 1px 4px 1px 4px; } div#comments div.comment h4 { margin: 0; } div#comments div.comment h4 a { color: #9bbde2; } div.inlinecomments div.comment div.text, div.commentwindow div.comment div.text, div#comments div.comment div.text { margin: -5px 0 -5px 0; padding: 0 10px 0 10px; } div.inlinecomments div.comment div.meta, div.commentwindow div.comment div.meta, div#comments div.comment div.meta { text-align: right; padding: 2px 10px 2px 0; font-size: 95%; color: #598ec0; border-top: 1px solid #598ec0; background-color: #9bbde2; } div.commentwindow { position: absolute; width: 500px; border: 1px solid #598ec0; background-color: #9bbde2; display: none; z-index: 130; } div.commentwindow h3 { margin: 0; background-color: #598ec0; color: white; border: none; padding: 5px; font-size: 1.5em; cursor: pointer; } div.commentwindow div.actions { margin: 10px -10px 0 -10px; padding: 4px 10px 4px 10px; color: #598ec0; } div.commentwindow div.actions input { border: 1px solid #598ec0; background-color: white; color: #073d61; cursor: pointer; } div.commentwindow div.form { padding: 0 10px 0 10px; } div.commentwindow div.form input, div.commentwindow div.form textarea { border: 1px solid #598ec0; background-color: white; color: black; } div.commentwindow div.error { margin: 10px 5px 10px 5px; background-color: #fff2b0; display: none; } div.commentwindow div.form textarea { width: 99%; } div.commentwindow div.preview { margin: 10px 0 10px 0; background-color: ##9bbde2; padding: 0 1px 1px 25px; } div.commentwindow div.preview h4 { margin: 0 0 -5px -20px; padding: 4px 0 0 4px; color: white; font-size: 1.3em; } div.commentwindow div.preview div.comment { background-color: #f2fbfd; } div.commentwindow div.preview div.comment h4 { margin: 10px 0 0 0!important; padding: 1px 4px 1px 4px!important; font-size: 1.2em; } /* :::: SUGGEST CHANGES :::: */ div#suggest-changes-box input, div#suggest-changes-box textarea { border: 1px solid #666; background-color: white; color: black; } div#suggest-changes-box textarea { width: 99%; height: 400px; } /* :::: PREVIEW :::: */ div.preview { background-image: url(style/preview.png); padding: 0 20px 20px 20px; margin-bottom: 30px; } /* :::: INDEX PAGE :::: */ table.contentstable { width: 90%; } table.contentstable p.biglink { line-height: 150%; } a.biglink { font-size: 1.3em; } span.linkdescr { font-style: italic; padding-top: 5px; font-size: 90%; } /* :::: INDEX STYLES :::: */ table.indextable td { text-align: left; vertical-align: top; } table.indextable dl, table.indextable dd { margin-top: 0; margin-bottom: 0; } table.indextable tr.pcap { height: 10px; } table.indextable tr.cap { margin-top: 10px; background-color: #dddddd; } img.toggler { margin-right: 3px; margin-top: 3px; cursor: pointer; } form.pfform { margin: 10px 0 20px 0; } /* :::: GLOBAL STYLES :::: */ .docwarning { background-color: #fff2b0; padding: 10px; margin: 0 -20px 0 -20px; border-bottom: 1px solid #db7d46; } p.subhead { font-weight: bold; margin-top: 20px; } a { color: #24326e; text-decoration: none; } a:hover { text-decoration: underline; } div.body h1, div.body h2, div.body h3, div.body h4, div.body h5, div.body h6 { font-family: 'Verdana', 'Helvetica', 'Arial', sans-serif; background-color: #dddddd; font-weight: normal; color: #073d61; border-bottom: 1px solid #666; margin: 20px -20px 10px -20px; padding: 3px 0 3px 10px; } div.body h1 { margin-top: 0; font-size: 200%; } div.body h2 { font-size: 160%; } div.body h3 { font-size: 140%; } div.body h4 { font-size: 120%; } div.body h5 { font-size: 110%; } div.body h6 { font-size: 100%; } a.headerlink { color: #edaa1e; font-size: 0.8em; padding: 0 4px 0 4px; text-decoration: none; visibility: hidden; } h1:hover > a.headerlink, h2:hover > a.headerlink, h3:hover > a.headerlink, h4:hover > a.headerlink, h5:hover > a.headerlink, h6:hover > a.headerlink, dt:hover > a.headerlink { visibility: visible; } a.headerlink:hover { background-color: #edaa1e; color: white; } div.body p, div.body dd, div.body li { text-align: left; line-height: 130%; } div.body p.caption { text-align: inherit; } div.body td { text-align: left; } ul.fakelist { list-style: none; margin: 10px 0 10px 20px; padding: 0; } .field-list ul { padding-left: 1em; } .first { margin-top: 0 !important; } /* "Footnotes" heading */ p.rubric { margin-top: 30px; font-weight: bold; } /* "Topics" */ div.topic { background-color: #ddd; border: 1px solid #666; padding: 0 7px 0 7px; margin: 10px 0 10px 0; } p.topic-title { font-size: 1.1em; font-weight: bold; margin-top: 10px; } /* Admonitions */ div.admonition { margin-top: 10px; margin-bottom: 10px; padding: 7px; } div.admonition dt { font-weight: bold; } div.admonition dl { margin-bottom: 0; } div.admonition p { display: inline; } div.seealso { background-color: #fff2b0; border: 1px solid #edaa1e; } div.warning { background-color: #fff2b0; border: 1px solid ##db7d46; } div.note { background-color: #eee; border: 1px solid #666; } p.admonition-title { margin: 0px 10px 5px 0px; font-weight: bold; display: inline; } p.admonition-title:after { content: ":"; } div.body p.centered { text-align: center; margin-top: 25px; } table.docutils { border: 0; } table.docutils td, table.docutils th { padding: 1px 8px 1px 0; border-top: 0; border-left: 0; border-right: 0; border-bottom: 1px solid #a9a6a2; } table.field-list td, table.field-list th { border: 0 !important; } table.footnote td, table.footnote th { border: 0 !important; } .field-list ul { margin: 0; padding-left: 1em; } .field-list p { margin: 0; } dl { margin-bottom: 15px; clear: both; } dd p { margin-top: 0px; } dd ul, dd table { margin-bottom: 10px; } dd { margin-top: 3px; margin-bottom: 10px; margin-left: 30px; } .refcount { color: #24326e; } dt:target, .highlight { background-color: #edaa1e1; } dl.glossary dt { font-weight: bold; font-size: 1.1em; } th { text-align: left; padding-right: 5px; } pre { padding: 5px; background-color: #e6f3ff; color: #333; border: 1px solid #24326e; border-left: none; border-right: none; overflow: auto; } td.linenos pre { padding: 5px 0px; border: 0; background-color: transparent; color: #aaa; } table.highlighttable { margin-left: 0.5em; } table.highlighttable td { padding: 0 0.5em 0 0.5em; } tt { background-color: #ddd; padding: 0 1px 0 1px; font-size: 1.2em; } tt.descname { background-color: transparent; font-weight: bold; font-size: 1.2em; } tt.descclassname { background-color: transparent; } tt.xref, a tt { background-color: transparent; font-weight: bold; } .footnote:target { background-color: #fff2b0 } h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt { background-color: transparent; } .optional { font-size: 1.3em; } .versionmodified { font-style: italic; } form.comment { margin: 0; padding: 10px 30px 10px 30px; background-color: #ddd; } form.comment h3 { background-color: #598ec0; color: white; margin: -10px -30px 10px -30px; padding: 5px; font-size: 1.4em; } form.comment input, form.comment textarea { border: 1px solid #ddd; padding: 2px; font-family: 'Verdana', 'Helvetica', 'Arial', sans-serif; font-size: 100%; } form.comment input[type="text"] { width: 240px; } form.comment textarea { width: 100%; height: 200px; margin-bottom: 10px; } .system-message { background-color: #edaa1e; padding: 5px; border: 3px solid red; } /* :::: PRINT :::: */ @media print { div.document, div.documentwrapper, div.bodywrapper { margin: 0; width : 100%; } div.sphinxsidebar, div.related, div.footer, div#comments div.new-comment-box, #top-link { display: none; } } traitsui-4.1.0/docs/source/_static/et.ico0000644000175100001440000002362611674463545021353 0ustar ischnellusers00000000000000(f 00hvh F00( r5(H73iKD]ZZzols$jV4{H5Fg@Hg @' 9c]sE{c@Ec{bFQEPkG\ 1}m( @_-!p3%7)&[B<]VU~okWU#XW$iU$zu5{j6Yv1GWw"X f$I qJ QJ[JډJc4jJ5{J 1FJ qGI Q#W6 Q$j#XA${#h1IQ$j1< s4{A a5S Q}A\1J7|xp``?`8(0`W,"4(%p3%v>1IGF~QFja_~wtdFwG܆ h즋" ij""!zi"""!g""""ۆ"""""F얋""""""Gzޥ""""""Hi """"" ih s"""""  c"""""! R""""!|2"""!|{2""!|2"1"!5 y@y`"!""" 2""""G s"""""H b"""" i R""""!yR""""!qh2""""0i2""""GR"!z"""""hr"""r"""" """""FB""""#93"""""GB"""""62"""""hp"""""%""""" ht"""""#|"""""!"""""k """""""""""Y s"""""""""8 b"""""""&R"""""%2"""#|2"#k"Y?????( f-t1!j/#i1$n3$j2&r4&s4&s5&u5&]0'`1'^2'u5'v5'v6'x6';+(X2(_2(r4(u6(w7(x7(z7(y8(z8({8(P0)s7)z8){8)|9):*c5,i9-A1.R4.E3/W7/u=1x?2A97>;:{F:F?>{I>mH?DBAMDB~ODJHHOMLhSOQPPPQQSRRUTTaW\YXx_[c[]]]^^^b_^___dddpghhhmhkjijjjrksmnnnrpopppsssuttwwwyyy~{}}}t@4LhO\b$8PraKx_ *?VNdcpI 0M}Wfm:1n{|wFvu2!5yziAUSyxj?]GRryxj>E-BYyzk7l`, %3Jg~Z+DaT)9hzC&6Ooe" [q. *>;'#QX( <H/s=^( @m,6#>%D&K'O(R)P) Y+ q0!2%"`."8'#g1#4($l2%p3%q3%q4%0'&a0&r4&t5&u5&v5&e2'p4't4't5'u5'u6'v6'w6'x6'/)(r6(v6(x7(Y3)z8)v8*l6+2--m:-v;-w>1543Q93v@3lA7vC8;:9wF:><;N?<VA=?>>@??zK@AAAoJAFFF~SHbNIKKKnQKLLLrTMONNPNNZPQQQSRRVVUdXVXWWaWaX[ZZwa\d_^e^i_```iabbbedceedhhhphqh}mipijjjlkkplrlwmoooqpopppxqwrsssyvuwwwyyy{{}}}~~~ŻjjybO =iٙWa"HuihZ!.SWZ% 9bݫXxaBmnczq2 !*NwܐVr-% 3]wt\#%XzF' Dz:  EIv- N}I`')uHYH޾Hn65S|HJ' 9dH<%"DpHs0!.SDe(! ;g9pQ("GuM8b> .Uo0@m~1% KL  *Nwג7%%?4%% 3XжP& +_l,$ =g^/#AT($ ! 1>  )[4 #Ck,1{R(%+_f|xp``?`8(0`<5"=$H&/"S)m-*" -# X+ s0!b."o1"+%#h0#+%$l2$u3$p3%q3%q4%r4%+&&8)&V.&g2&r4&t4&t5&u5&.('O/'t5'u5'v5'u6'v6'q6(v7(y7(o7)}9),+*V2*g4*x9*:.,x;,/..70.C2.z=/211u=1l=2z@3666X?9:::}E:><<PB>~I>AAALAlKCODEEERFIIIUIUJKKK`OKMMMZPRRR\TS^TUUU_WaWYYYs_Zt`[`^^__^g_a``bbaccceeeofhggiiillksknmmpppxptsruuuxvxxxyyy}{y}z{{{|}}}~}~¿ȏՎV)IzEl~zEzEtgzE{=?bzEM+$0LqzE9!$ 8YzE5$CdzEc/$0LtzEW$$ :ZzEG$!Ce|?>$$0Ovo*R}u7$:Zc5 ?ac&!CeD $*JmN$$0R\%$ 4Rxf,! .eF <]v=)6u7!$EeږM'#(Tc-#0Ot׽a+ !AQ$# 8Yvh=$$6jB$ 1!!%Ty7!!!"A`&$6jQ&"%T@$Ay7!$6j`&!%SQ'$A?????traitsui-4.1.0/docs/source/e-logo-rev.png0000644000175100001440000000751111674463545021276 0ustar ischnellusers00000000000000PNG  IHDRoi*sRGB pHYs  tIMELIDATx]ktT>z\$m ȥ!TD jV|_CWph PT\"B$$6aIf9qfB%= By}; vo`!4ChVv[12 !HGiyg):QVd8SmsQAj2~~AH3qU:?!4[a6SRu ǎ7H'1"_Qq!JbBwx$I-S^QO>AO~( HAPU)=Ojjm+ v$~ئ"33zviJn[*.\v(/E1U`Ycֿ&y3g>=x$;GS@]d1YÓo"۾X6n8o2 ,c_܊U?y" "cdL5HfFj~}Q]H錩/Oxcq'~lӕ_ ţeW\| &cLMhdȶ9-՗ $ Θڳ9i˗>xa6>#E _h2$}앿"a\l߰0/"ޑҦ.*:UQyٕ~`:oYfxu? b)<̜>җ'rYgԾ6ngeSMkm>uv" Snhj ̌ry_ݚLM01@$(]vƏ{_{#&>4l|c.8~rK05bjԈm;14*:Ο3yK|ީT\> 8nd٤B]j맻]8#&[5TEUlu#u\/kk^6t=Zo`Ӌ-,R'*EP1#EQ DfsnlOYYYҨ!${G2yZ~\pN|olӋnϯBu-\$5˘TYgNR^\8gF{@|4Ņ0ov2֊^:j)D"zM En1]WfN@wǛ뿨k B|c!>8T'JԉaZxubOW~;c%dLynظedNSt~WX\f-pO',9UI21`xĥd  ,{ER"Z G 4PLq@$#15! G}\.-2kEfV=G15Q&ph!9Ce Cvj(# 5#GX:InHJZmڞU__(h݆' H7cHκ})"Db-&`i\eU?*YJ05 D S[GabDěrqEʪ9կm"4LwtGTدr{OPۿhj?:}"i b:/7yA@eK#$t13mj51K &^w !%PSSSֆlr{s^#w4DmQI S#3a@57Q; S#:į v4yR+A&P0j/))-&Z4S.[Z2d^!j8J01-j(T!05Q)"jԌ+@vpd"'4LuyC͉cv,@A1i_qLq|s4bvGz!U !KIQD1E3[1vI $00h6FL̙dnu˞?SScw\LGaʃcf-N]y/4u: c c PM18_h>4~h޽f l%&N^>?2=iC)9v!˜j>hN'N~(aİ}Wx+' u0?1sL _/>_nH ! x9zq@bzlLؘO_6Ac6~t=F&מc2\汋rh3.婓Jx`x^_>_mqKkj+-++Y.zw3TU+qܹ~M\_:pBI" D5 JcTubd!P%+~fz*EP]6R2;/uz] g,'Nd=C^n188D,dZ}W/)~ǎ/z~*0P]g*ݐ[{s]b76 $?`[퍘JTDDKŽ t "((}qqwZΦO11fZ XSXk71E~;{GbN#"k" r@4˗mrN"srLڀ?Vh?݁nw'?0l۶`bF4]2UU ;llgL bkx'ۄ&%QU#c*B{awE|DǶBhZ-f/wIENDB`traitsui-4.1.0/docs/source/traitsui_user_manual/0000755000175100001440000000000011674463545023047 5ustar ischnellusers00000000000000traitsui-4.1.0/docs/source/traitsui_user_manual/glossary.rst0000644000175100001440000001733411674463545025454 0ustar ischnellusers00000000000000 .. _glossary-of-terms: ============================= Appendix I: Glossary of Terms ============================= .. glossary:: attribute An element of data that is associated with all instances of a given class, and is named at the class level. [19]_ In most cases, attributes are stored and assigned separately for each instance (for the exception, see :term:`class attribute`). Synonyms include "data member" and "instance variable". class attribute An element of data that is associated with a class, and is named at the class level. There is only one value for a class attribute, associated with the class itself. In contrast, for an instance :term:`attribute`, there is a value associated with every instance of a class. command button A button on a window that globally controls the window. Examples include :guilabel:`OK`, :guilabel:`Cancel`, :guilabel:`Apply`, :guilabel:`Revert`, and :guilabel:`Help`. controller The element of the :term:`MVC` ("model-view-controller") design pattern that manages the transfer of information between the data :term:`model` and the :term:`view` used to observe and edit it. dialog box A secondary window whose purpose is for a user to specify additional information when entering a command. editor A user interface component for editing the value of a trait attribute. Each type of trait has a default editor, but you can override this selection with one of a number of editor factories provided by the TraitsUI package. In some cases an editor can include multiple widgets, e.g., a slider and a text box for a Range trait attribute. editor factory An instance of the Traits class EditorFactory. Editor factories generate the actual widgets used in a user interface. You can use an editor factory without knowing what the underlying GUI toolkit is. factory An object used to produce other objects at run time without necessarily assigning them to named variables or attributes. A single factory is often parameterized to produce instances of different classes as needed. Group An object that specifies an ordered set of Items and other Groups for display in a TraitsUI View. Various display options can be specified by means of attributes of this class, including a border, a group label, and the orientation of elements within the Group. An instance of the TraitsUI class Group. Handler A TraitsUI object that implements GUI logic (data manipulation and dynamic window behavior) for one or more user interface windows. A Handler instance fills the role of :term:`controller` in the MVC design pattern. An instance of the TraitsUI class :term:`Handler`. HasTraits A class defined in the Traits package to specify objects whose attributes are typed. That is, any attribute of a HasTraits subclass can be a :term:`trait attribute`. instance A concrete entity belonging to an abstract category such as a class. In object-oriented programming terminology, an entity with allocated memory storage whose structure and behavior are defined by the class to which it belongs. Often called an :term:`object`. Item A non-subdividable element of a Traits user interface specification (View), usually specifying the display options to be used for a single trait attribute. An instance of the TraitsUI class Item. live A term used to describe a window that is linked directly to the underlying model data, so that changes to data in the interface are reflected immediately in the model. A window that is not live displays and manipulates a copy of the model data until the user confirms any changes. livemodal A term used to describe a window that is both :term:`live` and :term:`modal`. MVC A design pattern for interactive software applications. The initials stand for "Model-View-Controller", the three distinct entities prescribed for designing such applications. (See the glossary entries for :term:`model`, :term:`view`, and :term:`controller`.) modal A term used to describe a window that causes the remainder of the application to be suspended, so that the user can interact only with the window until it is closed. model A component of the :term:`MVC` design pattern for interactive software applications. The model consists of the set of classes and objects that define the underlying data of the application, as well as any internal (i.e., non-GUI-related) methods or functions on that data. nonmodal A term used to describe a window that is neither :term:`live` nor :term:`modal`. object Synonym for :term:`instance`. panel A user interface region similar to a window except that it is embedded in a larger window rather than existing independently. predefined trait type Any trait type that is built into the Traits package. subpanel A variation on a :term:`panel` that ignores (i.e., does not display) any command buttons. trait A term used loosely to refer to either a :term:`trait type` or a :term:`trait attribute`. trait attribute An :term:`attribute` whose type is specified and checked by means of the Traits package. trait type A type-checked data type, either built into or implemented by means of the Traits package. Traits An open source package engineered by Enthought, Inc. to perform explicit typing in Python. TraitsUI A high-level user interface toolkit designed to be used with the Traits package. View A template object for constructing a GUI window or panel for editing a set of traits. The structure of a View is defined by one or more Group or Item objects; a number of attributes are defined for specifying display options including height and width, menu bar (if any), and the set of buttons (if any) that are displayed. A member of the TraitsUI class View. view A component of the :term:`MVC` design pattern for interactive software applications. The view component encompasses the visual aspect of the application, as opposed to the underlying data (the :term:`model`) and the application's behavior (the :term:`controller`). ViewElement A View, Group or Item object. The ViewElement class is the parent of all three of these subclasses. widget An interactive element in a graphical user interface, e.g., a scrollbar, button, pull-down menu or text box. wizard An interface composed of a series of :term:`dialog box` windows, usually used to guide a user through an interactive task such as software installation. wx A shorthand term for the low-level GUI toolkit on which TraitsUI and PyFace are currently based (`wxWidgets `_) and its Python wrapper (`wxPython `_). .. rubric:: Footnotes .. [19] This is not always the case in Python, where attributes can be added to individual objects. traitsui-4.1.0/docs/source/traitsui_user_manual/themes.rst0000644000175100001440000001613711674463545025076 0ustar ischnellusers00000000000000.. _traits-ui-themes: ================ TraitsUI Themes ================ Beginning in Traits 3.0, TraitsUI supports using *themes* to customize the appearance of user interfaces, by applying graphical elements extracted from simple images. For example, Figure 8 shows an unthemed Traits user interface. .. figure:: images/unthemed_ui.jpg :alt: Dialog box with standard widgets Figure 8: Unthemed Traits user interface Figure 9 shows the same user interface with a theme applied to it. .. figure:: images/themed_ui1.jpg :alt: Dialog box with blue labels and an orange-outlined heading Figure 9: Themed Traits user interface Figure 10 shows the same user interface with a different theme applied. .. figure:: images/themed_ui2.jpg :alt: Dialog box with tan background and raised widgets and labels Figure 10: Theme Traits user interface with alternate theme Theme Data ---------- All of the data used by TraitsUI for themes is in the form of simple images, a few examples of which are shown in Figure 11: .. image:: images/theme_image1.png :alt: Gray square with rounded, gray, shaded border .. image:: images/theme_image2.png :alt: Yellow square with sharp-cornered, orange, raised border .. figure:: images/theme_image3.png :alt: Green square, raised, with no border Figure 11: Theme images Any type of JPEG or Portable Network Graphics (PNG) file is supported. In particular, PNG files with alpha information allow smooth compositing of multiple theme images. The first image in Figure 11 is an example of a PNG file containing alpha information. That is, the interior of the rectangle is not gray, but transparent, with a thin alpha gradient shadow around its edges. Themeable TraitsUI Elements ---------------------------- Theme information can be applied to the following classes of TraitsUI objects: - :term:`Group` - :term:`Item` - :term:`View` All of these classes have **item_theme** and **label_theme** attributes, which specify the themes for an editor and its label, respectively; the Group class also has a **group_theme** attribute, which specifies the theme for the group itself. These attributes are defined to be Theme traits, which accept values which are either PyFace ImageResource objects, or strings that specify an image file to use. In the case of string values, no path information need be included. The path to the image file is assumed to be the images subdirectory or :file:`images.zip` file located in the same directory as the source file containing the string. [13]_ However, if the string begins with an '@' (at-sign), the string is assumed to be a reference to an image in the default image library provided with PyFace. [14]_ The **item_theme** and **label_theme** attributes are transferred via containment. That is, if an Item object has an **item_theme** defined, that value is used for the Item object's editor. If **item_theme** is not defined on the Item object, the **item_theme** value from the containing Group is used, and so on up to the **item_theme** value on containing View, if necessary. Therefore, it is possible to set the item and label themes for a whole user interface at the view level. The **group_theme** attribute value is not transferred through containment, but nested groups automatically visually inherit the theme of the containing group. You can, of course, explicitly specify theme information at each level of a nested group hierarchy. Adding Themes to a UI --------------------- To add themes to a Traits user interface, you add the theme-related attributes to the View, Group, and Item definitions. Example 10 shows the code for the unthemed user interface shown in Figure 8. .. _example-10-traits-ui-without-themes: .. rubric:: Example 10: TraitsUI without themes .. highlight:: python :linenothreshold: 5 :: # unthemed.py -- Example of a TraitsUI without themes from traits.api import HasTraits, Str, Range, Float, Enum from traitsui.api import View, Group, Item, Label class Test ( HasTraits ): name = Str age = Range( 1, 100 ) weight = Float gender = Enum( 'Male', 'Female' ) view = View( Group( Label( 'An Unthemed Label' ), Item( 'name' ), Item( 'age' ), Item( 'weight' ), Item( 'gender' ) ), title = 'Unthemed TraitsUI', ) Test().configure_traits() Example 11 shows the code for the user interface shown in Figure 9, which is essentially the same as in Example 10, but with theme data added. .. _example-11-traits-ui-with-themese: .. rubric:: Example 11: TraitsUI with themes :: # themed.py -- Example of a TraitsUI with themes from traits.api import HasTraits, Str, Range, Float, Enum from traitsui.api import View, Group, Item, Label from traitsui.wx.themed_text_editor import \ ThemedTextEditor class Test ( HasTraits ): name = Str age = Range( 1, 100 ) weight = Float gender = Enum( 'Male', 'Female' ) view = View( Group( Group( Label( 'A Themed Label', '@GF6' ), Item( 'name' ), Item( 'age' ), Item( 'weight', editor=ThemedTextEditor()), Item( 'gender' ), group_theme = '@GD0' ), group_theme = '@G', item_theme = '@B0B', label_theme = '@BEA' ), title = 'Themed TraitsUI', ) Test().configure_traits() This example uses the following theme-related items: - The **group_theme**, **item_theme**, and **label_theme** attributes are explicitly specified (lines 24 to 26). - The Label constructor (line 17)takes an optional second argument (in this case '@GF6'), which specifies the **item_theme** information for the Label object. (Label is a subclass of Item.) - The item for weight (line 20) uses a ThemedTextEditor factory; this isn't strictly necessary, but illustrates the use of a themed editor factory. For more information on themed editor factories, refer to :ref:`extra-trait-editor-factories`, and to the *Traits API Reference*. - The example contains an extra Group level (line 16), and shows the results of two nested **group_theme** values ('@G' and '@GD0'). The outermost **group_theme** value ('@G') specifies the gray background, while the innermost **group_theme** value ('@GD0') specifies the light gray rectangle drawn over it. This combination demonstrates the automatic compositing of themes, since the rounded rectangle is transparent except where the light gray band appears. - The theme data strings use the '@' prefix to reference images from the default image library. .. rubric:: Footnotes .. [13] This is very similar to the way that PyFace ImageResource objects work when no search path is specified. .. [14] PyFace is provided by the pyface package in the Traits GUI project (not to be confused with the TraitsUI package, traitsui, the subject of this document.) traitsui-4.1.0/docs/source/traitsui_user_manual/tips.rst0000644000175100001440000000520311674463545024560 0ustar ischnellusers00000000000000 .. _tips-tricks-and-gotchas: ======================== Tips, Tricks and Gotchas ======================== Getting and Setting Model View Elements --------------------------------------- For some applications, it can be necessary to retrieve or manipulate the View objects associated with a given model object. The HasTraits class defines two methods for this purpose: trait_views() and trait_view(). .. _trait-views: trait_views() ````````````` The trait_views() method, when called without arguments, returns a list containing the names of all Views defined in the object's class. For example, if **sam** is an object of type SimpleEmployee3 (from :ref:`Example 6 `), the method call ``sam.trait_views()`` returns the list ``['all_view', 'traits_view']``. Alternatively, a call to :samp:`trait_views({view_element_type})` returns a list of all named instances of class *view_element_type* defined in the object's class. The possible values of *view_element_type* are: - :term:`View` - :term:`Group` - :term:`Item` - :term:`ViewElement` - ViewSubElement Thus calling ``trait_views(View)`` is identical to calling ``trait_views()``. Note that the call ``sam.trait_views(Group)`` returns an empty list, even though both of the Views defined in SimpleEmployee contain Groups. This is because only *named* elements are returned by the method. Group and Item are both subclasses of ViewSubElement, while ViewSubElement and View are both subclasses of ViewElement. Thus, a call to ``trait_views(ViewSubElement)`` returns a list of named Items and Groups, while ``trait_views(ViewElement)`` returns a list of named Items, Groups and Views. trait_view() ```````````` The trait_view() method is used for three distinct purposes: - To retrieve the default View associated with an object - To retrieve a particular named ViewElement (i.e., Item, Group or View) - To define a new named ViewElement For example: - ``obj.trait_view()`` returns the default View associated with object *obj*. For example, ``sam.trait_view()`` returns the View object called ``traits_view``. Note that unlike trait_views(), trait_view() returns the View itself, not its name. - ``obj.trait_view('my_view')`` returns the view element named ``my_view`` (or None if ``my_view`` is not defined). - ``obj.trait_view('my_group', Group('a', 'b'))`` defines a Group with the name ``my_group``. Note that although this Group can be retrieved using ``trait_view()``, its name does not appear in the list returned by ``traits_view(Group)``. This is because ``my_group`` is associated with *obj* itself, rather than with its class. traitsui-4.1.0/docs/source/traitsui_user_manual/images/0000755000175100001440000000000011674463545024314 5ustar ischnellusers00000000000000traitsui-4.1.0/docs/source/traitsui_user_manual/images/themed_notebook_open.png0000644000175100001440000001540011674463545031211 0ustar ischnellusers00000000000000PNG  IHDR6IIDATx]A&Ǒ|b `AF/: t!s 5h梓O2Xfp FOutfUvVfVeUk>Ȉȗ* !GKX qŃC"pY7|/'e B;~4 ޿ӧ_/ I3QF&.2{; _]KDΝsR?;FN}3'W_ 6R m@'c]1I0#'ORtG`b`9}n9Os=}{^v|_XLnL6L@1"n1tj'][ D@퉾b# C=3qIE5Et]g N\.y[p6g `u[;vw|f| @Gb{ ؋2˙nyAG-`'.z[]g*i=.-`-^ҷ%jC\ċk=_e=Y"?~8v-E>5Z`/L=b^O]Z`!?6o9qʒLEVTZs:$( &wB'Ljch>g&^)y)(&oƬ1!P&qn,Ne n+78" (kYɁ/0ˠAsmފ?eA&3CQ7c-BD˽}Y o#9$ b2 \}tUND~j\6K~q}[ݻôLeynuk8p2 ]9exT+q$ AN+ڔ7gjՏqJL4]d+Ɂ$ Ml&nM{y$՗b+nfȸ肅ClImkq&4"qCW(;ٵ'k'M z|a= qa Ew); WPrߤ+[v,H% XwCI9ai@ }&@J3Šl w%Mj6LN;rf =g/&. g 7ܾ""--gw(y%X,8e7 V[ i7%W1٪ w`kW#{[&Gr +s.\ڌH@ ]LV 2`/5yIŵ;(r e=n @Bef9q-k[ܥ^b-r%u!+!nX{jaCxf^aK Uɼ.x8=覝7>q&{^S,i尥avb_ NWD;NvƯ%|Y>@\G)?~% -eVje28qF>0UIxCsfN\C>5 k?!JCy耀tG@ĭP: v]!L?@kCsp2*kӯ"Px9r .?wc/@y୫+q Ӛ9e|;;lƮ͋2s'<~[!m,58q3>yRdC2U0pFM A?扈xt'mWK\L k )_F+`O ZuXV*,z{_W,I}< O+kw- FlQv Q[y,[XYkg43Z 7Y7f} r^kڬA4Sۊ-Cp0>B `0oAw B?eA&~C9kx+ܛ)طfL?2CHB0 7#.CZPUGs<03'Vk Y,uem< ܽ>eI[+sp[ñAѴ!nN]֧Tw%9xrZѦ=qs^/VG Pb[ #!B}#cChw$՗b8|aP_aoS6] eA.t2ArMz򍸱f@"-ȸybpriQ!Їqr`Dۮ!kp.t nBnR a?c w!@$^J;qsMem`#&;"4 ok1ظ+KP Jq66 t[|O BDsZ6Yf~]tcO2G krf 4U նzq6%sU !;(~~sQhC\㋖z(>zNDκ@C7C͈ك׫ cK-S%,P3 0-}aHth ]&A~oRn |doj:5j[[_+]Ɂ@ŬjH3]Z' Ȁx-+C6k(w+.ЭRz,7b٤ܲ(.@kZĵn7d8Op:罯xg6#eo96Zvi&3tNA\.֎v6L84K{rôq w+DA#;.//PgrU2W\\aBQVmZ&oS pYu|^=h΀wgFH8q1 Jr)"Rd D] X1wà$"0Uܙt"% ̫@OO W0R(+.A^w|lK!}6/^m/gb9lYLhd 4#̸K18TҺá5%47'"g?ѝL\d ^YZVE\+^mRXc]HOz4ZzƸU2bdmxFwB(,5U*K-F+{$ЊCpQ}lU_?J6] mwp )լC+%/EdMVX0ǍYkC[Û( .ML ;lIY"ƇP]pb ¹$,ד'?H~{ +ܛ)طfL?2CHB0 IsI{=_Oçǡ9Zk@4R8@.`+"qkM))듼Ճ [ FTwhuYXen}J+9Cӊ6[6kp:L,zp\*W#`̃lrqVm"ҐRfO?lpXstմenD`&赨o, jc+7=GB+u: 59ZPh"v&G$c}J69kJ)(hc$D6-n 6Wܘ^C!7)S ʱ $S&' ۄqMw HVt84"nIRb'H2G4 6sc=fV-[KN2h&k<6&pM E\enȑX2G8Pޛd ?ѶZ{|%@q}Ŝa:O'0>|'<(YE|MtmO/'%κ@C7CE=c.B#߱}%,P.qcrhcZĀmѼ81&A~o"74&[]>ƪ2A^WeYn~e*.(2W{dRZpK@+T|Aŵf2(6r e=n @Bebk6),+ K5hZVH\UCSOp给dΫ5.M8??vw$ly]ͪ:@?qX;dȡYeÖzߛ}1L{9E0}b';e~VW\j, YޚX˗K L4[(#ʪZdp|`j.!aߜ;3_#?D`9>qWVyD>+j%"n%jZ[ A@탻V" V}qநyD>+j%"n%jZ[ A@탻V" V}qநyD>+j%"n%jZ[ A@탻V" V}qநyD>+j%"n%jZ[ A@탻V" V}qநyD>+j%"n%jZ[ A@탻V" V}qநyD>+j%|r{^ӿVzWs!P8a⦛MRl@Xqo)Aloѣo,eF}͗,AlY;FS^ĵ2&osvV\!`|z(~mBܘ"c%)Tϟ_/g~+@w0}wfkӯq/.ޠ!0ei"Ͽ\J8^ }_'(*X!#7 /g^\~o["nɈnZf}6R LL,'p힟838ibϞd!1vTavVʪV~VfnOG\ {nze~NSiCW:Vwnx^qnמM3m 9A&,zgX^c|6~/ggy`McX޼g5wRXsRpfl'M`ޜ3MkiDxd3<ǭ&591Ϥ*8ǵ2L1#EQ e¤g3̽[7XVŝ\R|ftJ Rs $BLe4tčg9ăy9Ͼ e >Xsީ:|DxS֠TLy⦛MRl@XqXO ]ܨt> %iZ;L80q\Ov؁k xc{ p=Ua aa=iAyn ]9a4쎀>J1WZ;,D#ö\ka6l2}.t;:woxWZ06eCe줦mmTœÆ5*߲&3r6$(,f$VIt֐`<1 T&r0w&:2r#JBx%դMMl1p"NxRgOlz]%^7ӞN\4R;<|(rK.rx&g`~>$YAjQH#7n`iTRX 졏52f,x]odz%4kJM6!qyϹP @*Nzn6KJ!ae`F($tA?gsj.#hIX<q Z;#y,vYG~~ߘ5fd Z;lq>~ߴvd=a'w Î? "3@hC#p}U!p@=Z;l{V٩sm1e/x'мUC5S+pŶ&P/`?qA>XJ~' a7ͭI7قI+n<`K epBܜoC̼lrЄ{)0pۼ_RJ/{n;^Q3>wWs64yd}5|gUܟ1GI#'[ܤ̏x^9|j$ۤ4IerO*#z2!&nGtMxD1="+g{εvY)~ ^UH7% 2# ۉ׳QqvXRIv$,RZSvgD_h;VLzw6LzwƊ>Sñ}N}NG*3rC}N}N]J4.HDde('ߊ"OcTݬsag/ӿag/ӿhi#m-+8~L2SI,$6A^xñjײDWs2l'ŕi1M֪%5{>gD_>gD_;(cy1_,Jsē'e`wc9Ge;gRtgD4Wa!>8oCUU 9ޝ 9ޝkVu w$QIpvlD* Apy"xAH|qs!c9=/e9`9^Ocpg}N}N~rjp!-ygFVfг.0#Q{$;ag/ӿag/ӿlK")bioH{ R lxxni[֏!7Iaxp2y=?9!gD_>gD_hqag/ӿag/ӿv4Qqag/ӿag/ӿv4Qqag/ӿag/ӿv4Qq7QV|68bR-8os?tIƕ[Z-ʅ-7;mFHȯD_ڏrſD#\ʫTxiRit@Y~WG(ZW,Y?z5Yotᳲg |p 88<\`>5ݬ=pE0uL&}̠.@€X03^EfoUc͵oVYOkmks$Wn,y̥C qǡڝ,v7DJ]^ܢUaoˀ,09j(NtArVwdn7{V*¯u4QCwA?,Gk[u_[kޗ-&Y͹2qqHȈTxxXz-c?౿EcC_,o=G"1/7vWwǨ[?;Xڡimi?o QwǨ w[n.׺'1"l>ndlr_(652v5_*6;c<[?;-cw_ԁ<^;"ц`."#M$g9M\zW?wǨ[?;ԺX,vWwǨ[?;Xڊ౿xxXzQ\O"1/7o Q`;j+[?;-c,V-'g]4e3Hmem1#V?č7ᖇwإ6߲\'q^SOCqPɻl/?]Q?yC Ԯ*ŗ4/B.~bs_Ȳ.~bs_Rp^2$}w;.#P&"EC_<SQ@w?..~bsP>]˹u5s?19/?]MEC_<SQ@w?..~bsP>]˹u5s?19/?]MEC_<SQ@w?..~bsP>]˹u5s?19/?]MEC_<SQ@w?..~bsP>]&?q뜕UPrW0G_t@Y~WG(Z_fQEdXQEQEQEQEQEm*E J^I$`I$wm#ĉqf8' jOqL4}O C*VCՁ6\Kk46sHk 8.ʾҚZh^,+ٔ'V*!'suGY .bg"gO08xhc#t/ xMJT{O ^Dp@FÕF8$ݍ!o5Honگ"F~a+XCDmqǥfRUy43Py3-MiqU &}APQʯ͌笾[Z<:yLkhs O+1`ܦ.=+΍6Xi AU3`UFqOzU/!'stϼ7[T~>\]?Y~>\]?Y~>\]?Y~>\]?YgBYȮt{'?"2k1ȡi_̯+2: ȫה?J?yC Ԯŗ4/@+"Š(((((((4Ն]ŀ0X1?^MYM->;U6;3$GJk}>?H+׬3pĖwR o#qRckWWGG_a7W[>$X͐T ~p ]?=6>?H+׬mw?.x z>?]??c#^z?.mwH+ף#^]?=6>?H+׬mw?.x z>?]??RYDx_7"k;H\^ޭԅXDaGéYO$HJX0x:VŠ(0w^޿S^\[Yq#yDٵU#LZ <&M$j0qš{Wy$|O{iivqi "'<`qT-|{^>w  p t}Au t/Wn.^ n6i%Zx[ ݥܓIw2H%Eڐ Hed|}̆~rqXo uv\F0\^8iJH99 9_kDҲ}/XZrCxg0H$[Yaaw92xV_jZf8[mu@ӇгngQUps^rGҾ7侹{^p,P8yݨ,?Ə9䛸$IEG/a4yX+$<,?Ƌ$<,?Ƌ$<,?Ƌ$<,?Ƌ"Z?(Z+pːGQ{ך|cBE]_?SWduWG(Zt@\5/ViO^p5 5X}@C3U(((()HQ1hn:C{}E$x& wؐ_Tq KЖMJ9FYj$l[tv>jt˳tF浵)IGJd_jk ^};kXa)ެqݸ vX_lԓ6SO‘a $|1y Ki7d~,S.eu@,kIf k3;[T+9P+ҋEdgkʏoQ`5VVz3բ)ikؓY,ԯ,lcnL Fv*$eMPq'8= `7ꎩ6on, Fc+յFonGe䍔~]v1/s]&W.Z`sE T?Ul\|fڭnyox-8y|fNc|cZFXIrsm&'a Ёi7@`ݵ5٭й?CQo**j(AsfBG5'騣k7{`*4_ ~ucBE^sPrWnVa _*+R5"^P+e) (Ȱ(((((na78lsEm/9ĒieFa|ݘ+Z@d!G:yP?w>~a{r0M[tMV `RFчFWRO պ( oClbVMw*$7'vI9jk5"]0_ElZ4SjJ_GrPV;YWT`}5rk;I洖HI{G2@@`8?+ϭAE_CxoѼz7k>=ǣ&ѿYQprGQZ?(Z+>1ȡi_OUVekE]jW՚SQEaEPEPia(5 VSytYU`]K0&5*|A.=0rOEEgȑ @9;Y-iU$&'FB~ok}zlMeqlPj^@7ZdyUyv7|ٓM֠կ6m;VT+ԫ @F9LӴ]*hzw%I<: JJ?g:޹]XGẺTin 5er2Qq'zR7|DcԴ=TeS9!p1 =>M<s 5-֔wQ媯5V_c^[K k}uuaό`myF+hn$y׏ Y}U|[6[fϾZ @Utxfrrt@\u/ViO^>l/͟|u5d>l/͟|u53:A8,^<~ʹHCT2)^Oϻb!w7L_G?#7 p~fJ/ `iyϜ?.6Go%z_4>r<_Y_4WN?#g9]fWN ^A8?3@^l/͟|u ^A8?3G%ziyϜ?.6Go%z_4>r<_Y_4WN?#g9]fWN ^A8?3@^l/͟|u ^A8?3G%ziyϜ?.6Go%z_4>r<_Y_4WN?#g9]fWN ^A8?3@^l/͟|u ^A8?3G%ziyϜ?.6Go%z_4>r2 xJd_O%uEE=B'UU,O@+=E+ib#?yC Ԭ ȫה?JYzJ tVRGi= ɀvoe^:GO^*2T2B1Rkt4[axOHTUk9$ԧ10e6푻v8>զڶPڅ12$~F|l d`wrw~'4 bShZTi"7.I/̓^_K 8N`;Pr@GZ̽Y-ɹӧSt wPTvt8zP:Xkk¥7y8c#ΉE-ɐ䘖 D Fz Tz[\yk մ, 7^dW)`]$>~VǑp&~^۴gWR8ݻZKWX~#UNK\$SFZ4b; I"w 9,!>jQKgi3LIRݰpv-|5jޥj\u}"L$sax]PM=η3]۴%AY's 2 FW=GWhA(UL <()`Rp@5a_ݾcC ;˖˾i ds8f~ MK.IX!AnB~9ӤQ#%Adj>dkZO+͊}8 +<рX Ae{` l2Xg<4t׌=~GQxM Og-];Y i.Gbj>?ͧ\'[}I̱G'7 #63y `)moRmBC=p]D*L`Ar+>W$yR c\UbO? oo:ıJeenxc[/[YX角A#IR1)"R?հo)  /g#KQKrLLdwQs ˪Mmj)k˧(EXveb8;2q4wm5{m?Ғ i9& Sd#,n<sE{z!tX1r酯Fyg#͍#ۛy?pAܸ5'IJfv3Bo $?62wqlkK/ Hn2c 2g1rw |/  4e4rAE+ +L /?_֥{?[Iu{>d"l|rqq;+-kC&q{O=)&K=f8In-\Y)&V ]2 ڀ?\Y[̿ k8K)HoQ#K_0fޕj\ua^Z5C04>XX1 Je`f*A +Ҵ6+n/akƭPR"@r^0GYt@Y>BHС1=A?"ŗ5/Bj*?"?",?w??w? Ṟ,[@ݘt?QMXJ`J>%=кI$|LgoOT;C(;C)ߞޟs>s.ooO{z~j~G~Ep-oOT;C(;C(=?S4ygoEgoE}緧Ə=?S5S?w??w?O緧ƪ}!}!]ߞޟs>s.ooO{z~j~G~Ep-oOT;C(;C(=a8wxJԞ}!dӏg%zSma Nh2^5F[;y[5cX[6ڝ]IB*A   F s ^j~\jh.@0<0u vZuwq\-5W`V(2w\'^^fzuf:e෼>%LAs+ k2kz}Z}ؖKEŞ!BV!GNavաV,Dj <2X #w VI+XдiڵĖNM,AU頒u`Шʤs\nj+EsX2#(MNԻrC!rC3񏝹OT[yÕE,DhEPI>fڅz}\SFIp6 XO#5M~TIt]E,-PD ?|,0aY=?#GO沷{t -+sx끃[OT#jy⵷D9ªI1TnXE Veg IqwPiPvZ̓=2` 8,ztv[3h,@Y;Yi]ЍX3wWi$:Py"kX2dn2/B䲂Aj<1+A鸼,g<4&'eJ; =WMa- Y!ÀQBxʜ{U6ׯhM$FY#0"DnG GQ+ZuMJ!yF9?,4l+XђK,w,GqMrd .0A0yZEŪiv )20VaQuK1&_yys=u NKFYy.ep,pyjl<;.cQ6b92pr|'֓^:P^[?oV֚y!SlC|W3칚[ S77|.@절'מ h$pꑢgcu$W#/SVRYVكI%EexGPP*uw1A[4[M#,3e >zD~/e'lnbk9ĸ툦)q@EWTgiwH*#Nq}?Zb ֯n `άq$!c,sMp[%"8M%gi+Koe%[oα;DUZ@ +7`H'#-c]Z5m|M.q:I#rNx bZ=dV ȍ۵zͨ!qg[{x#R$R w1k6`Yj>B+bѮ5in+;y<#kFT8?0=*]GzV,1\T8) ȨA?yy5ˠ,[E%(/1SQrI☺Ѯ4tLGXc8/`T(I^ZE#ȑȌ6X~WcBE[woZyU_5rndQUٓ]3V>#<=CM]K3ZӟEQEq,Y?z%QNEa G9_ӟEQEӟEQ G9_P G9_ӟEQEӟEQ G9_P G9_ӟEQEӟEQ G9_P G9_ӟEQEӟEQ G9_P G9_ӟEQEӟEQ G9_P G9_ӟEQEӟEQ G9_P G9_ӟEQEӟEQ G9_P G9_ӟEQEӟEQ G9_P G9_q?/DO9}+2?traitsui-4.1.0/docs/source/traitsui_user_manual/images/ui_for_ex13.jpg0000644000175100001440000002440211674463545027143 0ustar ischnellusers00000000000000JFIF``C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222 " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?Wpm`V/oel8!Yr7any8ش mydU&CJc p3:5CNe=tODs־G-sɣvQߡZ3xr%O 34DY[n`DAM`<~Kmƛ +*ZB2r~on%r&wKTc,5Hg;o(ҋ|Ч uco kIcá+vQߡZ_ ƤCvyx YNX! g[ZK:4K$1ȒKf0,nZ̮TEߡG_m~3T[qxFYE%X Hʰ wVp推Pqvz3ON/B8 B4;o(Ӌ|ЬQ9Prqϝi>vVf(9M?8 ?;o+3bT_m~QϥLQʻ)ZߡG_k~fbQʻ)Zߡ]7#鴫Y?) bC\=F0varbe81[N$4kQnjYfǧ eX$o:8' R4[T^m~lE9T{'IҠ[j>iCiIb3 )8 kV.-.ݧ֦*%uznO h39^oז\u|6qm^_y-$P),'`;y#9ڻehOk"iXD/mc^~eqddLvvS[Ċ?KKZR5c¡Ӆ;|Q K5l]QBc2;b0mgecv N+٣u OU%GI ğ?Cć^'SI呢ʭw)}yu,[T~|S6WVݛŲ+J$sO8h[xKGQtIOEdfkgcf$ ۸moU_?K°'iO"sڳ%۲'u_VӋۛ].9T-Txo*(Awejw:8 Q\#sGaVGk{?K°'iO"J3U5_|ɜ1M8omM/Zi;_٘q[pN0;v@è^%ږV1Zlʱ\!2sS°'iO"x\EHI0o]UWwmU*2.yoDW!"RL+oY4;$1B2|߼ÐY!N|`%c^Y2 *[((I&9K ğ?2+u5I~#Vו1|Kae`" ME%,H_[+?K°'iO"h8 0PEcR\'{{g ğ??Xx~'Zk3+N3?K°'iO"|A WgG]+֗d(aOE8#ޏ#޻?V$/Q ğ???1_q~EMvI?z__OE8&&?U$/IQ ğ???1_qMwɪ1Ʒp ~ު¯'O"aDvfU %rLBI&+0KծlXl5zw2Mxnm&+;mj\Kq zo?? aW>-Xկ4X6ީn s׊87N{"凫]Y/umpA|~TЬi⽽Co4Hj xOp>l5 i$̎yg7f>9'IW_E]v-Ш^_L?> 9{ u\uxJhݪ7ς)?}AOKnDc?*`}X79ϛ+ͰcVxZ߫oMuMbu䍿) PȰ1Y֌I+晔q8eF'}Ck{oxO.WW;QaBN'zWacZju;~Nd=]8X>QKG\<1&@n $uo>iO{u+zjMw1.<8ʣu293K}rɅ N꠲l-$-bY|#:'xl=)/ϊޤS[j:KFJstZyKKngU,RD_ko܍a>a~S=C@:ޓe ާe|yndqڤ;/]6ȏ'ݖCƿw?sҎ~ȧ7}(뺧T' Q\@QEQEQEWO}TC-d,QY NFP__(N/YEem'W ? `jQY EV_Buo:QfP__(N/YEem'W ? `jQY EV_Buo:QfP__(N/YEem'W ? `jQYG\dZ/fO3^g][ZRM Id9CrLJzv[Seτ)__J:um[P6k&TX%Iv+O"Vu ^Romfhnmuul!s֫4}F1#_LrK$1!]@G؅; SxKk(%i-e72CHmnc½ycqrإgʞMB.9IHHNU;p. e]J"ԯmŪZG33Ϊv䙘W' ht(湚yD+ ŤJ̠F.Te-k427ȗXGebv qٲ8x*U5oReOM.aQZF? ZHwDrKEi7QW ? +rKEi7QW ? +rKEi7QW ? +rKEi7QW ? +rKEi7QW ? +rKEi7QW ? +rKEi7QW ? +rK+xB0z֏:y\U##dzewwڵōZf\:WA_G]K]VK+UcwrOA$WfNcjM}h>i,Z_[M$oeA9Ț zf|K/myXMO_J-zk_lE9iG]yu tޥnZ$ƲT[pAGoi/fyaiuZϣO+ drLQqOzwgiu=܊^xUVUbn L{.#ƷZZ8G lv+vQ\7vŚGqXEy#:~.$p88Č5+{WKf)1ʱyUxldX—C;_ij.V_,6]G!pAF:*M,b弳[VUFG2Tv~FTd/ pFy\ޏ];[vieXcde}wM O͐1lʊY I') G"%0Eco6W!..9fz[iyQe H;I:~B%Q??Ȭ]#zv ֍$O n*NrsF M9Kl1 fha$o`M@Q??Ȭ_]PIX"46r7`qp3V.㼌̪64Cц}A -(TtQvs|<g_4bn&qP!IKzwҒ#rp3F_Q??ȬSX ߿ɉ gẁzv- D|O AV`AHA.??ȣU./-fi6u)w8Fr8}>Yv}~f[dI ,<Z.Q??Ȫ:o.mYa8%GPs<ۋ Ǹ -w2+5|gy* -a0_|ҩj펙pI1pʤ ՊA8ppj"9EGP\^[k mS #pqF<}(ߜ"9EGE`I??ȯ4Kx""z'z +}FO2%' 8#yrzWOVyi7m$4d 2vpMm=tmd$ *<<;qN8%i(qx5w25ՙa1Ԕ ڿfcҊm\|!ffy"\!؜#*۴Yi+Hm [X d"I-[$c;\'5[o7o7/ܾFڗ/Qm/e[(ݐ X9DjBL1\ax NhVRCC2Z6l ) PFPwIo7o78/{j_̾B]I􇻹lV>l= I S`BTiഖɯ-; ʰ'yFC*,E!|A̟M|A̟MQϹ}Re$.:̭,Ry"#Ä *0Կ}KGm;UԦK2\DETc'߁\޹=JZ/cWh/$ӥfMpI '( 6##;|A̟M|A̟M R{j_̾Wui6ԆOKFQ|:p J8fBGƻ.[M"Gh`Hy&20P .B9, \,n?'G,n?'Gq__smKtZ Qe-AVR0;מ-…\,n?'G,n?'M`i[Kڗ/yhc4y{O̙@Wºحiut,w-3[6 pM.˨ܬlU72Kc! *hw24w24}K>0Կ})3so%@!i-IJD#!Ѷ/l籓XЦ#vb;nf`n SyXڢ?f;qߙ??f;qߙ?>R{j_̾fM:bXlEEVl$u`@cg[|A̟MqoܾS 8/붍Regj1cKn,nݙ@}>O:F(CT5͐~jUI"L67zfدszj6`s[< .KD WVVk98 Ʃ[CӧȮ^y[L|&xWہpM3%Lsp\mg]ʼnQ<R ˃ b2xdclIѝ͕kk8tB>{ӧ/^x݇/b-@G9qę3gΞ={!Kyep[h=k5]!{8|8 -= ͅl_׍Ps _~֭[jd7 ]JjC7\MB m+{-AE-)]ׯ_}6[jµqeoUjG\T5VUU 3ϸe^oڂ&ɓ'׮]>gN^jS ld y1UQHwŔ-ʟ!礜לykbPݼyyI>O .>}ѣ.AvbW[\ŷoҗ/_vXPޭr'N֢~k#0 %UQrXr"1x͌97mW*\"˗߼y;w$.S?Az&$}'\ mt 8 &oEڥK\fԍ*kT">\Jm#h<'m7#_ygÇsr4,?7_kyK2P' Z>)y&|=)\[2fpWs:/J,x\zUk\=~zhP9݋i˟~7n0BݠEHeӼ蟓!:mq|3MU+q T/yr,)DXѓs9\)p;XBL_Z -C*m ,g= =ْ5)_;!W#Q"ps5: %4ed[[_èU"Aa)KsC>HY%6?'\j-阔ӹK9Lq5˩=+㿫@^M6&ƙţLTk^ۤ/s_~sS`HekuH#FmCrݤ_הVWU uwNs.3rq];\9N"QW4Oiݍw}MCri32F4[Վ2_W=sCn|o7 ɵOQMkת'Yu/s!uQ{O+P\+!V=<i|U72w^{ i=hHU7*ƨqCkT޹wNy|ݍ!V4)i|͗Zu$n_e8d.=ji{e4$ת?cU7ϵ5_C|{Z:^ ɵOuoU;S`|zx;7_i#4$ת?EU72w2_ndMkeG=@qcZbzV4q{xQ{O+P\+!V4njy USy9mwc!u7߷Zu5_CkM㓬i|͗(zѐ\TQW4>ת|;y/=ji{e4$ת?cMU8O!y*|;n}KWNq&2~?̌aZwI* w%<[c#{88?xecGq^`k3K*y/޿Df8pge~z h+++A?}Vt'r=+zA'O~0:LwFp'N8vbFD?.ebM61tUBԪh>x ~G=~xd|5׳3gN<)G m˗/>|,OP=Y7)W>~Ν;O>%ES)MEKiylٳgǏq.gКH6{jaߚȱ\rߚuֵk>|`>Rӟ+ U{6'\ Kt -w?z-m2;^)XWљ=}͛7dÇ}A9uy&WqCܹsW^u Ks>{ c3XNNO,{W,)L[|_ze^3O_ .H\d)vs5Z\qEjC qܜ7n,O9+OSH %5!4'*?}D05O'\YʊdMB+g=6)ÌΎWmHY+m޼yN&l/_,e4m.~ـ> 3P4^8cUln@4ϥaoZ+W:GÞbZLeڌ8Im{P6Q K jp\ Q,zRUl*c@hK%ŋS~!UB4}\o2$rArU4`gdܪw,R%ISLB3ӒTӲ Y5PO)f)AU4m7 ԛ(j!IBP/҄;5S#fe>-n買ZM>qu5的6\~\qRUZkdf7٢ų7:|kQ ^<`~饩4|>׶A󰒝fڴ8)ip㪞CoɫyMa-} eI=k{!2KTa?72h1˘@ԎƏkn,fJ=em{r"&HW"*tIіMjFQXΰ.׶! K Puf- o\&ے1dNvjςoyǵ 2ͅ3-¬aI3b R+@xivshF]^ ]Lwm *Yf6jn15IENDB`traitsui-4.1.0/docs/source/traitsui_user_manual/images/list_editors.jpg0000644000175100001440000003255711674463545027536 0ustar ischnellusers00000000000000JFIF``C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222"" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?Aloou;ޱwKQ@T(T :TZD\K3%qRLldu5WR٪Ccn7ep1 OZo种jʬWKa  cy6< OZu8s銊 㺇́ǹpIR?_QOzx֫ G#rqrUl OZw种jEG(^D]@,~* +;RcӀD7Rx~tWsw种j;ֵ]]ʹVvqu7I/2p2H Q w 2 rɍqN.rw种j;ֵ]\l#3jS E2Կْ4Y?QxOzx֫K1GJkGP2@2۶0(3Efہ'80y6< OZu K) AE/zbћ f:gzQf9;ֵG?oZ2OO&.OO&0y6< OZv?r4e?)f8;ֵG?oZ.OO&??,xOzx֨'='kLg0c pO qgþmJmFa&Rmn?r7N9[TG_QȂtYywk|<"DfzӿgV_QG<r 0|;n?r"*?ȣك޳(tY㕽G<TG" MWi\gUPΚV(>o+lQ ѷuoUF*FaR(J ( 5- Qvӯ;F$Oj2^ɗ$rOb}{NUTWyUb6gigk%"xI@aV%݄2a竫Cuk$8',;;O m!D:&AG8^Iqӭ('ػm+[7F"Wp sܚ]\&  pxCqgt$*U3gTn3KKH7DiV/x<3f1Lܪ7$WP݀eA xʌ*#ZO7'}?hx~cvW QWp3'Ԛϵe5ϳ?ٿp\QjkIf45ϳ->Օ֓>hkIf4Z=5sF}+'}?֓>h{jڌVW#ZO7'}?hxϵFoG#ZO7j3Y_i?ƏFoE=W>gڲٿi?ƕ=Žt+*Ei G sSՔ>)sa]KKf%UU~ u/-7=WV?6{ RHꑢfcu$vw̳ĀPj{`DWWIU_G kUӵNg1;-"[is s!R:$xl:8?n>SN+O 1:HQX1b26= 銒º< u d},+a,1 >keE[v5ʯs:RJ{KWm]ILsǧ }:[h Yfu T-?:n$H1He@mi9 bFG҈do#?6DyR3a,~z{ 7 ڶ#hrY r8-EvF2}9QKIEZ1?Uq]6W-cGeKI+ x "rO.wע?_IrO.wע?_IrO.wע?_IrO.wע?_IrO.wע?_IrO.wע?_IrO.wע?_IrO.wע?_IrO.wע?_IrO.wע?_IrO.woAa]/JʸoE46'7kig(w5YH( u/-7=WV?67@w?ԿjP_Xۺ4jQEAEP\Fqkky$):|6pۚN$f ($} tq k~3Hd'= .?t7Pr:/uM[8 ̴ُBbb.N紙|lマq~}UKj vUջ"}ʻ,rç0w4|=.?} O.5 /mn9Z BX.Iiughg6|(c'`r?>O0??4yz\U|;,-=@JnMYhP+pF#Ew/xFn9n{ Khlt;.52?7B BkStmi&9-<ar?4yz\MI$hВ+$셎Ő-8M E+8>YvgcT ŗ'p#-&]`etH?:~;|^V]wʋ[xqwd0|ۢ W!su5FΚڄSCix,F3Z?\ߘ—/Q(} Igjgڢd!Q y~UUIiY/HgǵP*䟗Y9s~c ?\ߘ‹.w}Emݫx٤HR` <1VA.mum5EH$@HGne?1z.EpSφLJRiU 7e\f?7';p=ture?1]ﱯEde?1z.EpkYz.G^A˟Qe.VG^A˟QrYw ƽre?1]ﱯEde?1z.EpkYz.G^A˟Qe.VG^A˟Re?1]ﱋރº_]p"[{ekm,8棫)QEUF*FտºUJ`wS=J(* 8ʰ!+AVFkDvo,8[v`q#$zU_VmCwsj184XUlCnu1+##VSPgͼJ9!s]!\ȬGF#$WF[mo3O$I: rNѯύ7G5hc^F>6?Mh׿9z+#C4}^o&P5謏kc {|l!9Cע>ѯύ7G5hc^F>6?Mh׿9z+#C4}^o&P5謏kc {|l!9Cע>ѯύ7G5hc^F>6?Mh׿9O쫆 ]=_m/ }r@棫)l|ESºUJ`wV ; _[5To(zmL5(Ġ(?ROuMu|ja>p:}Gvy麅\@$gu%hғr1M$H2O)"[MG:= 45e -y@d:r+D(H8t_ګ>ӻZjV3ϵ/jZ6# ,KpUp9e&|;e~ .E "w+_w|3%w{.mo$!Q*SphFq7UGϭ?ƀEfjh_4U[ګ>w|U@\ҢW}n4jh TVoϭ?ƏU[sJ_w|.iQYګ>?W}n4*+7UGϭ?ƀEfjh_4U[ګ>?΃º_]q^&m\j`Pqw vπ(`}WR٪Ccn߃sa]KKf%UUFQXQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEbAӿkG-?+d5ְؖ|EUU7,[idkwW< ; _[5To(zmL46O=Gd/d{'ߣQ?UIE5Or˜?UT5'Vݒ{:u)VcN8ϥS^uGu-p7Qx=ف?U'ߣV&&hnX6"_1#ocjd(5(7e7~Q#O`^?*h*e"}f(tخX :R\xE)EG);X_:*Q O Y v56>*}WR٪Ccn߃sa]KKf%UUFQXQEU+1N 223;fpd<"HRUdpxV*S0\\[Q\UlU{W04O%LQ%خB$HǴ\nQQR]Ơ)3Ư yGzg:%X)xT' >c5E㹹2 p6Jq:YYټRDF#eM#AOP3`*]xkڵ d3%U`]}0)su,p^خW`bjMaݦX&TQM'zKԧqkILԑQWhs9X>|R<&Pp9a偓4Iyl{ƒ/ Km Kg#?wtQv@U :KEQEQEQEQEQEQEQEQEbAӿkG-?+d5ְؖ|EUUF*FտºX%$wIѬJ2X=wS-]ݤ4sq,4h$d Ps:9e]I0[CqngD*'x5++[}K0I'8X#D6DGriGnfXC>77bjϵ+ RQғK;X\KҰl|e{VRSIד0@%C;9ن ]CEDm-Y5vbRJtڄ(NeuvdI$3-`189h|G|jD2Il\XŁc vc"}l\>:dc{1f1Gf2Sߠ# 1QR0((((((((((( c\w?ia];K!Ƶij (G u/-Ȫue`NcFGۺWR٪CcngѠ`YZ̪IY H FImzbXpxxV%$f.c,x$&UH6vN1׽OEQEQEQEQEQEQEQEQEQEQEQEQEQEQEbAӿkG-?+d5ְؖ|EUUF*FտºUJ`wS=J(((((((((((((((((G-?+d5ZWNka,(sa]KKfG⫝SKn`ex76%C\=|=UYVeh5[EynD~fxNaC^M\6 j6 j/׮o*NaC^\w>77NaC^?; z fAsM0>y0>yK51׮o*D>77NaC^?; z fAsM0>y0>yK51׮o*D>77NaC^?; z fAsM0>y0>yK51׮o*D>77NaC^?; z fAsM0>y0>yK51׮o*D>77NaC^?; z fAsM0>y0>yK51׮o*D>77NaC^?; z fAsM0>y0>yK51׮o*D>77NaC^?; z fAsM0>y0>yK51׮o*D>77NaC^?; z fAs3ZkxI#ԥ:J@SnGZ/Em_yxs=w?; z f>jږ.T.]DY.iX/,II84Ka|aA-ƨtraitsui-4.1.0/docs/source/traitsui_user_manual/images/html_code_editor.png0000644000175100001440000004774411674463545030346 0ustar ischnellusers00000000000000PNG  IHDR IDATx mWQ}/$b0XraD)jT`@)gtuD`Q,?j,@̀(J_0"B^>k:s}~^ݫo{ɓ'_>wtd{y矺Vy= F@uGO{{yz\>vǍ}-Ͼ P},+.G?Bhl@;e{l,Q+*2dTt"[Y%jw|yF@ ^rƃݖhYڐfɀ\5'z* 4NF{{{/?X],t#ФM$:ÒdfTK@d;ǞyKN۪3w[tҳۭ굯x}nxlΒ+@IVW J@4_3y'SY}W] %Cy7ݝyM7}L?~ mtyx/hֽܱ+Z"+/~б]wM{큯/IDQMx앾:|hY`Ƚ~a>-|}Nُ~XgKմL4K<.{-@V{>t{?r; OҋNɟ "t{ߍ:ϰ,_vR7{y}Ww?kq:_=R@ %#M+XNѴUM |ԥU??[>vF$}7_?)O,i@`@IƯX_s=րI\e7wH䩻瓧?ؒË_?{k?JjO>:uUigXG?H:_?O_yOOOwOi}gYq}_ !"c *`4CkAq6i0]y5Wd8#j%o Jg?;+ kOzOnݗ=/7կ?Gb6aPϺ}px/Ӷ/`"937uWM==(id bv@ׂ۪ptiw|aȃw3ҜMFw~x嫾ǿ>qK3-ip ЛcEd%SP^ҿ% `3 []7O^N?q;ݯ~]M/"J|I le%AE;+PXcVC$_)>@'5Ds _4[b08u ['J2Ĩ4`Mb@`2wwfg홅<~;sy{ԸMg/k\G~w?3|>Nk߲z \b˟m5|RVm9:EVkhH@@T E|A K<7=1!bκ|2R g}ܳN\׊r}ӷ-яeu<\Zɡ׬O<{|a.h[B=w=:|Dng#׉Hf7W%`?zoLdjڛXh5s&1d"3YJnU$ފ[q<L@M~~]{A삨l~κ{g>Mkt?ɺϒ'yS>+!Xzp{xɔ/%{-'.|/s?_Cu+s}: 8Oe3E|3qR4OPC$`wqAKSeZV>hA57?cؐq=P'LO@?$maj%/O{ť硊λ (ǾOF`P>} !8a?\)\! 0n>ug>7|#9ȍm/=k ϩ'B?\ ww>O'ײwϽ7)rɫ!j%Y7?TW?[%8tS[ QoߴN|"i`C` ~=}}k/j1:=\{ȹvKmĐNw؉>3,u#!G@T>@ q҃oa8? 52DrE%Wܤ {~.4Z=UtKٍ#`s֩}sX3A%N<"X6mJ@`R֤ CC\@`RIa2@gzg̍ P3Cok@AZxG {A5'#GrlyrĮ5#-@ @!в79]0Q_@'u$ t%, äddҙ\IS8xe\Vx@@V(\WH+&1 202$;MFzH5lo@NW4`qJA`t%)Wa#˫%>YD8! FaV.5ΊN+Q52kI'VSGUIQj"W:{$%)֕cN)kC=XK֏MȦ>K"= ,IRF/!3'bSr- )>m5%l3f0V)C}n(WL`IIPM'o$Sb:,7OŻX` )̛)ZJqxVO`'>tvJknk,U|kX.!QO|TCS,}ģC\l{l"5|ȏ9ֹ,{Ɔ@ V|5[yr;YǪnNfG-L SZY3|wmĆtKWc59%zBV9t28%[O?ZhKa-4C XR5h@3 0k"L'`gH@`"DOϐ D@3  П՟!  Xf@??C*@@&4@VT&"`Mi  LD4@ XR5h@3 0k"L'`gH@`"DOϐ D@3  П@`ɿ ȬN:㰦ddU,eN3Z"O?}.MZ,󫁜@8Tv>˄"P`= [ }jCK'0`y)&Yr{?*RbK!X6Dft`HuF D/ H!X!k&a֘QZRǔX`T}zgk,+7|Ցf0 ]#P*XFl3iy/eYf`C'8L |3bF\6H_ ;N`[g! X#, 0<kxTF"`R5XB@gJE@`$H`)  Oў3o=%/eOC`M,/@i [ VL`[­'8W|X PN`tNK^հE'p( SKTI06ds8# zv׆mjJf0'G` Ŷk}KV$n EzVKK`VFj=':DHIpQoRBk"P-Ȳ@`pH)E,u! X#  0k,ԅ'` XR58R BcQ2ixA>F)q+0kڔ 8vABW8\T*'0-؋MǞ,au#I4Yx1) 0#Zȅ! L!XU' D VһBKM@~n9Y;UL ~m`@$0`<z%>8跄!B XJ Xf'`~ h(%`"5)@UJ8@`v지 R>8*]N!OiKP[M @`@kY>,PV G`\ovɏT<c? QņG`[B!¡F T\3f: ^!BLl*`C+#0`ML0%@K!JΥb~>'9cTN`qXؖGfgIgH`\E&CЬ0Y0 pq8hU١7@`@fVg  X5z6 X88j&`|v  `mU١7@`@fVg  X5z64~̭7_ Ú 0? PL*FE  07k3@1j IDATCbTBsh|Oc矸O:o{{f4ZsoK9z;?|].G^~B=<`C {k׽}]O|ȔW^r_\zF!! BQd'韟zӟ-{o}GǾK?ju",G65Yے_/¯g<0 D -XGzUZOGAE^H VaM=o C@^s4sXG, X ڃ XG, X ڃl|~A< P'Һ,9W`I]dN@#x^,I{ӟIlÏ{ds1 0'gX8 Au@:td X8 Au@:t3#g˟`V-0Ő|G{/Fӊ$ 3ڔRޗ:[4ݚT+X)h%R%?%ͪLp&FtG *FflHj)jUZa Z&sD+ %JJc`>uį8:VP [a! hU4?o`^9x R85hRR࠾/"vPF}:H4iF*fade}T$X:o){GNw- F}*C6&$ƣqx|o8-_whTy%,`]N22Ҳ3fa N`VЂ:ZsĠT$X:&59Ww6\MaV0\ٗ.' -2?,?~U"[DDv[`[sڹFa%PчDjoP+%*2PFuR2*^;UVAor3=.|KMIJNTòh a4g]SmC3)4ݜzINF[eK&~Ԗ>^fh ޗJ->"YjśVDR6QҰ:o2Ɯ6OdE0$w5.;gOv'^uokX/?{O?JdU c?qzz;n^cI%@`b-;RU(?-H=! 0%vX%+7CPsY\@:lI@#EP@vk &#P-d f"@`;:@v`,sG9Νr @{;GڹS΂!\rC`਀!/Ӛ'OKdQ<= N~I'>@@ ~pF2VSuPFҩS~o2i3Yhր0)%jMK{(JNd)y$b7ᤑdggS̯Nt6T1V-sGPր̃hNznY{Nd;$Vp"1*PaeeDltح)K_lC9n'Ŷ`Sn 5z${L3+Rb޸?K )?[~@E827f?SG7 *("NHMq[‘oU69pP+3$P-a*pqՈpWQ*N#n@v^cʛ\~ ,+LnTP5C^Jt"} 3CJⵚ`_Sx'P`y (l&&CW|xx @E7gyE!wH& Mf0`;%ge&*H*S!@`(~k= j%F0-L\@:@-%ˈTx/aBx$6A[1FM@`e*au#N7 D찖x;Jϲ!D=C`G X;zY6HZYg(kGO<ˆ TX=^3 Ё@]|IC@EՊg, n~pK@]e:nke3ATtK8z( 6 4z 0(Kea FA+!-JN$ˀ.@v,F2 ]8ˬ+!`D k2kJ X+9,@څ& {UwYGs<8jϸ"M37T_9̨7<|F[\oyL BHo%P`I^b+ɼ,,coPT*F&UP=,,?ٶO{Ĥ]'S`y#.v"t}2/OPGRϨv{3;,?$m3LJ%mD4CӳNPMu̯uuP0Ptkf/)\a-6}Vp D_~DG.<͖nGkO0#V 0&1UlԌ™~v=f`^#vүC[[b &}cZFuR8&S!/~7CQ YtXk9v%%[l^ԮM Pj[IJ0/a9z܂u26{kL0QasH]8+dRtsxeyIw~U"[DjԶC`/B+9 ӓaVKNQ:_~2=PHZb{{Ci} o+ ޟMdpCW9$ ?>{1騼 FPR+_?yHm+KqAq3R%u,rհߧ񾎯1WBԐ, kKm)ޯ՚^ɠTSp\?)q wIǟ||0jOMJl3$>1-26:$l+C>>M1Ii՚FG#\kc?'%٬no7_@m޷MǼ3# Бi3# Бi3# Б@E5*y|dJ*C ~98 xː<R@"4{dH~T5SY3) Й@-% (*!mNŀj&5z6 X88j&`|v  `mU١7@`@fVg aa=강$Pу֐9C ɇBe(OVIoߪm% P`_^$IAjLɚIgV} p!P`!\ j7Q"eF0 V}V& +#$jSbd(HS%3$,Of(/Eok@ouM^&n0F?MogSXZKhokm?viƦ>C`*,Ʉx73Ĕ~@-T~A%X}˫ۖh_ BjX|@` "Xy N]-8O:%Kl%/۔n` I<,K%PkEHp@`0CI!@`l؄ F % Xc> 0k0&`Mx1}|lnovO^oG d(鏋Lt;Hg*TshY 1 +805I$IAj)c{22uSړΦ uEA`IV 2 jKQF}q&mգMaa6 ȡE:>ױi?R0鷀Vu_uv f.`R/CA5HplZk6JxKTշC)jk'ɡ8X|aa)KĀV!X[]W_eLQ{N&^ӭ܂P<65X`q1siscpkM_e˯m:Crueה?q&nJLgbTAv53xy5tz,+ͮɏybۆ!bjkMJx_Dkʨ95'AL N E`j& ->O: 3Cbj *>t)NM27?YӜOfa *nOi}%2 0vXӱf&@''@! Xӱf&@''@! Xӱf&@''!(}LJŹ~y2E0i &Xy?`^!t3 N,OMqX^rA":UC~j jjM ^A:X.3,P/HeZN;^D!=3cfH[ b@`)!X[]υeva4a&}빮!Pea2'apj?Ja@6-arˏ^}Tέ6|a5O3yuY) TH`}ܮ} V?feWBp'A/VX3j[\q_V*bjx 3)Tɡ]:Z|ҟt['Z'MSI!N`IKgM@O3zvtvF+;,gTFKq@`H֐4J/!! XCҤ 0*kT$*g! Q leϵ y3R9,Qx='ݽGGQLIg2]ŶJo* ȖUjEYJxv2XZxSf%lZUf{%j$(◂^Țy/YT ; &(SmWeIHJ9L) Sj%j%vlɏ h8ŧ{["uĆ*!0H y4YbGIv,\f,S(xKU^h, m+t( PZn k`A@fa KѰ< ê A P3Cok@A @5Mţ?57@`F3<%/XH<a%ddc a@P32uxe1]&0+`'3Y A;B.,FbW"0gXM+'(N A_ pY  П՟!  Xf@??C*@@&4@VT&"`Mi  ` =BMCAdC}3RJ=̲VV=WQ^?9'0Ó=!;:MbPh!kj5x3_`ǁ'#)s@IDATgT;~@,-m3OI~Njۤ?8<>^luצ:R::m(ZSe( f j wpċ_~ěG.|[X+>@k>}}ooտOĆr %XMǸ8KbcĤMCZ,gr+Ŷ|jȡwz{M}(1}v9C3}PaCIG@<"$AoejۡU~cH)I:[kZq  ̐\E&Ig&{[RC+bܦM>k%0ۃkʺ ̰o15WfgT١`3EśX k1F! bNB y&K˚an XC,|TO>: CIM+Β aKE`IyjeQgL?8R4R̰nFrs5ID`Ra $ɫU J>LFUebAVH; a2OZ}ߪuq. Q,_z_vm3Pa5Rf*gMSSD!h5 V t=c4~TB:p19P#:T]j-3jM Xqɏ2\D+_%騼zMUS ; JYPp3-bRB`fBGd K|jVZ3|@Fh|ڤ b8Z Z, ̰Z!ł%5m R N`[X k1F! bNB@`1*yKZ@1 XC;QE2t A)3]wn CA02 -Lr5e "0P8R4.xT3lF?E9z,XKwOI*A&pAMY&4>>P%1 RC?* K#wp%롌ʫə$m ZPmj 'ALPC, @]5c%Z|ҟtfR||mj0?fb$I†NB` ̰ueggTƉ"k7 X>}4"`fX4kѧ![:߬&*gEXCҟ=/vCM Uxt OQF`d8 -L$AT{ҭ 0%KwOI*Y(KKRk/i@`X3Vd6AP =aSj !"Xb=md dk;l@6ppL A P3Cok@A @5@j>;l@6ppL A P3Cok@Z^摗[o6@`e6eOrzhݚN9;yeg_r{CkM`T꿼~_:\L]&Ъ^@wuad{о~g}Z! :HU`i#ϙK#]J %G=O&tJ3H :.kjdAjQ"ɦS/wT_GL7LIn;9l֭&#I9-˪| @PB:ϑQ@`Nh,yDjYuO`@0^@ijm]lb5fWGq[AbC},~P@V$dk5f:~#:_}L{;D vWYWbijms =?WW uP5vv^a\w[Uc4\k~-,%FoźToA_RҜ,_|Nt-%j%Mh;_B B)L[c=O}cN~mP&G]/z\҇[<wD<2?̣g@giQ4 0 FۥY:cR@% 8 0k. lM \Nu[w'VN~_2@cwhYk;=ﴱ`?3LFѩ.<=Iɸ3 ЁkΛ:d@`b|g&dIENDB`traitsui-4.1.0/docs/source/traitsui_user_manual/images/delete_item_icon.png0000644000175100001440000000166711674463545030324 0ustar ischnellusers00000000000000PNG  IHDR&u2~IDAT8T_hE{ۤkUisBm,y0}bZ }4T_Bxʞ;Wv}hů~kj5b U93 pdʊaIR\WE8?Bf$1xqC<_yATyk_::4Cley \ kW7 S0|#c ? e &]J/ CO*oƵOݤ-=B%=`}?wwWN]~+IENDB`traitsui-4.1.0/docs/source/traitsui_user_manual/images/themed_text_editor_with_focus.png0000644000175100001440000000471311674463545033141 0ustar ischnellusers00000000000000PNG  IHDRc: IDATx݊E7n,AĐHBA|EN|Ar%>(+˨a@>ً@{3g?{fz?tSUzzDo{k/ R^)UH ,İv'H~v9 ⢖$7j&ɋ%m N#ThֽWERZ׮vtXڽ88C1xΜj<$( 8;/BBNʡx,qHNxd! ;Y~Q9q.3|{VBZ~žM_R^c=) oOM4ҏ7 IGO`*NRVn{:Q++˨N2 u<l!)"mO,"6s]m@V Ak$!JNJ7ߐ_].0eiVg_9(`#3᫤K% sP,v6j&OgOfB=|Ip#xl$%'$G點Rnrkf\:yK[hg6r5#"Y-Q\azE`y( B~B[%EM)O3i“os4Y־?[Ȳ?GO,4Q_ZrC;>(>kM|(SF@>s^#GuQ:i Px۴3,B i2`H-dP@SU|ƐQOE % OU|G* w֭\TF&+FMS# *26r;SfGO ^P/IV BI&$%,DMgC e[EVB8J8V9hx~PߑJKo /nE<UU?qt-4'`GH+[o q 5HDhF4C@ph$KEDH%@ %@" ~R ~rсR x;MUyZOO[tя2_S }Z|YA/x,z@4K~l?ڰ3ea;=Es$0egZ04 ;mֶ>ٶeZ!;>ϒ@iaN䟴S\h ڊ$0aNhRl'ebHJ")zJD! L@5:$pzf7NNZuj9UC] 3~,ΐX3 L@H'Df+Vy?*> 9$09A'&:X[ Id+vғ%$0Q_M N3E jΐ@jϦOiGH>n<!P#Fl@~r5~jϦOiGL=i>|H&9s~\i@,,(O>}<̚$)?A{OnHYqX$L@غו!^pKß] a  ͊4q4  `ߗ@p#'H‘An)nh⁃G?(!rxws("& W;J GBI$6ޟoEM'`R cxPU; W92cIN ) %f0:'Hi~ IJ '=E!+gET mƩC=S֙IENDB`traitsui-4.1.0/docs/source/traitsui_user_manual/images/text_editor_strings.png0000644000175100001440000000707711674463545031140 0ustar ischnellusers00000000000000PNG  IHDRIDATx]=%] a6e(JہAȑ3ٿA8Q 俠(q(8eZ\{^鞚,Cuuu}:{?Ӄx^y| xw/_(~Bמ;geBg߹&E&'? &МKAI /Z~HOE.3g(G'gߞe^٬<{ⅩMY[ç*G9^^zI2 4%ק"]'mUk6~f>&/h{, #=s%+=TҬ,lY[-}RH_gZO=u\|/(06+02E <(!(sYqcs{uP>7_=C*7AKd YPrcX4 ~4ot]~<~1)oOu_d(/N?G?R6L_јSLb:j]S/yѠŏ^;g<ȥ9dB@#xPB QB':1pߖ4ǜݨ|}.]`ױS,}8%j\ϯzǂ,{KwT/3]g~TnlO9}i?ϢǿQ[/ق8.2~ %^=4J/)O!cXKr5t(N_B /F554zFiffJ{,hlLrnElȘ\tw1Q.OzT¹`Q-ƆB1!]:*W7k- 9!(:`mznS,, wlc0 R/BMVaڃcOKcK_ONZV~͞!5H{c4M L8PO j8%FWNA *xZ :$VRs`eML z?=\=НE"GvZ=ED1´uycPloLW_X.=I,é$Û6nwx{RAB!&/SRW4ۿ18G6M@l.C+!Sz1,,x.~bL,1C9LӍQƒ@>XWccn-94E@- ~u9.!-ݰHCC)f 9dyoB {n2$ED6~Է*&k߮N"VA@S 9$?d'aN?}F-nEzkOofG߻jk}lP}\gfCcÏ5-}V"uM5:Evk[uË5\ml#m RrIs^5A~2f[bPqb\H\YB  -Hrd3kKL37S!c!d=K?ڳ6kD>zH˖,YmRN&)l^2nmanSBLmufɍI4/FbbQ?`<nr8mB?tX+iw`xv IkOafXHSo֦T=2f4ӿ~F>ɏY,՘۹%GO@z "<~q;fpcC`= DڼSi5ˮO˾bv<fEh+{kjꊖ+v_= EXO6J[?"K1vQ +@ВK΅.-?7}0 A 6)IENDB`traitsui-4.1.0/docs/source/traitsui_user_manual/images/simple_enum_editor_closed.jpg0000644000175100001440000001056211674463545032236 0ustar ischnellusers00000000000000JFIF``C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222+(" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ??/·^džiLy$&gcI+I5ŏ/m~A|lXe M4̑X/j $_ KTtx18ڦNh_Kzo:>Qc_Kzo9X;D$=G䞛ǫy8̒:(f8zNG?ÿIOMԟKzo5a"n^,56݄ÿIOMԿKzo:.-=Y Z2DpH?43?Ձĵu4$'?;D$=Y. :?|EOHusm P(}fsK?ÿIOMgw/IzbiX4b>K$'?;D$=Y4Xw?G1?Y_KzoXw?G,M;xk?hgw/Iz%=7Vw,M;xk?&<5Q Oiw4;D$=G䞛ǫ;&<5Q N('C4?Kzo?ÿIOM՝ N( cG}C]%=7Q$' cGӿ熱 >P.䞛Ǩ_gӿ熱 ?biXP(}fsG?ÿIOMgw/IzbiX4b>K$'?:䞛Ǫ 3ƶ:kajĂ0,xx|Em895.Y+2V2WG9$'u,lnAboehb{ MɃ>X۵m#2s8w)ݤ<Ř2eSuֳ' s; ?~&V4ŕc 4XC:y8*ǎxW_)0' *E-r &Kd]_?xkV)j#'Tat-|HZL03HygcR]WX4$Z } qʂr19=sڴڃze%RZ\\Q r++gG\JYv9ݑ?^3^s.x$Fި''C{OWeG'9ivi3y(eV9vxb:@MQ!5l`̃s?} p\̗B)W>W(G}Vx~RW>W(G}Q}RW>W(G}Q}RW>W(G}Q}RW>W(G}Q}RW>W(G}Q}RW>W(G}Q}RW>W(G}Q}RW>W(G}Q}RxKG #WzWQL,Ld| rҨx7Mu/`<HQۚ9${n+qUj)'4e٘?lXȦ;@8cޭ!FO$o2ʲYk99S|s.wUňەҋW'%Uj(*E5xI熿kΞ/`Ik`E1D6_6|_ޙ[XY]I )HPXtHj'k_(?Nֿ$W~!Vn]a+7Sȇs]ckYEں o?J  ?%oAs]ckYEں o?J  ?%oAs]ckYEں o?J  ?%o Bv"M_kE|  ?%otr Bv"M_kE|  ?%otr Bv"M_kE|  ?%otr Bv"M_kE|  ?%otr Bv"M_kE|  ?%otr Bv"M_kE|  ?%otr Bv"M_kE|  ?%otr Bv"M_kE|  ?%otr Bv"M_kE|  ?%otr Bv"M_kE|  ?%otr Bv"M_kE|  ?%otr Bv"M_kE|  ?%otr Bv"WC'5 (,yبSm4cf$־utCI[9P\ğ>7i= H9=x4W3[|GM_Vծ>}>d7m(pQT#traitsui-4.1.0/docs/source/traitsui_user_manual/images/ui_for_ex1.jpg0000644000175100001440000002404711674463545027065 0ustar ischnellusers00000000000000JFIF``C    #%$""!&+7/&)4)!"0A149;>>>%.DIC;C  ;("(;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?kY77VŠ6`nO#+]ޫ{8$]KhhO*.X-|)aԗk7*Lr7~#88֣_[pOes?ϬQ+CMc}w ť}oml8<5g:ybFk_+|ya3 gx;T#&aj4F7X?أϬT:vu^EgcyQC8 ZÚV[zr8m9uN.i=3Tdo}`bB/? ꒹TyĮnb #EF-%H8Rx#֒Ú^b[/~ˉ"f`;[ڧQ?cSk1ϭhE>Sޭ:+-VvcGTC#G|uӢQ߱Z];SluZXQ36Bszr37h24k$QR{dx"*Xz1ϭϭGGY++*XnRFA#T[GJ883{JVy<{H3INv>y` ww>wڭ95Mws!$59MqZ%G\)C6Dt)۴ǀ 2OL` Slt8!hTq8HdIU, oqW*IԅhӖYziCui.2yBH@3k<%iw5]<.pq%Ӥ>>o$mr?xbg%{5TXji2tRb; x[; 1. *25+x}Ho5ZZ-ȃBÂ`b26Ardqsڵ^~t'H~k^tE:p4Ɵ܊N&RLɠ$F06ppr26i\SU, U7 ԯz޿?:"Wz|veZ##Z{q'ڍĖV>1g+$4%?RqF.ZUӀ~?ʪ59N1SX["i-!(nB*w2'Z u>(k>̳(OӚ޿?:"8Yie*`$[Ԩ,RVp/?n漘%Vfrl1jV-WZ$RbJ키.{[»OUӫSq[~^ld՜}[Vcڟ$&33J~..et_lI";xU<8+HFӅ} ](wΟn>>E/ٮ]̭~TKK7WA!hK\/'e5»OQ k;JsbjK [WKmx0Y·ZmԓH 䏜w51L!I7H=Ր/Ի1䯉Tj䎚T)8 :yL]&0|/]Jd}7gPDYTV Eu[*EdLO23֮Xȵ'|4-K_M+ xoD(7 Ȗ+ދ"JHє¦ ( ( ("f5"99`sXSZKKSlҖhD!QU}cq_GS_}cq?7.iOUY_!n/]hj=W >ҞecG>At{_(Jzn/]!S_)꿯VW>AtcGrNdt>J7/k{}:_2R["ۈ\/V3^S~itzmr5HћH`29 WGqM6Y[nfx泂U2c+) N(jVq-IJ(o-pG\YZ"ӭ!mGXf%$OԬ7s'G\'ؖ-"渌Y%݆Ŏal5ch-ZS^_N n~E!ÈOC}gZ;jTK#/ +ӌ-!$Vd4ɤItIFhݛs2pKrHkž-FI%ӖT{uBmnpY$`MI8LC4Ѥ8Hmd1 $d\8&3LvAv=дx$ҬV%۠ێJ?!@k:"^{X>%Df! ;C$4n_v-ݠYE mHRhrTⶅ[D g6WL H/x4Ky@ A i^&5X]_OCn;ynkrx7x# 8 E^K;!%F i\wvFxӬm,t  08!>_*t-/ ҬB$nv \Z -o mgH&6dvqo62v[Ks׷O.&" Uᘩ'jo$7'Gi4i֑ċ,̰(2:f8<Ձ K3N#A+Fps($O,Zm#r׃ĭƷk-E ,OLֵ|&IEG'?Ə9=5WB$G.Oor{ChJ*?9=4y} ('?Ƌ |oC5+!5Goտ_ ׯ|sEiu4j_i]upf?u=K !EW QEq.RX-/7ؖieIO-Kx`>\qi\VwtRjJ AV;+G÷oz($Y2̩<.@-EsV~, {S{`o-.P`#ť$XxcvX&WH$K-^5f%f\28f]Er~0?^f:KM4(U Lgpvdkm)PBݺ6NTϻc`#UK홚)3(0xyO&oF%o֑hMf?Mf?MoOxyO&xyO&裕xyO&xyO&裕xyO&xyO&裕xyO&xyO&裕kk}Ye٬AOvbqP8_#~_f~̾/V3^R)j]i"ԿҺ~ȵ/|43῅+*VK Z^L{s^qj&IeidJ-m#GH]CbA#5fiWCp<)$N$N2NNMX364lPcB B;6fYEEpYDH:sZPu΁]K$,cđ9;U܌F\՛}>c5Dp4,QBonP{h%nVͣ/7R l|,l^F˅WQG51Ui=4o|F@&/*kb>cxoѼz7ke>Ѭ_ ǣ&ѿXh?/Qc2L_UϰX=4o|F@&/*kb}ɣxo51T}X G37%;57oտ_ v.۝1c NL)5oտ_ ׳z#C~ȵ/|4-K_M+ XoD(7 ˲MQDk! ) AHX;NzL )&C"+[M[5X eYgWCr~n+mj:wF]O KRWA-gp8rB[[Nɼ۴ ʊch5Mjɧq)iQm+3rfbNIl)mԖ7v%^.P!\oOW{Wǚ\Ьq** E"$B2̮C<*xVŬ-ۀ4Qmnres r8^ۙo61ǮsF2n2tdhi`H#?,'cbSQ+A%WNc*,<p}j樂Bh|@duazg#"-DɎU[$$}(nOX6K&b[]p3uvE7z}:7)ѽ?:ntoO@?OFtپ|oC5̬8`x=_#~_F|߆-K_M+GRJzB(p(׵o m_;q󯮾)k|9 BEhmWe\F]BHOJ7:f-x5 Xf,yQ0UIc dIڢiz 8\F6vn :+ &ﱸ1:ܭY<8?$ WwMKt%U0 dFqmWMkza{  \,p$ ZЮRܓ|5_z?$ W){rOܓ|5_zh.sےφG#CEsܓ|5_z?$ W( #'jG(\ĵԤ-oI-<,|oC5sFe~KriOszOWMyrGTNW[qI(I " z>wx'd#R[>oo&0XԢoo&[,jQYko7Gx5([m_,0 mnO(O)PKsMjUg qgjǗedg5g#\OZT<= <= eWNkUTT@7;Ef$$io?_?_լ#۴X-6N"S1PuPJs[JV,˙.#Gyv^XXe$\[_?ʙTn-YfgS$.p;sEfX_?>Ǭ^/U\{; 2Fa29ՋxnWRuec#-ž,pğŸenws@Z[J΀X20FC(8 9qU~Ǭ^/Uc?/**^躞d`oȲ$e>`2eS1U,M#SdCBsm;<Dc?/*NQ̷6Wzlv3\Jf~=v*q<M*{D1246ko2UKX[Ax T}X_?.=cAx T,`_#~_f{[u@Jųs}J?߫o(9".ais9 zg1'W8ŻrX?1'wƊ)rG&>$onE ?7}hğ4QG${cO ?1'QwƏL|IAE#n ?7}hHğ4cO (wƏL|IAErG&>$onE ?7}hğ4QG${cO ?1'S`L|IAY7N#I,''֊(Kd4traitsui-4.1.0/docs/source/traitsui_user_manual/images/ui_for_ex3.jpg0000644000175100001440000001646411674463545027073 0ustar ischnellusers00000000000000JFIF``C    #%$""!&+7/&)4)!"0A149;>>>%.DIC;C  ;("(;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?kY77VŠ6`nO#+]ޫ{8$]KhhO*.X-|)aԗk7*Lr7~#88֣_[pOes?ϬQ+CMc}w ť}oml8<5g:ybFk_+|ya3 gx;T#&aj4F7X?أϬT:vu^EgcyQC8 ZÚV[zr8m9uN.i=3Tc?"X?أB/bzU"dq+HQaRuy㈙m~eg_o~ϭ|7NfUX$>p3F%i+Hpe;Z~Җ˶Eً߱Go~gV6f.Xep U#'THEyw՛ BPno-P' kJ;}5d mƥ([h$oEsShịO(eYbrO V̗[K'}.h ͬ7h[RHpH[Un9jΝm| t^PyU[kg&,yW23ze<I?G?rN($.Ԋ&D]DJ[ont͒7x#VG1F}Qí?j.wsU,c{4m9o5[qZE dd6{奟c5q左߉j\~{hqxqQ Ek}Tvq|lЅB!ƛ7ۗ3f o~mO^ >cqױBK0µehy'FvVlw_CeD0 N;y#=?JDwĺd1ʉgPS\w<:om'DFDh=zW^tMtIFumѣͥB-x(m,Z^9YpL̊.J;ϴi>6Ardqsڵ^~t'H~k^tE:p4Ɵ܊N&RLɠ$F06ppr26i\SU, U7 ԯz޿?:"Wz|veZ##Z{q'ڍĖV>1g+$4%?RqF.~2ǘ/4EbI\T# UUQu4?ъ?6-~^G̼>aS»OUӫSq[~^ld՜r.(ulf& 9*5ۥ6y ysWE _??G+~tEt,~[b؇ [ڮ.Դ2*Y~.@+OV<%>*i]ynp93= o-X,<^pRz|g??K)p2[uFUWi 5fE9dy+^=FWArα>(@֪O[('M®0 aJF Ա?1‘Y1dW<^m5L(Յ+fdPDZ{+G4 "\F}{/Ի1^'n4x$Kx!靑ވ\Ni*S[E_2+ _j_gHf) moJ{x;si,<zz ¾hUV%dbLDIM)k䥖^:VJNTe{.OMN^|7 oz$ǘS^x;ćML=o1eGQMgN$)2Ē?VG`$am3NJݷ|vF>{|s:w< ?w]c+1{xoD!,5m&MVū[۬sˉoSbyy^[;>a PSX6Y%D#&Ԃ9Ia#n#ṹ"m`%ӣhdgF۷xR%O.5Xk4\\G{/G]pT|y# Ȗ+ދ"JHє‹隞[hua Q>25KN^inZ[Evqp#/r|?l\=ooRLIHʈݽݝnPm-.r=–ޫ9Љ/V`71RʹAuE.acG>AuE.acG>AuE.acG>AuE.acOKԢUI 7F ~;?*٦GgĿk%|xk ?D}{(C{]X a K]yYM0‰ 6[h"6Kdt9$Q\e尶ӭ'HeK$#%'֭\&?co~ڼ+7v󎙡lfh#JAnН͓>(Z>촫+V0ۢя>M#LIZ< DbhD9E1$: Vb򭢏ȏʋj*x|ҚKX\Hϖ ?UswݥB\( 0n}Oob}_L4}_L5w6'?Ʊ>/?>/?/ G7瞙dh7瞙dhCoOor{Ck"zg"zg 9=4y}OxyO&xyO&46UCk"zg R,9NEK +W-־/?DI_8?ZK9kg|0%u@θφוO (v:}\k˄K{υX3q!\v@aPJ]ҹB7yg9- t SPԵ GYG$b)a߂BW.999d&_Z[Iuqkڋ0hLgRv;8#VJ32ǀn@U3clZ$$e/ pyJ>n 4 77ǣ2 I4s8mB8Lr>n -buXeY #}̭ʪo$W^ze$w\#+,39v<,t5cm11AG 7u&Hq'Wd@7`7hj-nYb+HvFgdqrj>0eVV-!yY \+NrBrF]j\p<:Ko$A}ݳ B#6#0nzcˏ4/je>Ѭ_ D+51T}X ] r }X G51UG" 51T}X ] r }X G51UG" 51U%M=lp4_Mn_#ʂ3_^׵qo~wy^"Jž׿ ^_=nIeK붶Iqe&RS߂ryH8 ? w]c++1zQ9O qjvp]%[sypf7sq.{%d1޷$(pPIJTjṹg[[{%ohnL̠ȭ$7 Lc,dn.'(_PH>1^.K{ ! %.^䌙 &SFWn`9άu% p#' ~5v3/b>z?6OG'ѽ?Qd~ty}:9ޟ_Ψ}:loΏ6OG8X?#:`NGzd~ts ?D}K +W-־(Co54_Z5MێtrN((RTNRo-C?祧C _hE/w/iP4((E/ a _h/iP4QG_}?祧C _hcGܿ.,KO?祧CEƏ/]{X"G,KO=_r E=-? &X"E{?ȾAw?czZ?ME=-? &(4}(?czZ?MQh"w/iP4((E/ c& 4m촉IV\991VKXtraitsui-4.1.0/docs/source/traitsui_user_manual/images/read_only_editor.jpg0000644000175100001440000000605411674463545030345 0ustar ischnellusers00000000000000JFIF``C    $.' ",#(7),01444'9=82<.342C  2!!222222222222222222222222222222222222222222222222221(" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ??/·^džiLy$&gcI+I5͏/m~A|lXe M4̑[ȼ?<RDWf;+oo$Roɥ'd4Q_IzoMխuX^Ks*mf)lo/-q A4g.{dY?;D$=K$'h,r`_/䞛ǫ5&QLDe+[%F~e9X;D$=I$'HPI8d9X?;D$=K$'4}^^`4K9cr3Ty*+L nTgI5E8Q#g(b߅lJrZ6(8nnAKgo9+F<ΘH)sa}F{UxK5/"9=`76jfMf(7\F kb!K&Ѽ/@Cw) (((((((((+#UŸHk^5_)a9?w/xIuF;4Vw7=_IO/$h'h__4r0Egcx/ ?WAM.hY+y&o{E;y_]覢~Ѿt<((((((((((((((((((qyVOQ@traitsui-4.1.0/docs/source/traitsui_user_manual/images/notebook_list_editor.jpg0000644000175100001440000002607511674463545031251 0ustar ischnellusers00000000000000JFIF``C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?{-T4mpI?ٿZ8ȑ3FjڴY1ވ%X&0Gx=qkJw,?߶ ?,?߶ a7o\)kW&n 8%93F@G?* dfbUz!?,?߶ ?,?߶ Ҙ٦ב ~bQ e춱%Ķ6FtPTێ8UEM}iӧQ^)"cltH*tL>P+t-6+Xn|gNK~po_/Fudž[x!w7f̘Uu=ZLg erGi!޿_΍n-oR$i7wӒ7d.eVNt4T̖F=sFuU!fcSj\BGxmR be%[7m8'Kegnդ"[hXc1]OڣoʏGߕW29[Y ʠ:ҲeuK BۇF* )T~Rf Ue/ͣXVA2_BKJe0DlI2Y8 7P<2 6]O~ddp?/QaisushUsyyOﭼSui(`kͩna<^Yr 9]ty)?7 h,3W头rY“es{ub֪fPF0JGy}+tWMfo"5K\Z^xDX-WuisFWn87'=;VKw摂qS~o?F CuMV#k.8r7+dg(O >}S5@D39Zoy}u3AIt2.oʒ$Ica#\)*ϒy}SX[\mem+k*4JOD*TsIZ>mOJ6h8Y r:-ORhwoB&(br13slaty)?7o̿<t}}oDCcظ@U: 繭M/cak2YsTJGy}UEZyN~WJm&կ/ne5 $9JƣgO(m[y>P(}Bvs~֯/+I/eK9g|e]Fqx}Nh9~В]%H 1cfp:S~o?<RD ZOⴒd[݃qkigF a~zz{Vגy}u͈Mh֖mJ@t :C݃L0CtL U ]V{kYB(P1 ty)?7cZ4>Fݯr {- Ȉ9#LzAu6Vn1ӂbNo isomokifbfX̛>QaA]3:Πb6 c)GU"M~Q7.8+S~o?<V=nS՞?7gD(*0u;9ncM2IWb:O<%?+UZwjݭ]*5kܫmk5 *&ݜg'j :][7z|%DK$X#W䶊X7o $V9Fp֔aV&Rrs:8jKu!2񝛛vA9j%Ruّ$9y``oVn2?<%?D7KI֬.eE-Jy0T͂;fV;wisml-Ep'ۊOS~o?δUhroӛlWk_]Y5a (lsJ}]7y}bkrS *iTʝ*ME7{=?v$u߲=?>XGaS~,?:oae{tXQMϻ^ٝo/`232(B'A<`,C׿j;k?+7H!losG!?f5#j+ vMХי) /0 M$qȐ"#s9è>*dҼ^*xM녹xnmUAŒV~ xL^-vHY }ŸqU?bmɥr<։G=|=ԦyK7+|ҩ01]k{;t <>Z,:i+ ӣ V,sKT֒wKt޺./zǼοB`KAs3,Rc qڿ?P/*} V^_ (_BUG+m_ף=#"?пk|Q?WzG}jHA@_E/ZrOz>ڿ?P/*} V^_ (_BUG+m_ף=#"?пk|Q?WzG}jHA@_E/ZrOz>ڿ?P/*} V^_ (_BUG+m_ף=#"?пk|Q?WzG}jHA@_E/ZrOz>ڿ?P/*} V^_ (_BUG+m_ף=#"?пk|Q?WzG}jHA@_E/ZrOz>ڿ?P/*} V^_ (_BUG+m_ף=#"?пk|Q?WzG}jHA@_E/ZrOz>ڿ?P/*} V^_ (_BUG+m_ף=#"?пk|QaeTARBuOUm+{XRUTA*?Oٍ:^1T!eך/=,/p+3gLW'x-nַ5/)"F#tIM_iv6ӤIoIgp'pVcY}$oӃZݭ,r¼zʹmwm}{cqqpw6)'v}WEiiUm&%7u sY_iiiζ&?)i}?&?)i}9t4W= 6AKOQ 6AKOQ΂CEsii,t4W= 6AKOQ 6AKOQ΂CEsii,t4W= 6AKOQ 6AKOQ΂CEsii,t4W= 6AKOQ 6AKOQ΂CEsii,t4W= 6AKOQ 6AKOQ΂CEsii,t4W= 6AKOQ 6AKOQ΂CEsii,t4W= 6AKOQ 6AKOQ΂CEsii,t4W= 6AKOQ 6AKOQ΂CEsii,t4W= 6AKOQ 6AKOQ΂CEsii,t4W= 6AKOQ 6AKOQ΂CEsii,t4W= 6AKOQ 6AKOQ΂CEsii,t4W= 6AKOQ 6AKOQ΂CEsii,k? ̓BuOU[R9eӡ皯uOn oe^t\lǜGN?LUԦ)."XV+斜ԭcMJ[cm$[gFܸy5e8C8rGZѤ҂_!80rh Q􋋣X3m;f Uug}gOxt_d۲ͼm1ީvȨߘ֖/ XD*a E8sI=pOjXL.EK6Z_Z}! pOljgqHln!U( r;pkGT6"ZL'E(qeO굟bxYԘ^g$lUٜ )=WNu(kxo>iyPm9\>M:HP5>D9"6{8z鷯TJ>})zx~tg1"ѽ?:g1"ѽ?:g1"ѽ?:g1"ѽ?:g1"ѽ?:g1"SE`*ki/o[KZ4d.W[K_K~[*O'u _K~[(_V}M>U_G?ߖ h4]v?ߖ ?USFOQĿ­d2}M]Ŀm/~%-k'ѓh_m/~%-ki/oY>SE`*ki/o[KZ4d.W[K_K~[*O'u _K~[(_V}M>U_G?ߖ h4]v?ߖ ?USFOQĿ­d2}M]Ŀm/~%-k'ѓh_m/~%-ki/oY>SE`*ki/o[KZ4d.W[K_K~[*O'u _K~[(_V}M>U_G?ߖ h4]v?ߖ ?USFOQĿ­d2}M]Ŀm/~%-k'ѓh_m/~%-ki/oY>SE`*ki/o[KZ4d.TjX`~'?*+Q"Lo"m%Hˎ'dtraitsui-4.1.0/docs/source/traitsui_user_manual/images/button_editors.png0000644000175100001440000000456511674463545030100 0ustar ischnellusers00000000000000PNG  IHDR(oh w@R,i:qoPh(ha=PP2Q4wn(n((;ZGXO7w7L7C~#hHzNpZg}(aT'h2$zHsclhww =Ɔ&@qnk!@qclhww =Ɔ&@qnk!Q%wh9X| R{jѭŮJf(na*_X_#>{zV?yPqwEzŦ U`s}.rL!qQ AٱN56M %nc@Tl_g=tF mFծ1l;7LΩ}"c&4Ne,u|:{!ۑ n|\u>iO&n\]5FT3L^R^ݧv^~/(v v4ÑiTj( yҫGVA;`S QB7jYMS$tQpݠ]ž$inN#~}N?s%zzE:H7=;Sw'0 p=z='@qS m-FqSm-y{7P// )RX}Q@iP*cVKq DϹW&ϲ!@qopp{n,'+W&ϲ!@qopp{n,'+(n>AՉJ}U6*- HEs]-"#[xɧ'eI[ޫYTZiOW9gL uLcM(Tӎ5Ʀ`aĎ.*bSwL> wͶ6-i mMP!v\GB84ɉ8n F*pmFڬQV+QEF꠾j{ڨ mY]:s^VLÏS_u;R Ru>Մۨz$UF^غWL7vTOK]~"* +ڥR1> )=*4='qpj8_++-4%_vWWzG/:*ލ/('4A➣O[xu jFIENDB`traitsui-4.1.0/docs/source/traitsui_user_manual/images/range_editors.jpg0000644000175100001440000004616311674463545027655 0ustar ischnellusers00000000000000JFIF``C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?ooBZTt=,K$rkG LH±th2X7I rLmdXsd3 'AI-5Ru Rۤ};`噔$ea^2\֭WI=S8S*ӡ/i Q$\ܾ>n}&iwco[ kK,wOqqKiw2BY'YY ;an ^ڷ?Hv//i Q$QO mS>d%H,TmbsN\x sq;YsфҦK* Ͼ2C tMnSuK6X"򢘔 8rw|wȥ3Ò(_??;Mŭ֍ l"\ _pl $U܇% ųJk%F)],jI@s gkI8+tZgG/i Vn+˫4'S,qcjB>d1sry`> e4G,腑%Ƭ} b?#Iתܟb"ZgG6.7PQegTYA g4 393vyb;dGTVNAZgG/i Q&:??KVgDzE=@-3# ?(lj玏яVgd{ZgG/i Q&:??Gg?(_??&:??F#{o@|Ѣ|98ӵ? =F1aB6*H@q֏mVx"&ff%W] S$/cWu4/hMo{GpǸ ]hqGAߍOG]Etycx`H#rY kERO.#OЙ' >$/c]{Jc'Ld =OxrCi>_ {-c^=+Yi)3dR;gu~U4sF 2J2xԜ91tN,%<:݄[RYH@=};kɋ w43(?h0 ȫה?JIy\x&#;]ɭjx/,8@!dpASZv,/&hcIg`"GN:tVweX'jwS<5Ͳۖن r!y9LOO Ly"2 r )t̫ii16Qo`w!qc^*߄`-KPKO%S]zCey5N`sQX \lZ)7nT*^AAu-!,u;خa$*ǵhEV{;Xa)* Mಐi:}`-aI%yس3`I88?S=Kѽ?Q? ѽ?Q? r?7ׂ+LF ^FOO%{Y9z3|;rOGYcE';O+G_*+Rjŗ:i Їvm~W(ߕ |c;oSQEvm~W(ߕ .?c;oG?TQp!ߕ >i>v¦[#!PArcEp~(|c;oUt}yힽ:V;!ߕ >i>v¦vm~W(ߕ .?c;oG?TQp!ߕ >i>v¦?Q;O+5#2b@$Evm~W(ߕ \ݵ7мH(5~|c;oSQJC;O+}|MEϝ_vm~W*j(|c;oSQEvm~W(ߕ $uf8?Q;O+^Yudf^j;!ߕ >i>v¦vm~W(ߕ .?c;oG?TQp!ߕ >i>v¦[㶁teAoђW׈|cFI^Fq㿂z߆UVekE]jW_gM?zQYQEQEQEQE Lօ{ 7+8"6$|c*9u\= %2:v3xj҂A$jh 7KK|e2:%'&km+wƷ/l&Y|ʂNݸJ]x6zAun F<iݠ2<q=φ 7RJ,R d ˰;nI Kx#PTpKI ) ((+>1i^ $o#}x'}^ ȫה?J?yC ԯ"eΚ (,(fCqgu{qeo,we/,ј*tfGEfڼ-Ͳqqg4E@<Ϙg%)ӰtW!cIo5!xG̰MUa&I-6l/K"Z0╶\DtY{pqc#PKhn%[F!XqFq򺃂7CUgZqCu:KĞt68 e¡ﻜI-N<}\7-qk%)3Dl Tvœ Z4<#kAZY-HE1DvXfMn S~GOw)"BƳQf7ѤM1ZqJ>IP`*GcGn9A6-ڧ 9xi|sFp$Xm*4#*]Ԁӊ39Gh0v8 N N[It>8o*GaH J׮wV:լSv-͵ɸ] '$z*LQE!Q@Q@R/ZbYݖ(c'c]I} FѲJFR 34_!ҭA^Y2#d0)?6Ox6ojvS]B2$MCcK֯2 KPg@w?srymxry<^+Boabg_$uXg9sךe*yj|OMCOk#,SDIvw8 Hr hAERQEQER3*)f!T N]9#(n-ʨh ON}(h52aRA@8yfKKF3o H Pb6tت7Euo44 E+D{2y@nRKײuwWr϶U/ס_J)5` (Q@Q@6I$/#(p:kuҡαk]G\n{c=.gy̽UO=qoo$M,1gvPYl#fߤXN\Io!ChC7?0ir+^OŻS{_[:\y8%a>c5IPH#NQ&ET((+>1i^ $o#}x'}^ ȫה?J?yC ԯ"eΚ (,(((((GOw)"Bƀ-yϯΘʮXR0AVlv>$xlbѝ} g֣."Ot#Lx:7;mXR Y:gl}JL!i1 q֤(((("(F#:R/ ѤH]AV=E>7ƐđD @)Q@Q@Q@Q@($A]x.mmm)^)P2 jZ( փ["hj-m\K')#VPEPEPEP^!FOO%{}x???dpg;'kE]jVO\G=СD,~i?+^/Bj*i?>ҿk+MEC7? 'GWx4Mj*i?>ҿhQPI7? 'E+ҿi;+ҿhQPI7? 'E+ҿhQPI7? 'E+1i^ $kIE8> x???dpg;'kE]jV_UVy/VtQEaEPEPE^->Kcx!~N8D^Î(kvZl>a y%8# cȭf ,3QYd#g?p5cQ@m?S(`W}??GtOi G?ƏXwD6;OT =g?p4}~j#'OQ?V?? *?fo?@m?S(wD6{0+~h}ՏGtOi G#'Oف_G?Ƭ;OT ?? * o?>g?p5cQ@m?S(`W}??GtOi G?ƏXwD6;OT =wm3'sU&[2J:Ō*^U :p+þ1i^ $kձќxt@Y~WG(ZW,YO^EVEQ@Q@2e/$IvwWG(ZW,YO^>]˹u5d>]˹u5s?19/?]WYJ+1I:RrzʭC<7J]A |Gs?19_ZC+E- "@v@=*C_<Nxn# %M̻ AqRPJR @A#뾞q=Y7~g?2 RT˹0$A0YIss4pAYX*I')]˹tZ_Zuiqż),.z8550!/?]]>]˹u5s?19/?]MEC_<SQ@w?..~bsP>]˹u5s?19/?]MEC_<SQ@w?..~bsP>]˹u5s?19/?]MEC_<SQ@w?..~bsP>]˹u5s?19/?]MEC_<SQ@L'a*O*O7ׂ+>1i^ $sW8=o_*+R5"^P+ȯYz( (8-gt7wyn6s=,sUGc$O}2rw$;u>cR(!oݷ )@V+ie>",=dU FCձS7?1 g8++FvgY&elw9JR+(X \nMau<}W-Pɚi~dBvxJ褝anp~]8[ڴ^!t. 4 PrTT2kk=Նѵs\5 4[k,lc<)#+?djkHԼ1@i>v¨kE]jW_gM?z|c;oSQY\ϝ_vm~W*j(|c;oSQEvm~W(ߕ .?c;oG?STTvH(qRS%GWK[ue9BS8]0iՓ8g50pYqߕ >i>v²5;M'E|euaU1o33ίw(erd4x#>i>vϝ_?o?"E@O;O+}|AwX.?Eϝ_vm~W*Evc(|c;oP.?EuG,vm~W(ߕ vc(];9dc;oG?TuG"AcQ 'ߕ >i>v ];?o?"Y??Q;O+"AcQwXr i>vϝ_?o?"E@O;O+}|AwX.?Eϝ_vm~W*Evc(|c;oP.?EuG,vm~W(ߕ vc(];9dc;oG?TuG"AcQ 'ߕ >i>v ];?o?"Y??Q;O+%41 @灀? C۽y)=\}rs랁M4m0?+>1i^ $\׮e>YbT?7ׂ+V)ɪXUOTIDL4PrqQQxQ$ 1Ӎ6Ķ:`]1,.vprkӨ_oos5˻%5Ca{6O &>28Mn ׾a+o+Z_؛h<ՌCsNv)Q$e ͵1Ζf\E+1CLlD?0=$m|Th_UQ_j`h 꿙 >о53}}W?G2j*/g(BŽdT?h_UQ_ ~о 꿙 9QP}W?G3s &B/g(@MEC_h_UQ̀ 꿙 >о53}}W?G2j*/g(BŽdT?h_UQ_ ~о 꿙 9QP}W?G3s &B/g(@C@01, @,n^2+TVEM q"H[uV.n!%3Z$7BM\dTn TMtJ?7ׂ+o_UԚ&ѥcV gy???dpg;'u|'?b*?zZl/>WG(Z,YO^>l/͟|u5d>l/͟|u5?#g9]MEC>r<_SQ@Ϝ?.6GPK$Ex=j{*"iz)QȧQ@Ϝ?.6GP>l/͟|u5?#g9]MEC>r<_SQ@Ϝ?.6GP>l/͟|u5?#g9]MEC>r<_SQ@Ϝ?.6GP>l/͟|u5?#g9]MEC>r<_SQ@Ϝ?.6GP>l/͟|u5Ess \8$f=yϜ?.6Go%z_4>r<_Y_4WN?#g9]fWN ^A8?3@F?΄ɉ#}x'VAcr`ٜ.zd׎cFI^Fq㿂z߆UTڇخ|l0gv6b)$Nu<5"^P[/5cyŝϞ=n9^M[{i_:!+vwXXgrncBd6D۰I|k=q\>@wy@TY2m9/>wa$|[N-2"vqXiuMU4-퍓X3#txʦIW=(0C69ʤ,vHBBX5<mŕӍiR;s9ƨ|A2O|V{[Z+m*+s I{ g *nMB M[  t{,淹{7lo" [arӂ3+Jl-h԰"n ~dV}w5;H?iE9?'8lzнyXЪI,fEST2wW9yk0ӠҖXNR s!s|ksX%[KtAoжrY*1wu<~\V'Z+ئvdA 2pXwؙ-$2R Ҫ\fKsi$ bѮvdxG08|O-Ư &NOib 4{@U>\ĝ(?A MqZG829q~oѴ{-DuPۋIQH@98բ77;6#s` ʭxK}OúrZ5qKYUi(ٷԓ׿7Mʹfɷ nqr7#8eV\>\j~"4m$(³@Yͼ>m͝+QW,;uud0WP3Q\jQ:[hDī*(p9=$ G5¬0+,%َxU=Ozw_-L_Uoֿ[֨/*d,RU؂)ho&/*_-L_UiG<2 lU( pp{{'eC2*nUbB:J}ҍ~BQk #<+p* Y2s*ԀYr{nI<1߭зs1Us:[ufh,N9*8Mj5Ϸ[4vABys/6IcJր)$;0P|sq`H\CMFvpcːp3:w}VZvw[G6Ȯ{oz[[Z儫qb ]cax礮oBE socjv-bApx玒K_ԆoђW}2JLwOLat|2¤lnAZۚwQ^-՝4ۚwni7QEdXni7Q8Eni7Q8Eni7Q8Eni7Q8Eni7Q8Eni7Q8Eni7Q8Eni7Q8Eni7U{CFi%hN\!<~WaϯҊ(4kVwƲ0\|fU?4_j6ascw/msC*mqF@Q@?4*XBK6I;1x- klr;\p8QGZPѣ&Yqs4I D.TcPѤ!iss O oG(XcƟPѮiwIi)(Os/ R̶6܌# dpOJ8E^PѴ kI|khk2FOuPѬ!hmK$msy٘ ###_fSDۣ{qA(}^traitsui-4.1.0/docs/source/traitsui_user_manual/images/themed_checkbox_editor.png0000644000175100001440000000306111674463545031504 0ustar ischnellusers00000000000000PNG  IHDRKiHIIDATx\k\U~SbcES:,jdąU Bp@HAhE΅*RE451Vm!s{&3ss?fKmBRׁJk ˟I7ߓ9NzSb&zj5HFa+/11]zF%/:ҩ?=f{$&{3E/2f٣=4O92%6ȡ?8<_{:E{Y3uf.=9@O.5aIrKĤD.qGijItӧkB>!vSQv8D09 0p]n^<XS.7+M /УW~SEk<7d*s돯$[s ߒp`XC|"C=̜9uHO >ˍϹ=m4 ^1ٙ/=Hn?IT]~I }[;yK''. q>2)u$![`6KZ A{3 ׭Ke$e{_ ηH#J/Ecm [r5y;% Iھ5Cd"Î? 6ͥ֎*.1)5~l kQ3,wN§ѻE.2,kaT?"W$xoQ²J5DS~=ϟ[#c|HP9VO Rž虎H$V 7!TQ5VH`G>!&l^%Ğ!kJ ;Ur I MeC$@rn9lvgH2}꺆ÒX-H,M@Abp'{Gրo"#DY:*KWl!cJu|7P*ap.rTǜFWM&`a>0r@.'*{j0˰C5` ^P"iCTI[a!%Jf>sD3,wN>E{EzuSJazz-)h4a+0)[FE~CrH XgdStޕov4Ui0^s½zx.7&N_?]J1T__0.Hl`x㙋W~$J/yKW$l^K ~.>~TSY z0k26u eހIm>aX~}g tۀÒ[r f޳ 2`$CdŤ FV?I*KWB}-&~#Q2-{ϝ"U ׅD%PZZb[Ø"W쑒69zK|]?o dXY!odSw~N E dcJ_1DXZ F2Ҡݍب7ĽEK.@fX>-|z)l{;vav;IENDB`traitsui-4.1.0/docs/source/traitsui_user_manual/images/custom_enum_editor.jpg0000644000175100001440000001244711674463545030732 0ustar ischnellusers00000000000000JFIF``C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222F)" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?Aloou;ޱwKQ@T(T :TZD\K3%qRLldu5WR٪Ccn7ep1 OZo种j+>rr~o种j7ֵ]esOQOzx֫p6< OZuQ9?7ֵG?oZ=r~o种j7ֵ]es'Ozx֨|'=¤6O֪jVy!;qԒ)^2bmcPTMB+7t7Ҵ5L{Їpwc'|zΛ֊kkF'Ӹ>[^ͫ$p ̪as֎VœΗJԭ*Q,($NJ?t$yfhXB^@J"b8]FmB{}9Zy:JUv2;M.dk2 Űʮ|ܶ{TY\O4pk\щ`g0vɏC+LWDFGטޓ]6$-B t3*.TH7^+ӎ2vI(3;Uibo.I\|f[vK fgxS{TΖz[۴pAR}35?fWM]L_9ezJOΕ*] ^a02tR*槩h-y}' “f =I&-VPk7FG:4w6r],4ʈz?_I[`5_G4d vr[׶=+#Cj_F1>B"bUߠ'qP[K|ƖbhJP+F:cHG^R^ 1 bL21`0`Eg$sw ^DDV8TO$+ny>="qsk9c(`!G\zԕ.%Р{OA gx7)<)sZ }k K73}v9T[IfmeśrpB9ִՓ-!Pw8IWR=k>i6Mu)#k&J;/V۵zb'Kz D"Xq\ͷGZP?wm 'PH ph\hۮu9[ehƠd^`T.|QZY\x[`,cAzsTuff-Au`zÚ#_Cy@Jϖql5)"L2R A"2B#PʽdjaY^GsZO w4㸙{OU'}(IZip@K)-#ZIlq3:E{{A1m9eF0G{A?&dmOQy N}GQJ@d_-|jNI\FZm  o,GFьSp84"sE>RnREӮn~5}x}+ uJ1}k,B~h-<ر}JQNkD}™`2KVLZ>pjmc/krH\]=:UkivdƥYU@ 55O'=i+W &L] qx96:J٠(c&;W jc{[`˒XdE_j`;TY jzlBhgq#ѹ8#8CjH iT9 GXמ'f"宖lyam]=ԺvSٴЂ$l3Nv(qǧj7;w&l!1yaY" #goNZfXk->r*OD˸dp@4j9'QEƩiV:[ ǦGQjka4!;x(DFJ1֛E }M.nF4PEP0WF/ NO#zb;qL'%Uj*E5|A[}WR٪Ccn߃sa]KKf]S[tzecV^_ڮ-8Fql4ttV&E?6 /V6(ݢ6 /Q ?g>/*EamO_o Ϣ|_UvjwHy!e\u+7o Ϣ|_UxS}⩫q=Q]q,y yd }1\%υ#ۗVHmќ ̫ۓO _ѷ9u(݆֊HS*_鏽ZJDgBcADί]V&B1ƴЯti fEy6 ҏ3_6q݇@1]o&E?6 /Vwe$wκ%MoQ]Iyʕyǘy5- ?g>/*M)C>T;7h/M)C>TmO_!Xy?*1;~XtѧuHO*7_:UNj|w Aq=X}=UJ=˂dnO8Oa[Fi%u3qw2|_-CuX:5ķ\XO\il#$Vn;Jg~譯M)_‡f};ַ@"g4wˌ̭!c`*8?hdk?(0y@v961 >TmO_V&E?6 /R+ o Ϣ|_UxS}⨰V&E?6 /Q`7h/M)C>TmO_nX_xS}Ÿ3EݬWF/ NO#6 /U9{υMJ}Mཞ2jN]3(` ~c 5RTUP 5RTU_(KQE_(KQ 5RTUP 5RTU_(KQE_(KQ 5RTUP 5RTU_(KQE_(KQ 5RTUP 5RTU_(KQE_(KQ 5RTUP 5RTU_(KQE_(KQ 5RTUP 5RTU_(KQE_(KQ 5RTUP 5RTU_(KQE_(KQ 5RTUP 5RTU_(KQE_(KQ 5RTUP 5RTU_(KQEtO oj<3nONQ@traitsui-4.1.0/docs/source/traitsui_user_manual/images/value_editor.png0000644000175100001440000002332411674463545027510 0ustar ischnellusers00000000000000PNG  IHDRoK IDATx]O%ՙM%m u Iٹk,f/Mqz!b/i,f'H"Qmt4>i{߻N:nսQ;[>^F:Չ;Y>/b!"@jm$Ry?V unٵ_{ߧwWg|{o~x/"@$S*ڤr\J=|1}ЙJ"@w?l3ЃھX&U(!#Q:CqFb!# ;nAb\k_<zg0=@ Y( XX_I  ;@݆"rݭ>>~ƞ{2\9p$g>p@ P\j|Zk,kR}7ǁC"@v]S'7O#A_?pMmBpp}"Jܹ^|'&q@ff"PV>gMqtNSZ@ v{^n[w :UE$JN"` 23tI[g\v >,C!?}籮[_!\[ Л#]ÕW<i%:f,kH'L[әi%Fmċ$g*u9cVcUe٬Q?IPL >6BA5%G+#!"Md3_ @''G"d &qÁ>[a~J_ 4%58%)3{ݤsI?I" ,nċ3~ : m$ KXD`4a~jjaD`T~M'[|8p ;"@6n,lǪ$2_ !)[u|1\H|3q($͕bv,1)uZdTmB`kĵ\y1n2Zy@$ƚ6I4uh'E km[b8ԠYmʩڈ"Є . ᤮Ihh[#!7MԂaR{z D`hnXMo}tK^y{l?@=H0 |D V&C: yFtRIv&wb_*k7xj*Hhb8Dq$%ce;uh+tZnJ["@9@vk}Л~1܉f 4EŲQO@vk~mRrEj9B~Bԍ!2 )O~hnCnzYm#Ѓlu_i51Y2 6s­3rR ;@vv||}1q]UHZ-b@v!Є݆݆AZpJ.ƥ<%#)-E . pu+w#;g8 hnMnA lJ"@@v~%5}BvB@]w N#z`~uݙ;ιޥdn6 Є3 >ߺ|U7ouOOy ҨNNh6hd8tDM-%Uk* ݼսUcE5#YD.}x'YЇϺizt|;g藃BSCh0dP` D5v v#C5:k$jV h="zdPIfVil]HMִROxP7\Q*9b%zٴ d<#p{cN]x?^^w w]v"gҾɞpν6$6'zGId5Vv9$#UkJ:Fi0St((ݽpjG$b"'ʦ<ւjA#PzSi6jdo6e"01Mmg;g\}|Î&1tLor4!m89$#s R! 9g km!Ks n"%ș[im9*|\LA@vUИbv4a7}]~+=PChrWaЊ7ķ؛B"0;ۀ;)j?u]z);LBhtJjlᵛ[\;~ Glz&h1gUlCrM+{kQhn2`9~uI֭ ~kϙlYW l-H洲NlMح*4hὃwHtG LA=F`(@sXײ UFEoMrhn%0 R[YcA:w(X+Ul^ oяSC"YU}7l1U9KڃÄUۍ4HA[sg Ģl1X-F ~{P 95}{I ЄⰦDtQú&6nwvxEO#Jp 2Sz/kzЁ,&6n4&4Pz}[ɦԢQY%*E+P KG MvjC#{%pw@R<}_.蝡k#ЄݦYT_>|ݏ?na׭k%O8⡮Ů\[[maV"0Mm0.wow}ڪJW64I?GBhn nDmQ*r7(É&6ϵ[J"@b4a-jRO@m՟7p{4x>m lL@ߺ|U7ouOO,9t&(OƭFGfA㧢M-Aq*v_?y y/>Ja6Pe_HHx۝gp-9D`hnDEU5߳WO0%"34a݈VAHM2elfiK|d"XuLvS/}Wp$%hi!=XU9(mmmG^wR-AZS}0J"@zhn[aAV;F cnA.O6I@v[ЂhACN"hn Z-E|$MYЂ(Um>ZvBrhn g. hd"*BӄQ9`**N!ЄݖBmr:nRĔ!Kj"h2Ӎl7V[@UO}i`*Pvw ܔwS#%mv;})&& 6F% 40nGKi1M'{kT]C`n:̪a6C_w+86wZVvn~!Ys4霴A xlA0n߂dD`۠&dm7ׂ/с#ne ^~ *C3AvC:'b`A< yABp`VD`l\jZ891XSA'|ޯ۴ܘVK&@]9 SHj;r\SǦQ7[#s:C63kL@k٨~Ֆ|'&k8&Tf+" Pݜ}'s$B4"պY9pPS0*SH 933"@,e<^uk>r~MR8 czC3N 2X!0Aek {݈n?&! 2`T *=B %[_FPBH8[ul%-[?d|{'QKSIK2lsG,:~SZ Lkj}|6icpUg* @@`u}|砏h-/5פbuB!ZTV`>PBX!:Cz+A$J+[l6CФ}!C!snaunVlgߡ&^oW25[ -:oϣSE'Ī suIDiz >1 4$N]y ~xP_tPZ[1!&#s1 ~bv;,djl9 3[vZ~W]aOB)TjK0ChSa,OOsSG:ʱbHK^[c!h;2ۄ'VPBԵ Cд_j Csʠl6ЗUc~8C5DLnn#[jF>A'[ue;pgVv B-CS+<˾6tr64pu97& AAcY9LJ{ins,  D j0"D`Gu ?[%xJZ~[=WVSgCDL|3-P[lrSF7q!斩!P-7mX|:aך22vUwLxyIκLu~kc=+4󒨘c55D`J4d9~uIV ~kLwv$O |M,6S [iFA& Eo ɦH*@D"m hO QO( 6`$$8!qV[g3ٜܯhs"P4d@c3m!+;&ǓC"0=*n~?{j] RZeh`¿bNI(488"(9$A-v%9w ^ͽݙsj^"CiVL7Ijb3A*[Fݾu;~md9qY9柣y<1=?&I0kT"0vsPh >XN?C9GclU~`o|QM{XE(8V$@6@Mv=#{#r9ad0p3itcC}ASA+l~~[儞-[z݇v}G-uaNYWt˖i -:)Tc7ۓ,n1Qxpvw-0 [YUichLn)hn&߾uÍ"ϻie$8 6LJhn9k hŁlT"4a%Xq.BΝ &zr  QEhn) ΀믿u׫7og^<1>9Й<w4y|M0J"@&F Q|PP[_"&d r"k4"0%s۝ԂZ )X${,;P|MLG@)s\>8S!5 Z˔wU*zٔ|MY-F"PS/~HPC^ˇDsݭniiKh$4:rLK@ĦyAJ4qwNc "Ӽ-XW }!D5K;wSd/9d' DF`^kֳ_xj?MmЭϑp o'n5G#IE#gp"@hrWackōn$@"P&6-B#* z3vr}IDATЁE 䛩t 6d*hn3%D`rln˂Dl Y\w[#_bG 3}o?uz);LD7np8ݻot3׺v.iAb֘~Pi: Pm햸֖Ivݍ5@ᵛ\;~264~:=$״ց;Md9~uIV ~kLwv$Z㹠E5[ ұ9\0e"P݆NEo YH*@DN~tbjBSA D`ql݂AɠrN?Aszze'aLJC"8*UnC=LXLC)-'&3sƊjYD9Sgi]38T/:C:FT^$g|Dsow=v-qXdsIu:+" P݊;~ocsۻh1YaVm+bV 2)("0On:>a"n5";BZNu &[ J멽FeqCȪ C,{##{#r9a$d0p3@} 2@8zg(C(!a"\[a4.݇v}G-uaNU9?zGӆw#-YD`#Tc];& aSP[JIb1}!R #E`cvK]'?܈ Mˮ܍,p"@y[Ż<* q62 Ʈ@m՟7p2xdi3y^o`\];Qsj88b("_O,2 CfF^PA3۟+?E?@-3# ?*xCHdg ~_M:ǵf]*QV xږȲmk[&"N۪G3y.͹6=o{Hv//i U=OIj..4 ѼЙ(A"mVSI,p#v/#)UYXǼs'3es,+{Tu8?wvw?TMYK&l1y<_COp($^ kPUeKO2%acVT]}M Eݿ [gcR4yf?/Y:ݵ5Ig$EJ,O9R[5ZMWɽi([dthY~G8SgR_y>%R<m 1<г CJRŕZJi[m$b8`A6e0 ~i I}ߚtӯ= YK?TMEEWԥ?1%B*_&?,j*(/cR4yf?/QQGԥ??I|г  1>/o>bK?TMYKTQ)}O_?,hB*_&K~0[Ϙf?/GcR5}J_S|ė 1<г R?$YK?TMEERa1%B*_&?,j*(/cR4yf?/QQGԥ??I|г  1>/o>bK?TMYKTQ)}O_?,hB*_&K~0[Ϙf?/GcR5}J_S|ė 1t j<>H~cOK]Q\OM穓U SIYň/aV(QmUO5C4Wo>5"^P+/_*+RR^2]Ü)tdv> ]pEh}I"O*kE]jW/VzTCH=%?>'SQY\A/IQH=%?.Km :d!niȸ}~WeA%Ο-] qҚM"e%Kdi}I"O*A/IWֳ#H3F\-%N8 jkG]Q/&VK/:A/IQH=%??5S] ?>__.W?YI"O*A/IW!FUښ`QQGA% $$DUqkZ*]V-l @FUQ/e{__ud_zKUjkGGA?T}G\~#$DUd_CS] ?Q֥95o"mprhxBWqejGSH=%?>'PjoڬḒMrRDR6GUɿzxg{&lA/IQH=%?]U5 Xk`*p/P!<.*:DžGLaf̖gۊsL0kMd_zKU:J|.5 XlzdV߉~+7IFiݼif#hR:O)TWs'G $?U%(HmY16{wҖ?+U1QO?ɲ]jj.MzKT}I"O*м'\- Yj֛Mn5m i<3*eE#CuSR*O%W~'G $⫏:է23ſ$nH6Ңg2B2#HC@'hvdc9y4udiy9gGkH=%?>'\[Hku-Ō7',ÞQ?Y@Uׇ'G $⫞|W&u4b 91oSqt _ºhMW:Q;)jtd_zKUͧ侹m̗0?2(#Z my=j#&8=+8ZXqK6ƒd߲A/IQH=%??5vǀLĀ~Cmika<3ɿnYZʆ*xS%`'YONW6~'G $r%#KTq򑱞N.a8;5'RGD@;fЉcL%-ƱAi9,?ҷN[iæ `FEjYȽsa'#Avq=)DdIvgaURեBH>hF׮Zȟ/KOivF׋rZSҽLf&5)rIWUeRVz&?xo G?xo _aKqGПMkE]jV_UV~{_gO^EqwCI 9`X̙mܰ'޹u 8<֊+y #,1LiYQhq,3gKEqv^)j2eudVF7EbnK`Eߎ.f \O%R8R Lcb 1Fq%s/LSio&qmy[*|p JUK%Ac.L>/LUO^OF-Q_V~&QEQEQEQEbBbB3 xz#ukĖhZ4Io2 |Cǫ*BR1ThJߙG(>DUK8k?j;RoN̆hc $?zr~\~<&XC˖/\I7۹c>h3^YR4o45J|4y{N!]O mUO$+o"A@!Nztmkڧ#o!(`ra;̀wt#+fzX՜\UV/3+[oIRTݗI\xiXgR!+.y{\>*aUO .gF41uKmumS_J6>pʿh=͋XK$63@f?1d|_Je8$֎!?G%^?X?r-"{)v d9c~WٕڷoOhuwb{W͑o Nq"F*|ęWha/6zJ?ѿoukjVdyic jX~psG@?r,eo2'JNMKi"!*[ԟML;hpE=*__BO*j3Bw?B JUxKUX.!˝ {x SSjΖiԋi6*ׄ1(5KPU>*վ UiQ'zPbUl:xGwxGwDn}7t@Y~WG(Z՞?z'ZY9Y_>Cwwn$y$WO1_TM̗Z!7]fs88Eer̖ΐ|TrDl۱) ,P"z)yMm+q#$rvbH1I@ڢCOo>}~[qӾ3gxA0?tA0?]?zb?GQE}YQEQEQEQEU[UbՋ[UbΌ/3W f? k1,qw H 3޾u{RpT_U|V&2mY=JIVCg&X3Z^ JA>d@# bhLsPkmu+s5ԲFheK gO*j|zkC'ά⵺f#Ѕu9_f ;ISO!cdf?ht^+AI5H!62+$FU46SV_2W uL?"?*hnmdn`+xcW8"צxgb0\d;G6e7OIFmoxo`a|Z奫^M3Uǁׯ5WB1ZV{pbPktVZo,K΃~ 5b-Fu '\%RI[֩4 gЍWE%e-ĉwGO9"#*_S^n뱏V e?p_fXLDu%m3(rM;@)ESմ贛|]Wx_)~>w}SE:g%tuj56-ZY25cwK?F'c)Io?ιcM{;E$aW; B >jn0S{k_-;nozg@><*IRVl|CCɨ@$uݜ#^fMO R3MhE5cn{TEAxHM@ͨ@m|%|u{d% XB\ӡV3щG%zUԬ?%sHP>bWVIFgK|O5C4QO5C4WR}߆UVekE]jW/VzTQEdXQEW?_pUW?_pUt5abEgaEPEPEPEPV,!m]WV,!m]W:0LJΣ\Cd$ovϽx,a_M{?X׿͵ʓ+E˜L=z5X)Y}XfT/K+'&ߘtkQ߭}{$ ق3^e]IҳT`yEVl :*һv,Q oIկ9'g>s~hNֶWТMzY͵gga’qZ ?|/Sysc ,rWgYXZ8JNKR1t)FOֳGw2%Yp3$#8=A{տ_Si+ ^nƵծ @q`l_~C*^`?LdzLn&ʑI$FpQn+/hdf ǜ:w=6'EGVkjUm'sѧuՋmw<(S$4J֟?V5NsQNZ(GZu*k3ѥb[dg`kUom`gXS_-8xStdwѵȞXaw e9YAS&a, }-Wʧ^ؼELYNmIjfu"ߝfxqKd,{Gho?@+Rsӫ2=[5^4MTi $dL!WG\5b׵=?xo G?xo _}MkE]jVOcY<'ݏB~WeZd_k^ КzKT}I"O*,zKT}I"O*&*r2DУ&A񬋇݌v_@(UoA/IQH=%?w}7?ȣoU'G $⨻1Ec|H=%?>'Ep,(UoA/IQH=%?.goG"}I"O*A/IQw >c|<g[zKT}I"O*%:&0m$>HE?V $$DUf !3V rrG"OKzKT}I"O*3/G"Ny3T(K/A/IQH=%?[I3\UH]-ˌ H=%?>'@i? x_I qw/# tH=%?>'@i? x_I !2e?k G$DUd_ E?QBx`$DUd_ E?P_d_#" nq3D>R(+j_Ï< ȫה?J?yC ԯk^ (i7L/0VE^sjŇӨho(qʪ _Ň˚?KFUښ`QTTQ ?,?\~"_Mw0(#*aa%jkGGA?U}C4,ȗS] ??5XcDښ`QQFUEEP/e?K%#*Mw0(*(.i?X/A?TjkGQQG0YsO5S] ?>_Ň˚?KFUښ`QTTQ ?,?\~"_Mw0(#*aa%jkGGA?U}C4,ȗS] ? n4eYRc=+ 좹qZ4sAYov/Wg/#?菦>?yC Ԭz9+#B0XZi_s5՞?zQPI7? 'YX։Caw\YAʷ8 F cXkG7Zl4.ݮ}XlLhi_s4}IҴw/Ngk 30*p>H$UmwMUܠeI vNM_Yú$f#\ M6d*qq{33ZK[ C#(q@2y8I=I$3Eq556e$sN$$+ҿhЬ_kY#wnzn}I7? 'OF\?F?筷QjJ+ҿhJFwg[o֣m?չ7? 'GWx4M5U˻?nz[o֭ϴi?>ҿhѮ]#wnzn}I7? 'GpUr0G#ws+ҿhJFwg[o֣m?չ7? 'GWx4M5U˻?nz[o֭ϴi?>ҿhѮ]#wnzn}I7? 'GpUr0[e/3IllTi_s5$oBJceWVyeׂȰx*ڊw>R(+)>o_*+Rrm1 v!PBDfw7$ƫK/lTn.eG4P{/VzTvW57hoc.c"[iؗp? g0̸U嶰uݛĩxOk tOdP@Hŝ]xó%pN.LC! oukx`,eIiݕX @RIp S$8Wt*.q8 ц kP^5# e6~ Oi\Si?P\eeU~?WEpfvmQG\?_}/m?(mCqQaWKggO >i?P\eeU~?WEpfvmQG\?_}/m?(mCqQaWKggO >i?P\eeU~?WEpfvmQG\?_}/m?(mCqQaWKggO >i?P\eeU~?WEpfvmQG\?_}/m?)A3mhݱ+ko1YVNf_5XP4gΞ4]3E4]3E}/@}!3+‘ݣ$n W)BA巑- &Հ *-[՝xWGe)`$wZa?ux՞?Z-GPϷdIya1gy"8$c o/nmmZV@іDY7)=Xsta?t}~s|,>u ^ܬȗ3ac%T)xv-^^ujv&tX/pGa F#?o??]a?td] kK.[X+>r˓\\Ibp'O>y?p9JNT榖.3 U P}ff]ϬiGo??]zU?-G+>w>߳]o??]a?tiTTmqbY٣W75}~sGOAG+>w>߳]o??]a?tiTTmqbY٣W75}~sGOAG+>w>߳]o??]a?tiTTmqbY٣W75}~sGOAG+>w>߳]o??]a?tiTTmqbY٣W75}~sGOAG+>w>߳]o??]a?tiTTmqbY٣W75}~sGOAG+>w>߳]o??]a?tiTTmqbY٣W75}~sGOAG+>w>߳]o??]a?tiTTmqbY٣W75}~sGOAG+>w>߳]o??]a?tiTTmqbY٣W75}~sGOAG+>w>߳]o??]a?tiTTmqbY٣W75}~sGOAG+XdE)7.ή:H88u`^kƣn.#o;j|_kKqGtraitsui-4.1.0/docs/source/traitsui_user_manual/images/list_with_context_menu.png0000644000175100001440000002011311674463545031615 0ustar ischnellusers00000000000000PNG  IHDRP#I IDATxϫeW_B[Jb!Rh#! ؂=jp 68Q7@ΠGQG H2 ZIEi'b*mQ"{s=?=gϣxZk|}'q@X*;O|y}c^@N}Ʊx@`o@C`\ w1gyn0*#/~o|-> Fny44!1oL__?~7u3c/"uDǟj$@BuHu@TG_c9v箼u!٘7_2l;v͛=' {Do&!C _dƿ׭+}eN#R2*mr3x#W(2g Xl{%'T9 lâ3]0iɷ+ܷsI2mV~cmpy`x%av.# )JM t1*hǰiNR.[:^.^ˣtuI演 goߟ?(|SyJF#{tYX1ۻzͼ{D[X2+55&akd# Ollƚu+ǽG뿞ww!4I\|xRb(,jPmgK0.a~KGp.]iv P_ь]e1Ƙyt[udk& ͜F#3p{Twlg&OlSָj 7mJܰ.k\'ƺέGuںtr0W[~@`gSQF߃HMeB?4!LJA`JI`w{E2X s D v B PD=gXDjUd!PD=gXDjUd!Pfe>pwg3Ć/T,b@ݧe'È(@*R /sk21+Ih*j$Hո+"Hh*j$Hո+"Hh*j$Hո+"ނO8Un & 09T_u/3y@F NRGL{ɣ s7i!m R"92#O;vXXv{M{Nj5+!PI*W(Fgvǟ<㹊IaX}ZSP17GvסzK,{Seu8D%Rx'P:lEӎ i} KzͰ2NR5^x(%:7%YI'yM<@Ϥ.aM}䁃K (=yIkRt J<x oQ a*0xbd4&6z. )R&I?x+Ϥ7t/<~[i KcLEO<= 9x/e(SloL)ӛW5Ѧm/>M.{L4س>a(S<= /?\;u#PRbmp'98qce"PHEiwԯg!Fq^bh+ "o4'&Is@@`#D}7_{pu'~A< ]imSf~ydx|G3vɖKFǔcI"cmyd4։](Y. lvQJדۍ1K(,Tٛ$Ԍ]WM}ƚ$L"\"eDh$m<̿=bC{$0HddkۍЌb#O [)N#Y@ƌb<-f$@!0dOIǚj3.3{MRL"Li1[|\\OҴv?7/D@`aիe -ƪZW46 F(;6|S=-ƨIPdeD1 P" GkՆ,i1G&(MlaQxZv+%P=tJ @` ! Rs> 0"5  SEd@`n܄"HG2 07DjnԇF@F#"57aC R M0!QQH&HM((|$Cs@&L}@`Dj>! Rs> 0"5  SEd@`n܄"HG2 07DjnԇFH`3ύ7O==y29 {*R k*`2I,@*RɁeS_< A`-Lj-;e-)Q# n^%bt=Y)]2:x@t`L)go<_~(]iGQ{إkfx')y{FT׉EÒ,kjJEÃȼ& PgRKx=_z^m5v)%uO>,+o s͈HE*9(niZ4ng(?aEȂ0|p>Y R;000ndA;"PH뛂 v?KzEVAj/&_R*d؎Nb7[JuTkHDcLboӄ@"))HB1Qn LKvL[%H8ps/Y̰fa*#U&$V7!r=2鱟6ꈉ]»jj@$P۽\I%Τ]1H$,& P*Dj;1jPT˲ P Dd("UƲ,B*e'Y %H, @JIB {3m{:⃫+RK|QeX۽IbS?$jbM7[/ٷ"BbdyXݣ0$I*wS?1&1&1FjXmF?HxQ_ƔN=S@mV,R&.\D@`#T'eZ'4tO[Ƃn+3t]2kvn;F!pBN^ u8"clUh}R ,ZEj1L pk)"UFL"֝c"UFLZEj'u7 VcwX% pby[텐44b͎">~wD {~7,7wJeZL \&7ɚnR"YIbzrcIM5--qᩄ@"ո& Rh菶4a1@vc$&&PH HvZ11xj(u\D@Fi/#7:LD9RL@`BԶ_mKO~uĨ*( 4;(HE䴢TpLjȈ3iEvYJқ48 6*!-[jb"{X!êTHA)WHT=J(1^YVeA@/J![m3ɕ@BA$1ˑSG] jsV,@`Du!ѠD,\M|Iq0y@`iZoAM>TuDA?\[M 4IFWcDǀ Ї@*R)CEx,;{ԥq1 +̭e&M5N{X*}b'.sn2_XHI ~tlq"";3.zWkĘg Z.r JcpGc0 [,Rz){ՔC%PHٵzVL4{7ȚC< @" Ї@1Gnt2H')eyM:belfv2ͻ`yh&Є +Rv''8f[d[X?wFOmC+7İ!F[1gTDhY*HZ1gTDhY*HZ1gTDhY*H` <kΜ!-Ru|+b?;&\!nj\ŵugӨ%c%R?o/6F ?f"PǏU4 [#<_}*C@i9=sq8!5($ `@7D R{ R|L0< MC/ gԞ7!nT7z!=@ t@ " `x@"͇^@`=oCn>B{&Hy&Hu3Dj@7D R{ R|L0< MC/ gz<  vpHke8 ,7I|FIDAToIENDB`traitsui-4.1.0/docs/source/traitsui_user_manual/images/unthemed_ui.jpg0000644000175100001440000002540211674463545027327 0ustar ischnellusers00000000000000JFIF``C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?YEղE>W?7<|tZE?UMm@]1ʆ8zDψ'xgl'9_G#XXZ׹2.yeB{hm5@O'#E>vW+cPom..Zoǵqڋ? ˾m,0… W"kI[;tjʚ{"_m~Qϝ~WGƆ,b(˺rK[ M  [50*>lq]ki>exJN6z_)iE>vQߡZ~%N-60tSA9**xOZVDiR4ewUu kCBpSRV~dO R-?QϝiE>vUtkHs#}T7Uޭsj.#Y]TY$ !!Wԗރ+FiE>vQߡZz-.<[T\F0BK$uۏz-ouk[+{¯ lAFqN&䣯.}^i)=bi>vQߡWnkfa96-/%6Fۻ/zU8<=ut}[8%% ~?QQyKK<-H˖Ӹqϝi>vVΗ`e{=ēBLp~c8wP4#YKvUw0C8vXw'eum~ho V7N/BN/B5(gcӥ!.pA|+a<.AY: ە=ssE\M*WMIu-0K_+cHӧ {ᰂg4LC0FxSw>6ˑAO'' QNn315^(k5Q6.HeVϠ=4˩rv4iZ_aon^_mis(&OحN噡r\@En2 T͢"G\˫YrNc0A֛\:GOzznpMXJ424QC"2Hފ'8<9ywc܃KYT:,b~Dldr3jf*ω}6yb%Cػsykr tӖ6Y#V#?p晥l%ʞ}*(I5_oot1nlh[Qv ?(?2'ןHB[@I#9sIQFP`gּ'c*bѫi;m i֤x_FJO=ZbV61eQxqEx}?hn=?TpO65gʵ=[ZI{uޡRYN+vFsǵv6ZDұʉnA9x_ƽ#GșV·ᇉޗ$+\`TjVFy==pgr!f͕J"HPlpOGlV ,4Hat]Zn%Vp%vdnV+/֗d)zEV_JwOOɴEXc*Uu7V7V{YMmIaKs;Tڿ,m;Rx/GlQ9B_2 F[aOEU6I}yy >rįi[HdYn qp}Ky[ݭr fLn9 >٩?Xx~'G+֗d)9eMmv~j;"_qlI8$)E`"1Fߓ\"iͅ䡚;{`8V$/Q ğ?襋˩rkjPTI8I~ȋYoIv-b<.28#w͌5h61zo M8 JD.I *OV$/Q ğ?'GSM? B1|ݿr;Y}ťM:KpL$SK43JDu 9<,- _wLly]cV$/Q ğ?kYWov/6: dv<rZJa A' pH֦[=>B^=gQe*_kZٞQJ5T7)GrIlnKKNp\:tEC6?WWU|_b'o.o@-'2B p Cڧ~o:gBK2lu(|14Hz.'_9ԯ ?ixB ŕ.b“nZԫ\nw(_Pȣ(?}PЮ<@ȡXt2WּVl g ?*Y xLJY5Xu)${t2z }f*=xۥyhchj?/>ǥמ :m&zk%AY.1z|׌`cD ,Pc88_ /1U>{ !-# 㞵ӯW'5<5J49+t@ Qvsu!ogGџ ?SuW E9iG]|ViS!EWQE2z 6^YKms ΋uo`UnfO)&㴷QN3+Q[MRK4 bʄf䌄< sҽX}α~f!@܊_3F<$*IZ[ڍ~tV3OQNp>@8YYQ2ZݼnJs 2&EtZk#NX@rJ&7cq߽]ןj> 4(-m`*b lLTT.@rq&- ɇ\4^&M &mY&iubi q3WkkjGCt-Ӵ& *eҷ>7n/#Ջ\cBfSV+l-se.:J-e*11R">hOqî|~e]BKx"+fb|`>BѨh~Oe5\W[V $xÜ?5b[Y4twAfb+FQEQEQEQE|osRh>x_gG|'NoQu\/wUyOS oϫ%o3)ϨltV,>+gm.h$!APy+ jHIngRXe >WP$61מ `iO7䲠UIb@h.︿e܇`ѫ\)E~s+G01zׅ IFJweFo?s}׏K!s1j8X/{w6>%̻P>`7 1SqR9*I{&o?s}ћ\quS+hMͤW\hR6MSݜ:UW·nwvr\ VBI%vaвODS_g{&o?s}ћ\quMYU+"s")7OsD; b`o𞧞f}j{r?e.︿3y@˟/.3={eFo?s}rǰk.︿3y@˟/.裖=^&o?s}ћ\quE13y@˟/.2(`׹\qtf?_]mG,{L2 d! 2 BGQ[ui&kT)+M>xE}K_<(;?sҎ~ȧ7}(뺯?*zO4hΎU  zpǧZʸ..6qr@OȉWV^!%-,yIi$Uz}k"{ =?._*gk~L9I|nn}Y4W~z%RhyE J\q]w{\Ud_yrT,K}YL[>%RSB4EKi$eM cv0q7|Uqt2i/(XK,O8Һ/>ȿ,K}YLޢ~ȿ"{ NxٛV{\Ud_yrTs,+=?._*/9fPcQuVpGẛ;y(_w_;si?G4 O E`}ɿWw_ջQ_x$0}$Nrsj&>xE}K_<(;?sҎ~ȧ7}(뺯?*zO+>X%Y e1q<օr׆5 R-Z[y?tm`@S B';HGGCokJ:?ɵNzt4f,YM,W2IuW6j7pZn{*tZwF2)!'n}km9O2Ios߫">Iꂌb͌Iip:`XgU]3QU[ubfuhmSQޯ^ gF'ЏB sUI./oeo?,(ڹ#][d}|Vhr,RKPBgH?TuoyiZ y"y^7Y]@x_{/d~}E9iG]p SuKwm\E@?Y(""E*nDӶ[ ]Կ(4WKgG|'NoQεe$Ų%L!U: 9=Xz7wUyOS }oeF"-n$KYCH$L28 Qk7Zn![[]A1Lπ-0K'נk>T6څݹ "Y+8+ ;QX6MN̓O6NAWl[T,yYY2%  uAoE j#B oz%Aw!?j]v=V}p%$qGT:GɃ=G[I$|Hᱜtܿa^4 }Y-0MWWvṼA O]Uu9egGfHRe.Pų#[S?ն6\HlEW"I6 7~Q5>Vn+t67wsZҿ+o o7G[S.Edi_ϕ7J|)]֢>VnkQY?WmMҿ+o o7Ep5+ti_ϕ7VO[S?u j+'J|)WmM`}ɿcJ|)AjGyCHBc8Q6An|{uRh>x_}/d~}E9iG]p SugU^V}VAH;}>cz w}ffwawO+4m:(8hYŎYpWR7u8ɻ6e"%29۹f\<>P6ˈ$6ycM 38#5o!%yEUK|V.gS]բk`)9e oAS'O뚸;w j鿲W_E A+/"C$Hn@7,"V3O0/A Ӭl4;M ,#gV\)˯._y?a(o ^~QENgCJ!%yEVi,fd7?(?W_EiFgCJ!%yEVi,fd7?(?W_EiFgCJ!%yEVi,fd7?(?W_EiFgCJD;(l2LCϩMDɝkr>iS'=~;QdDMb镔uux\.bp%70gW+RM}4b 2>LzUi&kQErRoSE_/ƊY|Lȧ7}(뭽ѴJxgl']9H:zWVEJy^rGu5uS97M8z%3A{4J[ 2F8T^E$W61HB)ʂ=+oߔoߔ77LJ[GH 02NIPG Q) Q)Gc}'U,p$Rx\MONC!HS+n92~^Ny. -GG. -GWKNy7ycE&m꫍f@Dxf[k4xUmm-Fٕ:W Q) Q)+}?yI?%k̿u[yj???u[yj??>oA=7j_&?yI/]~ZO.]~ZO.b{hwMڳj_&_疣~S_疣~S%hڳ2oߔoߔ+}?yI?%k̿u[yj???u[yj??>oA=7j_&?yI/]~ZO.]~ZO.b{hwMڳj_&_疣~S_疣~S%kgFXf`y9q-<]-<]\0mO&U)u ϴEhٝYC+Tpyu[yj??O]~:O.\2(|uRh:Ȣ_9#traitsui-4.1.0/docs/source/traitsui_user_manual/images/ui_for_ex12.jpg0000644000175100001440000002244211674463545027144 0ustar ischnellusers00000000000000JFIF``C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?Wpm`V/oel8!Yr7any8ش mydU&CJc p3:5CNe=tODs־G-sɣFy.YSOews/J/B( Ҽ(iڕ 6m&ߺ3̀hcv6*.7'|,GoǎFzeFN-gY$ҋ|УJ/Bze޵ l:ǒ@ ]ڽ啭s[<7r+r3U)EM';*3j2/( ?;o*h+!DlP*I"DG-ة$ZKO jG@\\G Ok/z+H;o(ҋ|Щ`qXwiV8d#Ś#b \: YI.bL1c'  =ij?̻oװ1qϝi>vVKAc#~4rm4bH6q}ӏg* kV=gFd9Ib2 5%mr@Y]?八"Ӌ|УN/BhzI#,"U$eXFr;~+x8MsGTc(8=ߡG_m~fbUrrqϝi>vVf(9M/8 ?K_+7vSOJ/B( vSr8]6k'E$!;##>m5(k5[zi1s}'8:WnwRoYVmlrpq<o6FU&l~+$S|8w\ۚn=t54uibb& k:؊Z۵g,j[Z Kۨ,bȨvXC3=_鶏$*&TKp.: Ȯ 5'VWI?Dje? 'ZKZR5cϡӅ;|Q K5l]QBc2;bNMމa,wjnx9G 3Hqsk?KᏉiO"[/J4o?÷!GSub ObS7xlqc 7bB@pr26hYtko'WEET, E 0JoV$/Q ğ?~+S(k_OE'*ޗ$(P)y4y5¯'O"U$/IQ>Rj5u-Ÿ*DpCy8{^&Լ7tv[y͝6oN< $ó2]+:eO&BXUt_bbњZyΕYǑ;~q-m+viGy/,R+EC,;cVbHzT7`g^*x3Ť29Kݘ0s\Y]HnK| ӕw1BiY "5(%d>a^}r8s/1PIIs 4",|UϠiM^5w**FjF}bmĖUEQX|H uMEI`R2dcg>o_ďt_b>Y;q-OwEO{ ^}y+Es>3Z>=𦻣gT.Y`QnH]zʊ"0J\^G՛^F۷ SuW E9iG]|iS!EWWoź-ILjV?k- pLsU4u(i&խ-#LI"JÒ!B隷,Ʀl./@薚IsYk%{e12ȅf ω6Uy"fvGT1X1}J@vt 5  |c2:)Fi&kbMgndIa,cڀ@,.I "b<^}ZԮ5-nn-ǔE̚\a_/n_1;\@urhjyνwh#ZXyUD2F3e2yCs⋛@xuYY[B2W>N3Fj̺LMX\_Y#D8\+ 7dcQ[ m`h^n WpaN2>jhJ1n3ΩVn5 }i?~5o}^ZEs}f >X3WzR,O9I 6ϹPǗ,p7<R>6*v䍷m9_`WO"E9+9QsWO"E9+T9E9(WO" (AsWO"E9+T9E9(WO" (AsWO"E9+T9E9(WO" (AsWO"E9+T ʓzԿ6vke1gA۹Aw֬a[RљGc?ZooP8j+m+V@$.삂TrKH'AtKqlm=W?G3~]z_kOUV'AtaGkOUQ_baGAt{_kOUV'AtaGkOUQ_baGAt{_kOUV'AtaGkOUQ_baGAt{_kOUV'AtaGG7 Od 9eeiMwsOE}VSY[E9iG]p SuW=N'bQEp6wD}=TKi Br2t#}od0隡S%R7`6˅>_ @)GIj~Y[IulhTD|sU;E˦ǣa3omD%1~U^0D p!d*7*=@%W#EcU6ExZq吾iIڳDxdKv-sy"Ms*Cn񒷲yJL  &7;Iqkp>Z*%lT9PP@:T芉aj*TXTv騣g'ZG'ZG9\Qm7dt8ќ랧֭OW6[D*92<GjU#0L@x_Z\ZCi\KHKw(lFzVEmoI1(HB(vפThZ4kQmݖ;p0:ҮZFi!nFc`Hy16T`V#Fb9Z]ss [N"8Lh2CanC0EY;fm<WYm1f m'JKSW[WheYZgllT qoq2zm\,i}=G?Ə'ms>ОYQǞt!s2QQ|lO诬u¯VpV#3j~Ҿq5[<'ؙ2:C#KTqcZZ]]h?hKUs ܃L23\x |UƎ-p/XLWtw_6^~?.Up}RQYGcijܗloq F \nw,!َ2 ^.j-kIam~PKi7YJ|O (m@ ?+Og~13oS?65o Ϩ\Ii^ZQأI Y[FQS>ME,$142Iqne1*2G&s/oI_m'"o~10>#CSx~]mYOI䶑KrwHY!Vѐ[sk_'Rujئ¹#[1מQ P)d?)3x^KMUa]Z5"XCfFjόAl2Aawogl@\1 Ͷ_pjm@ ?+ͷ$ŸN7?}biL_iϨ %,(,ፗ8]у>-I KE,do_6 ?|O E/g~11f\|-կ~ݭ^ŠCo. Kq iQQpOc -H`l4M1_6 ?|O *Ujܟ_X{m'?g~11fWQ P('?=_6 ?|O ('?=_6 ?|O ('?=_6 ?|O ('?=_6 ?|O ('?=_6 ?|O ('?=_6 ?|O ('?=_6 ?|O ('?6>6ȏ'W㟉AM54Ƶ+:ͼͿ8VҊ,Ju ^9jIJmtraitsui-4.1.0/docs/source/traitsui_user_manual/images/no_sort_icon.png0000644000175100001440000000114711674463545027520 0ustar ischnellusers00000000000000PNG  IHDR&u2.IDAT8!1E{S6\4plpa0Prb#X0Ʊö*]%%þ^ZKn_8 _ %PܠX4>Z+eAl }J6[ՓnA̘?ie׶kkr胁0.b5*ž`b ؉4F O+(y3,O:_80Ueʺv 'SFR2dY^?ŻcZ[VUHB>b [:#'`n)ي9՛6VnVƪ!2kHiL+7֫ ]8wpHHr_J ?:"L !}Nq9jO6^ dS "%ߢs̨ͪg2OB_%4ɷh8\j<8=R=Rp৚0q4Aq7mw)X(s<>juV),q{|z֐u *4IENDB`traitsui-4.1.0/docs/source/traitsui_user_manual/images/themed_notebook_closed.png0000644000175100001440000000440111674463545031520 0ustar ischnellusers00000000000000PNG  IHDRtXRIDATx\=UG QhSl&MDB Z/zHiRJ2HɊEZ)HKx{{|=üWo>?"pX>?lL|D &6~z oC@6G݋~0X/^vWbwqqf!Xa#u`OW_.He#[! PL[{F}\!i:30Ms[G> fߴ*XT9W\gneMsp>웶>\q67(9Ρ\&{;d=-Qa%V9fkߒęhcܪA9hڭ*O`]  CTp[VkYF9,lT9," NlbceAUߍRѬ$cbkٷ`^Y`G6c4\ 62V$QYqyҮ-DV_yd@M@|^,=|jUK)fAD- RFV3ʘт8֬{gp+u10ȭ%tUddpIDW-x)`YY,a+u fUen4o K+|+}:/*Fg 4 T`ʾi&GZx̾iV`ߴ*,T "7`M.%+x{p]s 0EoZ?q'cUs}rԹ]?oZ}OսɱoZ#*7D}6K 9@8\M[s863Co#cj?2l7fwrnD?V9FvѡSq[A`yL=)9C}wr] +5X%UZfbeڸ-{:f*"[Z0*Ev^U \܊wMgaS4zr1ZE)vU/JK徜~W,1܇!vdWRwrII6j? %.7jF!ڗ |oJ \r ;gpɀ1-!W5^|BRc CP{ K{:grekWV[ (NJ",* Ʒ7,H4b1,bSD`*g0Ve4@Aa#F= fߴMJEoZ*@m nv&K}Ӓ+AxܲZ`y|Ih 2,5x), jA&%pZpרCuY7Goc!Q ~$eMWz$Nj~ C=Mya^ P@b2'ִ*]b] c EB-3&mݩ5VAp)&ʇ CcSımΎ" s٫.JFH/ǪOT[,;3/4W 5QB. @cY;[_SCܦ]VV̸F> @나 OMoYauYe&iFJ ?g<,C" G B7YZaQלn\8HfQY&{'e)%38k p jSe`l$pZ1ù=k =9­m8my!9^ks "k-H~XP7!ЀT\BCԂ7!ЀT\B;wԂ6!Є VB;gǼy~cJkA/%a5^ a ~[!j8h@`PԂAeC !@-HЄn<ˆ@BZ A )SyLkt̸''(!2}__eKB\ 0C_p`f@ U5RdR/[>,#pZd5iz$}oe~odRٹGR);fCNU <* pZj{vA4D\|+l jjx:B )饌e^抑ܛ\sc @:j#ҹ.^1d['LD Q]?@2u4NhBjA#oMNTl4 K)+ Kf\b#HI%g 1)e?'Lf^SKDzOX Msr&vITc, "L\AcԂ7!PO} s/1TwS8ZpĶfI^'EZ0YR T"f7oF33SLЄ6~,aF]UanyOq z#Cu1Q Q T'pknBhAغ_4+ 쭥?Q3A462pk& CcU4W *\cF-v<ML$j?$*ŋE';Z6҈d\^Y rGh Ӆ. jC i4L1F е 9Ix{8O-Ğ9PCq wf ;Uβ>FhM!Q6#'DfTjG㳮Qa QȶvH$ޛiwyJ q!O\\ ,VivJ &;]ư#(/t{Z`mU{3_鿻,HkDn~Я8{YUqnq %\-)ZM$ ^P& m'bP fTJۜ4Gaכ{/pX28uAu(8<,ruiP #q4:o8/~y0G?9Z|?s~^kx4+@CV x!_\C#Ԃ6P!А!\\C#Ԃ6P!А!\\C#Ԃ6P!А@]cޛ,1lQ@UyN,Y/qZ?~!P@Z &T{ zRq]~.'@-8 v!@-3@".`f[D؅@.VU \QGp>㎢%Tz]+y|Ih 2,7 HZ0⮳f94 kArDkq[zDX8Ղ$i# 0?!eI0/]BO}C\x+h2:wbC@Na-ޒnҺSk уREqc,\~l8ֽM!fXM`V#6YK3euҝKq^xzΥܛ\sc @:ywٚ..ir0݊!r?fr J%k--$zo_&آ v?@?']4!І޵b'S}9c([!#Cz(,*R.&¶Ұd%6v._ x!0wٳl`Kr.3Hc6R~N990g 4IJ`e'4fM,!N14IYJ 92*kk `;C<@Ԃ+Yf P fP n Y?Gys~϶mvHZ=G%pOiP^VfОfBK,}`)rzQc*+6dӘތs9 yԗCTTRj|42^"QrnM%N@#Lv*$'mɹIƮd 61)]f.+7SFEMe}L;"}ne5TXF]eNL:>W 5M'LD &jI'lLIJu4"j2hrr~o种j7ֵ]esOQOzx֫p6< OZu w$2qNo;;QOzx֫o捰Vhac|'=.v9XԳ%ҼUi=ړepR|𘰲`z˿M3Q|Y^쓝 J+C/nkV>o+lQ ѷuoUF*FaRPY N26?)ՉFmc|@.P=BT1ZvXaָ G[~- oSvn*<'uij2ZX@h~ɰ m ;Yԭ⿲-6R -CZՔ y5[eIE`̟T6|x{"t m2+PxP8IUn_-U2O@ ; {T}5j]QEQEQEQEQEQE[QVe_*m{ẞhE!P8Fv/ŋ;JᑚC&mVU8hWUxJ֬FOQxf}*k+3.=~,jx¶r9 X69`#GJ$亝lҒIAYYo~5R?U/"*QEAEPEPEPEPEP>L|E^\>#1x^MnW;_ ֯C/nkV_7@w?ԿjP_XۺWR٪BտcngѫECc/0Ko ĢZ ƢUj hm?0J;Yf=pID*B$CV2I®I,qdt@zn sM]>Uڰ~(ڰ~*(]!?߶ ??߶  >o?0@?߶ ??߶  >o?0@?߶ ??߶  >o?0@?߶ ??߶  >o?0@?߶ ??߶  >o?0@C Aq¥|7Q >o?0TЬ/$oI?'(] #\>[ɸ$7LZ/iı`0 w(] |7TSxm; g*_?Q  ?߶ ??߶  >o?0R2ՇoGՇoVo?0G(ՇoGՇoVo?0G(ՇoGՇoVo?0G(ՇoGՇoVo?0G(ՇoGՇoVo?0G(֬2?z°u!|3ȩ>/ G0|3Ȧۺ]&'|sFjf}gOJ_΋1IeE9x :Vf o`#ϲ">|!SȂLF_S_>|3ȫ%a)<2`AeE_SmnxI3X W늴!Y+F}c_U).Qufo,X{ΓM.}gBf 5'ȣ>| [S2sa)8ʋ0>|3ȩ>/Gȣ>|p%QY/(ϲ"ڹ-@L/(ϲ"y癣ȗy;0eE_SUKk b8$ʁdl _QeE?3G/j,f}cxLjxYHD/2E5Ҿ ?VF}_xJ+uZ$UF*FտºUJ`wS=J˹/^N$qƷ[uazM?rsrGҺtaMjR_k/@Xt^xda{f&AB*(N"xSvEDqLsjZ(1)^jK߾CQ_ d!/G~MZ:[ x*OiIk{`ѝa|G'j.|m&%qx^@4%O3=M1Ӻ<+|@vlbp{g~5Ϗ|LnldgHr@)g#E{8YӧqӌUUf?*諞Fc^B{ȿ|'ִ6OiS0= y-Imy-.|lޭ(q1s^zq^ƻ=tE˕ByԓҔFtU*N*=g{▼wඖU*Pxž-n֑S~/S'Je }*ݗW+(S-QKT]I46H.'HWq=7{ė0+>0{id|mdG22.3)tz- %ΉUR׎S66q%lF1LwR44&.o< =P/b4[;I)*9iٕ/?կxD/2E5u7m"s5W;_ ֯C/nkV_7@w?ԿjP_XۺWR٪CcngѩE>JUg~tg~tQF}IjX%ڡ}yu>󦝀=YЫG) *=GG󣙊Vbj͜=lj}G󣙅lhdZǨ~ts0%i,ǥ4 Y 3ʃ$)3?:3?:.u.@˻cNݸe?Ʀ~tg~ts0.4ۗaw_>>󣙅DI|cqqǨmdU?:8 y&:-sWoo@\aΌΆQ~Wkfgo cgAN+-g4Ύ=GG3&ŏIդke*BPq?:3?:9X*HhI>}Gp,}_E\ZǨ~tXlI;YDžlV%}c>~t7}PŲ٧ڥjJ}z96$vB8m"ss?:^"\ME+C/nkW·_5rO ; _[5S~~!jU u/-7=WV?6{ ly4h-A~*Z+__"C#FYَ'ҫXjvg^7yM靹CQ}}k-!B#'=9E,s“C"AV\h_(oM%~*Z|@9f*s\sZ1izTG,p$2Bl__CFI [#MiqImmJS8'S-G-QOmYIo3*h2rsjk{=(Ѧp&S4ry؟dXdXZӿM4b?9p*}aK}}aKkNQ}7Ϩh]K/QK/U];}GG.>ow -G-VtغwƎE.ʿdXdXZӿM4b?9p*}aK}}aKkNQ}7Ϩh]K/QK/U];}GG.>ow -G-VtغwƎE.ʿdXdXZӿM4b?9p*}aK}}aKkNQ}7Ϩh]K/QK/U];}GG.>ow -G-VtغwƎE.ʿdXdXZӿM4b?9p*}aK}}aKkNQ}7Ϩh]K/V/'cmPIߴrsRxgOMҴ{'#ey[|ǘv8.vf c*Ksks 3t'9~ _0hQ[-% :ew-8=r7jI' jO߳oVjs^u{aS^} {W >n:߅-6k=׳Wpf9H&@2Oukg~zT{B?Z$02FpNqJY;=v!yMt[kg~zT]w M+zT}S*ᩳEc}S*߳oQu56ho߳oQO.O>ש~Ep٢ש~G?߷⨺4V7?߷^?U]Sf^?Ukg~jlXkg~zT]w M+zT}S*ᩳEc}S*߳oQu56ho߳oQO.O>ש~Ep٢ש~G?߷⨺4V7?߷^?U]SfȭMթ~\a;!ytۂD`1 擒kso+lJF Wf *6D nsa]KKf2x]FK越qdE/[5-^%0=G6O\xo_CYdҡI֡ 06 ϡMtgw(3@\.Dj'H= !6b3[W9v5 jWS[Y^G<}L## =G\P'Yo1[`Sn,;kO\}kBK״DF&c !yݖq@uCo}ig.=А6v(f;OR - %Tl d@wT:gKx5 y%7s6նڸv2(*FQEQEQEQEQEQE[j}ڶĽʷ=c,Q]>S̅7lmqsm-pVq@[j Wwɯ`{Ǎ4^j[ݰBٖ'JL3q^U_SOZv>jfS\`;t^ҳ>I9_suS"QDjj{T9R(J ( ( ( ( ( ^"ejݬ/ȅ/\覦o+lQ ѷuoU M5K/]hWƟm .׎I$I{] J+#WX;Z_GBv"cEdj'k_(?Nֿ$Q~NՑН/HWX;Z_G+ VGBv"]ckYE.kYں ?uerEdj'k_(?Nֿ$QН/HWX;Z_G+ VGBv"]ckYE.kYں ?uerEdj'k_(?Nֿ$QCeIS}ߝsں ?ueKG~t}ߝsں ?ue!h?>>>%.DIC;C  ;("(;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;o" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?kY77VŠ6`nO#+]ޫ{8$]KhhO*.X-|)aԗk7*Lr7~#88֣_[pOes?ϬQ+CMc}w ť}oml8<5g:ybFk_+|ya3 gx;T#&aj4F7X?أϬT:vu^EgcyQC8 ZÚV[zr8m9uN.i=3Tc?"[(Ћ}mة#ީ+HǙJ ;tTbrT'=i-9]E%"츞x&o%}_}56߱G_o~R)!6Db0TƙƇo~n`Αm:9!C϶kwh^KJQqQN2Mm*5{wY3٣!=U9<CE̹?1[NQ)Ny۹О0<ۍ- <[A D\Ktnt0ijG45o`n<jFl\XON+ZŜLv 9"L!2=*rhs3v6 .V:˪FrJ`r ~F?#}G̳LFiӶzy~WB9T{''EA&Ho5UIjd d7"+| f|ʅ95EWmdtE!NJ)FQXo\X%&fdxBF7JFVrK-yb(uB 6;NwW :T䵾<$QSڀr ņ4}{WWn$gJ81Kn_r3)N$DlAھo;I1ƌVd!A=:Zq\UǶ_EmUq2#7QO[TUo:O"F3+j,o:O"F3+j,o:O"F3+j,o:O"F3+j,o:O" [Ber$ץל|eR_%u` RJ뫑i"ԿҺˆQEnQEQEG_JW$6-淝&U-ۡhUNT)鎔&a&dr-nrW' ⹹[Tl:{HdM&FNެLʊQ\ܪH$J~Ҫ6dڪt- ʅ8@=1Ҁ97ĶWbuXt%nA.pPĐw/ҼKIuqiieΜr]2F)϶<,NDT[+uUX@@ `qO#Gi}ӭVyw}p%ʭh_/*4ƃ,qkM_v2!@8&]GQQ}Oo@IEG'?Ə9=4]%<tT~r{ChEW|eR_%zό A-z^Ou~MEiu>NzE$3mՇT^շq⻭6M/쯨^A3%&$E܆)!ːj‰\(W&;{gif+p2T``̠cד+"]12F-piޡYY]okV-嵴I$m\iY{m|f<:n .#-0 <iPĮNpE[xTDDfwsKnc1rrʷ^ 4mRSUKET7G)fE@%Xc4XC(J~ӂMȡ ޭǍroV/@g_L4}_L5E_*xyO&xyO&裕xyO&xyO&裕xyO&xyO&裕xyO&xyO&裕xyO&i*x.NS7Ifvgzmy_!RW^ %_K|.K66w\BFa׽u2htKv!)>c̊drFk<1&ú[Y9XK*:ֿ.{?5׌b*'8GF2V1ggik mFehdt Ɗ< 0tzxWGIao)1edID-h@P:q\O.{?4#Oc\٘Wzg6aqt2Bݣw +3++i`Q>b38\5q d9z9R1\.?4#OcGf/aIac2O/"J;)s1%d䀠 *֓:[kI"Y ݂@]{ o] ho@GƏ_+="YDRѰ qVGd4upBG ?5Wgo|7FMy.?4#OcU_>={xoѼz7ks'=?mO^=4o|\ ho@GƏ_+S3׷FMǣ&=?s'?0 ѿFɯ!o@GƏ\ h/=>={xoם|eN_Jo@Gư|c/˧f2tapXV%̊a(&traitsui-4.1.0/docs/source/traitsui_user_manual/images/themed_slide_with_focus.png0000644000175100001440000000146511674463545031710 0ustar ischnellusers00000000000000PNG  IHDR@%IDATx흱J1=,'P,!K|' lDp9fgٵ~VlL6u 'n7vpXnqi۔fď7IH@`sk[FǢʨG82 %S,2njxAea$ŪPoU}M Q nm8XA HIKWY[W)[?"x^SmP :- ԋY)tselGߙ2 Yt8Ѭo.!4FS}L,Qic;tpYM ";DJK _t>@LeQ֗kȟ)ts&O?x0`.s4HeNm+\QЕm#HC"\C #,G9tFS5]*!PE`"38R0d{7ry_yDߟ2 BG&2" 'rYY*ieD=!a"b =JRz{2[#`1ʭ%*xQ@X+UAm\?c L@+oـ~=ց IRk ˍ]4v3  WԶFƄ0% ' DIENDB`traitsui-4.1.0/docs/source/traitsui_user_manual/images/led_editor.png0000644000175100001440000000103011674463545027126 0ustar ischnellusers00000000000000PNG  IHDRz*DIDAThM@EmDHt@#t@ ;@ PZ7bF C2?2+{ytjŲ_5n7> p}uIm?7S8)7ˇ;S).D4 /U0^p)Hal yS(m0\qƁ0d.O%Mc[fnJjlqk-e{ma\pIJnwm\8Qc' *yb_]q O. ;J rp>Lx?C-TT3upS PM%@5SwSqSlW]8)8tAyR.ꃚaA2~\ Qa7UV\ uDU43 a238Li?%;~ͳŢ}neG'E0p*k*xSIENDB`traitsui-4.1.0/docs/source/traitsui_user_manual/images/search_table_icon.png0000644000175100001440000000153011674463545030445 0ustar ischnellusers00000000000000PNG  IHDRЭIDAT(-]OGggf?^8`bW 4 JEA/H~R7P6J@(‡X"6YXۻfwg6c;:gwC-}>cU@[ͭO<B8cUu򅪆_yNͰS q-~UkLFncO:|dB@ٶ?bqål6[TQJ:9 T89jm'4s:{$Q*˫xfN(qhFSi5%Osi{_QғQ Y׮yz'@pJL$vvH!jF-U1Xezق xpxr2;88bq!eQ0Y65:C԰C<'Xن\F /bhM|n=SiݨoS=T\z]R됾!^47.*cx]A?'&o_ss*Km˧ϕ(ˊglwo'GG&nmm[M(u(b$Dޫ^!Q?{vvv=gf'cJ2R#'w.%0wn~'Q=YUub0ϫq@ x3!̽ K e߆a~;L|Ѩ3=IkzIK6 Fa/֍c,&!XApIENDB`traitsui-4.1.0/docs/source/traitsui_user_manual/images/directory_editors.png0000644000175100001440000002163211674463545030563 0ustar ischnellusers00000000000000PNG  IHDR' IDATx]}%gu{q͇Q1)X!BPH$M֚i6` EiPS K)I.&{{LsϾg}>fyfޙyy;ofNΝ;wGO$IFGdIʷ+XA\\^e@8$ dI,5*2+ȵW"Jb5Jʀ2 l_o*Ue -R!,)FP6ƀQe P1JSRtYZ~.G>Zgme` 9q#ʥ /|l),U C+R8o`=/ONŧNpR ?ҳ5ҕH 2H%)lR2@ikeKz-)%ltnHbX ZֳF̼+DIP*cёZά_:IӅ@vFKٞ.ӹJʂӹ| M`Nk|WRd.5+OοS o0cũd(I~굽:Sɋq^G$,C<0gRC9;7H' =5 dӖ0,=leD)9K<5| 9y"M\LI} >wy4CV)vh<_0X-@aHÚN!Ȑi- ˧W¯k1wI/K<Nƒ)| @')Cv!(SX[90m/f'R"e$ p<`RNၜqJA+imq KS"5HY*@S ]rEnjeye9: wB2 ( h*Hʀ2AHm| ( h*Hʀ2AHm| ( h*Hʀ2A[< f ˍ7/+@ n|ݤ/y)ʀH lq4e 5A_8Zuy@"=+g@w.O;Z5e` h)}g/ћ94Oe7sVrY0~x hte@hC"jϬKSbqG"vP8ο7<o$ "e4q цLJX@Źtd&i.Qei:PB"~_&3ԬVԫoyK#?1ݔhbհ# BBXPjwu\Ȓ$o^-94E=hCCQz(k։;|[ⵞX d8 'Y|g9 S,/I(Jl:qA;K[$%5bZo,Fŋ>pM W>'*l))D)Ï,m a{y6C4l.}'R.T+tTt}0"(D JCQ׮wxˈ{]Gwv;r#G&;#[Gvvd2z< yd.oi3h*%N=XO}N4S(|W@Pbeċܾtg/];ݛͦޕ˻Wvg{d?O>7r#a(ܗ-?FepW<7}?pBB3fBb3pm?>3YQ}!:u&7 Jo(Nσk2F פ:y~u(:򞩢B4̷{ Qab~#\FK]p9;,<@j(1 [ʄ0m}zF K|Xq =9e4}ӸXαl<Y肎gEh"J-m|iwDrAzK}3llyveW" KY-e0JB QyFez*&|*?_#0TtCmhZ<˿̦KIQ?<]^8MM8Fj b*6%i~9>Kӫm 5G_ FЙ0TtCm$7DYWWuGmvt!ywܾ {Y%5%i_86qnER"y6N*ɥKP@w~|_g^|G'>ʢ }KK H+mv{3|Ef՘7_UZM} Ath&V@Gq,%)'c<ǨSypE2Ҍ6 !G)TCe` h'Bۓ舁+DzSb;Xaԉ,R2ahCORĂɷOdPej12a HR K=U#:wscGŷecב'wd JV( 5r \sb !EӐG`MTPNj7ghzv"GOeI$c {WQBaGhZ!-YRe% \-WSW][LJl4xKd lVHoY DDnȕ"t2麃~*e?eeS h';"ꃶ#^: })g@;׬WDG4(_dTyqS>+ӛJ [؆ų6^5@ ,RhONh@mXՈU;ޥeԪuY % YɂL( HU(m*Evgy'UP3WCe`= HUmOhCPUhKxeS HEtW wjtD/G OV(E{2n1ڰ5ieIYB 'цNo!ц!Y)FE O翐ODwцLU>LPX1פPq:.#0zEG 4~\}wUYhEYe:U4JP`oX@Cxn ?J =z[}T2 D3PHF 7_reV΀Xf mWר0eפBB1\ڊalIk a'|*ыA/(V,%16mUPhiqm܉i;bPnk.bU D0PB oꗧXrI^IҀ@ɕB{AKϓ*1`eNʨSBufSnO #$p#]CvIqb-5TbX11ҮB7gz +ETϓ=O*h IR@d d\BцˌتD?Oʮ5RC &D +k.gE*=6 U#_)VŮ5{R P?:8w1ٟ.y/q&iKt4g4۷t?}Q,RI0U_'Gxkkh;"':󠌵 IA0 }͊}At6IbAO YB!lM!cȉ PMgIyw ړ?ЛJDՈU;'%k˶;O11OV*yR0)<4Mx?OM1/P;)"JۊJ+)?OKj%x'xl<R<%[6;)._yR"x0Tv!{*DG 46U=f39QP$͗=#FJ\=zv|aq1PQ_԰))PE$E6FQ7]ޝ%uude :bak5#|*E-R㿫Uhw*5"e\@mmb@rtOx0l/^'<##\j9HEwцNrCC <)bf-Ygfّt1JPmo͠}E*ˈ6 DG 4x^`0.5zn :M;y},M<{O-/{({-ړŬ :bဟ'=ABkȧ}FO?hOQ ->cE,Rх&Р5|1P'wJM̶ms\h5$:Sxs)RV{EoW!k6tz QFG6 Ɋ0??! 0f, ?x˼#y YvV lOVl #yRg9C;ʧPlh5v8[cxcX2]y8vsSO 3khOV%ItD2,"t:/?8 "ىc+IbnF:LnYapȡ3l1|BVh lOVl #aI^pU",yO &>Wӿ^/\AYEq_ ?{Bt•a)q'Elxԉ$MA._Iǒ$}Z5 * W1[ 77~tm_~wq!qи  Kv?OKŰ,`ؒ+J<5Fҡ@QJMxۭǟz.]y6[K-5NN>Þ%=RF2 4n}ܳv9RAP6@_eP+@ ]7m5u (@Z )e@<Z64e@(`@T9: (g@f ( h* Ge` &'ee{*en$ٗ<E+ʀŀYwEї<— &]+-Rc?*2ENWZ~U*e@Tow& HTzˀy B_7seOi@%ong&ѕeYΜU)R8}4֐/O [OoG'd8<O/!4loy?dX",/SF8T&eGjH XDJ;wX~ϚMɿ' G'd³ 0fya%ay<`~iH&4Ct`NVlNJ2a%aQhSF&ވ)IN*~E*ȼ<}FF t+8h[>94YO2f? Sezr%glĬD2%cA&á( ?1l \l9v@T~+G2$)58`yCCtZH/He^Cy™+"3&*4Z2F12:eiHb|AS&'qV@wtr9htk0ufv2GȄ>s=Ҕҩ7<*T:lu_⤹{<%I!ᅃ^,|@}2d;BYȃI&viг!}1W2`xمsXo,Ѻ81 vbgmoZ;)zgG)RKE –1\ik(UJٹCmAYO SK!,z{HHFXYr(lM¥OY !Y4lHm[d"eԚ!OIR{dN(>lG9s/#BE#y4JBDZr p43C5C˸.\P*1E] Vu3{xYP)@ HAmҢe+ HtٮPy(@ 56Uʀ2P-R)Tʀ2&ZdW}+@mHզP(@ hj] ("UBu (m2`ނ?fHw3婙2 0`fM}yWP"0T_nKE͔e&u (d@T'w& ( h:`BUN2EERH0*@'"ݢI)Ze hnѤeVT$[/m}rMu)~eÏ1,5fJWM>U/fsUIDATYoFJ1zE@zB 'ӟY*#0,G 8oU :Gy[pd< 4RalA&<+ic2J al(^2' FC2qNsRv& S@̳ !L[ֳ7r٩@PX]H8{ö\VV4gƳ!X&<[aJ2LSYzʀIIM┌YO)sC M~d52R ᖇ{c kcQh cXə>yKNd!n}x>@_lq>|n%9 ɼ`deQxHq/Y ]_+2LUð:Ce>=]\lO)Ԁe=^*[QJFA l`NHSAUf`tN=o{w鰦y\ΰ LKnKsT)~qTZ6.NQZ{|vau/kBTEM5ͫp&!Yzit!gb^8Wje@Z4e@2EKN(@ȯIwaOhʀ2`0 ͋Ae; ?N_IENDB`traitsui-4.1.0/docs/source/traitsui_user_manual/images/alter_title_before.png0000644000175100001440000000735711674463545030670 0ustar ischnellusers00000000000000PNG  IHDR|FIDATx] {^.]j VRMQ&B&h*&5>0KbiMilJ!$k[By,eX~s=;ٙٙl?=?1J%J+vlKts2,j/&x)1{|4 b *FSm/${Ocx0,2P\bCcD W&T@ #ȍ@ Q^60LSQ J?Te|,>mupHMZp̈GǗ1!+;-]*Ϲc`,Ymh$0Y!EB어E\{v-D2Y}6flxn&\*Y<&^woM;K^쨙į/](݀vL)+>r"ɉMɥW.j;}&G FKm0[dVhw* @@~+\%RrE="KO'Ԥ'c;8 P K>Y:imxRUkgeщn}^3 >%v) اI^-fҫAZA+FJb9@^x4h쓩ؤ^V3t^}uۯ~C8j?X3(io}eثeF{ ~O4LYXD3X OęiiP4ЕaUXzd 3 -mזIKn}S\7H]S{.!84)5M?;OՆO}fֽfQM`Er7XS/N.fկKbL` Sދ, p;ύO,qSqS|U_,WZ;?w6{ ^ -of$So=qhv=v< pYWϠ8e` }dJԔc_ !A#S1ۇԅ-$Q~Mh%4_Ӟ7Ukk„ 6$yZ+G|2SE%+etР2oxН%-eũ'r9>RLJ 2iGqm>]zõ3{Nf.iR]ADB `yhy{3PN>ɱkUͣdL$/ag@F~R.o04#͌+IaIM0hPCp$,"~:g% w*Sr˚GwfM `%=J7_,!Gx D\u!ԫя%fziR8}W*?*H֖-Ù[ŗi@TF\Xȝُ5|%ľ*)SȩtwF} sJҩN|[?n};_miϖĢWv^~ 3`ƀX6-;cPp,#1 'A $gh"a"!LWN9tDS@0xf}D4z(vWmєR8028ټ/b 60@Ԣg9,Hyшa w " T:모t?H@-##p6D2=򍩀bz_{S.PSA&sﭡ#ɜN*Dž7ƀz&-R2 W^34l 4zg) "D6wHMG35hp9? C4URk`028ټ/0230D|9ְoL/ߵ) p/oLQS-*]N#G%QT7)M4QT7KQ)ߘ0/)*loLuG40/pց$E:嬾E)!ZkȔt#`BpE(SDyi>ଋ12z2"4iwqC( EtdӾ9Wv"` @sxJ"Z1 \ ߘrTu9ݢ4rxT" LuL!">!Y@ȣ ph9v䗬!+% r?ǎ\=]䛿 ewCj$ $:D@C8dCBbC$ :# ~'S2|Բ&8fxZ)< @X^F I"GK`L xn0x@hhj"䤲k))j@vPTSwa)DPߞZ}f^B3L6QSb!'0>'+>W׈):p e4C4-3xiiXz54us2֋Op7s.WU0y96YY\YZm}d.7<ʲLp΀۪ζ[ui~x킍tN/uegY>n\(iH>Hkn$tMV_77{? Þu1:$7#L}` TW;sq2?_Zd4M$>PKl;8>gH-\A:fClh0*m?#ݙ6j¥1W&GuU3=G cׯ(hB0iL{P:0 SDw$LvZ>؄~x&Ƌ6a_>0^| cbM;-lX|`i`N0//vZ>؄~x&Ƌ6a_>0^| cbM;-lX|`i`N0//vZ>؄~x&Ƌ6a_>0^| cbM;-lX|`i`N0//vZ>؄~x&Ƌ6a_>0^| cbM;-lX|`i`N0//vZ>؄~x&Ƌ6a_>0^| cbM;-lX|`i`N0//vZ>؄~x&Ƌ6a_>0^| cbM;-lX|`i`N0//vZ>؄~x&Ƌ6a_>0^| cbM;-lX|`i`Nw.~.# 0Ms!DT|6f^#MC>3@.EN;GgMrPmzn1Uɸ΍|4~S7ź|YII3>K|~{sdly.1!اɇM,˯Z hDUU͔vkH>PyǯユV43w̛d1K|tt_|gݛoj;c3Gϗi=I(rF@kIENDB`traitsui-4.1.0/docs/source/traitsui_user_manual/images/set_editor.jpg0000644000175100001440000002414511674463545027165 0ustar ischnellusers00000000000000JFIF``C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222k" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?1ߝc}:%j)o4ծe6s) |\Ώ˝6rE˧_G<>[OLf1۩`M]?L1ߝc}:k(K"6\7Ac$3BP$Q Q zfP*=ĝ=y$٧f~`i? ԼS:.ow|/bY+ 6`RH96_n.dKC`0]R0F5]vMgזh-&7-&fWE< A biɨ|e47PHV-z~h?x4cl:Iy1ߝc}:y|G KY:ï ?hUNFsߚ:$wV60mYd$6ZO@c}:<~u|+3ý6{d!i$#ddO9999'vt[@;GoΛEMwoΏ1ߝ6.~tyQp?M1ߝc}:m\yh;GoΛEc}:<~t(?7ӓPyini֬Z~hǖozu|G KY:ï ?hUNFsߚvyבS>$16j 1̄F[_p9+X^iu*;$*$`$ddpq\ľ6KeM~>lvJ4gMf=~ɝ'MMN{7cWR2#^ J79{g%z4o1Nbq r2$9<{ӣ"fð'F>ݻ]gӊ͗úM孻ʉ@l etiKwͥԏ1"bNٮtj/ЋĞ#eloVZxZ7 Eʳ2i\9`zvqGi洵2܅ Wo: Jo % =!ȅ#p:}$ ng_O$ٜ6Oo~&N{5QO}~]nL6% [t[9So^g=?_ :+RT8.u9I80k\ ɹ 0e2qVSF" k!c11R͠YKWMEӄyb S8s*K&IVd)ZT$t)=H譾Z'S >ىqkbd$j A۞ +E둴;R`oVy?Z먥ƟcpϪj! RMCwP_ZٝuʾWhbj7Th_(QޣꊯWf/SQޣF?zO"(az_p4/¨пQWuE\>KNF?zO"U??)i?TQy'jT9ŽƶAY^4aZ(|_i$;;kXHR`A[X햲[8h?yϷ}o^zlvQƟcگ=?O@O}Sފ>[U@Y ~U>ߩ>h?yϷ}G+;{ʾ 4jg>cگ=?O;z(o{cOWqf1mW~Y ~U>ߩoEXai*{F𽏆[.Nᱷ0n_n>QNPv4I%ds3hoW3y#6]f-]5L6 (AEPEPEPEPEPEP_uZG:Ϭ ((((( 7:rRWC\#N\L( ( ( ( ( ( (!E:B?ΛquO@薮7jCa*QEQEQEQEQEQE5Yt}GΠ/8>z5T7޿3Fke\_濙z5s:wkqo,Z+f"ƽ}gPdS$+]B1A}~j@OGMTcG?ƫ` t ?t: %K:7^V#+.pO?Ut::?l?€,}~h}6?G@O o?"׫:?l?®A66GKR5 PMFo[)+{F[VJkh&QEPQ@Q@Q@Q@Q@Q@}oME:B?Χ͠YKWM\uDtԡQEb ( ( ( ( ( (t}G>}gPdd`pE7>|%ZSLoPEEa_S(G}zzK=Ǹ½rx1ӎQwk0/("E`?>|ķZ2M<$,c]Xb+^gF[VJkѿi땷; QTEPEPEPEPEPEP7p?[_n>QNP@s3hoW3y#6]f-]5(l6QEX((((((Q>uY7!;Ks#!?1LB+01+п'hB( p~fJ/ آ1+п'hB( p~f¬вT1^h 7:rRWC\#N\L( ( ( ( ( ( (!E:B?ΛquO@薮7jCa*QEQEQEQEQEQE5Yt}GЊwoʏ-ߕg`E;7Goʋ)[q*<~TXNQ6woʣGI(1RA8## Z7:rRWC\#N\L( ( ( ( ( ( (!E:B?ΛquO@薮7jCa*QEQEQEQEQEQE5Yt}GΠzSLP'֊{oܖHYr~8i*QC2H8?OLЉTʊ7Gsnwo^ib8}7 x.ߛ,bBy[^ҭ洚 9atO~\?/|\'֊)d?uFlV?uFYѿi땷oumaEUQEQEQEQEQEQE ?O)tۏ~S/~uDt͠YKWMJ QV ((((((G:ϭ?gud˪W) TM[&/*(տ^bտ^bbտ^bտ^bbտ^bտ^bbտ^b_OgE F)C 3A#EPѿi땷oumaEUQEQEQEQEQEQE ?O)tۏ~S/~uDt͠YKWMJ QV ((((((G:ϭ?guQEfEPEPEPEP Fo[)+{F[VJkh&QEPQ@Q@Q@Q@Q@Q@}oME:B?Χ͠YKWM\uDtԡQEb ( ( ( ( ( (t}G>}gPaEHȊ91XQOoF#?z,(?ף}Sш^)|ꎛ|D($<\g`#ѿi땷oumaEUQEQEQEQEQEQE ?O)tۏ~S/~uDt͠YKWMJ QV ((((((G:ϭ?gu>_4|_ip3⼸+l 29SڬcuFP)7u *U5(8猝~h%_!S=\@#(NePppXqϥIn62 Lzc0B@EYchԮ#q 2N)D$ Jes FB._ϒ! H (T$wzd$Cu <옙Y'~W]Ħ?zaUQmDP30(vk^+^toumFo[)+QE@QEQEQEQEQEQECqu6 :;y#6]f-]5s73hoRaEU((((((kγAYAM#N$%' տ5bn:3[T/5oE2sVVc~j3[P' տ`A[[yo@2sVQ/5oEm?֣1u?b`A[WuRͺLn%IWs[Vv|NB]~8F[VJkѿi땷; QTEPEPEPEPEPEP7p?[_n>QNP@s3hoW3y#6]f-]5(l6QEX((((((Q>uYֿה^xV^ni.nl 2:0H(g'^/:.t0yl{󜌖=~*6c0?12[O-ŵ4І$2l!ne g_xb9,t.c @GwH񴬥cm)Vm&UmJ f[cVomǻ _3a8ES]]He<qӊ4m/a[& w # :DЌY@uWFdЋlе &>Q U2w>as.?ڤVW&2V~A@|'5kyNeԦ0 ywN:qE־?U-Ē\GgA 0?8Sm-WZ!$]$HߏzD+hdHa˱*c~I=LCxgKwgxw1$Ti? *@[I3\Ui? (m'xrT-._*( E?Qt*"1E U1Ec|9c|<gs/T<gy(@_y(Q΀EPQ7?ȣf :db oBwtraitsui-4.1.0/docs/source/traitsui_user_manual/images/list_string_editor.jpg0000644000175100001440000002311711674463545030731 0ustar ischnellusers00000000000000JFIF``C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?M_VU2YDGwv2@3( @ɬ)|qh;)f wkO[o t17iJt i7>kl\ZOϳacT&s!ukvjQijV2էQ+R/s\]:Kkm|yH. Zi][l.n.KdRp|Ŕ;~lm5I|%˙NnLZ;s0|X ,nNibyEp~m@  dLZlZXL#k;s|c\]LJuf[.ĀTnY ˁMM@G y-d)bbF5nqaF6LGK C6sJpFz2Ķ" F('KYjb"d,$gY[u+?s-Q+"cQe4weyX2_h!v37:pSm^gf?fx܎G8.7ǚv.6w^K;\/7䒒HV`NO˷5gC%ݍWVgdJ 8_ߝS}o? |ѿ:<~uO}~.yF?Q? .=ϗz7Tg?pG(/oΏ>_ߝS}o? |ѿ:<~uO}~.yF?Q? .=ϗz7Tg?pG(/oγn摼IHL>KoU.!,rbYntuI$i$pY$pJg:%FN\`:;zpk6:奬{Y-"dYehz!ISI\'9PKkZ%Νok{GQ3;b9 pÐɹOde=3?2?´ GtO G#'O*(7'Q@}?+JwD>;Od Ң3?2?´ GtO G#'O*(7'Q@}?+JwD>;Od Ң3?2?´ GtO G#'O*(7'Q@}?+JwD>;Od Ң3?2?´ =cXԭu/Kӭ.纷TX%Iv GFbx>2){w)U9$PcIt޸̚Dž{Y-m/`%YT7dDt3^\j-i0re3Cl&?qAF' ;=K¶:Q%G]>X30 EtˋV62,^=1E$\# GU`fw ϛKikipima4q**#i&ø7piMц@mjK}`X߇ǔEfџBm*Syd_~}ΐ r[xY8] }^mHvglB5C#U*5v ={i'SG^g¦y#gؑ";6 (/ouoƺT[Z\\[+wZ2?2@랖?5}cWD:v[VO*#dt$f6H^JToy|9 >6QqqHњ D$994AM5ВŽ6)U # q )4ߋXDM!$U~fmpyg`{N mu B r,̌@Ar KE|1m>j{%VIa97՗:}4mA}$b_%Oy|nȜ`8e=f9|_q"I $iJJQKoB0`N=fqwyOpG{qF`2e]V7\fhZkyiNTo82e- ?|4=Jk{4k[ 98G&ܶI%MjV?n-⾽ʻԮXC"V8׌8݂~(((((((((.nlt;K,MռR]Ĩ*. `K F2?P߇RdiVCPnH0K-cc0||$R5ku$!u|ȌrFsIQ nl}K~nixx<`^o1dɷ<WR Z9d#&0 $lt_fo]{,ۯ97p#4uKi$yfIED(T( ' J( *9[cHU I9I@Q@^X⹻%VH̩=~gETO XBꁝTsܱ@QEQEQEQEQEQEQEQE_hگ}fws^_|W?'5#KIis(,xDN>0=x{j:,ip6/ yqnDwDT # |&[KwvOGc;)P C"Y@á5;oHM/ wk-y6JdbW3cxFH_  4Ʃmo[;f1 tFy.`xEi4}X.$wZF  =[F'<eݧ5s/T_5MMH뗰ME-K{}5Z3jp6UfX&PPa'8k HݒV3p+dۂ66#|[ee㝮%HHFM1]A8R)?'. Yç$hκbc jEfDb'Y(zͬ3"̲l{Mf*1#~-ťnݒi-I)MH# +Miʉ\ZJ<׫ÕǸ|g8IDnfwRE2Ck +/ZυtRcYlc(g@ qkR ( ( ( ( ( ( ( ( (1Ii6IC1ʜyc9ς-'Hɏt;nc" V3٬֗[B&R`Y[ .X2-T4nB6vGj$ -yw麜O+.m Ѭo2Yͪۀm<~Yđ%>w{hNT2fOU!ao"׭4MKL@Mٚ5umٵpWh2ǐ3ǷYѠk")n/dkҲyq\|f"՛ez|'gxzG 0)jmU ȟ(w@*1^kɪC>MA61N y-=nv?n0׵-CZ 84.m ٚ(. f8!׵-?Z9-ZX-QU")f}8'sKMya+_iirѣM8w6#q,mC |5Uե&{$b>42Pܗ ~QD^vm5%[@[Y"[9̒8W&*Ep]:/vٳƟin.-OmD&$Uf[#6rXtjK)E rl"*(N>@xU g˻缕'+sl ev*ڠ brIs5e:z(`Y%vT*sJ)[QQaHI;|U0͍rP zKm:k8$aAnorLغ}Up0JɤCK6Jie!!ҊZ$r$ ʰͲ6_s~mytwt{K5c(AS$s~a?~dѢEN S,$0Hbx{L|;6[yv؁wc'qZ4>%t%h!1E1s@x]' PA[QEQEQEQEQEQEQEQEQEOR5ku$!nqpO=]{YѴG#ڽeĮ+,[%~n yu<1iux=fL}BI tZKulQ [Bf[Ab}C>*X$O'(9Un.ccSG 0"׵;y/56I,RksFhD|1Pq]Ujo ![p@BTNvN4H~-n7}{c8ǚlg&3\3%n5I*@ *s^ ttXɚbDH\2i QNrx_Iɞm3Isw,đ1ضq.v1co>Pp5cy$(8 Т(((((((((-#M;I.JCmm%Č2#Vm* crFnA2: HI#FyV ްOle'Du xYŵ q.f $d-sqxs\7IXy)-QIYT9D|qXXu~]I )<:ՊgIԠ?exzymtK]6rn޹cS&J'dg{D4 *+۬x""Ƞ$O3њ8nbgw iJ!,B qzߊ4U܉{nL2#d)wq%'\No>DadO-13*sy QEy?<+ KU-twxd p͸9(I*<4AZVgu7>a Y !X) ԡTӶȗ N~i=ϛO 9ϝ獽{i:\1_M=٢yIm%XU Md`jV8X+fTKImeiV6ȄaS\WVșL-{Cr\%Fyےj~(tgw4鼽i,ĥp:l3W%vRCZM(0pe;` <)K{}wTխ'v- HtrM9` sNWcXk0AŽOderMq*`HY~ $ p t)ѯo>myM'A!hcu`zp&M,R "Hb(o@89ǿ^,ϺP{e_fux,V߇徍de #0:SOJ/b(ǵ)߱G_m~fcڌ{Qȃҋ|أJ/b1F=AiiE>vQ߱Yr 4;o(ҋ|ج{Qj9rQϝiE>vVf=ǵ9M?(?;o+3bD_m~qϝ1G"SON/B8 )ߡG_m~fbQȃӋ|УN/B1F(Aii>vQߡYr 4;o(Ӌ|ЬQ9rqϝi>vVf(9M?8 ?;o+3bD_k~Qϥ1G" QϥiE>Vf(,iiE>QZߡYr ZߡG_k~fbQȂƟ_k~Qϥ1G" QϥiE>Vf(,iiE>QZߡYr k-((qK,Gh'8($&Ђ5k5PxBcmj.CXXJRCDF}:+իGeBK8var}2>LӴKHڭ7( r23w[ZC$YWlr(+n;o>?Mp |'-Wkw;09},F%Q2/ ywUR)ΑZ54uK[hW~m2[=>{ |_ hmµ>* kOڬH,n+}~xG}O"*'4<`T|Z3hjvI?Z_? S==aOES==aOES==_OEI?Z__?}G{{g ğ??W~'G ~ 'N3?K¯'iO"|AO_G]*ޗ$(_OE/88""?U$/IQ ğ??_q?qEEvI?z_?Kk<<W~'G*ޗ$(Q)yy¯'O"U$/IQ>S(+_OEI?z__?}GQWg ğ??W~'G ~ 'L}5'wpKy(KwkI9f aW'ǁV>ɜyvKDqQV oJ/W_g/e*]+1ɵ35jir@ jFxX2INUⲍOaA|_h,w3$L[^23qf(cΒ-m6;2<"5\Jxl܇e|׌2$ӯP;+ĵFT}'倔0 (Q@Q@Q@Q@Q@Q@Q@Q@K[.7yh[p3\_:?5uŌ:I8A1v׽|s c ?¯366Zu;** _q'*SodW!4q[h QX>n^_ǎ|. DmnDjWy}l)NV]]<-X_h؛ŊzY֮M+f5zqOt>a-Үn|~v=sp4[-r5mS6sW.{؎i-̺-[(7dqXtzW:ig.IZltrCGFOr>/,03?+-#WJd('d&o$я!0i❀u*f/GKlRZd1e–`3q_?d[1k &>s=`B4vkľEwg5/ukOmnkc.S<$ADC>ʛS]?KUsϋQubIE'(褢 6__ ?SuK<0c͖8{~ȧ7|(CH>e|pfʏCdt_o?KWuD^{+_խ~!hXTט&{2n[+E DIYg?pY#%DWGYXd0.2:?l?°#i5{jW4iFԱ hTr,HC+, Ѓ?bV"-kV.}~W=υ_+N _Yv='VtG6ݞ19~g?pRju\^giilp3[II%߱^d(+:8 U{W0Lb9!^(,g V/ L@&x :V8ugx4\*wXw:oSGqʸ/k[x5)(cF00 zWULTp26::( C?ξurk,>םuW.ѭnKc*l3c*Obt$t'c4&Cq^/'|?c>s^ՙpz59ۃQ>#)75*T-J#5#,}ꪚM}KZU^?A를Jr>t'-){.*jq_!u=8ȻnC*ы^_; A^`MERHrMGXgE7x&|wJ._)(]CؿRQ_q?G'3־ȧ7|(sZmޡ5@ 㿹?)_?J:vB9o$$Q}3[}r(*XsV6jlV5''p8ƪ׫zo}[PW{NpAz#_F{UqxAPk2m=ؤwvUl oʲ B6fdegbOA ?? FFK<:Ė&Dj#]?R (j2}I}M_.mf>\\ѓxJTŪR6Oߘ2x7*%V_+Q U Տ?'? _mjHmp ($m5i 5 ֻ) i]Hq xAg3ak/44?u<6VHtUЊMWi"զm"5±UV&7 ʩ32f9fYR7&ֺ"}LңX|v#"y5p-I(%1 r3nsx)v6ݟ;޸զsI!%7)Tշ hˆkچywk!*r>ZZڅ"ZuXRPʷDF~СNߺ^$׼񦑧Kkp1V3O aJ koZMOo@a x'O7#XdbI<1qcniu`00*sӕߪ1mB^ٚ&H_ dsqI>}/G~z֗5'd{J u~MyҲGQԥO빣]Xtn"ےp}^koxأ6@?CWjY3}f h?P#&+"JGZQU$e:+>} NI(пn9JG>RU>Q3-9{*e@W|6?ѿuVhZ#>WJOMj\'Fp*φ m#wm(??W=OE/]CؿRQG(褢 )|Og|(NoQk]O>ȧ7|(s>+cz[y'1޾K8M⪥GT*jM&L@Ҿ觮ĿtkdO>WيnʕWO V3Mc쾮8Tqii-7E+J,B+ Ӝ~5wOɯV2%B7I;4 _Z?E/]bRe]g+p)Ƽl]S&[_+?~+?~xXcg}N(Ǖp? yy\Wf$e9v⹸Biءsp>3|](Fnjjv2fvL3S7k'֨x)[am.['1SGN8oM~G~[Vq0Q&yv_ ?c)?%UASVφԥ EBS9Jik# [ :pZh袊Ox%}{urkqcV,5~_g}O3 NnٟWъfC'#mC&#y}汛f#Bc*ǯ]|1O5"TGzWZ?8XJM@S__s$}O*~a]?O_Kgn'=|>f= 0}Mo^zĸS-+XXAhB*+_S#0EqȫTr*^uyhϪ"zN¡a_1;"Uz?C޼'Ã*ы^^wgqHz~{\'FS:?5GqC>;/g6OiO,?떯___(褢QubIE}ZQ"_ Aq (X ?Stϊ_W=NN3kO@5Mkg#N.2p=+s#EyzEzƿͤqi#V=Hڰ?+?V |떮 f"tM%*n} _7@j$Pf8q޺n2%Ќn4 YtЅu~.{Sp:ZUb܌s4(N*Nw O| ?0o:+q^_qŎӮepC/a75i,8V8bFI8 c^C]¿O +`>0Ȱ0shϊ+:?5}?{#^mLZG;*/ڵCKnlZW"ojpf=)ǁjlǧ5r{b*JxRjԇNSןZ1H~?xԊkDK RjU>XN Su?m\ŹWvaa^zŸQqsX;(OCp`F*J3Ubv!EIG-9o(Uh5kGҸ+KF}.^ N [|8? k+|8?? WWgg!Wurk/w_j_:?5{ש|S$/͔ԕ ͅdMSWoK.ZoG>.E?݋E%oS $sK~=k?sҎSEӵ=FݧMڏGooG'~"6ϵoϨ+xUGFQa`XNrO@y6Sdӓϯx5J5 0)QS.z KT[ pvpɯ gdy=#[Hv'$ nr܌-\4gcҚYss ,}p´_u%58/u]'ϭfO/ƾfiF7=$UFimAi hKByMUi$Y#v30>ÊsNodu9<퐨Ӏ+|ŷV67{`0VIsӊiaq?Z?}]={o⢟Cؿ]l.[c| kş{~ĞԤ\- c[0xT(7x7йlao=J _o O/ GF \ҸX&rלѣMZ't{m\nۜ}qԼ=2,\2 @+YK#XmJs)XD| ųuKC:}$\0ɥ 5ib3ZЯk}dsDn^O0y)$ OOG?aڦ+{(TƽNKJU*5eMi\6zuQ^s\a^ ׆[? ĭeʧ55lz~oksM6mI)Smێ{Dž+HF*Vd`ٺYS/9kף-w 0qW#Z59?>^!Vq-B&T*6|8?? W׈xtS?o!u<,ޤ} Osϵt7Oszb7?6r{m:.w #/QubIE\7)?1_zQ"?^O"KmZI!!Lg?JL_QyBf|]o)?_WIJsn T}̍+;97V?G_1:Ӥ(6+ƀԶo+nJ\ַTeV.PH{ujic28]_9mXz CJKo/!v TkĿY*>[Lg<ywEWʜE{\'F6{#^+_okR+.i[y5iZFRHM21RHEpjxUI Xr*D"xXSgSVگ!^l[G1_(褢QubIE}K~=kGsҎ4$Hxed$E9iGKGگ<=f7 b_+T;Vp?_ƻoOѣD&lܿloS=T]u x@jzCAg ̓ω'Q±=H\ ;ISv pG^#紟ѯxyxzK;kaxyw+o_UqbQs<+O>)7?.{Sp: (uqC RHtgjA^Kit{kx̓H 5xU5F)r*hoF.?uo@6?Sxm0t?3ٟEju\_,^ݥ‹VV d3\")ghH I;zb[9og4V*3)D\ޯBubW)~3;Af%I'` Qo׽vxkG˸)S eP㨧ZЌ*5<]G qxTA ^_3E{{g<8dcq0;~"?Nx PujUF N7էs$ ti%Bn2ēk>,_ $* X*3Vۛ{LdeVaʒ:޼/ox:^ڲ\g ݙ+ߡ_}O7ƾs=׀yƦ4XG5|BT]{_? mݎdmndeC">Pƀ#*naF8W''-s5ӿ^C#. Α1V5/M3W o 8*j= N;7)?>ye-c=hv#?M7Ed׵<+Jnz_+gz\K"6R#;T9L?]w? ? W ! S^.xwF\_i7Wc( ׈@0? \'FJeUhzY{/1Vt=j'^mHYp‘ȦBƹ95Q%54k٠d2~gM+BcgҽZLތLہɬkNqɪ(סNGEqVPT** rPdъ MڹjKC֣-ȦRagJw*}'!{UxTW~Cf.^A?1_ߥzu#^EOz,ۛ_zI>'эZus9_h\5/S0 JK>k%Pv/QwJ._)(c#__ ?Su!Ӽ9l(\y'\d|uUЖ[3W: [_G;jiuMw9!#V\I W4/"JF>;}"W;[H&{K#ENޡuk5嶌пa/ WEOL%׋mZ’ ֍q~h޷ךG_`I@Һ7#\ΎFGɮU+'Wtb7=ɮu&A"=+iQIfFFpH#iߟי_uoj 4W<\&{}{nA!` 8*Λp'(8 ~%Ya?#+X;#.hw5?)MCZmx4WIx#AoM%q|idn 2gW_2#=r?k뢖N W:AJ7}/Ħ.q0 e .p:Z{x́m2|~u?mT?IMF|5#& Sj)l/–/qnѯ翵t 'gs:(+:?5q \'FR1DۃvRb؏N}*}j} 2G}鱑HW7.TϽ@b*cͪZp]TH 8Sz-Q֩I^6mN%'wQm9{SR=D*^&8'-JiTSH>{*m+!{5xހ?ҿ/ WW k^A?׶:?5~{z s|ϡ>`ӈ5n|ż?kq$Og|wJ._)(]CؿRQ_m?G,'3־ȧ7|(K> F]0 by#)A܏C޳~ȧ7|(뺯=N/bx3޿-?rYYj_ L&߳i]6eauf. 3jtӤ`wg ?2 ?\'W]>ߘ 0Hsr Blh++9⫭m,mmVO3ȅc33}968y>y_XTgbE 3o+)⫺UV1xjmݢ[iK0!\lj> 5vL gJ֢)+#;?٫ֶgh,>#)Pp^5dH_%tWgV#濋QubIEl7)?8?WE9iG]p ?SuouORMO:u٧o*9r$W0D~OS sxBn$P 0d|y ~u kp]! eh#la(1F6޵fntVxHHՙGFq1boDom7<k6/w)]nFlJ_^"Jt#]o"԰PavKysQ]gl&6a,$*=~Y7ۓoQfIEc'vxMNy)"MR$'zQMb\GQL.k"cQ5oTbW~ eDW27P8 T9R}&+Lb#_qb~AQ+kf5]+:?5_U_:?5?ނû\ [wý ,>J꫒`žvo%uOy5]J(%Pv/W῁O1/)_?J:ޗFbofuHm`fZy2c}Wq rуE9iG]m#q+HD2H<z*\ׅ LSK[ZAioyqyQۯu9glU%>Pნ0:mn tˎ;y!RSi gnP P_d T77 u(oՑܱWd^[5 Bo! 4vb7Kg*I/Lϑ|O:vSӿN%%p,j&,z;U KVd>FJmY J]&&B J,_J_KsxڅΤ٦vج^p{f.HAH.[samdPiZ,@@jQ鶳\ϟ..[hw`axbx5IuY?YF[tWXݫl6'KmKȤw*+sG ]")-R) GB( J)I@Һ7#Yq)IbӵY#e NCЃE+05謿j'VLd9LoAv>Y+"?E2oOL;Ge$B(RsslBt(w*yg4Qd1Aj(a#؏Εբ Wl//n`U`8fVmƳ-@g:ʛP_d ,Ԣ^&, &9=z7Vwijm2vp=ҰV_B*{-@O-8R-5f(OxwOx諊vqLC$ A4h.RXIIO͠$O(њmh\L4Hj iQRLJ"SsE74RQRL1^^KŦ_Z&Kw+:?5M?"A?|ZN0kX);h9g$ƸMNq(j4H]CؿRQG(褢 :__ ?Su\͠YKW/E9iG]ٕQmYi,Y ۩?|gS'AL~u_𦛔8rK[0blZ5c9$8zV_Ij6K']"uе2YjX]Y1?˼v);:*_i꿯VV35_AkJ8Pf$e9vӂXi{ EnڠgD^fg\CYZzVwWpTSD"XDi:LVo"#;rv? ZzIB<-1h\: Ԟ3OEӅyOې9jS\mUKϻOZz,򑜎}Ɯ#+C[VJ+욥J],J=ZzEmwĭGFq}GgAi]@[c',9ܦ0t7o_GB7CTJ((B0](^K{ږLurk&<<99ֵsԷ?-/?Ƹ+/\Mڝo?5G_!ӏ;KRkCq7jvp t7FV46OѪZ_mo -[Qʳw[ݷlzk˩I_f} ַ2Nު旛'=5kwZt"H LX0{0<:7S9D."m!5-pȅb$kB?Ơ)tE#EVl݃pp{{իn{{JN3+E1qY6;b/}nmg!h׳?RY>]j_~a+$bI1*$.T ۡjwzޛCk{mW[\h2*̈wf'یm\.#3F$}z2AilUl_3֩9h)jGlLwSI\LqI)KK*F `@lG'%(Xk8#2!s ] ` &jRk|vN8'n}( FdB1UQK`T?m#b a>u.E?݋E%8oS $yZQ"Q;wG̪6n=\u?3h?o򹚾6׆ G}H-Ԛj[2HϏ`T󮊘?듕\{ۋ+x DMq %$.\Gf??EG361M KobiK~bFO)izeJ 5IȽI f??Ef??EtU tok+wLv秥fٷmJXePI3洵_AkJ8Q̿xyi_"sG Bড়W/h9< lVu?ӔRBG? RnNΫK o_f??EYwYs5`ov $c!Yvޡqx1iUAub@8a] Sfx[c:?f??E[PHX lnVݙpmy\AmY[3F 1Som 򑶻++Ɗ IH,Kab8l $gTӧ4;,oPĂTS8ky>n/m:8DV"Nɽе]}F8E[E|R<$ 2~B0E]}"Rٽ8-縷mi,M+o.ȇ$Fݼm'8 8J\ì_3֩굆>n$ݻ{n:Y'2VW$XHIRqx9HUHբg#}1jVlV6-_>G'ap"O1rh8;@1sTҮl-Āy]݀Q0eE;96JDzm̳<20`<x{RԧR55tۇVFU3~+ '?))|_7w6q{_+Z'ftW?8J\ì_3֩굆>n$ݻ{n:Y'2_(褢QubIE}t'3־ȧ7|(6нӫ4Xl,0Oq_ ?SuW=N/bYao'ڏuc*E5&:Y̼j~c*h,Y7dlqF B `B~u h,Yaol>Saa.nсTupy1R۲Zm $ =*:)]?l>e`q_ze6X,:-mі%NI$&7?«QO%`}*+()B[;g? Z)]?l>#~96k 6W(OHۺhu?[aoV&O zc8=pB۶8 )9#@J( ~}H;Cz}*X(s\䫭urk_*/2QEzÅQ@Q@^ o[CjUtU|Gr*?qTb\gƮD۾q +>MQ-sgk-G$2E#2lIJf ’@ q?PuY5`68Qs*;Fvl*Ff%]z/&Y^;TgMk&DvIcc_3eѥ3Or+/hT9f#Gu? ^jKZ,[bc2@m $Z4aOw5ꑽЌ7 .qkT=c?;:ݣiֶ&64,E$ "+0ji%{;v4AJ$S~ ,9b]Č_ug-[Oeq!26s? \C|ZL.E@I?g c+K iW[ VkyNW@ {]˖?Xk7JlܾNn;XV mv!qBc#WG"Hil6LI//J|(==f8౱[hIʨ$w$=ӹoe̋m(;$0:\9RjvO$.>8Qs*;Fvl*FfS%Ѽ t.RtX#uJ!rFHc0'SQ엺pkZn-۬w$ brHݱ3ĽFV-,31qkFDg'ˌ8-z7M{syi}u5IS[Pºa(6tlᨮ5>PԦZI i¬:23@rw> 6{'Tna,Qp s$ W/|Z,_3֩Lq]CؿRQG(褢 :__ ?SuL~P@{zȧ7|(뽴?tV[3}uῃ'7 >M¬Q\66+dV(W'7 >M¬VDQGBxVwy0>nO3ڀ/dYZقv̈ nAݒr6ẕMpg[G9qH?{Ls ~My07 ncV^ Xt8s~,<s%Qʩ eD),zg7?鼿QOo/;[8#FʷC,[zC瓆'>{U"Rg 9Cw=Py_w*ny9ExC]O~,Z]%O,`=rN}sր&'7 >M«Zn2baq Qǧ^[1LT͏rsӧ<hdTNu+݂M¬QEC?K d*OU?tc #*,,PDBE2yq dzZ_n&I์HHWhIB*9 [k7 K]2(6 uB8>e$#/.D׶XAgmv/fyUyEǙ%73 >X —*qo1{䓁Am6S>縙<kg!s@:fc$sIEcym^7:F*JJÎ  lQT%ԼzKY<3,Z[xKfR\>w^ mdf=XI?g'tLjj_=^4Q,gb@Sv˷wuM&䳎IdyD.p0Hŋ,m pwBU8wV* ?r5zJf`ճMfht`hQiHBfUU,_XlCՓbI@+?nI?g#}aZG_hR0iSENe"|HbT8%z #Y7uͼG7=f72miUy=nj;Фtb8zU\?j]CؿRQG(褢 6__ ?Su* 6BJȧ7}(렗U&.m4'6Vvn**98 :_/RQtF774m}i~+'6>i7_cSL\?Qox(G?dbcS=M?De,p瓓G?dbxwM(5;~+L-ddy rМr)kU=XB(%8(䟶KЌY2A(Yr88e#>Q-YAF 'k+|]7[{^[VV-ʆ6j_/ c/BA΍Ѥ-8#z@Cg9;zywLuzPd.A'Ny)~&h(䟗ރ*HRxrj<], cN9ze,R1GF*e#u )j/k{[=r1&ok߶ >4ms'M?GEIo#Hf$衰 )IKwRN2o^7t<*09l'$6(/ c/Gt*΍ +?Gt(Q@2=V1Q? e{)M:4*-gxг#V#RH`C(9E? ey~(n_AΊm%q{< 39-m\ICi^4K[O-mYc u<tM? ey~(nBDM>GKx$m+8EX(Ž|sui,׶%h2x<0CGt(Q@2IZߊEX&ow$+m&+e,d !.q m$Cq5Ĭvh, 6x7 elO)Ps/2ŋH&*rVk;g_1F?GbTTRKT5="W~_:'H]k.CF~ޛ?c/g_1Kh9oIbkL1.E?݋E%|]J+H?WE9iG[}* ʟa|(NoQ;Q#ivDf*#yv+ו̗ZD[:wn٣UX DU2h# h5!,2jڂX,1yi$ʒ8c|>FbnRicnۍ;Ps {&YFG]Xe8,F%-Agv'72U9GR$܌B5 SmMomıO Bb12VRJJp#`3Q>jdYSYԢʓ. 1RS$ǔc PƟ/oɦ̑/ahH%Dz*9浙SdYvopKNeipzէ!&@\,dsArKZՏD?V= EO ((((7ҪI -j}VO/ tVP?u +X|//|CFz砣ANbz7?C=lz ..oSd?T ͯhw${0AhX<]:lXKXFM|1Q E{kuj1ojzs},nYYd(s8Vp2F/ 8kdE:İ}'r6d|ʧ7vmRQדxX 9[Aܭa!FKxuv3Ä7 xC2N-5D[[[m``TG|joyR8'+hI{AkA(gp2$;۷# -k}rq-lSʆi7>l3X][W=Ӯ#'OE.C)s9cpm1]lBG&.vI)iK{sqoQݸ{{fVv IbD%W(ˍ6I5{_ W\CmǗO2ȲTYX?p% [),n.eU)@FR^*8b_,Ge&,X!VI]_w" Gݕ&ΐmWW7&Du_:;<*e˜sЬԭR VE)IUdT"4U>)nrHQp]xGqyIʙpN6a9QxnZ9_^Zoh m=73AC >?\L]a U"Y:mRIm"EE l܊0J݉XQ,V(Cp_rf5̊13|x1mϤ6-dK*R!]^>#4'|KFV$#FDH(2-Yǩ[7Zs=|دm|4п _M|۟mOG_x{'bhc/?_&{I۟{o/}gLJ4qEQQPUQtvq=]dkm>ҴE; n I 7U4q=>s=tU_ }e _M{OkT߶w/_п _Mx{'bk߶w~q=/_п _MxxI7?:>s=#?m|EDUE@UFږ8mΗwO?_Y>Ƣ7mΗ?:_ؐ2_=nt}{G$?`̿}E|q۟/?缟ؐR_5?缟7?:?!?eθ4[{NW9i%?m{}SY,Vac/?G#I7?:Owq_#?F<=B141q=>s=#?l_#/F<=B141~s=?:??`_п _Mx{'bk߶wmΏ|=>c/?ZP Q c hT{s=?:O'Oz톱+v^GؓE{8F%+^traitsui-4.1.0/docs/source/traitsui_user_manual/images/tabular_editor.jpg0000644000175100001440000007732511674463545030034 0ustar ischnellusers00000000000000JFIF``C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ??xm h ew BJmowpqF,ۀ߷=l]C\H b nR#Md潞h1]M! d3/^xmtSv$~@1FxWOimlrO ։t!QKs:TZEk[WQ7۞Oe_D` /%X(]猖 Y?hZI.b`DrG Gkrom!$8e# 5/n$f%SbǨ d,팂92G z \)8+04?~tyF?ֿ iG&ҋH44]E^i6LS8͟ÓKq&)X'"@ڻ1~5emy ࣒Fl֮,WĻZÎz|Y0hvkDG2]drZZj77GGɖ( ic4Y=͓z7Yf@OJi7n1xJk- `kLjKD2y $rh}w)O\NU2)*GUvbvrI=yt4!ȟW$~bqI>2OjiOeZurQat\0F~wVMǎ"V?WVrKVF/ŋ;tbNavQӻ#ڎW9rU#hݓKoG+˹roG_s.*_v~Tr̻:֡i* D叛|"Mtx{ xZIZ"24#7=7(Ƕ3֯<\ye;xCovܭ6wPj {k{w>U+eO%[CdeI1咬UPno'/T'i '=Ji欟 Pc8nQCXd[,XRHPǒ9_`]<76e'4whZ-!vqY(5;MoO wKK}рy0&Dvfgf=Y'ۈNR9ݲGPH8GaG+˹CEnObL yyʹOסCzJ.o%fYM `b`:Q2]iQoG+˹roG_s.|M_ZOikc:dHdI#X!3StQR6lp:*IiwZbHە\/ʃFAlUخaȆ?. 4z2gz0%ws&! qytJt1-n/ ˍYe譁]/Aqo^iwH9#<ջ1[(+Yc2ryeܩk6rsnn*(,wUTxTuXKUgԓGNkNHR9*x2`dEQ-H|䜕 @G+.egSby-o6R.py8O \_^h"q?K/~B@$sb*;{ +V!U,͔'*'V#@cjqC>eܻP^ǜԸo~"cdfX`RN(N_KIH)XDsK>}cYc,M6Rx"]+NҴ!vX¤j9?Aֶˑχ(/cy#"bYP#6OJ׵?\=M Qb. 6C4vnOEYW`!T+k iw>:=8{q@N"p- &wϠ=륭(+(fh ,]@=tD/f̊+_.?G\?ΏjȢte=+_.?G\?ΏjȢte=+_.?G\?ΏjȢte=XQM=k\鐠9G\?Ώj͙V\?Ώ\Nj2M*][+0Rv'һTԎ5AeBrT`C*rG%w^N ,ws"r9YY\x[o.4eFIG*#F3]]e7D񧘶b xEu%F1q1V KD|9Or)z t5yL21]dOҮiK#w0*=2XZmk6>Gpy:~\^͙V\?ΏEkeˇP{9{2 |7MKkx;DEY[)A2d$9#/Һ.A4'aÑ!l`1^q< ]jwzd7M%ݒ+RqK7$sItw/$,cN P 3Z]Yys9&B|w"e}9 DXvIgwcU@5BmWD ZLlNi.K\w{tϵrz,Vm (X%H@d-V$o=z8 e;yeys-W3 J8rF)$t&h|-7Ĥp"kP11?P-*!0I3N*m.0~2}kRǖI eBǽSԯ,4ȬQiiU-\ AY1GWvi/dN[&&q,s ^sq?tUocC*'=GC[ٰf^IV\?ΏWBr2(py:=g#"KkH<{ \@\kˇ N};FXķԅ 6gD SPƚ,w G m`8z֔kqypnn<{XyPd9ԓQ"S7RѨ=qg[XoK{ VMHѺMר*Gl-mSaop9۵4l 9:DŽ#8X&I0P`qV2᷎g,8;#ӱ#l㻴2 ;X پou#¯yN[}ǭY c] 3*l}o{O" c#̃}y-TuXqg 5%}I{7,NQl`s=֡.a5Գ!]QYpQ\@E(_$̰/m"fTB >sNՓTYaY CPho{O#:_t:~ɋڣ:_t:=j|tyGL=:}&#u3KNhwΗz?G/Οb論χiQuwee[ d":_f뚵`p4%#3 *Lx){&?hk f춑T@ݏ ׶:󢥽].Nۃln##jǺյu-w$h#t_U};ė;"Lb;_ GahZ%Fd$QG=I\?b+>V$aܹsz܌V vF>*mFW>]Aϭ7Ηz?Gwh|tyG&/j|tyGL="o|W!sJD#ٷݞ3jsGqcwre2v|{tzQ{O"Ƌkigf2Iq -2w,TTqy]6;+ّ-^if6._seci,w9ΰ;*o&(o")-rX 9J,<@Pj0a1 cGaYW:iio6h; zJ_]h77)(rYFҸ드tNWmE%tiL͂| ^#mYt_-* b{`(l=ho;ڋlmHYd0v9:tҴыcI'3O׵}FE;Qt]a%' $pxZ:{-ь34%Hg/f#=5^EEbqOEBqcLH|IuDG~K 8ޢH^Wg4q7*1P 8&⃧j1`ڕQ\%By`dqE[E8r+\gyc#W]xI-[Y#a9VA y۞>DCd4On|0%z|3MZLfa} -q}=A |gV-,~}@\+ln @́x/a{;5o^xo^`dX:1?#Lq[j2uk#sr{Q  5ԚK1$2*@#nۿ۱ۧoAu-PpݡEyV<b{}*!Y7qڭ[yVrnEӠ{c/Rы٣ńyKwtyW@#f rsڇLܤQDQY(>uq8\y E-VݕN_}e].$IigEW [IuQ{4jy>sRsV?OWv1FxKVd?k h+h4#֮[lċIu!T@C{+oj;[ܳCr\OLdbF\#[QyJy<ݣ~ϻ3ڟG{4a°&#ri>sF7җ/i+Fخ瑣W?٣ W?=GAQy.B!p2:gu˭Gƺܗ1hP<[2[ f7Zז#\Q4sP8N_%6.H(2!"6A'>V]3Ov!{[yJ-?U2A_:t>>mw"c$ X#i ,h=:ѧܬʮWhAF?SYxB(}IKm%; yvu#aRhxrxNN ,V+n.èO,29uI"F)< n)F~.071S$2mG(AVDqIn6PA`yڽV|%}x\Jn q]}Xݕ~@+;m3xIwyg-ma[[aӿ/h٢;B[ƞdxg!Y0+z[F<ݧ.nztw'*ʀ0* a[(~bF\#[SFخ瑣W?{YFخ瑪:_SD2FVHYA0@WW\.y-s#4s"((7R~\qGa "RxEZqA [ O#gjP@,XbOS~m_Q}WK/w2C`<4?t8pu Nͷs `d+\7#A܎8꽣fK? Oegunhdy:9;)UO8 Mihcq̏$l]]07P n{ ׇ5$$b&J 搠.G`tZ4-be}G̋+-/un1Ga\xr}Z-En/!4ql+RFz$~X;eBXyh ;3=I?TvSӬ#f:nŧFb( 9ڝ+bf!!*"/ |h٢կmq ov|HdA @۸y&-c(UUGTpahw"N[^[.u;ip|"Ft>@ w%<,w241ʡf19{Ga4l% 8-A{rP7m3Okgi#G35RVQ ޥGKH걨 g#"-fY+=3؀Č`3ۊIk}j9cC`Tp>Ăc nH2s"բ Gev*}Po 3%ьvtO'rFhki+6b@dGKyZ-Xڄ&_נ=$E#⼸N7/!`tP N&!4` deUڹk}DR ] LIf'}GSq#0F-NVPyR`sK0E$6V?tʊӝMѩۓ8Q{ֳA$f 4[2$$r;QCqm-ZD3sή%\a9#967I3X:7F8q2 CcqG&#m+YWbF}%oyyr0;F9xGnԞ-CU&M\;\siELxXC$*r#uAQtI:1jBxËs%MpxlpK+80wL )8uSj`: eymbOoE"[Ewe+iƮU7*8asRI%sghKAX;q=CHtk:̢g4QxγbE4qIxΐꠓi`F2.Ӕ0x9O^EëXv{P]Z* )y^V%!x I gzVjp悻:qZ%e`Ӆ嬋,Ќ ?`xOB4ۛ{G6ϔqr5f,Z*txΏaOf>9=1֡T{f fSj]n)+*km)dH$]?nq +#QЍLJᶰKymAcUe9;9K o=)hݝM ͸?*miMyx-~C t.}Ҫb &03}YOtTU>@V;pA$ jvr;^"*r/N:lwqy5XgPVtlCWIlkkb1F{bk{i7ɦj5"HrXb Q uto!{x.&yY +G'ȃ ֱlqY5ǿT}Z-sLmZh[chRf:JoZ3f<Ș%_(, szzulww>y#c,ɵ@;yzȻ;:XIGeys]i髑o$X`s#+#`u..>m $`7icqU5wEЭIYܡL+0\zJŭ :[{׾mIS#Fc2z!wQ['wݻ 0m ϵ #NlmTyr3>V4ZƞcΤ*䌞}A M_J)hf|c` @A/'+mvK}FKn# C/w p݁3ދ{B4~+motD:zv9/5/i׋i{}eorE,Xp Lt=5T<:lT;qy⳵}/T70zڥ_ O%m,AyEv8,Etv,C[bzz>Ǣ70;5  $n9おG]=i64 $jc Bj?[%aOZw4C+o}y-Mct\VD?bKGحl_Ώ6?Efլ?Ξ:Za̞`]HG>T뺞/2R>Fgn8M$ޢroʑchc9ڣ5 FQT;0F[qcn1hYu+++(g[A#x-5q{t[]T.Xl?VΧgn([7.qu'ӭ-PO,nD>kngAOZ.GD!gHк<?:õ饜dpͻzB%%G+F:WBASsڹ|+0Ϩy[DZ4ɖr8\,M,Y f1ؾ`rW%x۵fzҵ;[(t 2J$aQ#V?šp>V1.jpN2Ny4[CV/fKkX䍭-D$-}hY9l$MĖmuܬ{.|q]m1W7{F%SFk&m5M*WS'N=hYy-bKSy}:< "[%Vjo6?GdC+o䵑 qiI Opn}:4<|BGRc#x4\,xN[HwtRJ#n~>{/aL8J&ܚʓ–xEm4Br#f8ⶬvIˉؼAg=p:0dfjZ=DXk#*d}yp*M:O$'mRt{Tz֢?O}fI'yT 0*\RN1q<ӴZm^z+"P1 ddGwhQ^W!2F䜐H@-nM]Ou̖7H\mW/ۛv=J`@[l̤8 dqh7z]6K4Y%|y z.D6Zon`PfRB6Ÿ;-[N>$[|8ʰ}7@}:US;Yeo*a ;$[tVvV(cvN{~6E<vj;yxI8]J[l6XA2#2Gl`9eIqO"B'$8Һ)<3 mvBn3$`ˌ m0B6{9$۝w0}&!P]'?pUxNT7^1ڮjv#Y-gS Sƒ8=@zU|Ib֒mò4a$$}ZOr"aIۏsנQλ#a/Kk_ͧM5U~I;U_P:Nqg$p pOp; ۟|u7V462 v7@:/Z\L$SnMVdb0vִԴk׵Λ20,r9ieemg$6ҺN06Hʘ%5Շ#Re.%WqrKF?{HIv(WQ?i.*\J?Q#9%أE^˟G\J={$bE4MHbɁsy?:\b{.%sy)H$t;3ĭ"[;x%6ܩbl'={walVy5VXVgN8GڞŸʻ79p1C trMB!7hCqjoxݯL>CI?tϵcF{Jy&6ǖ5G;=zuCkiIoo76GAZv Hӵ_Ӯ4+WݬvAҫԌb*Ҝ1|9kևv,qܶs(bGh֥EQy$ۜGZ.% TS8ӌd[hsy(˟KG%أE^˟G\J={$Ta0lY^08ݸ1ڏItkvM kA&7F2tMfh^'vL3E-n+xs„83Sίbйm%d< ?)bZ禽n7e{oܻH6.U7nBcxxzlMDmݵ9{`-6-E8X` h]Ñ!Ĩ2~i8^y?s=ޠWj7WQݺ<v,rGӣeYrJ8I<-c췶/p.$V1iǸr>v%ܱ\4Ͷ[#TiW1€6ӎGZ]j6ZO,3[Rd;9+Ӽ;oa%Ƒ1 #8&u95 {FPNH8snL߈"fGqdOy8 <ܟ*?4eݦycG20̉ t۹3λ(QWQ?GW})[yTgX#sm<[ pĢ1iFޤgX:m# D<R ež`}52yI"i`9?esj9iua4׏!V?.QFT>!WG㵪s Au|{*P;r87de/3hq o<_\y"ʬѡq>G{H v3-J1a!#kKYWY"T&EQQ~XxHh7=~ϤOIl-Gl8C=ri2;-~_qoC=f6BvտkW7)g$JVL^BB=2 B=ɭiB&-:1 =Lm|WL^ʷQy;XO`;v/xixZhL4)T trH9OS_m52 ffE#vپ~XLjKl$R[ ˒Y%&d\FsV!o)]2V G@<[@i$I*Op3G#tE>k)u'_؜Ė[(v1'$-t*-uF'D)$̮Oul֦⁩ x3p=\rH9Ѿ19nA^Kc9>r֐[^n,[Kg), #lRv6=:O$Q];eTmPG$D_D>%e$m۵{Bv܂:G*c~Ck:/4ֺe  xr >j1ZHX)d*N*xU 6NGMrH92B^coy$WarȠyBdTOW<mIIq)f29 ҶΣ8:Ra΍z+RDԟ?*~A"lQXړ'GQ&s56e $}VXB2JQc2kcֵ]76No* Co&`H̶̜mu23Z{O#/gqgyYO30;:cPҧtP[]J %TONGC|YϠVгAO)aO{{Gg $O)I<Ǵny0#LJQ¼֥cYKPMCZv '+œ67+'x-mJ]؎@5_?ke_jdi3!VF0O9_Ϗ]#M-TI D$=r=NpGG+i4R y$eJ#N5A.;Kv|P_?36R\\Wׯ\(Up8ZiSArTyi_ ^g9Et~Zq*/a9>r*7 r2pFI@y0n"MJ;ylc0C.y'jS_z-q,rCm:HС@rrF:cW>%Vy :}|Ќ8îZ<qEm-6Yʗ$g=){O ~f?<)|  0A:M&%e8^07v~r Ȯe&u MkEJ 3Jsz"M<6r(*Hɑ@xWU5*ZV pz3?-?Zq*kirTyiAuD;SbnIߙ W{ڍ2QMFRKV S?**ry$w^!6oll;O]o8gǾ{T>Z-[;5ɜ2+v&gcjWw^9"c@.{럭S4GQ6_Xc:,rvЁVin=! THzdu]CY]%I$sFa#D6.ɻhAo.6 _0ӁC{ 4{ ԕ+02e|| 7g9Y Ɔ }r^C\&h4Oo F IF1Z={/2/tϳ_e#8!ݟU}_ET,D"+뀝 }-n|y Cw\ 6uj6c0J糖v܅~{Ngr~P[X*qjّQ 0Lg95؟*ڌZ:\Lq\Kfr 1˯w#jf~Hl m<دtqsp .2*WryϠPu;6JgtFy]m0Ej+֌/mm7T"*Ib gy1'Rӡڋk1S#%Qc}.4KkHeYcI'[T#NK,gFJ[qP@9 ֥vIRAE0pF~l~T*lI<vJf=ڜu)iuXsKe̲fB=SGUV ?fi2;W>\D^} TvUʂgryϢԷ-Ƒo% /wy_0 >nX~+=i6 mO͈$p-H6(e''8[n=sh(hpIB~d'TFۭuaQG]Yo?*>m=GXTQpM7IXM/e1>[Jh C5ۭ^r*(T :I'k7qGNu¸x:䌟ΙkwaUd6Y7s*򣁜>whβPKY&9̯8 HҩMhs"C$ Ȏqb2z~[.QΰHqo('=qu5XnƮ%C rAOyH=;sj%GY*!@F?SYP$2\KrEi!̊c~BvyzsW-35MNPoKRP@Ym|'-Av~&14Ӱi&;`q(m5?]G-4j,c_W-y{KA'PGxQJv;@&6j9$y5)-C#g,ylqK٫\~ꮴ*PVI!*CEp1[mݻ:W\j!Q^izZm$>C^u0un**/j߷[QQo?*¢dfۭ7Vuq4rE,1V :~RLf\4˳ L@ʨ cp#} 'M UIhw¼+QA[}mOh-c$םޝLϢܬehFvH{y@aRr[q5ܙ"N0ӞA<3rh+ #OnS$[ G'qe N}?*ŅM2MvJK9g9v=\W^`n;.nW ̿A*LJbwwqiKoEОekum})@t ߞpۥ%Q"*FO[gmsw"\i~lʹQ5xn[]27,o*Y!DybOI4{5`~UDі0@hL$egQ p}WDQv*QGz˃GZ賞huvTR9 `?t'\O]/2Ycr.NrO]cHܼ1(;?T aFGG\w"֦-J/K6i"L0;ᱪi7Zc;RF11[ vN8#s˸rG/49~' 2s0 1V>;G[kY5"AŚ,{{- ~fM'H-E}9_6l<8^Nrhr#:PFTtS P- ޡ%t\ݽqƑ",R;̀H| 99"ugj=\F/13 @a8ݟ &2[X'̹VŒ\AM-5]4I `:}zB6_imjF*񛴌K/da)#'qҎywH: Xߛo0[J&rT+riY. /o(r3B ddsxfGȼ;Z?H\. I |t_Z֑[',C1HI2Ǟ%_*?Wzʹ(ŚvO,$\5 x68pzd\r5k[ <2˖. PBgpt?+=OGJSVs˸rGTd?hG<${j7N9GJSVR]Ò=򦾙hQA,̀5L>Y?z99#2+6ukqܙ~l"*^$r~b7|ߠlOMBnd7+ we 35kQ%&zA pL<${$:LZr_/$_.8=0{gP^hw:&=Pgke<xj7e_O(p.ߗxIetھOnʌcR73g,EywH#Lwӯ#4l7{j"NMQ 1>rh7Xl&. FUrMgD/|0 /$ۖ I 2=jʵZp՛ҩUFf^ܙ">pAjU7w y溺tTSX4VQ3Wzʏ+Nyw1c;%_*ѢywH0YݻjkFx=~ui7^@~}3Cxĺ[ۍBh9nJh>I!&kf7m=cZكy8Im4oesbg)% dGG<$J+=OGJSVs˸rGTd?hG<${+=OUomA ^C"ͷr@ArGJ۬Cu=^ʗpM4jQRTv9v Q.=58}"HIaA*y4cǛrq݁F+<[^CL=x[q 8MOx.novvLvAqaS]Ò=P>57=21Ϸjaie{fܣ۷*cP{6]v챴8O1hG#Yt N )lgdyn.əv#ܠ ֎ywHcGym o9P󎽹z>3IKeFPLQvj6ZtZDF"vkvAe|f*`7x4`е!awwt. ) gvFy ]Ò=Kwu8bw 89w5;_X^V+F05ڦo4K&?}$>a '@+NV6r ˏ7,ߟOAڇ9wHWYGBCK}jE^XV1 RŊR=qhvQK-orghq\MW|^Pe.['=~B \&5Zve*,YAԓ[F<izFGVrqp~Iitsv pv0}x BҭZΑq2s Uj\7w?j+m’Qy_NӰUg Yn % #z|wG8Wѡ2q-m3L5otQJ~o0h_5\=Gz/Ki\xO[n];]F2kM奩Q5&4fe:qOj>.d[_,Nc39j}ݾlI{es+ec<j= b1sKY%%An@c#i!$S[]] o!H#zs֙yw}F#Clanv7n՟/ԡ{.6EQov4{A+IrTn=zt-'}^ A'#8s+# )eh [@W>rO\qV_ \s:\ʛZDݕI'|/)NJA#ֲc4Cow.pONF}+F;[Z2쑠P,F0r:ts\֗}U4W r$6HAdNTCa.cףhoQ*T$dg㚵ˏՙzv5܇̞V%6PZgy?Mry?٨ejgOQyT!{ċwpX+O4lH%ϥ7ț?h_lG.?S>7ʏV5Nju$Sī)̺(pi߸iuZ4̋yR8"-PܻH-Y$5nv vRj#|G4ig,x) *s0Pk˘'Eo-efVfXNݟzc۟ iu)/' faUn\M&#xQ E|g,>06qJ I4mzU[#Gt'#8$(UK[*y$~b  $w:^6234V^3V/X²1teԃ~Tzؚӗ\%:L*Rt*OPj.?RhֶW!+z;S~7ʉRNjT~\f٩gy?GOQhyˏ}{53'<*- ab&Id&6>w'R/0}H@u+`{{MCP[ $pц(|, їH\)끌1Y𖓨j֪.ii]; J(Fs*8W d}#ONB\Ef,ʧyr=K1)A4oͫ%*8>e0qcP(5 [D[fI ml* 'Y4FӖvd"# @ŽQ^^w˶6Z$?(Jѷ@eyA:\Ijczι nnG=Eu}s9w;^]ClL1>@ .yO(zzˏ}{53'<*Cȟx.?Qˏϳ<'<ˏGT׮ʚu8P<-yU跺Pr&I}IQE'?xm.l#l#y"Pjs:[N i%O-u;qzt5BÒ_PC, g=*:@ 3Hܻ1QhSEmXNEqBpC(% bvX\OD70C"ߔH96wZ'D՗W w+`dݍQōkw;Ji 0N:3 ճ *8Ѱ+%QX-fKK[g961ߓt5Z65Ǝ*l! 䏗O<3{ej-1u2lgϥei^u x-R;%Bsc9Y5φfԣӮ! ou-d/5ZmV5M, lhGNrn45? HјT 7$c,m&[Xbxh 򞞝lHYcb%TdgrI4FݬM:3m' `r@18eʆX 0 ⹝/H"Dbh~X~q;z}@ p>U`Ozڤ4hUt Y-Ӯ8ϥEy4δگ". OR:ҳ -"E#M97m;}~^GaГ"kiqf H< &h“" ^3KӬOuqS$J#@ɪV_:2a@wysZL!RJNpsGC} }c}JKtҵЏ 1*-]6Fީqֲ|Skow9.`e2$@~=hJfEh?3ۏF3h|{kcK1"tQEQEKHq(+IJAFO0ۼ)IOCj'7e$7 F3H i~{籭AwK1 E oԳkHׁLoր)jx_&U"bg#<`kNVU +99?)$lHT7ʪsrZYZ>5-2d1oo 5c_6Ra@vp(דZ=Ȏ yU Ň#3kO>KkK)V(CLĈ.*O>??Ju5S((T{2*@"c3ңd[%FnX9w<㞠E5x;ƴ 9ooMi4 ;=n 옣 OAZ%ƥI y%V%h'8OzFjmnuTxmV?!rNE\,n|8-XNbx)cDuF:VHQcގI\v)Fs>?ϵr^/7ѩHZ4lIJB&7@ ʊ;m㴁^HvX, 4/徟ϹOɰ&t ,ڊkuگ5$:(р:|p}8;KhmɸQ2p)u;;Y|Gm EN@=Er~)\Mǖ s<`~j'ˌ3mrp_z/?J寴:]Vi,-^WFvK3(;XujP(+sZYet!9dGyUei}onv*eQ%/ҠKf3@!uҖ}Z$ӄfp"GպqqFN^n$yHr4JY{dWNG(Lch~T֛w7r\\*_4^*ދ+ѶΓO5IK G*e@0Ӝ gagG #R0 wlZ[ 10@ھPjuϨD%w~X .~qnkwwm]*GݑIxZV2Z@Jт$sׂOjm`C2㞼 MQ,}bhenvG!r.602 <^ˠ n%,-2D~m Ȧuv)enK4",Jrkmhtraitsui-4.1.0/docs/source/traitsui_user_manual/images/ui_for_ex4.jpg0000644000175100001440000001623211674463545027065 0ustar ischnellusers00000000000000JFIF``C    #%$""!&+7/&)4)!"0A149;>>>%.DIC;C  ;("(;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?kY77VŠ6`nO#+]ޫ{8$]KhhO*.X-|)aԗk7*Lr7~#88֣_[pOes?ϬQ+CMc}w ť}oml8<5g:ybFk_+|ya3 gx;T#&aj4F7X?أϬT:vu^EgcyQC8 ZÚV[zr8m9uN.i=3Tc?"[(Ћ}mة#ީ+HǙJ ;tTbrT'=i-9]E%"츞x&o%}_}56߱G_o~R)!6Db0TƙƇo~n`Αm:9!C϶kwh^KJQqQN2Mm*5{wY3٣!=U9<CE̹?1[NQ)Ny۹О0<ۍ- <[A D\Ktnt0ijG45o`n<jFl\XON+ZŜLv 9"L!2=*rhs3v6 .V:˪FrJ`r ~F?#}G̳LFiӶzy~WB9T{''EA&Ho5UIjd d7"+| f|ʅ95EWmdtE!NJ)FQXo\X%&fdxBF7JFVrK-yb(uB 6;NwW :T䵾<$QSڀr ņ4}{WWn$gJ81Kn_r3)N$DlAn]ԚƢhRF "`|j2ȩ}򒺰I,D RJi"ԿҺˆQEnQEQEGW"X`gNLpʌA8v6mwy,~܀qQ@fS_)꿯VW>AtcU CW)꿯Q_++X_?? C _GS_}cq?7.x45~ҞiOU² CX_?=Jz}=W ?7.}cqCW)꿯W|c`^}cqh͐]&۷qu\ί ?Z?V֯4jZG#~ V :c2X ?Z?WM}Xp5 +{%C`'' (/m51\AkvR.IY@̀%#`s'nsj=Zvo9Ap; vRm Gy}*ɥUKw6ZS qzc hXIǥY%KuA ~BnV.?-;N>yKv4J<_{u{ieoGvO8Fx鑓0,42W*7* h5Y4n BrN>PLtsM>-؝eyV( [\ o7Zwz r-:2rEZWz]#b0HP?* h'?ƮDT~r{ChEQQ}Oo@IEG'?Ə9=4]%<tTI^'?Ƽ!pAK^h_|4j_i]uyτӭmoe^I,*E>amxMK+LvIc07!~ Hc-N`ڧ,7utW9.fm+ɱY+̱-3(?>F5HL{̆Ѡg phDD'Fe<W(VmGb_%Λm+KHKw d2ET1+),QEsV'/.dYۦ\hw>pׂM_ԵTom,U$Yb#n s8'm,(}R߼8F(iddgwq\U E;b8f?Mf?MoWʅs"zg"zg(As"zg"zg(As"zg"zg(As"zg"zg(As"zgGJ Moٝ~^^qEHׂIb`eWd>5_ ͍do%W!јu]L%0yR ݲHn$O"c'qyID}܃=[ENa?Qa&ڍ$A#yA a+>4𮎓Rc#\[jѡ€0to['ܫ6aqt2Bݣw +3++i`Q>b38\5q d9z9R1Wo['gX̓ ȮlnIc9 (<5k%vΖHy<{Br7`8(Io"@KgK3F2I[c{mde+x U_(Io"vWxoѼz7k+'?o[bz7h=5E?ݷQƮɣxoWOmvG3 ǣ&ѿY_?ݷQE,j|7FMevGOms0z7kξ2ȧ}v\Gů3̞X?lLbW^:.4j_i]*ų3q ?Z?WeԜ71u1+_Fbc)u%.o{-[[;ƺ;[3e z?\0q<%A+_.xKV2?]¯9}Mt>ȈC 1J$< ^s F<%A+_.aW_ttW9 JG Gx4|G"sdYJjA '~jɛW(NHKЙisZ1/ Ztc_{ sVF& ԰3($6]q'MVy,Oo+ <.eX"9  g,OS JG OW0sVEQ|xB۵20HbGi;8k][ `[^xDŽ%k#я JGW<;XYAgl\Q&Iڪ0O'ަs F<%A+_.x4|G"s|]B/OXYJjA '~z{Xⴿ]+ecفQb _eVqpvg>tQ_Xq:7SEn>Eq4Q@:7SEn>E}OEn>q?P΍tQ@h}OEn>q4Q@traitsui-4.1.0/docs/source/traitsui_user_manual/images/text_editor_integers.png0000644000175100001440000000563111674463545031261 0ustar ischnellusers00000000000000PNG  IHDR `IDATx]=eE]EDE\L5VhdfhfALHпlb((*f5ݯn߾GuUuuթ3}?ڷ7C<ĭ'~x Bsc屚]=䇐Wj _>}9)&9,(rgF] rƏ{ϿXs;\ܸ!ysggw! u]Aft~zTog@Ywvt?ɹee2ˏGYFz*{GׇJ{'p60F:C`>2ELnXN4 eJJVOu/ᇔjr7mmhtUBNOD'|[!?y Ly>@ܓ\jÂWLNJ6(V ;Y]:XVMم%'3&cV 4d evL|94`&?Mы6+J3G)VȺW\#h0hdzD~wм8&dc5:jD J()n9\EyQaUDCLIQ"ƈO;hxOz刬{֖x<>q@$TXG'ZOkWPBT50ӳ1+P6hYw]#-Rܽvѕr~Zȏi[*㋼gUN(I^5oYo;]~(ݫ c/dLj<cT*N"p ))dD r9thKM~enYn8/w7v_h?z:wEfBBl)y~lh?]{xO1% ˸m}/Cyu%UÉ䨁nߏpNr4ARd;Ev?1TtG `:L`؋hj D Ͷ?%#[⇬oSDNȏZ ,m\ 64zrSTR&:7L"/OVˏ<?l5@D=& urn'en e{V+ػN/C`lϒ7Gzǎ0?d9!* 1T;C~TtP^ QҡCz16?Dϧ[c\Y{ qK lTϗ^zEgoa!?XuK~Xh~82?~|X*o1Æ<{غJ3,?@bC<,?RgЀz"%o1mr:v Eȏ =;2#CjKW4Ey  T<{[Yax><'Dbcf/WC A 9X*pX֒-"9:XuD s(̐ާ*)]yDR~Daq_q|& J ,GUVo0<3ϵǠCRDp**nc{gɛ=޼8Bj{)q(4ۿ1s*!޿'H>_quj3djUO@5~hbN`J`0#M;Α:S?Vx_0?ʲ'?pkqRDɱ"G. WJbK402= ""[rX=RĒ8׷Ipb,ECQ5 #u?]~}=Q;OK{^LQrqu=Aq6b m(~}ӓ/s[5EjN?cξ{&?HG~wo9\׷m>w6~ky6HT.~rߩ  sE!hLaU DygZσ.(A\c Lex 6DmIOb&tfCXw}+_lr Ԣ(u 'r;nNkFcR'"vAfGE !)FnjOl. >;s :?DK@#m뗛^ :D9CȡC[x|;km(A ?H"pmD@ ?H>v'Ь%?؝Y9p{/IENDB`traitsui-4.1.0/docs/source/traitsui_user_manual/images/code_editors.jpg0000644000175100001440000005767411674463545027504 0ustar ischnellusers00000000000000JFIF``C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222{Z" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?}/M}&ٝBbRI9|S/O _G^>­Gvυ_z]d.ՎON1ZZ EO} .?G@[𥢴Yv_B- Q)h˰n?\œ١\:M'V]%XgCڷD"9w\Vί]NV5R:\ƌUx@*slʴ%?whia ?tK M:]BkAwm<ɷsa!G' 0H⑵_-$" -BŔlVS̀@b qZڟ]?whia ?.~ooom߿?÷87}Mb[1NmZY.9=FWժwb@ CH V~?Ie k:@QUYi~6pepN]%wq̨8\;O 4Wp24]G.X´5 JKfwb$Q4H' 1'O@Mg7tE:>YX)U130qX 䊏dM4]G.Xœ)U#2]yi#Siݵfd;Fv[{=b9|R{y!t}+"YON{':kW@ CH VfOTbhia ?4]mGA*1?4]G.X¶?aG.X #,?[tQ0ʌO #,?G@ (Oh?F'@ CH V{'?CH Q+n=fQ(?wE3~_a >ߣпuE3amj<*$<3zQ=^BUFbo)5_F2몲w;\V'@?*S c^"WS~Tv (aEPX^+u~VaxAֿMnZ(QEizŞinr&iK9GC$^6xr:K2Y[m~Y%2:G QRaA$-wDK#y`͒2T6;nRFuiH8cw}m[]3OʰdfY`w120x<:ígMӥeΟ$DQG$"/,:m,$)R3{}Dr$?W]=K\5swc/>u WD$ڶחe%w3oFQ:wJ*~Sr~?]%։ޠ@khJ(epB37 yR`o]ۋG0 b@-ڵv?A\k k Khl3  Yz6=4xti/rgmv;@6#툩Q&KsHTT{_"n ) ApQ_]J.8o)e%#pʣw$ Vo;!;2yvyEb-xFNY(ڮjۢ#7߇ۢmٿ?V{o Ģyo&%E?1((A EmG~LJ+n=f{bQ[tQ7߇2o)5_Fk _ğެߑ({:qcX׼OI5{^EOQ(Q@axAֿ[Z5hAEPծ&)-R inPJXL./rrVq.B'16Hc’ ܸ0YyZܢ((yI9Hлѝ<*XI@QQ2[: "Q"20g` bꦵig5KA̗c>p4v[~yᵷX$/$0UE$xsUSYA]mgΜ֢Mm߻n3y3Hz:֗1^x6 UVHvTiمQ@)JA$jXB@@$`2hU]?P,ѝfth2VXe#ڈu i gMʭ( A# <ӳE*jK\&|Z[ytN1s3Y-jq4ȎǔI (v+7m(!EPk5_Fk _ğC,$ kK c^"U='@?*yU>7mݞ<0yӮ `/Tؼݣ+O=ɿexZii(6$FI6nʰ<7Z<0Og#c/=9X'V2\wqy{=&wd 3- F> psXdo8,n3nA:[Ȋ|ȨŊK/5Rjv'ap \1A<Ϙm_Iuk e~Q-WR 1a2SeOy{5t́B2BMXp;~el>z bU{)*3&]fMv7.prAֿV[5MBX3ʣ&6MBAڡF rrM_:`Ш[V(QE`kڍ1Mn";p ќI`KX/IV ;v5; 5=L#{Եx7"r72'|#> :zֿګo,#T7!gBDcl4}O¯Z2\^p"!(L%Jp>$G^BPM"^MgKk'0C,"E 'fd v-n1b)4oPZꍫ[Hx#h22/L)WSOY.`.Hh$K 0XOp`cרsVZ;~ʎN|$HƐM%C6Õ B`ۆH@QLI @M눔6Eb~7 H V4k+]??aq.ѵGfEk(`-$ڎȍƅ|׭3>ddvRef]:nZV> hM͞y1y|Y&G;A ",8zxLSç&k:Ʊle-Fpƹ?»Rsm5Nit4ET!BU/AټpH^KOPXfաxMwcg"QY5e򣌛L5t}\kn7 &fKy1eRU9U[VOqx_Qgd9owX}_ Y( k֗vjh[Y“P¿6^wV*5::hWhe270`C0Y$Mb+kO;Q-HO$kjd-p;ꨨ3rlЭo,|=Y7h(&_̑PmǓ օRQEZk _ğ`Z_CW'k?/C#X׼OI5{^UOG`*QEZnk_TU+qQ@nw^?ְwÿEPEPEPEPEPEPEPEPEPEPEPEPEPEPk5_Fk _ğC,$ kK c^"U='@?*yU>7m(QEVEfwܬ{тݿ1Aү@ɷoV_miߖ9eF'}?N@::nv+,/vv8C`ʾvWߘwZBT#P4ϕ_iaW:"ʾvjh=.Ju?:!7c 쿑#U02Zy#{3槩jz+ GӖal%4I$x'gbIvϝ_S4}:_&Y|c;o\?3jզsq~$O&&숩R4-vm~W(ߕ ƟO"i9*CMϝ_vm~W+j??T6>i>vϝ_i9(ƟO"aP>Dߕ >i>v±j?=@cvm~W(ߕ ƟO"i9(Mϝ_vm~W+j??T6>i>vϝ_i9(ƟO"aP>Dߕ >i>v±j?=@cvm~W(ߕ ƟO"i9(Mϝ_vm~W+j??T6>i>vϝ_i9(ƟO"aP>Dߕ >i>v±j?=@cvm~W(ߕ ƟO"i9(Mϝ_vm~W+j??T7#(ACa?ּW|I6Z勏v Wj?#^WOIIlK c^"U='@?*yU>7tG`*QEZnk_TU+qQ@otx~{NyG5X2GB{gj;/j>, ,8nD%eV t }kZ[?>(MI"M'3Kz'aD[{Da ;2 .5E~ x;;fs;\ i,w %Z(fU` I%H?z|e,t>\EF|ñ2qc|hTO<s}O)?~<|&}AxYᶳǬl՞NNH<(fϰäG LcP.Y$I?;ר+=^O.ZՓ{8Z[2[GCEbFH6' Cl\6nOUe6˶a9;Q@dV?;פ,-fhMWs?W_hM=UE*5g_wGpQFM#>_Qg_wG5{HW_hM=UE*5g_wGpQFM#>_Qg_wG5{HW_U:O׭>Dewn8ǭy&!B5ї;֛]ME”c-K c^"U='@?*y>7u`*QEZnk_TU+qQ@=K {)*>X!I3_3vGN] HPV2^Wn@ˍv3LWYyZܢ((((((((((((((O׏?#^sOס^5G?xW* kAr6'['RK|Оw3ӧ5~xL B?.,"hXؙE/.>6 Tu+OP]j =b_(/IrL6!f;W#m*%}Nbz +AJzYGq<궂;TE%Z`e?|vzpN/'ӎ,l4p$iV;S\hڒg(X^+u~U=:]I:Z,ػ F1drYLN` +u~PQ[(&lu[\E GΉs)v,Bƒp1=Bj:Fwui{ x](9FvH ]m@^NeܮTJ7uh0b Wܳl;՟THkCuu@zjU%kzE-쑬q0L_3sp_%Jľ*RX- ;~J&eBY08 \j>uik so7s(6 :*>oiz]%>[I$^bѰmϾB1shO :v1Y]$qeYI\xW#/*9 6F9$i'ѮZ^#ϛU߽Ԇ#k:qƮt.9i=E,K{q G j_մOH,dlrb@C(q}-sot sg" @g# `Ns gŦhtĭ52M#1pFWF`+x~^@C!?1$yb#%r[@3+uk M _kcdK-#n`>[to<'nBkKe+1/&θ] ӰNwQĉ5ǖ#\''k{ӳi'MdYX$ e%vzoQP#g+s糙/`M@H!Zzi[-IJ,E;w)ʜ_LoK>.1-0ڸы^5^E]X {+:TPe@0 3De#$l*2$$3$%Ey4~k])ۃ<7,k]QO™771 $&|7[q5VdT'V\.С o&Ыj[`__5LC& p;GB xn sWtJ{#b G.*vclc[xNS>6Hcۍm #i<՛>NW{42ij9' $bddVu+*;[Xn]aFBFe3郒4=\NqQqko w :Uk;tfFhbdw]M-"&Hfq}0lAc"mV-J_jQHdI8Z>Z130T ~`C rZd\tܛiXs| 0Č:`vyn+387ݷ<47 i~ ;h5{ gG 6}HcbʡBIpʆ$6ywjzA e|1Q P<> ӣ[DK$.m6 `МvZE4"ImKvCI'nPreTY}AUIQ,YF`2E rOS?t_ QXI,-ͤMbWJ^_?y-䖉xe$y7p &7g5b9jۖ4JgF-E;@u #8>TpA VG  HB(q(O׏?#^sOס^5G?xW* kAr6ET (+ ?*ݬ/:`ЩEV ( aVhr(((((((((((((( =?/^?j$Ѝ{O׏?#^YIzE\zO?U|o;QP0(/:`ЫvD,:|l2[P_K{ .v˯,NH.k؎xVQJȶɘm[qG`FMnw^?֫A G6?W4s̐(yRˎ}Ԝڔ*zU} 7+;XQ!EEW?{|Bb!F_{|B .*\ U} 7((oQp,QU(?XQ!EEW?{|Bb!F_{|B .*M 8OjͶ,BRPFG_ ֑9j.Ink\x!B5^p6a \Z]_CW'k,, lK c^"U='@?*y5>7m(QEVNt [ZZ;#:N6u%N@kp8XGg{;C1Շn&7bX!ʵY\'=E՘B@( tpUBQ*e(ھz7(oW/26-m_AFW?ѿG"d(ھz7(oQ̀}WU_<FEy|9j ȣ?ѿG2m_AU|=yz7(@Zھ*"<FE [WQ}UoQȣkj 6y|<=s -m_AFW?ѿG"d(ھz7(oQ̀}WU_<FEy|9j ȣ?ѿG2?Upxǔk,n]՚a Sf 9?hfy(V+X ?V}QmV@c$ ,m77Y@c$ ?ZIYC77Fn睷o"ZIo/(n睷o";oEgo/(_k'Qg ;oEv_k'Q ?Oϰv3w< ?OyE`43w<fy+?yG+X ?‹>hfy(V+X ?V}QmV@c$ ,m77Y@c$ ?ZIYC77Fn睷o"ZIo/(n睷o";oEgo/(_k'Qg ;oEv_k'Q ?Oϰv3w< ?OyE`5#p|0gQ^Uj$Ѝz}ٽP*\Dc'805_Fl㗡}zO?UʧE\.MTwOr191!眰V# =93ŢmOKOIDZn*%~o _iR:w#D_0nFL wTrOº$3 6u6g4:.au+fWK9҃ò]\CbK[d:* |') \=4/YZ6|k _UF )X׾a+o*='FҴ;OMIh -Q#rXb;qjM{т_ZJYI"y. h1*DL\;F1k:5[x!:D ߛψ} s i> thR{WG:Y@qgdA&w&[<$o#ya6 M;u(9lB^XFx ? H \SZ4᳕&cb|HI[0OZx5o[ݣ(Q@,NIطRX  =cyB y]"mX񝓝BX䰰54F(*Hy&̠F`HIu;(/K`Z%GҴm$32/<,UHRkKeԢȎ7;Y,!%,?kMyvliX!ft(ۘs#KjzֵZZ],|f,XNczs6y]֎?2 :sǭjKቿlE}Uh`KfM4#̅|zKWԢk_$, e0|(]WBD^ 4ٴ˻%@&V8?(W-<[k,V^ϦE,]M_>dr:ÞV)rK ME-ְlimwuo3[p,d|S/ /iug|ݬsJ`3^GF| 9|[TKF:\ݬr:r|qsԼ/mj [SPL~p Քh.i|Khzw62.)# \i%GxZIAwwq X%*LQ7,>Y7tN6qDXMpV HKJAt- s.Nϖn yۋ0F@8ZR]e-0a37?@3maEΨ [H/X'4#P#ʗPa9]`ڮ޳y͑RK R5A;w$\𽵶b[, o$R9'͗by]+bՎ!'Ȗc JvfX?HNVV0Y_}+ݲ gX(oXUon/)ĂH羷XLm )Ț3XEQX-x%͆wӡ,!MwXUe_݌<~'P2j*A/IQH=%?7ڤB#3G[{Ʋ.v3PEK7?ȣoU'G $Ϙ"1EV$DUd_|gy* $$DU}7?ȣoU'G $⨻1Ec|H=%?>'Ep,(UoA/IQH=%?.goG"}I"O*A/IQw >c|<g[zKT}I"O*YQ7?Ȫd_zKT]Ϙ"1EV$DUd_|gy* $$DU}7?ȣoU'G $⨻1Ec|H=%?>'Ep,(UoA/IQH=%?.goG"}I"O*A/IQw >c|<g[zKT}I"O*YQ7?Ȫd_zKT]va{+ɵ _ğU$wH_CW'k~9zWE\zO?U|o;QP0(^=q[wkk_TPNAH?T}]?ו _i)*RG* }]?mq&.˘?5`j/h2}pKtjDo;n/cߗٵ A#'vu{/-.Rx72XF6!7c oVNcUb;YN `t2^.E_kGGٵ A#f$2^K(4if،l)8޸'nϝ{IJgӯnDm}"z>I*bBS8W~ͮj]f5._Z F[S֚z;dP3yH6q:^u-Bua ]]y&82Ev+SJߗ>ͮj]f5.()3f5.kGZQ)omwP6A?uEŸ`f5.kGZQ)omwP6A?uEŸ`f5.kGZQ)omwP6A?uEŸ`f5.kGZQ)omwP6A?uEŸ` Cwnd#c2y!B5ǻ?yN!B5Ֆ.ǦJ2?xW* kAr:QE ( _ k ?*kp*E( ̳_V7rqn0\$umK(;  ޹׿1jYIp+_qÄ >RڻFN.芐S+)]/Y %UV/B wvJծ.TӮ,IbQ@`U ^2;+U`tӾyK(HwT)@Aݒ2[I.]:-:M+M{|vn4ny ǟs]T/:;8Jdʶw c'#M>DOK[(-;""'){i4P妭Y^BcHFp}42DҢ_f8Ws=){ITcfc]Z[_Eq-k/]+ Yp։kcomkmvCEO[Q$IO`('LKQ  Ѣk ;y?3}_'´h>DO`(Q3/?G%~g+F=LKQ  Ѣk ;y?3}_'´h>DO`(Q3/?G%~g+F=JKCV ג?#^sOnZVO֤ E\zO?Uj|oEKvάaH @@,=ZQEFgnݥA3:FXneR: .Omր$/:`ЫvW _BQ[(ɛzeƠ%ǚGprm"m0 ]k-FSsi4 f ʥl!)azTm;ݤx ȃ'?yeD fP@; +ǖ؃GԦd?UU[&T%X[]-ZK6.GGes(T]2Q;h7(ik}uNk#mV s%yFo=->+z"]nB>Ǒ G23++g"~T UwsL[9$֟]Evӯ~q.-Y[~ ܲ =I4.@5^P,j!1Qq'5jU/ شFxnzؤj\o]ŧFu=,2n2U `s > g!M87`0T3N[._M+ F- M6DΩLR2opn;d>y}I4z\ۉW[al޼pkq88kQX^AUn l]mʹaA$jy峹Q 1`f\1ūV~.My%eTu)I:s$JeTL4[ yfJ w InY1kј/{(EĖo,ۃq mv. (IjUK0a%YHa ÑMj+ N:In=GkS;,+1!2rHPHIn_Pk pVJw"s0ڌ mH!jF[ FLvY689$`]/BsgҢXy$ʇ0Gg&^Sӭ-nI}nFd֬TQEVZ_CW'k.z~_ּW|I2Kƾ۴gYj;cGyQ>iz6eoZ)ݵ[-գIIHPoH kAr~jByko3563L!KLH`xA 0Ѱ*v0l5MKMZSm-R$ծ,JX'1i2)9*.3nldukkJ[MM M%ݼhT`ym>p Ή.ulֶOy}v<t:spQpH$5A}eoX\[\ʙ#r0 G`麥iڄm߻Y[!k]>ѓ3嚱Znk_T-EV (3.dY0y3ZnSHnTજ+%y-LSRNRQ-L뵃+/͜)*nw^?ր#OK(ZRq}r,M (؃Ge᫴֙e&wc@OdHJ3tP<H4FB5 :b0QB**GrO=/jƍ7N.KiﯤiJT24'{dxh7 ) jl/|uto)a6ybcPj' v/IrMZJL* f{@c*9띪){1X}?BX'.G1#V+%TNx44s^e]=3f Z2C,>A'=mNdsτ!<hWF뫒 ,*lPao#R} 3bͻ3?X҆f$f n zv5ir}.o,y݌Aˏ峳E5&JrJ5Ёk̤m(_/`$q'=[ Kj6 1m+rF(cf5!z3_] >_C1ڀXicHuu.<ۙv 2p$IEMͽZ`ld!F:G*9>k>ZUqek³MB7DS*Sz͝(SVL䕓»w]՜x;yG9M1U^rzk.^G6c۷{Ӣv>yVGScbw-y0ɵV?19OІ5|_0䕑$zv@⵨Ͱu$±U^k~tk荳K:TFX!b nxlQRA^Lӭ,mbHaME(֬QEQEVZ_CW'k.z~_ּW|I2Kƾ'@?*S c^"WS~(Q@axAֿ[Z5hAEP[*nQEQEQEQEQEQEQEQEQEQEQEQEQEQEZk _ğ`Z_CW'k?/C#X׼OI5{^UOG`*QE8@}BI+fuﻦJF kp5m$αJBZXp)l\p3ڹֶm&"F{=rԢDI1nnݣ8Sg?w/Kag \-3_/ik_sQqŽvw#Gpۚnj?/QhAsQqG~? 9h?ߏ5nj?/Q8G;AFOG~? ?5(`wh?ߏ4}~? 8G?F?5(_𣝁~?#\'?ۚs;>k_sQqŽvw#Gpۚnj?/QhAsQqG~? 9m幺8 caU\+_sQq´XY2\"GbQK1:z`^Qj$Ѝtۚk@ {QB5Momtraitsui-4.1.0/docs/source/traitsui_user_manual/images/ui_for_ex7.jpg0000644000175100001440000003424411674463545027073 0ustar ischnellusers00000000000000JFIF``C    #%$""!&+7/&)4)!"0A149;>>>%.DIC;C  ;("(;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;b" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?kY77VŠ6`nO#+]ޫ{8$]KhhO*w*X˓ qkV=/⭃: [o}`b>߱V<1~oc/ \Cl$(y/ 9߱NU61^-R)r`;bFjmDe<3@(I1RvU)7dIta(|_m4:JӯEjR*yQFB1e;$aF oj,vL}exYr#K:RR%+OAo}`b>߱RW8@ K>dVn$l[$`ÚܽMmxf?xҼ{Z?̾{do}`b>߱I.yȂqo heynbH0傰9OCV!=ͲمDeTk9 =1zZ)]}3̃ϬRhE>߱VK[Ju(Q5V~(_*&Ƈ_o~ϭ1G* ϭhE>V~(,hhE>Q߱Yr߱Go~gQʂ?#[*(,_Џ}mأB?bbQʂ?#[*(,_Џ}mح}?K]qFOgX\:uk^ލ8Ot^PyWctۗKQ"2Hފ'8us.NVdrܟ]<}?ҧ{i紎Q 29b~TldsjJ?.h ͬ7h[RHpH[Un94ǃW7W+T浛_SrWmlD}ŏ0CCFzQW?Ntg#B}#>٨8ĐDR(g8Qu.wsU,c{,2=oDS/ib%.{?7G(@3ϼ}CÌg.[pʤ8 JUEP FCgo~mO\8,_ RV=NQzNWVou4!kHAy1B@|㹢}TGzwq6QhTI3C3tK gyKK#uqu9xsڮ{DDmJvOe~xO八RQ[thB-x(m,Z^9YpL̊ƹ-nnitdM莲qYn9>'+~tE^_ik򯌽?Km3JI4oG;3F`B Tzh-ݔ 0Y r8C޿?:"Wzˣ55SU-c\yw3wZw:G5#pa {7ֶ awEn yPHHV»OQ _??URiSGw:1pQԫ*}#+sZV7ڣ,Vx`ZJ)Ww# HϵWwΟUYOP]+K/qjY|ה??k R(⿲Ɵkeoy_~cuz%!58OEql18jWz?]*?չ-ҬD,/!H[e*"E[y>»OQ _??G~ #N[޿?:"Wz?rOMu?»OQ>Shkwӿ4»?rMMu?A?:w&W~ ;?G~ #N[ɣɮ߈?N hS)y5uoj R |ȪyeD8A?:w&A[!*i]ynp93=$j̊r>uWK]2OxH16 Ûx%)${W-Ygk^!f>kbO(p2HU@3_d+Tn׿wc3T΍:M^ݭcoB }Ixc>HSllDRC܎]oGW!@Q8ξK1zنH>7>7#7#7#J(=Ϭ?*Ϭ?*#7#7#⪮5Bo4墠P[0~Cq<-eoNIn͝Ϭ?*Ϭ?*'V]m+.sǹoGQoGV7$x[q<-eo97#7#q<-eo 82SVl}dTo}dU 82 o[t{)+x6w>7> o[u-q{!OV+NktÚ=MϬ?*+@%Ob{PɪK:$C #O$z +y4* 3u#ѾoGP?7)OFORQ@}dTo}dU%OFORQ@}dTo}dUQ M{vYQq8z_kb [Y?UY?UUF@&/*kb⨷>7>c2L_Uh?/Qo -o}dTo}dUWe>Ѭ_ @Z7#7#⪯51T}X EoGQoGU_kbF@&/*yk|'zBգh,$1SQПCWZ]FWtd֨k2ִWcꉟϜ[7?Z+O<Ivu|7N+ާu῅/_ )mΡy7lny!o8؍wl^kw$}]Dc7p[O:6]9#HdO-#`Yx&XegwwarC:[x}d!Bdn$cCr-cŦ{y⵻φn.&gE>vpFe|qRD, $~s,MEW(0T}ođIzӸCyEv|5  _ђG{whFN-W΍KRJV0h9|]aW-c%}w0pstH#OyB$D{YFdfmLb +3 W!opxa>9f4;m"+Xl8m@] `0 hm~/Ok^dw+F®`q{ ll7p -myv.@QA5jm{el E'F.B'"' <^E#n>}ץ q|ҷS9]/Nn%0y!%H""?"$JC@~lGt4S(,6eFv'[^-yU2`~VR}BjgĖٵـ5:)}ۈ`z $>oc;|?[̺MI&3F3:FF9ND0h/sz֑λ%RˀL Ǜמ9xlk + ުI$ݻqr:rx*;%WڤA zsLqpnN-^{)amaf#CCFW*fG }]lW;Czt_kk_XAXHP6o6-v[xuٱFW8SzUO"V]cbh q$vlF8$u-]apd_gz_xKI,<}B;x<=l/.RFl[zS5魯4B%;xvDdo1ldjwǩ\YKqhi7sfyjA@ ͿcTSoncd*yJT@"=A4o^$ɲ)$$XfmYA?w*fvn/5ܴѪ.# 8ݸqMkqKq,~D=.*=͌OYKa-W5o/Sǰkj &[\ՉH ]Nw|յMRFjWƅ[]] f<2xzey#Z]E nFxew)px5>]>4koJlmasr xX&sW^.V[,#u!*|ɐ@y 3Z5-M3^jEn\Ii4S8bn ͂RInyC$""J+0f ?1vc.7qr@ђ@bqɪe⏳4Jj'<:]@0r1EVߊ.MV\]@ٽ$Sn &1<'9Ȯt5tm1bQii1Z>ssLѴ3ƾtsn ASTCr8xR[n;(d,d{)3{n:z.شk->5ɉ>ucwlsb hYKNYK3#v c4ZxoG[r^;"]M'>leCKƲJ5&[ey42U0c&յPyf Ћ_,;>ߗ'+J5֓CnQGccI',zzo/m7ݜg͎q@xM;K[/,Rtv"hGޅ %DI$gs\֭Qsiuem-cKh;;9%b#9*wt]"姸VvJ;ym,II#Ϲmn>4M[[I ]~A [5)u]$n$i)CG3FHbJgY? iq,v ;NP#Igy 8$${@zxZ)>R}E}{G_m:> ?o'b^Ľ>yfA;8S_'O &%{x\A,)- c(|6YqhM=:-Ri<$SA"!>d)G +!NXdcix,nttVpsUy6 Tv+s1 /*'Kv"Se@bz 2 /%dI\k_P˰b!H qVmKK %rKs@1TeV%X9u#"w.!Iy!f$ $ W|e]gK0"<1Uf{ Z+ۛg|v-ّ٘ ;[q2?UGrO롢(\翷$ W?UG9B='jnI>=t4Q9?UGrO롢PnI>=ےφ] r+}V[l˜nݑGԞLo跭Wuo跤՘'|J?#oX͞$Imɸ yވ#ةĺL# KA" WP6nuQk Om,rʢ8Y3FVĺL# KA" WP6nucxGO+̸ m*mds0=hVY&!Y |R'tAw:xfp\KqOJ0F*@KRZ<@B=:tRnI>=WY/b,Zuy%ءd$i qWzDWS :6@m˻iBv|IS5ЮgnI>=ےφ] r{rOܓ|5_zh.sےφG#CEsܓ|5_z?$ W( #'jG(\Ƶ@ 7T5kEs? t?8?Z(o~WIoZmƧii,$Ol++g1^@Q8ξK1z׆N^v7G I-1""#i9,ABuRj5pڢڐh$y q\Q'[YuExL$e۵aWITH#/e 4ZjKr"Ia㽈 &😀y֓co>&pݘ-3LӢ)n#9\ك`P ' 2I:4Qp3Y..FIG(pAEjiH{onoTb*EU.88ui$8d+:?B%$u;؝؀O2GCEP28$O5E>pEg(_Q΂ƅ?ȣG: V"5E,hQYk|<gsy?e?|[-5ǧ*EKwc܏cKu+!cuy -Ϛ!$ߌf' ?7)YxɁ0bXl$c"9s9n2T36ܚWXmK󭺌x;c(xF_A&t)V܂E"1`;vdn鑴2݋n5770Lە@Ҥ(T *rI9+j>{뫙(M0eW N9vIn[5$4I/Tm|'SQH k&uDD[vISFX`ruZe3n݋`d1 :f{^5;KibҭJV7(5Ek||,hQYk|<gsEg(_Q΂ƅ?ȣG: V"5E,YEs? db8j;Տ& >qo~Pxh8po (Wg\gG_m:,~^Q (M̿M-; +؂Ayu[ ආ-Bd5I"4Hq+ {!x'%E(YHeݝ^[EstS ulL]Qc=Ҵl~ղY!>ago{sJ -Ou;#1YTtm=kVM#Lfhbw@1ҥ)Dʀ??0@?`뤿)}շTm ?$Lm#`x8Oշ?'d+K4ʉYy9X)>i?PP2j*?QO }~&mCm ~i?PGm?(joHv&f88$WE?#oRTi3z (9<(8fYI ɂIA3cvߥQm[Znfod&yqo AK3$e)^74vYA(##&Ӭof{+{m|,Jd#:z w&}/5'[occa$msa˴cx篵Yn/I-b$b&%|8ѲIt11g}:ѧ<-*V8 0xU(G4FU@.'9[]棪im o]Σ<;O9 Iz߈~߷`Jmn3>ͥ6#Lyq}T q)iamCm5m?(mCMECO >i?P@QP~?PT?m5ek2֌s3drHVkZŏ& >qo~Pxh<> ?o'@Q8ξK1z׆B(riCY՞4Yت qYzՁw[Gs˳c sO^x(mnIngEnF9zZWm%12mwc'Ms-0:+\ɡ[ٶ,WԥmYBa+'{tM2KӒK9IDNVb*/ mO/h$`[oI$6]"S= AɧYZxh۹m!lR1 H=8nF KCx}5'Ej kiaeGB3nvs{٣5υLF>xܛ8r;Dnq@$ڏ-W#61|ֱxC*Q8'+zip&bl +(B2*,,b% L[CeGt+5λLXAy؉ mP,[ۙe  "W:u-:E&FC+ A͛D֮utפ;!;Dp2`?i'hvo;!I渐!%U* @/gah t ?Y:_(ah t ?Y:_(ah t ?Y:_)G,}R)^8UXvU}[֫:}[r Gޤ>gr?%@Š( ԟOieG"m)U2 ,R^2a!2!+@9l`F9<ZKVc);\Gp`somlh4T̵gpےv$.)Q\.ᩯKm&[mƟb{rH+v;|#!EuPWZnf?Qۏ3ސ lO>ڤ`XHQ$9< Ո ᥅_,oK|V%Wtb#v)GÌrMqP^N8Ip1l "bvV^x{U]:5=5t٢YBg7!Nr5bͨb{8likG9B/IPÂr mP,[ۙe  "W1GPm%d/>;fyYub/;viMjWMzHlc٭ӴN / q-_ ,/2ydKx[ⶰ*J?wg+ GUW6VQjH.٥e&g Z??-V_W Z??-V_W Z??-V_W ?aG%Fvq5[] ?O+׿ׁeOBϜ[7?Z+> ?o' BSnKאbUXzʺ3 7_9_-RXӇU(J+/wKLQK+UWHw5(/ 3_9GC}/UWsR`?n0i=_p{Hw4|ZV2Adž:ߘ `?n0ije_.xw7>}Gڏ~c+wKLQK(Uڏ~c(Qoan0i?t4ʷ9Qoj>?/ 3_9GC}/VW<;j>Gѿ1K(`?{*ssGѿ1}7?°t4ۺ_ gre[_mT}[C}/u#G_Ә!$$wZ=npsù?7+,zGΚA *7L?GC}/*+=J+/wKLQK(jQYۺ_ gr/ 3_9GiK(`?{ iϴ;n8ǹڏ~c+wKLQK)sùߘ >}Xۺ_ gr/ 3_9Gxw7>}Gڏ~c+wKLQK(Uڏ~c(Qoan0i?t4ʷ9Qoj>?/ 3_9GC}/VW<;j>Gѿ1K(`?{*siޤy?j׿ׁe`?GZ45`5U%A+ե5}[t&s+C} ѸΊ*!΍tQ@:7SEq4Q@h}MP7SEn>tQ@:7SEn>q?P΍Eq4Q@h}MP΍tQ@:7SE}OEn>q?P΍tQ@:7SE}MP΍tQ@:7SE}OEQEAgtraitsui-4.1.0/docs/source/traitsui_user_manual/images/insert_item_icon.png0000644000175100001440000000046611674463545030362 0ustar ischnellusers00000000000000PNG  IHDRbxIDAT(c|M#>c۷MMMДڵ Y ڀ) >s|WG;:ઑ؝T׃`Z߿hdH8$[X^]k*ʁR؝TW:č@Ew/j2TUUOUw \PVNB#ќ2qO6s IhYjP@5@POY@wwu`2Q &d$5@,0IENDB`traitsui-4.1.0/docs/source/traitsui_user_manual/images/array_editors.png0000644000175100001440000001734511674463545027703 0ustar ischnellusers00000000000000PNG  IHDRy,GIDATxݽq{L#,:(P©"&|̀R%K̈U@7`btݞ陿!P=QS9s)/˃ p @ِJ"O_$_!|xŗ7Mhd +ۯo>{1.@nH_Zs3@`f!@~jF@ԚD@51 Pko .pw">yv+ _x8DۃZ4<qT}pHjMǛϰFCA$?>~trxoj;"fwΊx AS';pۘ_Boj5)1|Ç 0)1}ĝ׮Χ!f%rD`~j{ 0f]"G̿\3Pkf%rD`~>r!y!T%R3AvZ#n -✁\b5x  K5β. [υ#0TZ3!pY^Cm}ߑr;Qw$ 'xWkq?qkjMn3הdGOj&@$@)ЏOMb!@IZS<5B$C?x Pk<5%jMI~xj JԚ  )|4>yh(ዅ=7F&=_l\9ղS v8DZl:|3,.=ѹ5pwh  KZK 5Z6Yc4ڡ<ꛘOo^Tt4׆Q#߯`wuY_n3~Yk~gr> p{!RPkW.1Z)7m^C]vp Pkrs2.+@s  d\Vݶ>`]H度p;CrRk+ϵ 85&7iMTkJ2#SX P֔dGOj&@$@)ЏOMb!@IZS<5B$C?x Pk<5%jMI~xj J ߽|Yi5wvBt;2aBBt/HjMDbGjMk@`f@EZӢX+@Y+|hִ Pk֊1Z5-jAԚbGjMk@`f@EZӢX+@Y+|hִ Pk֊1Z~% knn|Mdͫ+{wQ@I@Í%%FML_nO{AkpXkSl#5"DԚSl#5"DԚSl#g‡PK> =U~H\jM~xp8"y p]5]X &PkjM!tta%($ԚC"@JPH5  EZӅ Pk@ +A@ $ "@jMV"@"@I@8D.5DV:@`ᷲ䱷c?at#4cz5&ͿkpHZ*iFθ:g^gu{Zv^Lj$x(ѸjqN#%[i$P.!H[ SkBP'LK mɨ4b_=M٥?+ ' 9D_k}`'| VQ错y ņLq9aʿqªyLz@@֚Gc͜P&" %3咒%Ovp̻V3'Ti:v<.UN=m" 0 G\ԂАvuO\{ Uj%|'x ;Waqo/{9SV[>](ozysħE!Hd9 5y3|p:n87K@:Ԛ5WԚ=97\gRϹ:{͕"fO}΍u5k=5{sn#@^s)@Ss#pju+E`Oj͞Pk\){ ĞWȏDj"N~: 䗵:}}:ЉDɥ p`j́78Dɥ p`j́78Dɥ p`>Xt#ZSYϟ|j3.~HvP  EZӅ Pk@ +A@ $ "@jMV"@"@I@8D.Ԛ.EDZp]5]X &PkjM!tta%($ )ɳd߾5DZ6@ jM0({jM.\FޯrT11 6 Pk65ULLBԚ,G*jM@`f# @JZS$(@rT11 6 Pk65ULLB ߽+돻CntXZ˚Kkx~;dk'5wZcpbٶ϶a*ޯY+|hִ Pk֊1ZxE^s{{'|1i{أsأy=v>hǧ8HJnvN:Aɶ8Q{1m7k(?K"!@YZSa5~DBl Pk,ˑ[Ím-ׁϡ|=o‡Pr?Rr{T kأÒأdXQkm=L0G.%'=,0G. >)s:.*@s  t\TZsэ,{nj~E|6?k\֕Qk|8l1e!LMZz&zF.l[n\u3k|a|5>DA[Zc0>G -@}Ej#Q@>"Ǒ( ` PklF@GZH>S;ɳک/C74V-֬&?;~>!>l+xz>|3܆Xg4:$jl}Lޯ٢ZJ1PkjxV~w/C{,^3|Qأgiczp87=Cݎ=Du8nm5aqc/oP~DBl Pk,ejMنY#˃!~[2Czބ~LְG%)'G%Ȱ=:,ɑ'k( {t;a]KN{t;Ya]|R^C t\TZsэ,@ e#0Xϵ"m~l+qp 4$ c˶CZL&\ٶqݚlg%ޯy7>ZDAVCך =?dh3J} U/ͫӏyM("^"dN _X#K=qB4@`ׄG.4a!i,^|~ H;@ քbes^HYq* #<).:9zb[Ƿr:@^0tUӃi&Ǎ&3Χ=qm%N2_~ݛ?|sf"i^C_3@s: \'ϒ×K!ۍsۍSkVqYxi  ?k`lmcdƕQk<=>znC3lF}|׾e&lc- Pkj[5[X_S+U?!=Zv>Wq|xʹGr8Nj^HnvN:Aɶ8Q{1m7k(?K"!@YZSa5~DBl Pk,ˑ[Ím-ׁϡ|=o‡Pr?Rr{T kأÒأdXQkm=L0G.%'=,0G. >)s:.*@s  t\TZsэ,{nj~E|6?k\֕Qk|8l1e!LMZz&zF.l[n\u3k|a|5>DA[Zc0>G -@}Ej#Q@>"Ǒ( ` PklF@GZH>S;ɳک/C74V-֬&?;~>!>l+xz>|3܆Xg4:$jl}Lޯ٢ZJ1PkjxV~w/C{,^3|Qأgiczp87=Cݎ=Du8nm5aqc/oP~DBl Pk,ejMنY#˃!~[2Czބ~LְG%)'G%Ȱ=:,ɑ'k( {t;a]KN{t;Ya]|R^C t\TZsэ,@ e#0Xϵ"m~l+qp 4$ c˶CZL&\ٶqݚlg8lj(Pk|a|5>DA[Zc0>G -@}Ej#Q@>"Ǒ( ` PklF@G`ỗO<}(᛻ :r]L8BKCt/HjMDbGjMk@`f@EZӢX+@Y+|hִ Pk֊1Z5-jAԚbGjMk@`f@EZӢX+@Y+|hִ Pk֊1Z~% knn|MdͫG{ǷGh{|޹Zn )19(:& ǴMykFOԚO7%6||@nxkctd-zo.ۻ][|>I>LְG%)'G%Ȱ=:,]Ntwo߽y?rzNx7^"pj!$8["pj!$8["pj!$8["pj!$8["pj!$8["pj!$8["pj!$8["pj!$8sأnITGO6uK:=Z}&Rk|,@c,{Q D96ٮQ\=uЧP}\ Pk>Pk>|q{`ޡ[.\wyʇcOkأk3`M;{tyߢo[ts"0̽d,n~жj &O"p x_OXDc 4֚p1A.cT ך qr#P>Z)HA|@CiK~h5Zv;KI[sh\DHp=kAveB{1m{.@=5=u5$o)@;4zś.oCp~$=*ӆ5|aIʉ|Q 2acKr]9)໗l.xf- .!@6s.@} HKPk.\$ Pkv@ԚKl3ԚݷE"f- .!@6s.@} HKPk.\$ Pkv@ԚKl3ԚݷsأnITGO6uK:=Z}&Rk|,@c,{Q D96ٮQ\=uЧP}\ Pk>Pk>|q{`ޡ[.\wyʇcOkأk3`M;{tyߢo[ts"0̽d,ԚYv<[Z3=Pkf)D`njG"@e5s#0f"O̽d,ԚYv<[W޼_~a2>C_nއ|cq* 6[0@IENDB`traitsui-4.1.0/docs/source/traitsui_user_manual/images/table_column_selection.jpg0000644000175100001440000004357711674463545031547 0ustar ischnellusers00000000000000JFIF``C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222h" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?.UM<;iOkVFv s'1XZz1P Oju .Jͣ{#W^:R=.Kۥ?)ৌ䥪2 `ǥéE>vT +a\Z]yyn!֪xj-V5 m3dKF(|+K@ p qGB([KE_<XTt̡ߡG_m~V^hԆwL #돽uic&a $Ʋ1pG^:դMHFm]&Uҋ|УJ/Bu[ɧL[v2E3Fy`Ճ@x`x?b7Gm>Ll˜)%JOdiE>vQߡU촭GS>auw I9p8EwcɅ;qsz7{6?;o(ҋ|Хд+{R &8(Lc͎䎆o|Y/Ye.Yf Ǯr~UiFN-ߡJRKG_m~Qϝbm}V/-lX Cc9;FqW.g4闐KpaI`ei :z!VmBT'/_m~QϝsQagt$`:u9 ⳓEd4ƻw=ErW!V_ P]dQϝiE>vStU"eMl+۳#3-ͦ"4mFin^'qV<[5%|Q2_( ?;o*KG%Or! ͝im=u m|{Z\ܷekٖ;o(Ӌ|ШuYa/-Ȼ+TgNǮ)JV]&[z .W,z|{7XӋ|УN/BMUK/5q\dG*)WӋ|УN/B1F)rqϝi>vVf(9M?8 ?;o+3bT_m~qϝ1G*SON/B8 )ߡG_m~fbQʃӋ|УN/B1F(Aii>QZߡYrQϥiE>Vf=ǵ9M?( ?K_+3cڎT_k~Qϥj1G*SOJ/B( ǵ)ZߡG_k~fcڌ{Qʃ]A18D2Mn TP7\gsn=.>Ʊ*?x?b[==] +Ij0HBrl:=k}Nk{/ :e?%RUH<*k *@Ҵ&ښ{]P:Uy%M+۲oTz-!}G^(_9]ŢW:hogfD*=zO IMjw7vyr&iPXcj9r]<41&nDn J;gns8MeO:~[$~㶈q5ћ!iϧd!Kj@'b?,[.b){Zi^ߖy?Umƺ,G6!B@߀0x8Ȯ:|:U6;g0 Bp 'v?o\- X겼ڮe:zVQ[4p0^ۻߙ[2pA]_ay <\gZ'K@TQ1WB j_Uzy^5Z3Jۯ|4tڸxPuaW9C#I=qOso:ƙA5ƝvJkI4LPecxb@SxLqnB/Ű݇9^? yB<[@s1T T:_ p4"&uimo6 B0n r9#]~ INu* 3G# s=8#ſ?G!-9t_o&K4v՝ROt>r@e(8cFYW rwz/t[khM)'c7[G0F$ g#ſ?G!-9$ەdM=WTsbJ4kt}k&3FkZ-Q͵$t +;Xwv6|2U٬f3&2@ݍN!-9?oV*^~k~1{=[Um\ew˱p'篨W/._i#V!HᲑ"b9%OL_Uxb⫮\ F|՝koc1PZn}K<kh] `c1͎I{KsFS wƈ͋YckڲoQG&/*eK/Uכf-;?-t嵓O&LP|=Gq ,2 /{w!-9OA[@c1T,+{e!nE=(IZ|:V mk>$3`ARzp7SڌrT s> L_Uta`hI5h²Պ AL_Ub⫳C?c긟qy G? &/*A[@c1Th`~U#s4y?A[@c1T C?c'sA5 L_U?q? AL_Ub>Gh tbſ?G~A\O?y'ҺOA[@o&b>Gߒ}(Ot3G -7LQ}W9$QJ?of/*A[@oC?c's~I>_U3G~A\O?xn}/ы]'vҍrkm|([|y-$tauA |5b}9YOp=T-UnuVV4z$4[nm@0C}1۽7B}e}[HGu. "xwQIw|Kn'=5T^'2[{+ 5{ic̲,`OMVnUI(%>lmH0KƽxjE#xW]n%䊘0Z˝*_irmb#]Xi:_ڭKU>[e鑞X+%ȺB _>?+v}?6sRx̑|_;`^'Նdwo>*)a΍zsY-~oVk>VWlqOlۀnW}Xox>?"izNhrk h N@ø aq5*U%vƞ&:Tc$.xCR-/:9+ԫ;˃ l(򎠢(((((((((((((((((((((((((((#ZOu?INLlWE󒻝 GVcYwA9T( #(TwxjCMwrT~H'Wc?S_j?(;9E9(WO" (AsWO"E9+T9E9(WO" (AsWO"E9+T9E9(WO" (AsWO"E9+T9E9(WO" (AsWO"E9+T9E9(WO" (AsWO"E9+T2~-bIp^CnO$ԁ Ib9_ܠOSy| W`I(OSEpT"y|' ׵`YOSy| 7 :qå>$OSy| .͖fL6ؤ}0 oA4\ZJ( iq"U5yNg.$9.VF<;[w^8V8J vA:ҋYV-< g2Aǀ;qy|}iY*wLᧅ Q>+w3~t]Foε^8|G!q+|~bFO߮H%u#rNwJK-p\XV?.#7G%f8FY%f]ߝbGpȃ5]ߝkZ(}f_kw3~uEQ"ckw3~t]Foαh8Am]FoΏK-}G>WK vA:Ţj1 vA:?.#7XQ? _6.#7G%f>DYoj,-.ef,8BGQ:Ou?x~趩>:ǎmsҥ Y8YYR:<;rw~h_<5!rצ;E?z/7,[Ykq# /O௟(((((((((((ϺX>;t9c(dbX#q8ZW_3PVrJt? C NA(Zע̏Jt? Cׇ|t':?xwOӮY'O~h_<5!rצ;E?z/7,[Ykg0_?͛QEy@QEQEQEQEQEQEQEQEQEQEu}4 Gz}:`i=b(<~tyF:)]'/oΏ>_ߝGY:k&p]ns0RW Qž~R o>_ߝ|ѿ:VH^I9/3>,g˴.FңZ$= e_(O?~T?%ocF%?[g1BA_ UOl'[tT@̭˷1'zMOVԴma{Ζj)nZu^XT* !V]EnIz3z6oma|kHJVHlPĮѵv2Z\؈~s ohB9|<{RI@ ( ( ( ( ( ( ( ( (t}G:Ou/G:o^SI,'4Y/9k|"ſuFy?܇^-50_?͛QEy@QEQEQEQEQEQEQEQEQEQEu}5}bד1~ݜӒ;+J`j Q   H#nOE!G@W(?ZPG$7U' ? ?V   H#nOE`\5m.,2ַ0 [b+/[g1Mn#+rB((((((((((Qþ:ǎm{μ;x?iס_K0 ~ dž?Zȱo]gѯ^e_<5!rצ;E?zy*|$,'WfQ^qQEQEQEQEQEQEQEQEQEQEgCASCAX= (Š(((JCYz?%okq]Q[QEQEQEQEQEQEQEQEQEQE5^4Jua] zqK3I$ @OJZ#?oa1q3VnWEVQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@ >ׇ|t':?xwOӮY'O~h_<5!rצ;E?z/7,[Ykg0_?͛QEy@QEQEQEQEQEQEQEQEQEQEu}5}9AgkC[Zw_3Q.skF/u C:!ؿ?z6=:!spol_ѿb|:!spol_ѿb|:!spol_ѿb|KTחrBa+ U/c]^==T~⦷0 [b]Q[QEQEQEQEQEQEQEQEQEQE5^`i=>`i=b(A ^aX:lM5ƭ arV=xfNmQcm$_5C#V ]-ޑi}y-f0 )e#j=0NsT'/j6<[H.Dzg#"xMΓ͖ @yuVIQIR y28ѼK%.Fxϛl#'_@tzÚmޟ=_}`N !$UުsO4 4} ˷c TU:4*^Ֆ6ԯZM594&(ː0\˵Ɩ.wEy5ErKBEUhA{O kr&{sk.㲛c2nP3a.Z5^ZK ̀JSEY˰19ɠ1"gH%ȚWa'7Dkignje9WFB_2\6āQ?"EvnVXmiesq9{#i1MMq3V?0=bSJC-袊ܐ((((((((((G:o^t}G:Oue?1?~E7,[Ykי| Cb^q# / ٻEWtQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@_3Yw^o-G܁A>*OzԺX>{daIAWGE!RoUQ'_Ek@RoUQ'_Ek@RoUQ'_Ek@z2_}neCe8RASuJCYz?%okq]Q[QEQEQEQEQEQEQEQEQEQE5^`j `j PQEQEQEQE3VJa+ S[袊ܐ((((((((((G:o^t}G:Oue?1?~E7,[Ykי| Cb^q# / ٻEWtQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@_3PT_3PVr(0(((oajV^0 [bGWEVQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@ >ׇ|t':?xwOӯC)}a_, Cb^xjCMwT~HXO௟(((((((((((ϺX>X>{QE!Q@Q@Q@e +RJC:($((((((((((kμ;x?i׸Qþ:ǎmzO=% OgxjCMw_Pr-zoXק§B|6nEEPEPEPEPEPEPEPEPEPEP}?=?ܠ) (((+/[g1Z3VE!EPEPEPEPEPEPEPEPEPEP_u?IN^5*ףּV-U>=l^d-U>=l^d-U>=l^d-U>=l^d-U>=l^d-U>=l^d-U>=l^d-U>=l^d-U>=l^d-U>=l^d,Qþ:ǎm{AS:ǎmz9K6Yω_'5Iao pleDUy?܇^K;>_ Wd_eDUeDUKEyW:e>e._eDUeDUKE/"_*"_*`/G`/REv_v_hEX?/KQX?/KTQp",ݗ%,ݗ%Z(}T}U-K2I#BWv_v_>|ѿ:<~t\ eDUeDUX7R  p%$he>e]-#rGԜӼ~t[v_v_>|ѿ:<~t\ eDUeDUP {k_ۂ3oVl $U,ݗ%,ݗ%ϟ/oΏ>_ߝ`/G`/SKyinjN2́r;e# _v_v_7,}IM;ϗz7@e>e=ϗz7EX?/KQX?/KU)_1#=Fyl̰RA_"_*"_*Fp+}T}Ugϗz7U.K k{JkoӪ4͐0Q@,ݗ%,ݗ%[T<ױ.UL>In>wSz= eDUeDUY=V,ݗ%,ݗ%⪇gدZxe:u6zUMjW~t[v_v_>|ѿ:{as}w;GmmM+p9<Ҁv_v_>|ѿ:<~t\ eDUy?H%P39ُפyM7+:ǎmz7=%'4Y/9k> dž?Z:3/ QEAEPEPEPEPEPEPEPR/Q{F;.iamiRp8)(H#nOAu_3FlImX򌣁䊊8[ie^<@j$7U' ? ?SB,Gs4w9WګH(^xT&P0?i7`ɕ?x*$7U' ? ?Qp5謏H#nOAu_0[bCG_PPa+-2B$ܼcnfu'VG$7U' ? ?R2X+,K,ym$!VP Rnl lAu_1 ,s$hH;[hPPB^SL"a|n+<U/H#nOAu_kYG@W(?Ha6m\IPV[d-%2Iya# - !NE1(H#nOAu_3^ytSY]GMMQ[mZu!cąSt ?Q   ˜[HgZIee˸̊(_m??G$7U' 5謏H#nOAu_0[bCG_PPa+-2B$ܼcnfu'VG$7U' ? ?RKJ5ƟozחWL."hI$>YiUH]3?'c MW+Ɖm>l ;V7nbRq{H#nOAu_qZߝu?o< [=ԓ1[4yxs]rIPx= b7#HK;)7(2yyC]$7U' ? ?Qp5謏H#nOAu_0[bx?iqjRk(a IjCqp?INLlWx' m'FSN6mXt;Jy& (WTqBS匴 _- V_٘/^֯~_- - Qkߗ/K_aG/K_aEf`aj7A 5Q 5QE٘/{Z^ɯ^ɿŠ(ϵook?0_}0 k@o(k@o(_|=_?zZ& ?zZ& (3>/kW/^ɿ^ɿŠ(ϵokk?0_}0 k@o(k@o(_|=_?zZ& ?zZ& (/>/kW/^ɯ^ɯŠ(ϵoko?0_}0 k@o(k@o(_|=_?zZ& ?zZ& (/>/kW/^ɿ^ɿŠ(ϵooo?0_}0 k@o(k@o(_|=_?zZ& ?zZ& (3>/kW/^ɿ^ɿŠ(ϵooo?0_}0 k@o(k@o(_|=_?zZ& ?zZ& (3>/kW/^ɿ^ɯŠ(ϵooo?0_}0 k@o(k@o(_|=_?zZ& ?zZ& (/>/kW/^ɿ¸Z$vf6۶1Z()`g)yY2)]|traitsui-4.1.0/docs/source/traitsui_user_manual/images/table_prefs.png0000644000175100001440000000053111674463545027307 0ustar ischnellusers00000000000000PNG  IHDRfE IDAT(c| m@-,>|@o655dTk.dA4.D j,F:smoL\zzʪ Y2>¹Xת"f0b=7O1q)Hc70ac1M>Mz#g_nap >9X2_rGI!oK_q(ahƯi{K/~Q_QL$eF}FIk2ݓ%ѯ=tN?t"g~%@t~uH+*\#$##̵͋Z_!LQV 1,&fXbX#E6#:|u,Q9֔38$BR`eJs.~q,X+Xӱ0jFDUBky rY1ҩnacZ,[cj3zG0 B[a¹C/*+T[pΖVykc@H|=@*u&XXXk<\^h-/3dQnFѥE4o+ { =D@ ɄK ͨ|K̓Mf@t`;k<XΙ(< @DĘ$N\cf$:9p HKM%pkK<+ .qCFt{O?Nr_o/ttX,o7}dIO`RxX],S'Y݉M0n7t=y@|c㿻O~'aGGՐoe5:=nR/n=4~T4r9$'C+jک\z[ .AVpFsr=ݩVKDI&++}%IK!zu"].Y.#bL{ut7. :bEN˩Ԫj@9ȉ\*rWQgDW؁1T}AP|c4IM7_I Uقzr]Rp,?ັw z5c<@uw }Aۀ^rr["+4" [y\H&Jutۓ~y D`<O}:ADw2HQF#?{u_C%LQV O,&fXbX#E6#:|u,Q9֔38$BR`eJs.~q,X+Xӱ0jFDUBky rY1ҩnacZ,[cj3zG0 B[a¹C/*+T[pΖVykc@H|=@*u&XXXk<\^h-/3dQnFѥE4o+ { =D@ ɄK ͨ|K̓Mf@t>+=3\@t>+q2j_n2`k&j_n2`&2c7K<j1zhW~'W B.yZ.%-Uf/6)$aY}yty_Ŀ-ޢ߱50`no2!&,iMJڱwvtT )<dUBjz-ץxiʐIlWԭdF/DoyLP崄[d0>sܗA᠗d .u?* ǃ˼. QDDžYJ]%e(o/ "ѯU=s{2PO=W 4U!pVIvK(9YE*=] @1M B+<ܔ~Y^@I _VRh~p,L#*AXFh#:<-gڪ*-.wѽrȿV>0D|@S閷')dD` O} :;$b}] ѻ$#@>! L2;$b}] ѻ$#F2: <] O'V?2 85G\W.&j5hwbl^Cv.&j5hwbl^Cv.&j5hwbl^Cv.&j5hwbl^Cv8t@t#.@ר\LMBgC1xHU&:!@ @2)y| ^}ICc*LuBD?WAD_eRG|x9<4 C &LHU> JfLVpaL#@O<41$ai aL#@O<bc3Fc]<{F 5B:\w+Ze/yF_e|$! N~F#~d#WǾn-{3v+?<Ov%3a^fVƎAʁ,YgcMD/@X۴q`A sDW&nrPge1@B0qNCPK#>}7zcX7[cM.;*2t*ѥ!tuyɜ+*AGo9Wѭ4l%^V4uHvTӠ׍PF˾p`b>Gi]V$ʳv]`ܬJSesV`5"#gAP.)CV-FF_ nq /Dٲ֤3:-B/rѨI^qe2 AK8{j}crh%!+cMGIXkTfGHe9_ K HV#He/ױS5VXu:$'xKs X+UcrBdoT @ ~F'yUً8UP|ixF_z|,)-X|+$z+R[}VHV49i?Jo:c„D_1=K}_ĬRT<螦^Yhhi%O螦^Yhhi%O !zZ[;‘-V ١WǾ:ͨ-AՍK6d>IraASq`BܰT)# 6cYH6,sQXDꓖ #``3XySqdwrܗX:k?[w&qE T %ܡ8ب%yEN,σƍȺm*ꘪ8S1"=(%O#-J5FX Ajxj[cϠA5X# 5%HovcKyi(Dd˹BFB:B] :@2!jFYYU0el ب8UITN P3cb9}D薌*WtĀ4ڶըUj 4s99gգYZք1z ZcO-t -V(!VOR_jT 2`@Ѵ(yAVl&g(Gx2kMwT.lT+Ur=}*{ṭפyB%v !̟ª[$$X~y_ .=~@ԫ5f*w!g]wWdJy*ׁIENDB`traitsui-4.1.0/docs/source/traitsui_user_manual/images/tree_editor.png0000644000175100001440000002140411674463545027330 0ustar ischnellusers00000000000000PNG  IHDR,=} IDATx&ՕǍБj`$M0 2Af:[q8de6lbh .ED]-6scD"Ck/yOjbx\+8k'y b}8*ʥõ$kHNw 35:^r5Ο?o;o7od2F/ZW`@Z(p\P: s٩4uɏ'we hmVvҸB{V=Jqj%3s9}_@ZH{\ glGlzl؎#=8<. 2_{2wg٥ekỈBߴٚHT)CaC϶h~5Дk's"!"I ɴtZ)2k{Qo|ŗhVC=DAMԩ)l# C@dH'*w6'?J D& ++ db*#ƶM0M[i lv" 2$Q:7mZʊSXd]7Yd23z"ﷷ5|k/iz=c[f ?1$&AsJx<22=j9zP-H`h_hzxBxm 4*Sb%CnBl'!mo) kQ j,Hq$BS~%'11O \J4>*M$@$ȞPoz#e a$p`.%j_C=ϥ% tKh*M*=~BP [#$SV$@ |i,P%7yQuئHXy$a #ۣr(;q#;* hh3($ҹs(@xDMM5$ {R&3i8إDRM:APD<6΀l3'M66 ݗي@受Q~ѸL&RI24)X&= @mΞ{M/)6JE6) pXlSlfLvG_6O2^'GkҪ Ƅ!*I ؚP=ixPJSh EA{TCM;\a; нm5M=ő<.-L LS(1G4*ѫ &6MNܳO?(gR|UBDJ?;Ej9(؇V'R^'j~>KՏ1Hu.%W&X'ʡ;^NЬ}q 9+ָ0%_cn&D@~E"Z:5Oc DD;Nm'Hܓ Si ,EDի6٬б&Qer.Z~61.%&7;BɊ ֦n*! ܺ"ybAq{zKV(mG5e()!I2=ke8e;)&vS!ܻ.@/j $}I]V ]DZ%Ud& yMMYPb Rڠ8bG"*W$HID6ldk,9Չ%l |]Jt~ЌcBkdSgba$'#[F͠M5RҦ(9 @Vrk1PBf5& [KvXm|>P"ԃqbdSU "`P'<ɘI{d~ImRҦc>J`V\ĶS0 4Հ~LtFA$R5+Ȟm&8Bpa ffB䱆U-\J\T; {H G`)'JbOn~2gϹHu{EX%p9p#dnDtV:OJ3@Y2 nZx:UWY%Y bg^A=Ssc.%TIpARï?v3ƾeNsI&~ %KHK V C&l{F.%J*Ha6B uP<'FN ʃ4Hd hRM4Do؎R(y~q4ˆSki} S{&8FH Rd$iB)}O~0PC)v~md_aǎHH ID 5|\xj*KWVTzl̹I`7,;1xs@ͧt &}\5_;p,nӎ=ʄh Rh 2ϧ&ŞCpX e.%GN` S~3c#5UAp aD$.%ZI<(DqzSUV*IڄS†Qm{lBb8$p\J4&,N'~*$dҠ8izog8 W.eE#ʯjB2bݴlr9F]LΊw%ReN39 Φ^':s>#WV1@D# UcoU8  ׉=$X5L79 ؐK?ئ8]\M$ \J",M5HT `6 '+0AM$|{#\uD FThAh p)BiF?DP00#N`$D`ߝIe$ɽ:E}dtKbӊI桓H`]DZ%Ud&+yMM $)@? T.%_:|.?bZ 6ISˢ;Ʃ!p)Mn~qM&TFEh)C{ RjJ#D3gBؐ늵T(+OqW^ #F~"> XKWmf2y"dBDDի6GlXKRD '9[mI\S2Zj3ip)BY D[*9O$J$_TG:b8. R"UX'Z 5Z,|>̙6$b-S\ĕH,Qk"!H7}4H$RUgYq_ z?3?bsM"Bc @.%W(KM?bPy>NwKC ]Z>p)BY D[*9Oj"$#6a]LH`*]w&'Kkm苾&l$@] &($hlMdI3ODD\Ϯɋ&m (p)Q& '&M$@'NDH~ˢabd&(p)Q&~xWש~n& dHzW~˗41-3wʆ5pcO DJd(b|91Ĭ!!PRI /a{I捏^,DV_MDlSǵTH`>ŔH"s]ZRꔾCMЎ"R!x;M$Е@=i_>{[Z3D# l2s%bkwْlA$}'sKH>Z'hSiHDTh*|yラfƋ؂fmm=Щ M NN%N`a~!@ Mkv8&$$Iz()Q `*DA4Oc(x)64{/[EV5֦WIH%o&*C$BM >0IN@V(I'H!^]$) $ Dr|ܳO?AYNC$0JTUj*X9[ @߳3o$8)D`2eHBH`P}Vզ8~S6!iDk@k"P|#w0 (*QsM$Ožs $AP+N/ a1b0 *Q[M$gjSe(R-GA6I!wg Z])KSi$8H٘2 @35j"*O2DIO$J|aVZ%է1NE *Qu"]yV+:aPr_.J$Џ@_%]D$Abf&{_U' ظ&λ,Kh 8JT^xeRʐcH`\}z'I`A}ZD K"q bę @`+\kA$0 JTNLw6 @_%^'4H`h}&jx>MQ7iєkJVUC͜*Q[M$gjp 6An)  LA˽"pDDI8 MQie|Wy]' 0y[ I *Qu׬xZ&$X@_%jN iZĊ\"H`JԻ&Rq 8۴vM ~^DV$@'qM I`}ZD+cA'W׉|"! @Uk">h}!H`^ƍ lH`+q !JTN" CZM@hR AUѲ5 i @_%j' ;Cwj%v*Q[M$gjyv! !M`ܻPkFYw G#!ؐ5VFw'Y׉4)DA$}:T4 H3KeT2utƓ $Wڮdmb$N =DkXPcߕr}΁H@ b?HN5OtN W5O=AN@_%^'NI*Q&'h){7.2bHJ`t5 3JTN4m1NE[4H6'W׉DL$0J\OGdEJ´[Ŷe8!=$@ UH' tj lHдvoO$$wg Z]'M`$ʢ/H*#^&1.v9[IX&($+lNӡL!D׉V-v,r-BIH`JvHn N$5n\\sIH`8D=IH`}z1"Fpg#4H"W׉@&oGHHH` }&j~>$ \S 8U8JVəDn]IIDAT∭MA Xߝ7hw]^s//$&l$@$FMQ]I4_'XEtl#bM m =DJA)h*4ƓDqM&;X"yq,(؋yt'^I&'hJc֎ǢH^ǖI6}>H:X|I` <;c?q$plTc_ @%c?q$plTc_ @%c?q$plTc_ @%c?q$plTc_ @%c?q$plTc_ @%c?q$plTc_ @%c?q$plTc_ @%c?q$plTc_ @%c?q$plTc_ @%c?q$plTc_ @%c?q$plTc_ @%c?q$plTc_ @%c?q$plTc_ @%c?q$plTc_ @%c?q$plTc_ @%c?q$plTc_ @%c?q$plTc_ @%c?q$plTc_ @%c?q$plw{y\~3doD{#υ vm\l+o/?7;! d?kM$ oH  sh ?nW?7<|tZE?UMm@]1ʆ8zDψ'xgl'9_G#XXZ׹2.yeB{hm5@O'#E>vW+cPom..ZoǵrZv]xsTԦ2U/D#m'N>j0x,Dv}8+`]:zQϝiE>vV{GҢ&{o-[v vN ̷uh.b]TY$Tr(I7t}W%VniE>vQߡVG5n'6,~RK\ĻcnAlh9J_W["02<Ƒ`vx柷>§giE>vQߡSx_R[E N̐.@f8L,l' *Hp>m١Vwk1]&MSx̷UCw/Z̹ж6PKdK}ۀCSx3Wr]o=ҋ|УN/B'Ze1"R276Jx+ ӵ'[hn"cRg?7/2TTfgi>vQߡM<ZWGn˅8##VټQ.J|ٛxTRIءݗ{|QӋ|УN/BFoOiZ(Ba`XEcZiNQ8"t$-?8 ?;o+3bii>vQߡYr4;o)?K_+7)ZߡG_k~fbQʻ)ZߡRAy౷i\""2Ndb*?5=9[dT 7dGsFǪ6?*&AG\-i KAceQ{mokv%sB!2]8_$є}5FbIuSqUgEγgqr#U?0aWR-$k_BiǾ c/hv5Z-2T[+{k E狅O~qgc9⺭Zچei^A$/[Pȟqbb-a}WĐezlrΤZ[jqG|zĸǛݷS|mgHׂuԒG~8\d+H}I)B㬢ÅS6ZI{uޡRYN+vFsǵv6ZDұʉnA9u-GOYTS{z_J?ofOZV/FqPUӧ~E`rYez|jYxsXZ)^[ڻ-O@j":G[Xo9m M^sO2O:ے̱x 30 1U_{2ܜu*Y<\Nb-խ2B+KW6v,cqPs횥~=h?Y?4NS7yT]ʄqGY^".Щ,~o{&#IEo)Td{?罏MK{}㣴[[j65e^h,Qh]Ơ;Mj5}rP)"wR\n3GZ?&Cc}[Qg k[O/$EZ8ڑ:6>}n}w@NiK.\b)4fP+y/߳lg/!l$罏M?&n<ף_{n챷/oYϊ(5> JfJ,C0=4\xMy.nPKA"Rgqy~UTs*ol?fGf(VWNKȯqZiڂ[]5 -bDrI7dRilѢFӑ#G~lf`]16mێ6Ն'mzݽZdkZVooG~ݳ=4V*3fb2'{3G -bfdӦLpHwiҼN63_'<6#4TRxJԴI;F$1Z+i8{ jWm?Co)Nrmzw_+go%t_S Q^qQEQEʊYijXFgi<6=I'2ǿBKj?=֪Qp/i/{G2ǿB./e_ZUkea=Аd=Nc6?=֣Kj+qmsi,.ж7Ώ3RB.^^Ha1=ܲ y I}.v_QLqa;$q T!UӞ$դ KX IlK7$!pr0>NWki/{G2ǿ[kZ~EkevnEbwa:ĺu֧isq-YH( '\ |\?=֣KjHti/"G2eTc#=P=fwX3VC=?`v_QLqީpJEbwa:Ɠ {/ŭ_Z/e72ǿi/{T(__Z/e\  =\E!Ȭ:yی4gQc=thiyտ/:j| @J꾧N ((()FFEg6]HΗMWkpA/4gKM1xQ?y?3GtO1xQC/4@L#zU(ыŽP+ )P" _3ttHrՆ0zu~UkF/ ?bP o+,alc<40"P*qqҮhG_Yy,X@bqj|6Ҽ[#]@I(ы‹03?&6;JJ@NHcr}i¶i Tӎ:V_hOP(KyRk[I'%xe2*t4TO-UFXы)X~fbF/ 9@:_'hΗF/ ?b~fbB/ 9@igP=0 L$EO֋??LzO>,Ǯ-9O?:%tGAouWM\ρ ]5|oW#Y'*?)?KLZP6Zu$0pqWtG24}K|C 2I"tdev%[1IG$F쇷YʁI,J1\e/hG25M8B$N;'Ҵg(pqz C"YӞ49GPz΂R}n?Wo-E44Ԍ7r ys*çl"ǿZ9: CՊOppvMg~uj#JԮ=6ovwdoe^:ZũuuK{b/%Vr;)gL[o΍g~u0?cg'вo;8ʯ~TV$Үm\g,ȳ3=285NU}IۦϭF3}m:4cr\A-n\@J|O-7ͮiw1pnq*<WpgL[o΍g~ug\Eő,ݼ~l}<ȓ9%+ik 6,uSp}=g~tm?Ra-ۦϭF3}m:*(ݺg~tm?Ra-ۦϭF3}m:*(ݺg~tm?Ra-ۦϭF3}m:*(кi8zq#a/Z+Ps S5ܰ2Jӱτ5U?JM }*:q?LzO>,Ǯ-O?:%tGAouWM\ρ ]5|oW$I}k ]<7c8qEŜW#3TlɌW=KY|܌w)A FyUmfOE U p>L=տG,瘣/* / ɹ&I<`bxeE?.s GR0kZkfU FBrW@#olU/G,瘣/(7TV/?پ=>%KRܮX{T4]_Xm;ѱjFF|{kIiVLjgmJRXnR>~H_0Xڱ0ۏ2عf?*ӽTCy0G^o.!V*)\ϱڮ++{+`ܴ1$0t‡:ǧؽMkq-vIաHhM0cb0q }] :mv B->(\6u$~'Ԯ.j4.MF6c9AQ8R<_c|7G%?t{hwߨ+/|!6f]$W$f46vOT-u{KbדL k⏵Utqf.l~_}6vqjT2P0Szʋ*H>Ss6&uevvڋh.uk܄>ii鏸Q]b6VG|hE|?-WKGjlZKnOZchثPm^p?(ȵ]G 祇sȵGE|^]>Ms GzKk"{XfoF"Bɕ$g{9 M7cȵGE|<zX~iGK(r?"gE?+tan=,?4.q?(ȵ]Z2-XeHA=i c0ۉ Ur@N=?1K#"gE?+MOrjiOe leq6p#*[ffKwH) 2STn%k?"_m$1GOvȋ-IqEi,GzqjO>CkO`E|?-W3ϳ???UfyE|?-W3ϳ???UfyE|C[sC촉n-tY0kt5Vu Ԥb\<]¬&8WֵmFUtRX'ңq?LzO>,Ǯ-O?:%tGAouWM\ρ ]5|oW!PE3OU2䤏=J6+: .Dk(*&(De^÷:uK1nKbpb$# :Dc7cA T`b&h" s{qk+ݼ"X sY=pQ)FgTdc<}j<4cA M,m# ? oCeVggi$n$MX]0{@1Wf^x]3C_dm&k!Ԣ#K0جWuYd`vH=A 3S٣d$oAWߐ2J6ZGT PNƗa35yKKeQ0kXxٽλW zu4mc*cIXp tpH liI.L^h#62#vwo9!5 oqe<(6@HUkKuM( i䌞Ubp8kۍ;ReԚK{43KhJ l!Trv_'"L%rA+U8:xv1 h@py>_L%rA(_'"x%Ua/G&9? sǸ?ȿq1kKRjVjl0N;v0=+;X~!4߅7BA$,`ҹ*-@>(>,Ǯ-|X]3?Z+?)u_K莃o?j|ӄB(8 ( ( B21KEd_ik1Ycz-ĸWSSwRد_ꏱ_̿u;֍G0X?2T}~e޾o_Z9-+W/]Nz9o_̿bw֎`}~e}WS}h޾s[W/Gد_꺝F,rb>?2U_Z7c}Q+zѽ}h د_ꏱ_̿u;֍G0X?2T}~e޾o_Z9-+70ne_Z7cɽX'!DE<ii7p籉c>l ;<; &y/GM_ʕd.y,l6ۇS~Q޴m{RkjR:R)6=em,oVȫՃug=}~Z꺢pR2}qN/TbiI Ba$.7Fc?5OGƩZADŏ?ޓe'E}SO3ΫI]x@-]GW3ouWM_/U:pQEEPEPEBFj3o ꂢ+@Y@4ǏSW?Oҏ/T9?Jh瘣1U|S|(O _fy>W?Oҏ/T9?Jh瘣1U|S|(O _fy>W?Oҏ/T9?Jh瘣1U|S|(O _fy>W?Oҏ/T9?Jh瘣1U|S|(O _fy>W?Oҏ/T9?Jh瘣1U|S|(O _fy>UO)g&? "Y?1 80Eh\'E?LzOʟJgW#7[+%Uڹo}N'"T?zO*o?3S[}.xfdwr#J秽]ZKEhQ{$3t]ʭ App6dqt'7^*o?aAxfX- JI)L+c;^]NSl#yonG8s~(/7^*o?sVzslMav/&G w2~OӞ: yn~O=6"0URNci8 fɌcndDVm?_Oj{7ҕAt]@{dԍ4.j 3Vi=ʶ$#qWտ筯&wiF{n#3AjGWp$~"ZRuy Ա̨"d,?5pWD6տ筯&F5okj+&6?ہ G^EL MP$ -fl;ל :f;~bf1[_Mj?];~awտ筯&F5okʊ=;~awտ筯&F5okʊ=;~awտ筯&F5okʊ=;~awտ筯&F5okʊ=;~awտ筯&F5okʊ=;~awտ筯&F5okʊ=;~awzjYWjүͿ']l\+Ura=OtǿX oK JjrQ]Ao$XUw݂xʎU_1ߝ_]h2,l9zt҅)%JRrZ!]ϨLJ?п}+wŏ?ޓe'E}SO3ΫI]x@-]G$fGhcOR+o꾧N2λ8URmpbvDmh=Csu=k-?+Ϻ: +[.Yn8ƃg iҍwDo:5}=ʠs[ZtQE;~9n$B)}vv\i5_~}^v+=?/oQe>| =;3(߲F_ڮf{e_~}{U,lO~}oϣjWoϣ/oQW`=?/oQe>| =gQ^'e>| ?ѿG]MM>UK7@tu$ϧ@fO+߲F_g*|q{o$2"AR9Rkk`-ȧ-'ωJ.9|FtiA=HCJĻY@*I@ڹފƇ c=thzI_oL_Dt Q%t6t_K&rs$ __;VbgV2*uNOOO=_X#G?Qߔ W5{UG?Qߔ ?cx~)؏ȇ3ڨ?Q O^<D>Ex,o?X##!+?Y IG" JOX#G?Qߔ ?GCQW_GDWG~S(?SW?G_gdAE^K O7?Gx?}j?=k"(ȃ_X#G?Qߔ ?OCQW_GDWG~S(?Q?"ZZȃ? "7?G,o?zDQG?Qߔ ?cx~)ȇ֣3ֿ "?ȯ%?Q O_<D>dAEy/,o?X#'!+??ȣ"+cx~)G~S(W?G_gdAE^K O7?Gx?}j?=k"(Ƀ_X#G?Qߔ ?OCQW1YGU0+ſcx~)G~S)ȇ3gWR$dSzaE} xғWտ朹traitsui-4.1.0/docs/source/traitsui_user_manual/images/move_down_icon.png0000644000175100001440000000111611674463545030026 0ustar ischnellusers00000000000000PNG  IHDR&u2IDAT8-0(f %,݂mj zK0h~#帩{%qbY3Νw]mkч7_$}K0pT*c|QO gY=׵ᄀ,Z=yfx_L.xمPi@"uԏ~FLuoG9zC~D -?*DT1 5> [UOd^w5X!98A/)KNhqHq\nˑ5M{ӡBr.nڬ-hcwoΪKN6zx)̛rJU4_ X ,8U.C\ڡEe 0@F CCE[MOdJHV QCyVo;k WHdZPGpPP/x~ &+O4y< rl;_{c8ofPЭCo#IENDB`traitsui-4.1.0/docs/source/traitsui_user_manual/images/themed_text_editor_no_focus.png0000644000175100001440000000523711674463545032604 0ustar ischnellusers00000000000000PNG  IHDRbx fIDATxߋUUǜqFiL1P2H4Mz z𭤞$2BRH(dprq&{]u~ܹ˺ޟ_>p) T"BZD$#0G3=F-%GkC`idWdF(JE\|D !ThL,_cUhO,Zx%>v66+3@' 8ᓥ[`k VBZq~M'`翤 +!=&[8@*8~| !DxCH@ܻ{$oaH3N?9݌.KWP )p2RzM[@6(5.=I`x6ۋIi_a :ZpR7$}ɞсvToESS9eӑmg,c7G҆x.<р(gnv1Y$0*aʭ0o޸>oО?V,PO] |5QE? hA3%bKL ռHv[o(m"TjBBz/d!hl2l)~PJ_TVV9hx~PߑJKB!H`2t T] D\h OKK=4Zl}B4%WЌi_I_w FIOH H H~@AO @DD_;WUy&G?C4 ģQƃD @#y~(zt2R H{x GZ6 ?ǎxrN?,?~1㯰*VԒx4 h#ªJ&yQ#(.~+K#'`M% WPB?!P6#@evPX\(~l#GZHCjIz~Xk]$02{OB ⴏt,H5"yzAÜS)'@Z?"_H/BF yC-'PB?9m9mm[ז[m[ZI҄zRq:A qNIцf7.Zuj9UB{ҏ:tD6gh@[N'Dfq۪!GIHVEW1-igVGK9i@#j=Mhu:8A>[Wlc'KHA%oD3 @Z?M|>;gL?_JR'!PjCʿsT v K2~6⊄h;xTp k}YR.qQȲH>.ᄄ#ٶe?G ҥ0xOngE FxE@$'bz{œ|¶d$Gb,[xtUdI@vܤ83x)B{$ܘBX"9їq4vx pG|R2( N朞::8X8:.lRmۊI-l*3oz !`.az~wOB$pfWX7%b! tf3]Rl|SGk(*n$85 6=T?~^9Џ,PԻ@ݦё xpۛ|D/[ذ=;TgҤ@WOٻ$lӏ]Ihn{8C{0ݽ 6<^6ڮ³M9 B!i@r0.+,ӂkHBBB6$I&y7MKR Є*j^iD$0 ʑ't($EAc@3>+ t@R04jz IENDB`traitsui-4.1.0/docs/source/traitsui_user_manual/images/array_view_editor.jpg0000644000175100001440000006757311674463545030556 0ustar ischnellusers00000000000000JFIF``C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222S" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?ߑcBc H$Zfnm͝*KiĊ$gqV\_Cy֋g.wi V"]Zi769wG6b3pqG{wZXB\m,pGVe5cz%וjkpO֕4)W fȱ%XH. a ZCp-jx/7-呣l6M=3z%ѽ?gkk>w~տ>_m8߼ZԮy/ƍQ$e/Ow_GC`I?ghޟ35\ 7_y/ƣ&Kz%tQp$ޟ34oO俙.y/ƳЯnmh%=34C;8EcŹ28,TܩƱxIDEYn >i7w @ ,LUQ2잠_zmmX^)J<Ou9MWgfQs| {gɤjnwi*40%b܀?R}8Q%s9k\#q$HhƬΕ6Nu]FtU_IgnquoeۙepB d8 9R0}tֿ쟏Sqq+x%YIk0f@#Qk`kTtsWQG5EtSB+Q_G"QG* "+Q_]r\B9emgU6RZX# $HVirSqlڤ\^,}B-BeEM^H=k;'MKYcmBz͠`en:711NT+'"_G;}CWoEyyۿn۬0rU=J5^Z}6[f<)mte\D`* ð[A;:Fgs*$ z<; \=T3+bx*!I2*OrG/+9 qeGUD&9ߔ Je/7o;^Ӯ-m< %ї*`qhArHbnuCyD iC.w s0kDxMΩF=Hmܧeh~!÷,u.[$hCecBCyb ?ҕ`+Q_G"QO ?G5ESԴ7F[Sŗ03Y.!K`p DZ}rH񖏨WpYX>ss 1#Ilʛq+z9P\G5EG7a@T yPY*SbK<د$Oݕ BF,BN:_Y[=*UM-N$dYESn@ ۯr&gWl<k-qFqUY7g0d `,cF:ՍzNIԵ/M6d%E'!R3.@( >д- ڽiE".`ylvsG* tax V.."E(L)!w|!6) ,d|Vgu//\XD͵i"0kn3ko&t+;ۋI,縶Id;fPJr AӠʇs=0HN$%7_j?(ʅsWO"E9+T9E9*i5j,"uy J[P3N=uzG}GRiqKfTG u![ʂE9*i5j,"uy J[P3N=\K<د$Oݕ BF,BN:Ԟ"Ԭty7KdhwDMېex'npB.Wð yED<,G)ԱU-3MѭTe KbR'qkiaylaMI\[oT|]fvvVҬf-N?2 QC@w(qn!ʂ~gWl<k-qFqT{]KM޺uique7ILF"]F}խ<:9v"1 W_o&t+;ۋI,縶Id;fPJr AӠʇs6WtP3zz֠e\JZQ玢0"+@ؙ\#oՔ֤J5͎q?PTjF.2.CFPTcF(Q\sth[:s{ ^ׅZ%b Wyi&B> H:߶ еds}Kk^Bnym`A[HV!|[-:l?ч?zun|y:n|y:m^^?z$VCNp_Xv'TKAmrMq-M<{.)pNWvqvFZIa"Aa^Mzd*M6+ʣ|`vX/׬;s%H& D=djyR8'+hH0QXJJbIʎsN@0 wtV۵H!ܯz|5N wnfRR۔C^޸C48/w7w/{x%y]#! i"$i$??l/J@/ף)?^qoi Ρyp"[ZyhT;#AFsW!u]:}B8-.m^ gdW~v%\2@Zmg2kuM #r0N# OU[MPG-Da*ɑp s !ƃ-M?\Y[0UUm(p8T~%M6\_5Dr^UuqUwxSC?WmhdX+Α158b^WbX NkVnܬnv5woڝ;R_KLp6 Ǜ(X$$$ 7W𮛣_w$Vd1&r!S˂n፸^N .icZ;Vd"@q,ѴcEŝC eUQ[N!kG_ģOӡ!rCa8l ߧX7w *CW/N㓀B |AN,o5X-"U-+_'lQ{]FZ^qO2ZE=:HDd}R>Qv׹^Ӽ=i Othj3i ,ȃAyU\(Rz WNmȱW"c>jqדmG$YD3 HIV##Bktf.#ݡLE4dpUv}g4s lu,c p8-} AVVEUAhJ/ 6r{>Mg7hDYxuUGfco[ly_n[,O Z&.dXZyg@(]kektFտG_Ώ1?=FտG_Ώ1?l}6Vb}:SbQı4M8oq1?sv{}RFԢ}>PADyɼOˀH2q&Ѯ.ҿ-7cKcYYgr_GX!qv4Fd%ہNxϓN{nȤ28(Qqv(CMPADyɼOˀH2vskp^E%Vǰ!B(@r*h~85z KO j@t&I崯 .ӐQ DPyW;k᷷-mJ'/n5 hM7|d,pwtEz=hVF1?b}:4=[5^j?6:F565O:]䙁ݻ`#sOXsujZnmk}mgݘv1A4-@k~5o)uW>W[f Сnr+oi:[Zfڛ7ps6Ѡalt"G^EEQIbmwef.e4+;Il縶IY r tYƕ_oZ~xiaaF` XmF,n&I`Hf$)$84hFտG_Ώ1?l}6Vb}:O{ٮ`)Q$N6 rq{L7Vrꐬ#]EeRRzO:#&}Kx I0:¿0Duٌam;u{Ѡ*h ٘z(=MF{'bM Iie{0ZD',@j_b-' \ssj&o'FvX؄y|ʡI75xm|Q:[Mjo Ϳ '9`tU7?ښVo.{vtkh}UG̪͞F .EB 0?1'v_NDڼ;{!|[.>iEo‚|@0tE5Fyk%ܖ#q"yi&O3B=$Ch5VI u >3DzS"EJ-<5zkhWtd/y(V6mPO?9+-oQ:.-ZPvF7eFՌt+a-(>ݤzzλx2pcP+ :k?ao|b^d4zOw@9C^{.60|{RJ)774uszGQVqwWw.2[I۪\ ?ưJ u]8l,2PHh%s|xNSny'uu3sjXp2IY~+yt%RK{^L6ӻ+BO3̌lP ȧkmB( xvぼ*i^Ў Y~%]m׮ODsWGP6M($WS>Qvd5m;—G3]/6w$$\۾ i4ۯ kVzŪZ*[\[}1G9b3<-/kӬέ4ZM-Kc](ƄeZqᰕ #HŠ9 (M:sswڝ1SQ '}q7C̺5,p8$oⷉEvznyo;pҪ2Inf13d- K8m"`86  _\ W ki&c9d3@>$St{;mWSrGŶs ޻D=zsV/It3DaXf@c,C€YYo^56]Mrp]q@NHIh:,b1di[V"Ȣ1:Yc}@3uy}sZ-AaKg4\[H&I¨=:-6m;B{{dK3fU'$=z~VegwJ[n+أD ;J˖'%#t>AVVEUAhJ4-?^sKoèYk][]^F9FY& F$,O 23.7c޲<=)CohźCsumXy؃zn|y0E7a^E7a^ ?տӪ7Yzzv|2x_TѴ6-S`b#pFj_Yg_*O  dDgj $bp~8 >,4ۇ&E*J| %$-¨2gi=J02 dU͋ F=5[\\Ki"ySO25˂zA hۛ[vF81'Am`Sp_F|=#Z>]eb4 ̂8č%*nl #:kyei\%7C2:.t~a@$UK<د$Oݕ BF,BN:Ԟ"Ԭty7KdhwDMېex'npBiX^ũs,Q$о7#T2T]eۋ{Hlu ˄yFBܙ g?0 9]>@.Ro?-:< Gߌv1~8Ol;_##[yw >|t<&MMQ7vZ#4&d>kyppMxM.ms>nnDFhL|@#'w8fOZk6Y71ܤlh$PnXE i l/#t!75 288 <&MMQ7vZ#4&d>kypqi{Ai2ku +rGQH Sp_F|)/ף=#Z>]eb4 ̂8č%*nl #:kyei\%7C2:.t~a@$UK<د$Oݕ BF,BN:7o]@KyeY)LA6/bk9K[h_a*pyuzmŽ6W:ta{WD,U1F 3\8Ol;_##[yw >|t\*Ͱ~|&3y< Uz[?BeM0".噤XS") 0|Syz燵(5*M62%mHOy [vv]Vy6YZIg=ŲK% 2PN:g,7fgź\# _S,cҹܪ>G?.`o'g3jrKoNMGyi7(Eǘ>c`uBF7@RWkNTsr =b>]ޛpo=*2qg*.QK3/uzkmSQe<|v+}Vܷ(Z0 ͷ6x y/$NErs+39U; z&i!p_E.n^}JG&C@DII~}7Qn6Ʋ+xG." of4?n lށ8Sڥ4>ifPmD8$'xP Ѽ/m5igخI4n@eGw *v]NTؾvlV6QʹTSHCx}+N-uk3F C4_E`ۤT83n;BkRP.PN:fYJdc{f7H=T t]1,+>;(k R"uRʻ vQLΟwlv߱N3&sƲ|45ZI3 a30-BF7ف»'@#n[#H (}6V0E7`oѰzh1^xMmtഹx-5^ E<YpFGfH涷{P4K"0;qMXh>ѴcEŝC eUQ[NWbisj[LW\jiZi Ѯ0E-V"v!D_2cw6XgCM@`;l6`c1In5h{XEIU<<bA-\Si3ҌwuĂi.KʾT- G]ۄk1 jJ`mֱ.ks[X6Ğq1ۃԍkvWS\=ͬ"$@YxL "{Y".ťڛIi8/+Ƌ qgAmOHvkh&p,yLmP.ِyIn5h{XEIU<<bA-]7;F$V#hTM/-xnUFT768Syvm6QԴB)mG!WC1&cw =*]?~jkkQyD&ĉ(CerqT|U4iZVnu - wQu KO`cXԱ6z}%e@deb@ `gw(o k^Iɬ-&Y"(X"9#  V]* i'Yy ~vfcI<='/H'Kkv(3Qs,]˵}g4s lu,c p8-} .yӨ|tyP|ui7ZַKn x9 l*ى0wc9mW7uiZLqewrks%4/+` _A 0&iV*#tyѦ9_#=9lTorow2Ō^Y9q :xcPNSny'uu3sjXp2I\o6Y5HBwTeHslݍc;gaUMSQʭq3yyd\Ă7iWմۛFRu k[hh6pbP*A٪mm {mE]2I':םŷ_ 4M~5}OJ3EXC$ݢ v(+;p!ҒxnXX$l]H # Z.$6fSEbQ~و_T4{7Eʹmq#C $n%Irw+B=utH>~%ĚnM.NO&bFߧѸqOQL?ohߧӨ?ohߧӨݏ#t>Rm6(-xwNB\|ҋ}cf˅Uzd𾩣ik,mZxR m#UFb&>y˽P!+$.pr@96_ Qolp1~s<-p,ftEw0ܪą$u`}Ҹ][A|YockiWLqquTYAJI#s[Pdҵt&; AqJ-.6Os%iȖbSś2ɳp d^XFqi{(Xn[6ݯ< b,|oݓ(cVcOj/,n|gX\Z8Y"-1\g>S1sJ#~RߧѸqOQL?okīZcɲ%pvW8;1\gxGu+,F{GeḾrR o HHh-# axoB8 EgM9|Guw ןfg)# _,bD=>IvVB= 8U=#Z>]eb4 ̂8č%*nl #:hoi:<\DjC.ƑăsT!rj`iu6'iu-dt;7Ui>d' 2y>kBEDd]ba˷U\#609`lj;;RwRië4vȦ<NX!~S m;KԵ=MbɳْI{?y[ǡ隭>E. d/崐w);3{:,fӠO"Hp0x 6774n?oiS774(*+oֽvz#:lA"qoW/_2J +nnd$i-Ss`n!ԅoC@( xvぼ*i^Ў U]?PmupɦMn F9mά\pFA5G_,bD=>IvVB= 8\6uI.mU$ 꿸Vped|I1qy쵩#Xgd()p<׭?kYx u7yEv 9 -YTήXIeq2j[y`S(mes1Ikpìg^ {/dH֮!fm~8'cqSxjMmu*$gDG#r2@d d3W[٤0d` rIcI'y?"X]ӋD78R !GF*.[1խ/PҠb;Ur>d%O^H=l]YZAVV3SE(l1QY?.!;kK2&۸\ț\78ᱱk:to Sk(`Ym(C(U]T[uX/ף)?ч?zu?ч?zu,o;IH^O Ψ [H/Yʚx\K(S4N=SNDXԚT;QmW;G'_XGa5s[sʪʣ8If@&A a# EEa)+'*9F9|nk]F-OnRd{X||ef̈Kyj@.\o vX[<*<̪7d Bd 8kx෻%XUF0ṕHLA]fo_arde,KY-ˑWˏvVlȄ"e+4|,e7nР I)45}GY4RgHVV(ٻbo#"2=ؾ s.}Ťv۔/pňT˟P?Ґ|y:`7-[Ces^\#Ȗ֢0Zc9\tfNP KWY`߼t]`~la{[_̲ZDB܌S#W+?[}6QL.mQ: 7n9$cqKFevy 1UF`[o9o\8xA}o/>[NT/AO emuGmݴV dc^+473 Jc~r Oyj0[)ç[[",20xq(Lga ɪk д5w{0Eyaw*@ڮmŽ6W:6Ʋ+xG. Z-ONd&GZzuż6f4pO7s,ȥGs\9:ZϨ%-Ա+oaOAt]YZAVV3SE(l۩GuGRXT[Z2d,s!s{gQnޱ4+U5=NW㿔\cLhx s^RZ7g袯O0Q=[4l}gJ [0,U('@/l}6Vb}:n.DUUgx9 SZ&VGO`B$GʯߘSq^F }[Pµ-.Qa}<ДݙH6ƶ kZv4?m lށ8f62蚔POY>' w*g~aNAy,m} K;d`X(PN03FIAVVEUAhJ4-?X>q^xR E76U@I'vو_Y.iWz .>#z#x$gn;lAW#ԮoG5MMUP2ǀxͶΡv-.fKIy^4XVf F wc=-] \)$as~cO0m6(-xwNB\|ҋ}cf˅QI;MGUHF}=%`:n#Jf[+[[-٤ x[J.pr q~X~%]m׮ODsWGP6M($WS>Q '}q7C̺5,p8$oⷉEvznyo;pҪ2Inf13d- K8m"`86  eKk;Kd)=3(:9z sVZ=3ZRk[ŝFb=I3kn[!KK6;KHx-"[#A${ %亝Y6Km_P=$gR1Ю@}~cg9Ԛ65i@Ƴlǚ *`nn|Io5+˽ܛ[i'Qj|qE{O:-e֝>7;F$WA[x. eJ pvcZ8Kk{ujQ@(?ohߧSw74n?ohqGZV5vr]ܺn$onKWsH$ t[*+oֽvz#:lA"qM;Oe֟o4ϴ ѩc'sH/g#u yQ"Mͳv7;10n񝆻!iYi ;qP@Q/mGH^x{-_Y_#!IF7ԑhRGZ[-vK3FV'hxgזͪV/ٵ?!!>Q)eS] tN!aa{k2tf%s+7Ϲd#,NwgQt^]=q]@6Xd]NJ`8F3|ȵ7}w4M.wk0+~ T Y^M -RhX 7p[' <3koaqNLmmdQkE` r #)+z8Ž@)HI ,Ė>{8 Z.$6fSEbQk:|_ޕh,XI/Ϊÿp$q=뱶 u.o ִKťVL|0ul؃-f +PDvVR[Xi!m٢$ T*>#+O۵e%唒~ CLyoqy0E7a^E7a^ ?տӪ7Yzzv|2x_TѴ6-Vu[mUf"\]m%>VryHT;,?[\\Ki"ySO25˂}2n |1S#5I_nvg]Q]Z[yynK.Uyinտ[\\Ki"ySO25˂e{}=%?ч?z`:}rH񖏨WpYX>ss 1#Ilʛq+z_YzmŽ6W:HH'Y " b.:S\:^u7Gx-< #W-)#SӭY-nI}nFd֩l.\GoUDqˏFyOZxWWri/FHmA>^,LQkpìg^ {/dH֮!fm~8'cq֭Kj6iR̩i 1&YuzgIy]ڴz6uq:o6Ь[ vF,y+ <>5Ʒ,zdxrKYda 1FŰ tk_h6I iv$r)VF( &<&MMQ7vZ#4&d>kypqi{Ai2ku +rGQH.V+I XhZDz~?ι >I{_XC}vP<0 -G+ٍLcxS߹:.mmo=T]dv XC#;*閺NjNsObi$}ΒHZ- JGw|e$|Es:|UB-ŧbG)#B alºMտLQM=[4l}u݃տFѠOo4ۖӶV \]Ǫi֒XHXk^#1J}j xJr-տ\ͪY/ٿ;6(KAC;|`ߙ [`8'x_+ }ڛB3VZEsyo@sqgmRY}ko4]Kp(R6Hm<(tۋGO[Xb9"nw1a'wJh+Ƈ2xWEӤ-m/]zeUR#;@_zy*ma UFwNvV;SQo iO -Oxq],X`Nh8o[{{HeO5P3"aNӜIHl4 WuogSt u@b\+>[Z:MgWSY%/]e lvWKLPЬ-%&F;fPJ'ӥ 4(}6V0E7`oѰzh1^xMmtഹx-5^ E<YpFGfH涷{P4K"0;qMXh>ѴcEŝC eUQ[NS&ӭ-"P9HT"q2E䪰#u- P߇[h~iϕٽmq 1qiqyntN@U$` vTl?u 4-VdХ[7bTG\\$F%%{p֙,1]UAT=طμRRKpi$g CqflAqyPADyɼOˀH2wM\ssj&o'FvX؄y|ʡI`v4Fd%ہNxi`ƣIrwFm~X;cҮ>=$Ch5VI u >3DzS"EJ-<4MƷkuyE=-J , anV{;+[]k Y\O $nNcԿӮ$Oqr^Uan:F#\g.Yjz$Oak6W:شSi-'xaY. P6u݌iZmKyRKۍB%M&?.E#t޽p=1.ԷjwIvnKoO,Q>g,#RLoķt/J@b}:ܪw̱c>wEA\H#|6>I]]iL@8 zU?Z\\Y4vڕ枉(L,RS}dy@PW%8ʀMwńZڹx*crD9B 2Ccr/!䷵6zhg2ٙ 2A|s2Hu?u+JkæBVK%D1 1#K:+/iVMo[*ܼ_6QÖ!\ 3>Nд'VIcڛ dɴw GE8E)'#ƻ{d/%ޣZm*y^Ko63lQOr I]]iM3sjXp2IH 1?b}:uo_Ώ1?:o_αm6QԴB)mG!WC1&cw +I;9l]mndf7T%el+$44; *DvQCn8Z4ڧ8+g'8 `ZSZsmF 1 'aƧO2OghԱdҲW}wWvVǦ\$)UcIT̤oFF]R #}^#W)8/##ҥ=FE4Bi H~^B81VPG(Gˍ TuGEi w͙0.ٖ"F'gG#eM@6vygxɠ -_Oi>eYؽ*Ol}FFHv5mg*GI,tI& 8^zԓV+4TMזȱ̦THȁ*csq~Y1gLI$fcI$$I$V>7AO775CS}ot/?ohߧMQ 9X|n?ok—SXqO~khWtd/y(V6mPO?9Ώڦ+>=:/lf/KonΓ|,mk-D}'̐7*[b3'̜`δ>?w۷;~9},tF k/T p[.n<.Cͷk2H#؋)[d ''Xnڰӭ"6ȱkob4f|8< i9RAcCq~F?ƨ}oMSAb?ưJ u]8l,2PHh%s|~7AU5QnHc,1ӓ~^t/HHh-# axoB8 Eeo;kH%rY2#eNFAl#]3N]I )j(FO'!m p$(7*8;sz3YYW6gjbRчݸ)e g OEuCs_ ɹ$Mi֖iC#"lбaF,0aY5of79B91hAbo]:ư]˩S+X( -"GqUE:; ʲӭ젵4K+qklJhN>D<O46O]+Q;Q@P2y<: 775CS}o: 74n?ojڦ(T,_ߧWA[x. eJ pvbڦ*Ʋj0߰1I or:rcO΂iYi ;qP@Q/mGHuB-:O[ڑ]]X%s$d aumbHaNQ@ 2y8uY5of79B91hAb+;AѭnmioڬPm'\ET;~U?1&Dnk]>"kk<@ JDžRW;~E$|kzuyZ/XϷ̋qMX0H#oN>En)kr΂mtIZ2e+I\iGVimonb8B(V6ZxGIբE|ȷݵT9j }.t9pjvϝ_ԡ~5[㶁teACaLtށ_1ߝ4vm~W(ߕ `MEC;O+}| &ߕ >i>v€&ߕ >i>v€&ߕ >i>v€&ߕ >i>v€&ߕ >i>v€&0Ic$`T }as}w'mmM+p9<ҧ/+ kS$nF|^8ei$R4tX%$;{T^%&y'_)᷵yG'b)bd,u\h6B,J%D66 U3qָTUNv/ QbA1hl\6pTAzg n[Y32I"+ DeMFsК{CIV? NIfY++Frn7qP7.u_y%|&|>{۰%s u O-onY*$% ]gO+{\$Fll `GΪUA%KIlDX㉜`} ZVqo&$ 4j$lU.-FKB%*nYUСR:c sz2u],KڭFvthmWvT`ÃH1#k#¾<cskZ+s+I,ݲN,Fv8Ndb:jn6(((((((;6BzeyϜ?.!g9]l/|_G?#j(4y]ki#gB 뵔c"U/K-1QnrB /?#g9]fWN ^A8?3L /6G>rB p~f4_G?#7 p~fJ/ g9]l/J/ ?+п'hK͟|tyϜ?.+п'hB /6G>rB p~f4_G?#7 p~fJ/ Սrw3d9>XjH,nR,3LH(5`hD]n$lcܑg;A3Ztڿ5m2ݑf6 p O YĖk:iwWR KY]+br)?xwO^Ӵ"S$Դ:.HNqX^%Ư=jyfS$Hw8"S1O9"MKzČPjc!T,FUeSl&A dzjvN43+V+HHKT3.q8yi#Vo% HCRGygu{g/#JШG(! K!:43ho-O[y {M69/e\D(R l%H;o .'H !F(S|yoᏳfnw?'^69gCj@Mƺ)ԋ1β4r~PsN:M3ZjӬ`76[Ƞ EVp60J B xe<=Qq2jDž cl` w((((((~U:qYOq#2cK?g~PT?goEgoEMECvQvP*#s>s.i,9528d4d`ہŠ}&Eq0[L 6'n18-ڀ;pLߍ5-/6Z:P9yqȥG %KQ\~4V+'%mհ3H5hlcw%ǜD'nd8yxV[Ѡr$yьr202TB vxO"&:GsJP,M.-r/'X X ޥ[3骵Ԡ J.prp 1| &:Go玑*/ jfʄfW.9' 1a$z:\ &:Go玑+z,o?6xO" &:Go玑+z,o?6xO" &:Go玑+z,̱MS2ElBݙ9;mTEARՀ!hs O o9B91k2O $QWX_/ʎDG$Cl bH)/Y5wHCHm:9 yy`O$ ]u1XWge6d*X [TQp3- 6[p=$gC)ijW'}ъ~岿_ha.,lFgX?.:a<̏ޢ[ɨC|'r:rcOkY48VE2"(rZ%y@lnq wOSMWl}ݿzqSQON۵[Y@]FHPp>­u#U 8?oуV`,u#F[5Z9?oj([4`u#U 8?oуV`,8;8=WMtraitsui-4.1.0/docs/source/traitsui_user_manual/images/themed_slider_no_focus.png0000644000175100001440000000134111674463545031524 0ustar ischnellusers00000000000000PNG  IHDR?&=j IDATx1N1E "*4\ U N\{p!UjJ *DM=x6>_F޼l/Ҏ Ģ{n#@`>(¬ <ˮ{VH@/9 |O@H-Ti5晝Q@VWuo"Q@&LfoY+ϻLX@4QZ=g5= ߈#_&jF`H4fv$i@#ٴsn$1 V^[A@BA m9. ^@g #.D{& tF{;0B@W(( lˆ ^@g #.D`ȯN@H r#{Lh@\+Kwۜ*RA WDX=SfL7 XV/i`ޢnF7k4]+8LJ@;LzmyS-t|e;$ 3gs;Gi l;열q`{>mtFD`5UW4> ' CUՍO s?6#B! tЂ5IENDB`traitsui-4.1.0/docs/source/traitsui_user_manual/images/table_editor.jpg0000644000175100001440000004700311674463545027457 0ustar ischnellusers00000000000000JFIF``C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222 " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?x"kX4JI27$R}o\SA-`Q٠g?h?5-2/A<3jq=JGf]n`3Ʀ5*&'٠g?h?5:h庢Y(uY$O16Zܟ~G>Yk3h4Y??? CCAtIh?4}GjU!Q $4>?ƣ5*}gP]}fyQc?G>ATr.>?ƏA< CCY??9dDfyG٠g?!QjU OA<3j?}gP5*Y'٠g?h?5>ATc?G,3h4Y??? CCAtIh?4}GjU!Q $4>?ƣ5*M#lj חeIŠ-} 1?PV$:"끟U9^EIqH %2?xG٠g?Ss_S/A<3jZht24aԺJBG*WϳA<3jZ(}fyNxewHQ*rG8?⋁٠g?h?5-\?ƏA<hEh?4}KE/A<3jZ( c'4Y~v_\㵼_;󘙸]$uI6ݕ·3h4[xƳ~,EçnTOKu%I'rHA'NpqQ٠g?h?5oV⳺x#[)%f rXH;*kKF?GE%xYJ.>glTlfyX(n/kK[E+$P2YwIilʃ/<˫4)^(?ƏA<ۛ.6я3ݜ}{VkI<7xgtKo dqz$ٙ}2XcUJ9_[)u9簖UZяZgV? Rmv?X*ԳΒi,R-B տmv?K_أ'SgtGc/ b.х Abswcwy:F !v搤;ڻC=h{}.fŴ{fvc=-"bw,;Qڹi-"P&Vbȶ)I?1v%܏0PզkpQ'KfF1nXԩ\;2ֽxKآs6>5ULoeTeW0qs$Uey}s4 rF ?xW]أxE4=:|V'MB7>K`w=j[%aQ~,zyk0rTxG!b硼EiVvWWqc?."ۀxHxG!b[+Y M'Ъp7rM K0=AfmuGk,WF0 ʯ~}+)Ǚ}.i)_ce%嵕гvafSz@~r:KXAj4ALW N.r?uS{t{f!)k KIB1DD?/Q?_ثqVFSjrr96X6v[m,20j'V? R'h?Kk]#$H[!?Ȥ3(# Dk?"2?_I}&K{ )4Cݶ$hgOo?Ə=?ٿc \P7 J"1RK=*;K,f cx+]:o=?ٿCr?$xM{L+"*4 *7mqn\A < Њ.zϳ 5u=@@˜xM2:]w78.8Q{(/ F,kdo7q@|\ ns[hX}OOo?ưu4KyU\I88X"k\kkGmH|~Gy>|'7\j,2kI'w!imztW \H2yo~gEXUG}Ϣ(UGEacCVQ+>.Ƈڭ?أVV}][t߱Gڭ?ج( jb[t߱YQv4>o~jb,h}>o~gEXUG}Ϣ(UGEacCVQ+>.Ƈڭ?أVV}][t߱Gڭ?ج( jb[t߱YQv4>o~jb,h}>o~gEXUG}Ϣ(UGEacCVQ+>.ƇPscS$ӛJ) OG^VVcC8U~ @?.֩icui\\ *r[TK&RQWc6%5 kǃ1*3;[n u$MAc?@N#~Ι'm տ_K oD^ ?t[ JjAZEivviʹػW% 2ORO5?¯x sCot-.4QGWN@53\ӅMUbϊY|'|$m>_Si"ʸXQo/$F )VVX6Bz=QD}+x#pIJ=pMt7doᘭ@t?(L6vиEϽoAZ?Z>$ր;b'عrvŠ%ۚ@X=Pl'.ah܌gg>weiUC<0*`F@z~O$ǦxH1(HOGbdh9`Ғ^׏Y:ͨͨZܼ%(x& 8L֙/*+دd˹2qo? 5⇍Uh Nx 7Jlɝm pjw~gEh'!Vmq,GP>Q[x,}y0up=3KCl7ZaZ{DS6Q}.['آoμϢ>~t}/V>^([ +CQzGآo΀3Eߝbտ:Ϣ>~t}/V>^([ +CQzGآo΀3Eߝbտ:Ϣ>~t}/V>^([ +CQzGآo΀3Eߝbտ:Ϣ>~t}/V>^([ +CQzGآo΀3Eߝbտ:Ϣ>~t}/V>^([ +CQzGآo΀3Eߝbտ:ϭ9ԧB^ԓi)b2?_-U`Ygm6Ɇo@K`{^ @<|_sg}dŒi)Gp3z̰J|Ϊc7Jv:qePicY gm' `](}7Tu{Xu,$~8aNiʽϳҨO%ғNsb.v||qU5+{k?w2iv1@ڥU2pGC[|GfO—oiYM?m|Ky rӁz+{Ux >\p=N)5;д 8`6~^Ž'I?wZoN:޼YnI,-:k?Gxn)G+7v7QO3Cjd}/Gx/SǼ_OL((((((((((((((((((((*)կtC-E?b'#e+7U/4sB "f55erp^$W_ @&4Fsd֧>~(pݒrZْG%=# 6L#$7O5Yqp2]4IrCC:q[GA>Гl壢Q kjms@R|2?}iq-b-wJKP*x w+%X}8=[R?!Piahܗ ^Y$ԚuFx?)67quo ^ynR1ocgAFh0YfjηɎ= H r{*u4uݲ͊=[ؑ&f5ӡTYD[T `>r&SʃMP&{`G (&OA=eZZFd{me \yl>P#p9GծI ߈ѭ-}x$2?Ҥ =;0kR7Ė8^>|R8Q1I.V 4Kvv\d`͸LՋ}MԖѳ<1Mt^8YКw=ɒLf[cq0W{2pv>t}zuxed|Rvv}}qoK"^B 5Q<%gwh5LtJP9%,s'}(k+ٮ%0As(-ܐ3jkjSER_l3! W3\:Zkimw:K!l~v(*r# ){vmYTi1F򴗶~8a |+Ӧt˼KXH2juaQC2]Y|=*O*4#c(RSϿE蚍춶mi(hVi" Xco%H`08Jz](cp\p;ې 'IcI#YS9nsiSi |@ U=p*=p* ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( k]#KQO  зbA<.pgγAײBRҼSϨ^Aki3;'pݒΛț~(&? WԤؼgPtCC=W~S#O,07vgҭ%MI2 899'Wa77|/T7P"\9 x{UڂJDЅ M@_ |dsQO UK۾}2Z?}ĺ֕XM Lʦ5x#k;8<;5߉55šD܃qn22,AM?r JILzD(2JQ%F9#\`fi[]:+dl? $g4X wI:T6flU;gմ %n~Qz,(??*8??+Š((((((((((((((((((((ZH1RS_)b2?_qi8+ǹdE{yr6dYFw-1Ɉ 5pݒؤ:ٮ^T)ʣ<F~wϗ}%kY-y57ibdXXUᶷa,> j6Km@acd0LcIwyϤCu4%ͬ՗ޙɬصoi!h29SU+]B0>__Δt_7UV[+}>u!|]ĤW=Cu|/y-W_jD8 "zlϤCy?z\ O*9o^*-Ʊ<0 gh^=h~.~5¾x\K{ղ{fҬqk qjV4nby]R$ _Ə>__F}~y|I,RѢh#k{xf`%[z ͏ZM.lm,專Ƞ2(]cW]ۏ@IF]/O/63ZZ]G,`3.ٱs\@5i]iܵRBg` `(TTaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPQOj)կtC1?{/SO[6nf ȠAo)OyѬ00#ӳ-I`fG-+HvsܐYEi'u1t'#9A W`ݳYڗ4}0[;M<X'I [=-3;Us°xcN}F=ĉ _icgi]HR;*?أQ+??u- 1Ik*Key>oKҭoOus>$2+9U~o~gbp'˻4 /me J 4gbp߱G8Xm|q.w\Ջ6v~b- 5%Fq0xfg0 >o~gbpg}v$[Gk5y,ASd`8:u#VVMWPP#u$'ݜsskQ{( V-gRG5\//@aoT (k>TUn??oح?ʏZϼ;mFۏo*+_VNq=amQz~}SXTm߶bx*>k>TUn??oح?ʏZϼ;mFۏo*+_VNq=amQz~}SXTm߶bx*>k>TUn??oح?ʏZϼ;mFۏo*+_VNq=amQz~}SXTm߶bx*>k>TUn??oح?ʏZϼ;mFۏo*+_VNq=amQz~}SXTm߶bx*>k>TUn??oح?ʏZϼ;mFۏo*+_VNq=amQz~}SXTm߶bx*>k>TUn??oح?ʏZϼ;mFۏo*+_VNq=amQz~}SXTm߶bx*>k>TUn??gmOS@$CFy$UU#>Q?b<"?#mImv?J?6n4qpdpQSM[cm;HOh[ֻ_,: @G bc,-x.[mHw,Bd98HFţ TkYndxy $`b֗5KXaS~֬y c`ņ, Q`53#6{Xd7aW>Tvd>"Ԧ(`Tr)A~=wK{xD*R"7`.'sc2UAuF. b*Fҽx5pI3rOj_49'5/?cv"7<YFHH[h8~sNJ,n^+2Bhr_j5E.a9/5???MnG* _KAOO&G%}'[Qʂ#sS9Irhr_j5E.a9/5???MnG* _KAOO&G%}'[Qʂ#sS9Irhr_j5E.a9/5???MnG* _KAOO&G%}'[Qʂ#sS9Irhr_j5E.a9/5???MnG* _KAOO&G%}'[Qʂ#sS9Irhr_j5E.a9/5???MnG* _KAOO&G%}'[Qʂ#sS9Irhr_j5E.a9/5???MnG* _KAOO&G%}'[Qʂ#sSbӍ>˛+btLќ7sOO?oͨZH1Y-)S>gr?Ԗo\SA3j:%U[Vlw.,I>O` He*z|wqZ=CEwB9#Җ F4dw1G*g;AN(V[u@lAfqV>޿?`1E.,m@&?g/:[M7Xd) ޿?3VQ·@O(}޿?o_·@O(gCUrqo_򏷯OLgCU3* 9_pOGz3* ?i~\z=SS?i~ BW.?=SQ) BFt?ZߡG+(zTFt?ZߡG#:?У zT}g#:?УVQ>޿?3VQ·@O(}޿?o_·@O(gCUrqo_򏷯OLgCU3* 9_pOGz3* ?i~\z=SS?i~ BW.?=SQ) BFt?ZߡG+(zTFt?ZߡG#:?У zT}g#:?УVQ>޿?3VQ·@O(}޿?o_·@O(gCUrqo_򏷯OLgCU3* 9_pOM7"`@ec R3* QYiekXFgIť'}M\_(Oj'V? T -)S>gr?Ԗo\SA3j:%ck͙egg]A)cj٢?GiEŜW]Ja q<4C-djI&UcdZF, QN2y.(xp%@2g^x7Kqz-u4o! tR@Ԟ]vkG糆!F\rx:mps?Y?G$s Mz΍~uIgOMY?G?XQѸzιI,K?{Gh 6?:7Q3 %=#4IgOMAc=GF?:$&I,,tۇ=G\$ %=#4sp?$& nps?Y?G$:m~tngK?{Gh9Mz΍~uIgOMY?G?XQѸzιI,K?{Gh 6?:7Q3 %=#4IgOMAc=GF?:$&I,,tۇ=G\$ %=#4sp?$& nps?Y?G$:m~tngK?{Gh9Mz΍~uIgOMY?G?XQѸzιI,K?{Gh 6?:7Q3 %=#4IgOMAc=GF?:$&I,,tۇ=G\$ %=#4sp?$& nps?Y?G$:m~uZ8> %=#5jQPI >v#wNO r Oj'V? P7sOO[ǝqOR|ͩ-)S>gr?u|U>ϧGM#}_3p/B`igl~ez5+"mV%6,Z?~W}F],Aio=*'=ymj#\aNNN'3ޗ/Mк]] @7 1 s]ȵ׵9 ݲgSd[), +ߵiiZֱZ\vsƐy`FgIMOfD:kzyG9}./Z1@8⋠4(yQ毿E毿G@>gjT])jTyQtyQ毿E毿G@>gjT])jTyQtyQ毿E毿G@>gjT])jTyQtyQ毿E毿G@>gjT])jTyQtyQ毿E毿G@>gjT])jTyQtyQ毿E毿G@>t5}*t#=ғhOj'V? P7sOOo\SA3jKo)C$0YTzޤz:5'KG'KJ%$i4$i4⨰QyϴTyϴTX h?_?iQI>iQ`%$i4$i4⨰QyϴTyϴTX h?_?iQI>iQ`%$i4$i4⨰QyϴTyϴTX h?_?iQI>iQ`%$i4$i4⨰QyϴTyϴTX h?_?`Q;_>k>߱G(\0}(v}}bP`QG(C~pҏϴ?Q;_9BFchأvrҌJ>k>߱G( >}}bϴ?Q J0}(C~chأ.>`Q;_>k>߱G(\0}(v}}bP`QG(C~pҏϴ?Q;_9BFchأvrҌJ>k>߱G( >}}bϴ?Q J0}(C~chأ.>`Q;_>k>߱G(\0}(v}}bP`QG(C~pҏϴ?Q;_9BFchأvrҌJ>k>߱G( >}}bϴ?Q J0}(C~chأ.>`Q;_>k>߱G(\0}(v}}bP`QG(C~pGv턨E Btraitsui-4.1.0/docs/source/traitsui_user_manual/images/default_text_editor.png0000644000175100001440000000117011674463545031057 0ustar ischnellusers00000000000000PNG  IHDRaJȆ?IDAThYMP$8B p !@ *$J&lﭟ-pz|yp5F0Ϗ8y|~m/;u A~i+RhXhmETu~؟|yќ\Grz3|SV8?IENDB`traitsui-4.1.0/docs/source/traitsui_user_manual/images/compound_editors.png0000644000175100001440000000556111674463545030406 0ustar ischnellusers00000000000000PNG  IHDR 8IDATx]=E=)B22  vlYXF ArN@ H&"uMluOwoU;V5=կ^鞯ݼO6xsِy 6OM>[)ے|Sath{,3?>Vӣ'gNO_|rSg8 aKmzB/`@a u196"h5,N# FD %iF |m;[Cr ,sr^r|j7yͨ>lt[rhØi(1@r$OS^ Z313<*7-_ѷmPӷ{_>&כXv^J5bl% go s,GD*MvG#X4$d(g_8JRVXyDi%Gr6{pr\.Qa7#%naπ!Ǟ1fO|0Oi"=`n7-XWr2kG6-qd+O>L< "o?Y"Ԣqa_KOst^BrNRr#{5L;R&; :bqhhcxd / UK@UWrѽx_/G[# wxX^<^3K4]2w+o QFL5_dHPmsv @t!Hv+Fi(ų蘁2r,EWI~waR vFP1MY3+v2rtIZ9brD>RS4-]a rEKx@r-iiu㟓v<Q8zo.q ʽ3~Y+k< <Ъ cZ417.e:Sy򠹣1d vʛ rI 2/B`o>B'1n@!ǽ|BS0:6-39.M}Ǧtw{:!G=W9 fv8/ɂ❯vgDUN##CC5*ozf/K 9f/AB^25Nq4{ r!pBCKL r"^djS_T758L iYr7X^{9sr\j A9 r\j A9 r\j A9 r\j A9 r\j A9 r\j A9 r\j A9yn)|_m΀mCˑ=mk s,r|s&>}]GHZAo9r6~*3&?V7AՃX<͆nI?M|t C,[3$-bg`~I0 +k"&Fdh5Qi_ѱH֜mP2T։i'kk"dW`f(Ot+畗_h"I 8)QmD-d#ˑ#~eu$l2V$mb}ލǂҝAτ9 T274J RDܟ;8yoJMPq.KPEj'>TԴh?G!JP!G9!8P 9@!ǁm?N;;|µe  ` Xˑ2iɛo9X+3#.d3|"MW($l !ؘ_!qtz}9D(.:E63qUQqy؄"9q,ǹʫ *wqʕ[Vk:#1c3)Ox!=&^Rn*6ǓuzlpDr/  ʱ95U3q-j[{&6ߓ52&\+C* l%(SQr"Q4r$~֣TR-F6id*62( Z QDI5rX[[IrO $_b8XM3_S{gͰ5:=X|$hpؼW6}QIJ_yx{b(I$-^m#EfTBEFHUmBE/p f)B% fɓ5  Фc-f7Knj7"Yp/GN6YS5m[)Y ͷ9V Ɲf噇1F&wks,G>#N/Yg}QkKaʚSNFG Z}ʹM|ˑ8ZT!R}#g"Z@skeڼ?l]G؎ȇxoZ)v("v؊3Wsp ?$};4o%z 'Gdm\[&'kVFʚGc9r6|`ɛz͚ڳOgFVH\i&>56VFϳsG}i~B9lBs4BqdrB%~ r(Ch 3kz`׮ߊi:ːi &ĬIENDB`traitsui-4.1.0/docs/source/traitsui_user_manual/images/font_dialog_windows.jpg0000644000175100001440000006766011674463545031074 0ustar ischnellusers00000000000000JFIF``C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222_" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?S<;X ?ѭEJ'' H?V&8+WF\Xh, * ˀAW (QK}V3*ue)cz[ߡL:C\Ыwg͕&EQH$)pqRu,m.E*?ppx rjJdT(?;o* V/XӼЗFR^ QT[CqR̙AiiE>vQ߱Y\\_m~Qϝj1G"SOJ/b(ǵ)߱G_m~fcڌ{Qȃҋ|أJ/b1F=AiiE>vQ߱Yr 4;o(Ӌ|Ь{Q9rqϝi>vVf(9M?8 ?;o+3bD_m~qϝ1G"SON/B8 )ߡG_m~fbQȃӋ|УN/B1F(Aii>vQߡYr 4ΧߡIZߡY,iiE>QZߡYr ZߡG_k~fbQȂƟ_k~Qϥ1G" QϥiE>Vf(,iiE>QZߡYr ZߡG_k~fbQȂKZͬ8Ǚ,|NҴBp׺(#?A 8?k[}ac [ *+JYn!;k̯Vj5ks ros}..©eD3N/#scj\D*dzEmkI f^hQG̣ 7k5Ï*a]F^{?#o ȼ5?UKK:D(G)hggd!R+.m^/#lSsI%~jH-@ZF._Yqђ-MO`gt]t(xO"hCK ;$tSW_)=heyUmS==aOES(+_OEI?z__?}GQWg ğ??W~'G ~ 'N3ȣȮ?K¯'O"|AOk×N3}k+_EᲖQx֒"1Fr@®OZ|=]9G+"ttZ2>_>7 Q)_}T+B)8jW*cknfk'\?Y jd1e:P* odXfIs™dgZ*Pa%V1z[w>lvex,Dj6uMw4$}E-3QۏdI^xHL{h彶/ 1wm: xz_c#EX%߇, ﷴH0paǡB] Y(EQk}߹⺜af_ƊEd.'7D;0@=kR掩zi)Ksܾȧ7}(뺮?Ҏ_OxOYʸhu u?jz15hbV6~quingזQJ80x#xOS0Z X>xEX.۰J4.]źp fOEch֫{Eyw̥|X1 zQ٤EP0((((((}iڦkza=X*ڬ1M" J!ːNBăS֊$6GksjP*F{#Fޒ6QEaGVlu9KPMO?rAT[ K0: +|Z] :im-x,7UĠ6C.ɨ_gw2)"`y?{8烊,YEs/^=yvc ,,dz !(z|$:zMX(aEPEPEPEqVzն]jڦ:t7vmb+2*ȈI&Ps[ҿ񍮓u{Gkq$;7|M đttV6K?ۙcv㙖HXBXp`0A!+fQ@Š((((((>.E?݋E%7)?<|Og|'NoQ[Yj-+k d $<ȧ7|(볼W|V[2WT^gVڄ} Pip-΂ cd$ *ˡh eZij6f{sL ٮ$'(K\[[-od#"?W$g/;w&3XPҼ?%~$ioSΑ&ԗI݈t$5TXYf92`Aスa([vmWk u=CPMfATAym6 !#zw]rU?፩s29;4i_񮆊ϒ%ݜ[??CE ӰoG[h!vsvmWhӰo] rD.{NvmWkHi_Nt4Q9;4i_񮆊9"f:2F 29V*[hkir]5\4,'ww\ cZ:o"ljVB:k=E\ $a P̓JңmvK%WY%V9QPU]ϔݖ-IRO2o3 :aM,c?ͻiˢ&m\*cpp Q [tF >Uom5$n;WjjP]Nssw4Č1'xmQ&^U@Ve5,}:cuuu=wIߙI#bbI"RŹP^"X.~-0rFU#;|9iĚ%㶵*X8K7H*N~BXF(Avsmq[© <; YO_w>8`I'kNt4QȂ翴?a?ƺ(][??CE ӰoG[h!vsY;Kvf8J՚XFEQ8let{knٮ{9b3\Z@rOBylG<]-EtX&PYvRVɦtwV郴Ӯ|M5rc3li $N9Q) ieLwx;pp *Ă5Nt4RC9;4i_񮆊9"fw֓H# U ҟ+#ėxcUK#`Ը{.m[zx~ue\ZG$M9,d)$Ԓj!5C֎9޿Q#?H/ؿ-yG3;vyWwɍ(T:o1?b}:CTC:uI4B,S%b6p˴rTg,#?H=??4~? b}:f_ΨX$?MUwm4%`0-F8ePA9QvR?ֶ_J+7u&f/,p{@IiVVm'us濋QubIE7)?<|Og|(NoQgy/Fq ?Su>oWylߝq5uaCՅ-§&4i|̅0/&GB"Y|=o}&`("O `O 3]05M$?MF>"BpF~.0CwNj(yu0T$_̗˧B({F+,@U;Aģ\1޼ WI{&X+A]'婇9sr5*ӊB WI{&X+A]'̿oOTW_ ?s +=G++{z}B WI{&X+A]'>__zWO4_ ?sJޟsШ= WI{&WW0Ey,?MXe>}-ę؞MP:I᪥wjguEss!M D .v|*'*#zԬloltc0D%בj ?txŴaL__zWO4_ ?sJޟsШ= WI{&WW0Ey,?MWO4}R򿹇*+`th=>a?Vb/OUE)‰Pdu"z AJҜE)O p@ѫ$7 mha&v,s8I{O3] I5m$upx;wogzK?imsˍU/_F<}j}?ɍއ=]oc3[_+n#?*n7f/?E=??;-CZf;zmЅs_羋5^4<7HC|yC?8I=NmYCD}Z֪uiendKXb0X*VknmEZ)5]J(%Pv/WaO1K~=kGsҎ;q5kQ"\_Z|~V>xmVBX*sِXmP0= x5(_-cR|p6{ }O^xk>/[]jjy"]rst$d HY99>pCA [i7#L;jQm*d ?l,˄FP][CήNYGR;s\y~bƛ ?9ozkۥZe=rpMz6 ?jºEԺ\w:OVmPH 0#;q͏XS:ДNK;]N, q1)$hrH,*/LB҅.s}voXq\~`r?mxEcVIk2L~@T㏼jdž=5/+Īd9Ul62:C2BX/caި8G&1-~I^t|9gx3EvL/4j削YAڧlޅy;}>YGQŬk*UP ̠@= eZ2ķ@"ہnך:@x3+2jn vdS+T(Sޣُ*=E{*~Et?wUT+T(SޣJpSQ z`[+NkI(Ԍ=s߯09߆m#n?^DdҎȬDFWgVw[K EfiwsK?$/z6UдHƙO΢-&5.#mQN27HW GgR݂ ppTTR{t9K-N?zO"U:??ҡLNQ3[õF~i]\O%H9q n3d0$6/#M68m+(c8ܭ |$!27rW;oF?g+o3L×2eDnS>D>VlQ>_Nxڎa|m㘨] ȡ>EkV3VH3濋QubIE7)?<|Og|(NoQgy/Fq ?Su`ѫ_/O>č\Zۛ,5{ "[.Kmndh^B,Q iaQ v"M(}nƯ&Ӎ6,+&GZAq&{srm R&̹6!YXjMN_-WRL]{-#!B\3n0nJPzeψ4u[X-nq_ YQ+%H:UoxKMoI_}Ķy>eXa"rrx^ѼQmos. Ȋ"iw1'h'$ Żƶ,5p6-VЛ!xOΡv7}/ZЍWxIN"vW.9p|xi}OV>vuK5>|aReA^58H8&ŅY\qwHdNX[* 8z&s\][swy}=IJќ hmV/X[etzg]*^S'{*+aJC1̐;"#ޟ+r6. Ayy~]j[de2 oheXWqK_7T*0T_—^/.nl WROJڠ(((( cAK?Vl&}ݕm"ϧLF@Ge\Vs\It.>fB0L~p?UBi) kQK=_yZvZڅgEΒIm"5~y0} ѝYA!}s]MsǷ-.srhSo$KiZh9ɊFmL_+ZGФwMswf/4dQ.w=v"PAN~ea[#AҷHmo|<~V׌4ҷMq,gY؀dCϡU[I[6uHDWA5R3x;I7(BqY РKN{]۴qqAk ۄ'90CY}LvI-bp TУ$pR9[kZ<{uiwi)ei XML8gI`s+Rhtzǂۋ[{_[iKܼ+ -4Rohˎ&g* -'Y}^Omus+"D@lA:75E>f}:{fD" Vi\pSxE]6q{fJYsǎx]/]F eZȝĬȎ![>n[3> xR{WG2Z @qsڣXV:Z\9]%̬Zgr ,[xT]=#si]aj&$G<齺7˻p7ѭ^Hc6v!0l"%X ;Wr jAsEsy$̑Gf%@Yc("^!t;[}_KoFfm<Ď. Lf.yiw.I4JGZdt A$Y!DaNzoy$.(,G=H,5ۉP+aV$)#{>Zw|pkvWi>N$KvKiP'@Ǖ2=dko  i7Mt#*vH#,8zo}֩#Ȉ]GvFdU#Չu]:K]R}B-P.RQGRR ?:zo#ޣaΆ?]6YNQߌgo"Iy #?V:vJ]Ǜ+ 80䎽~]?ƼKծtY^=BաYK+ё#|`ڹYԮ.-CHhȁ<$Gn1Tk=/L[.w.s& HKDZVA$Upg:\Ij{*{s8|ca3:wv\+fzvwj-ⷲRgU+%=+^EgwmsSx^У#D.an%@AU0H4e5hw ,Y([Y,Vp$_99̎Ta^M׶w-fff {L"] `kѴKiL/ܧpK+1 r;o)4袊((?mѫQT?5j*Φ"VkkK i^`ZE}s"Iƹ?uUSHˢeڐAo3H݃sOyI*-F~jVB - BX;G$S5X+,y. bZ mwnZQ4RXjv\6%w0ɺ]~faJ`S8]Fo&êEKZ%ɾ+FD/?2rG܁V[xHoEtKĥdI cp缳hwDakuyQ˂dCo͗753NRGho%Y.sZȥZg(_#v@:Nè[Zr_-X2:-kfj2`20WEgGkO4A{8^t\UsJ [_vGշnE2ɓ$# }[}&si2\Q*%Bʰ8R ~MAz]褎vA3 Rk.-!s]ZoGtRQGRH -7AV?Zz?,??Vf ?=@([Q.(aEPEPEPEPEPn oZ?mѫQVu6A6miMDdgIDTx ;tjzƵukiG-[]JnvLȒe#+,I.I4SVI,n r@Ày*|tY~Uqm+vu2J۬k|R|gN>m^[QHei֏ӥ2o4Rv_iE|Y-5(((((.E?݋E%|]J+H%?WE9iG]|(NoQgy/F|c?SĘltdu+xH% B{p%oK0nJN )<r5ίe:87!$rEq: ""0[d)%#2 zM(4mKmv[߿6l {nR>+-ۿ?h*O_i.ifgXa"ky⻫,u Ì<]yssjmwWIrDhһwʥ @$|DrZqo T)<\F"yq.k gb.p8ۢk+M 1b>[=kxMҥy wٌpI#DN/pjv<ƊݳxYI:РQ?KL?ΓVmb)n/ 1#IJ{?#R_ψ:!bA{v, a^"4YEih\wR^*QEQEQEQEQEfը]cAgSd0w4mFGuBP,W%Kc#^'.YoGtmmq$p#:?v/f{*i6O.xY-G [jLmP~.<)u. K4 d#!_H (uQE!Z>ONORA nb@bI=W;7-+ ҐC+I8_8)s)ne]U6!ؒ$$هՅXRQEaEPEPEPEP>.E?݋E%XoS $yZQ"\_Z>ȧ7|(붞:=epˌWfN>+_L4i۾d2CsҴe#vJq4PAϮG^F/?'s|EW2]M'effx9MO7Ħuݳ˓̪ISuKu-ژ!"Ii2Clȭ*6pE%BؼF/?'s|ER]ʳ8 K×" nmBn&dO1NwJmgW\ao_\Mxi_dijMFg$a eWzĦ8:.d1yA;/"e,SKAt._B-6ݬ%y*{[&_,faPj6Ƒy$ZE}pZ}/lhEzk-le:p~|цcnćO4s~|e債+h|1(AB˞.-5lG qyA;/"-JN bw?_E˸ɵew5.mQ0?\t^U7\lS+,qH~l}1Mm5Yⅇ_/zXYLEG[1"!}vq*C74q1ddhQVtie`+"Š((((.E?݋E%|]J+H%?WE9iG]p ?SuW=N/bQY\Q[}yeJcwDvl㞝k4%tlVn5Tx6,gI|U2iTV0DdNЩ- 4;QHaEPEPEPEPEPEPEgo{T#uYU))xe9 @8Ъ\mq&E^;i!pŮ1&!o`nŊ(Š(((((((((((((.E?݋E%|]J+H%?WE9iG]|3铊>ȧ7|(뷗\ׅ EXt,N;5i>Jf ܚaH#۵$Q0+iV4^3YAIrvogVKeE@ ,~G8<%Lg}_WyK<>g}_WyKCΧMIE5jǩ"]Ȳ31f$t?#t*!QP#%Hu!dwr0ˇhYΗtH2,kXop$p륋6Kkk3-k#iqA yLAWml|olwn4+ܶdr#tqRy(fd,C#z` (NTF9 i'NXMb0X$(@ݒ 4+GRno"yK<>̡RƏ)}_?O/gh4(RƏ)}_?O/gh4(RƏ)}_?O/gh4(-9k15-1_COAEP0((((濋QubIE7)?<|Og|(NoQo//|(NoQo//OS %GkmP: lͯi[1# /+I(eT!l8<.e{$sk%Pv/QwJ._)(c#̗_zv1\Gv1_+T:ۛ&}$v'Ljl{E/yM׷88F.7f,K[e=dU&dQvOJTvu _q\"_cN)= 4y!f*m嶋/̀Fm+UUjePj7O,Z#IpϚ~Uz=o+m9+Cbtew T&](獋mյku[Eo.] rBNP;+֧yiYBȄfW.9& pņIj@(QEQEQE2?DD?#t*=YSVdj?묿)^ ( (f]%Dr P2€4C ( oB&Y(LQEQEQEQEQE_(褢QubIE}d'3־ȧ7|(뷗>ȧ7|(뷗\ׅ H#4)K,w4NP~jj |EemƫFmgQգʆ=.!4GwTF]d;YFXpI- S4-4綼k뛹"-8mT,@GWnmILmmVI09 TxONmͮ Z4 $01<> nm cO'2dF8.GcI-Ι`nlmL1v,hvJLJ-3~oGq('9IaC$l]H #ISp*Oi"Aqak0$[{NG$gt<+M#dsF;'ަ,4?Ik}:m+!@ EQEQEQEQEGTC?G?$P0G.,>ըܙ՝A%)\{u&O近 I?G(ڟ#&jETtPSz/=?Q@mO近 6_GEI?G(ڟ#&jETtPSz/=?Q@mO近 6_GEI?G)% ™E1_CO܏65rN=jJQEQEQEQEQE|wJ._)(]CؿRQ_u?G/)_?J:b)_?J:bW5|uCkrxXZc`si$ye|UB~v çeC&e8@8/x>#lcۚ5c ;%#ceU[#8C/14EL_?OfR̟:2x dpz24L_?GORCgOQ<(L_?GOSy14EL_?O<y14E>jPAuPEPEPEPEPEP>.E?݋E%XoS $yZQ"_?_+Q"_?_+s_ʞ^1 Կy\A5?w+Gf/ynwFqAax^f˻f@JV?rϏ(?Ux˿?G*ЙwSoOP\Akև{:G]zqogS:~i2t܌^Ún->K BS3' rG[@/.;:_=7>%6+--o "H_"8/*F֞Ieۡooi`7zK=*F-7̣nӽUQko?8?_]wR~qtko?84 ~qti J+/]y Ӹ׈#fm2˸B0Ќ$jsI6;B&Ef:D;ǰ^DAmxض6qQy=/9]M/e}~\?j!s$e #b   O^T&ta7~$[M|'~/u ޥ__͇2vI>#Yd>ett#R{Oo"#R{Oo")F>EF>E/g CyCyC{92E3ԿԿ9)F>EF>EȦL5/(5/(rd>gϽ7GϽ7Gs!Sb~tt_?^y>gOQE=)t_?GOPyDt_?@E=yD>gOQE=)t_?GOPyDt_?@E=xՏ@ ʳ$[|3|&Za,q̪#} W,5#bE< =#o IVM#ֵdIٙ>&Lk˨I<20DזּAגVwRb^>'B֟kaH\- p؄͐q EQ/-G "*1pdVdzOYYHZ+3 u ,eB{pQƖb3e֑dmCvgXQhь>(\FYO7YI4<Ws4 DBʹeL|nݭ y>H)f[0;0lL,& ߳,svrH0@@b04tbQErL$Ԧ@ (ܣ;gƎEQ/-G "*1pdU36Ƌ0/QT4?4,EQ?#ih?#ih GcL_cL_.U36Ə36Ƌ0/QT4?4,EQ?#ih?#ih lOkϮ|O{ ͧɧ0ՌmBZ9۝X[f̮ zCn$3ٗPT7#?!]t,M%.M=w9R8blqnec<+f1m:B(cP((((濋QubIE7)?<|Og|(NoQu\/wUOS Q^yQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE|wJ._)(]CؿRQ_u?G/)__J:Q"W5|u+:(((((((((((((((((((((((((.E?݋E%|]J+H%?WE9iG]x)_Hkҥv,&ʫn ? W:}PSQ+|+ͯ_ /M6>#(k@_6 (/MS?=_6 (k@g0>#( m@ ?(??1G +|+ͯ_ ?1G`ŷ$R WaGF3h}bEy/oICŷ$Q_?XzmQ /_ɣa}GQ^? /_//oIC#4>O+|+ͯ_ ?1G`ͯ_ ?|+#4>O +?|[O E-'"g0>=~_6 (k@g0>#( m@ ?(mQ_?XgQ^? /_mQ_?X{mQ /_ɣa}GQ^? /_mQ_?X{mQ /_ɣa}GQ^? /_mQ_?X{mQ /_ɣa}GQ^? /_mQ_?X{mQ /_ɣa}GQ^A P)?|+#4>O`ͯ_ ?|+#4>O +|+ͯ_ ?1G`ͯ_ ?|+#4>O.E?݋E%_\jVv^WJ;48ltraitsui-4.1.0/docs/source/traitsui_user_manual/images/key_binding_editor.jpg0000644000175100001440000004043411674463545030653 0ustar ischnellusers00000000000000JFIF``C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222h" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?oE}]U r+ԯ!\\Oo 2s*f1ڼŧ?U'*ͱX_$.qVSRMuv}E=[V*KƠz+M|+⥅]'TX9I ϶k|e~<[xZH_kfX ^sE׈58 `Se-滱XW.H3ǡ()4cž'+Ec zpjfΏ4KձIZ_-ce #+d/?_bo&@?Amk޹W?iv$?ƽx-{6ZڤꭵZ0b,W?'5~5ƷE }A8|=h[UgA>T6pH#GʼnX?4;Ŀ'4#O_kVƲc>m;B WIp9GʼnX?4;'4#O_kVFຎ]{VIQpH3Qb?MD|I@+W\Gnְ&Y`p6 uim+ݴhX?&vx">$?ƏD|I@+{"[Z*ŭk>v6b,_W?'5?AmkޘwdMkWfOQbWGʼnX?4;O|K@I|r^ k_/z?,O1d KĿ|r^ k_/z?,O0ɡݞ|/^?ֿ=^ k_XaC<7/G"^%?ƽx-{?ֿ=X?&vxo"^%?ƏDK@ {"[Zx-{b?MDK@ x/EG"[Zb,x?//5_AmkޏEGʼnX?4;//5D`"X(5AmkޏEY>OxG2҃l jOD͌,lՆ|ErmƁA*i`;n#'X^ k_/zY~?_ihf9)c5CkUKt1v)Qx95?AmkޏEYVZR\_M֎Uiɩ.zv<:b~" NK93?SҢ7:=卜[$,8W/zf_W/9WgUUTSGNSwWO6UDqmY?U 1ԯM<_-j)‘'wi m K܏˻ ICUG;5G#??ttXDSӧ$I Je"1ұmmsqrC+ڨ -U~V7+zAT=sAc 9XAqeysKl9dn,'vT vY6Io%l GsoWDs ?\wX?jtɧntY@-+.n'P;1yMbX"xrZR!ci\wX?jt9ul] .Pq :4: *` WojRͮZh׍a,rA?$2:nd`?\wX?jt9u{ ;mIWyo8! 8PvkcOR,^-o$XMvF%h%#??Q΂p6p_O7" @~rv:Vo&mZ(ngs 9C`Oo,Rming&h4H6TH`sTluh- JJ^P"* eI$ǧJzAT=sAc 9XK^ZE)KVE`xn##4R=~o ZYK!M$dSϖ79;և#??Q΂! Iwf.k F20k|:H5=M]g{EvA3v윎yu\wX?jG;5G: tk6KeVV{nfLԡӬlm`K{-UAFcyn\wX?jt9\N̻8I~2]s9sdGI78ʪ Ns=sAc ?,VԡԦxqI%X<;v*F7d="H#e$r# _G;5G#??Z֮|= Qn.p.gww%vl!IFBTpF*#??1_ 9Xm&Y.<˪2qv]IK8+!r8[?8^29ϡ_?~p?gAbzz3bpOA]t ݳK_?"֭>w֗WW(<+4`'|Zvq[Ke]ܼRa,7K'Xo֞eWԌ7bK i'xdE.W(ÐNbzSX_۵^ƏIw.r^VF[u9eC)1R8? [=0s,mP#ʒ A#qnt?'Qv>rLU;#.(H ?4h?'Qv>rLU;#.(H ?4h?'Qv>rLU;#.(H ?4h?'Qv>rLU;#.(H ?4h?'Qv>rLU;#.(H ?4h?'P<<w%G]qP<[g@96_Uo'3yݝwuϿZtǜ/X?g|콾Vÿ;:mn/*!mFϜ/G!2TKt#.*Ce;A9?&_* n\[~ECe;A9?&_* n\[~ECe;A9?&_* n\[~ECe;A9?&_* n\[~ECe;A9?&_* n\[~ECe3^旦ikygGuṁ9H ?׵OLvky$\ەSc: $ ZڌD`vT)e zVBOb n hmH* <[zb+Xb $:q{[}1l=\\執j-Mڿ wo+D9Ϸj-Mڿ wo+D9Ϸj-Mڿ wo+D9Ϸj-Mڿ wo+D9Ϸj-Mڿ wo+D9Ϸj-Mڿ wo+E.s_P9K}>^c88vBQp51clݫз}6rj-MD+۵&Q_ G" ۵&Q_ G" ۵&Q_ G" ۵&Q_ G" ۵&Q_ G" ۵&TWk-}D3@K@HW'aWQX-}J#ŻIyue@@OzqsWZ؋[jM#ʃ° >o?I`4@o[RW8㯨30sFǭsW-八L2ZGc]%AЊ/ y ,^8 ʤy ,SG夞br 6z`oZuyݟcD7?hGBi{ס(0(h) (((((((((+ξ4ȏ}_GAj??q-tNeg Y$XͤM{#$dƹ'|[VVOBW{H&fp[afUr0]sY *Ok2KQU[x<;q >4r!*?҈4WM2FcMBqI(Uo¸.ɭ/G5%"?*EVUpЫMoI*>ɭ/V[sT-c?Z ⨴_k2K1QMoI*j3kտg?E4*[_k2K1UEVUX֭9-.W T}[_-c?Z Z~oQiw ddb Ukkտg?@V]pЩ#?~|W~`o13җ UVkLj;lۺ޷lsZ bA5%&C$ZZ~oQj3B5%&C$ZZ~oQj3~ɭ/G5%"?*EVUpЫMoI*>ɭ/V[sT-c?Z ⨴_k2K1QMoI*j3kտg?E4*[_k2K1UEVUX֭9-.W UƓ^ưkM91inX֭94Xt0^Zjk2\ہgRdR ҴY!.d64W,M#>B~5x}6x;@!)a<ɴQpGYg_E`[&,֭ex}^PN9'\TV521+t}h-`ܡ(/WT?p;. +?t_y_ QEظNaOU|/<⨢\'gN _*]>WTQG.}bp}|/G. +( >SOUQX?t_y_ Q _*(v{T|/<}|/Eb;?*w]>WT?p;. +?t_y_ QEظNaOU|/<⨢\'gN _*]>WTQG.}bp}|/G. +( >SOUQX?t_y_ Q _*(v{T|/<}|/Eb;?*w]>WT?p;. +?t_y_ QEظNaOU|/<⨢\'gN _*]>WTQG.}bp}|/G. +( >SOUQX?t_y_ Q _*(v{T|/<}|/Eb;?*w]>WUDxKa` 2$#Nn焆2=3;L/%Gw)IDペd|eGu۩ 0NTt$iz31$O=: M(4pFU;N0{OJw%=mW <|e.,wkjj. C#{AKL*W,`r& vO )[I0{d7= zhz>Gh>yzh}<u(PBy?qFmy0d=DUaX0F̿ܙnTgGϧ_yԖO>{Tum0}^-t%3?63g]'*6nhxׅKcb8hJLQ=MP`šUaa("ä K( {C~ŷ OfO$vf~~Ü֦=&}mϾ疿G[ J+=;.e$lDᇌ$@4L+,#)]iILjZ J$+n"`@sF/<sM7fP,}\|O/3.3E9'. Z@GNzcaAS_]s(Kj H%wigo yUruI?!ph'au5 9N;99,v/3zݾwo#us+bϋ8cǴzOүTۯXK<D].:I2q㔁!̸J̒c^ !ACny>nI4g?qZ4y_0k6mk„ .%yC8MbBLRlf3MVDy(qZ:]W WDڼ1'f6pտ.^~mWV,F냞)ko!;Ĵ4K˒Y|Hɢt1%fJ0L6s8+\/~2dcMom\=j1&y^̘Ûw[ }}q!KsJl 7g -AQ;!I.B  "v8~"-,O`fAX;uݚ-]-_je_2u޴Ύ `0֗.CqCLwu_0\-0fd\yh@bobX7$*8 CD4)bg 8 *} Lnxװ;mٳ̋=G{+  PH7<_JR~|Z>Z|1 R'oJUlon]`W ?}rQjN"&3Daj7{÷q0 ##dh)+4(3MPҤe@aoaU#ZIxř7M]: <[f_+ў4wo4o*ӫ 'pS aLX>΀F[uw(|$Oz]Ld^121Gi%+,. 6 !2ode5=uHésGR?:xv;/HbnŹA.`kYm?> yWPlM_I$45% _Jx*ϓp\S,ԈpʰiC^ٍwn|n1㤑<O<@ iKKV|w~ҍ43>&)4@^gOxb}p@cߩO+5c0?O<1{>|( o!2{j#-\v?)E3vsؙqnSIZ2+hV%^ee Sn^Xă5|)Ľ*-YRЀ(rzF{KJMe_ :AkswPi-P 8 !졟83 ϼ`2:_ ugG bexG܏Ғˀ0υg(?!zT2C"ܠ ҬAQˀ Ŷ h`4"^^2αKh4و8ÒG$| yC OeWFC"edpy] bF]f"WA zleZ9,H}("B w 2 V9n^kZ4 VрQ3O JTU`>@Ɣ94(@ &T׶|o |LkTnԀp?att#Ӟ sF^(fvbKPCO`i25Kܔ|0p % +5 .\l^gp0PZo+`V5 }䤾ų lDE07($*%AJ9 lNI@nύmЀi-Yk`(|<uQM(=HԹH KtfTv\m^(&}б=B ]M4AbXU7%JhуQ"$xvy{q-'I6n=xZՔ,WOxnjns˱C`$:T+!Z4֠IOh')%ie6Ƶ$Yy?,M/?YZ'HدX'oImLA`I~OYqSa=@=t:"$:j@Irwd33zI cz_u6`at^!-rx-qy H/H~-  A6@"$\NI\ds9$qy H/H~- ~1/ݼ[a-n[OllѓĖ2I~BtO{VRn[ I=D6p4qlet3E) |2j;b $Xs NOF1h.KmJ).d.I,!vmbI/NlIX134u7XdKvۿ4nT.LN,=r8Y\<q<Ѐghg6HuQ2R)x1"¿}FJ8~΃/xcd>3jˢTs>q2I6uR\KY]&6l|dnj?ՖZ̚R%M7.9.OS@;-j˖](qh6+FUܮmrƽk':ڲ(`sQqݴ~ \Ac)$]'[NUKڟĖ$;XD/3Z J DI lJm!$Z(3$1P)h@^^"`ߢ3ɰ1{/Ɏy4*t6rp듀K}&JV8%Nv@wN&$Nv@wN&$Nv@wN&zWo[uѱp@|~{ΕjRVXr7ɲ1B`@q_m^Ḱ>($1h){%a7rs'k6~\^Nƒ0vvncg7^2>']R-!/ڭZڪFϖh@`C$'# }Ew.Μ5AMy".m`8~ic@'NeXk< |Μ}ă->yX㸅Ǵ:xmy8Q.κ.}SGbth䡀u"g8IV~q'xr-:xmG8OՌYj˺Ȭ:y%T.ISq h؎}mn)vђ^_rjK KWNzH^?\SY>Dk -8Zd 8ŸCJ8ɥ40Rq<ξ.gN_h8PE o4\k~ ~zA&]'5>`I p`rOG=a(ԻJB kG"#$cIG@h#EGIǒH $F؏؏%AM>oa"1{U[`9zD:f/I<.VJ#$PJIl%@k(l%$d 5r@[ aJ9[ ,[oڲt_`F3N-{-n{\ch٫ŧHLK/O/?K ory-^~Pil${۔pG M9#e5J(/)1{-^%ךc N$an@HbSrFIdt锜@$$l:%gDF N$an@HbSrFIdt锜@$$l:%gDF N$an@HbSrFIdt锜@$$l:%gDF N$an@HbSrFIdt锜@$$l:%gDF N$an@HbSrFIdt锜@$$l:%gDF N$an@HbSrFIdt锜@$$l:%gDF N$an@HbSrFIdt锜@$$l:%g]_Q(S_-YIXeo]_Q(5?¬:BQb֯NxIMokbdzf "hvpO"ȲȊP19'&]^ZA[[ U8!c$j9Uqn)cY#WGH Z3/\޻keZUF}Jt׉d7kx+<=uf;ny`8=b+y_M[]Kojr)B/j"A[\֣\ꩤjxp}0&o]V5F<<>R7 Fӓ߽(4ެ_ ?_ -5u }WYWȐ˕9P2ci;Lҽzʭp9 ;mP&EP̉.TѩhWZr[g1JHV$`p{Amy{yw˧g$LpWP9}#+uέڟu+Xm\ 3znVzH5 T mcŰzG!mafo{* 4HhKӴjٮtW0ْxaAx<ή :֪2p3p_YI]r*M,j4mqGN*|=lz4zv~zCas|FO\p{O]i_HD7ωFhAs]3h]3k;[( Ɠj2\m"E8\6PHK `2x5Gkm:7֭uоݭw-$*R7كlF[r7?_ ?_ 12:&nb/۾ ?x~l9zV|Ϥº^mr}K7rKקUu!7lO-yuHK;€u$tk=N;/js2%ݿ[Ωc3=(\C3HO ]dUI#ܪ.cq֕薚uw ෈ny$P4m;}wTT2:) Cjs\\^_h7IpO%NHžǭA][GKHHlW C$ZߠXH:&2psiz%iݦo(H A.׷:~9TkT!IR}{U \AO%/\Ip>7Dr=hQZ@"o FYT*g^TӬ![͏-`[ DŽuhx+Uk:6&[mF cOOv-kdcJH7~ :چ{-.-1EnwޗWncWkF @FkmlU/>5;l8mLI FF]uέ{7E<}b5POOZes[&Ę\NzwuέVqi؍1v@9'#n8=tVO.nbda099k5'Mh !$ gVuέdv>$XyI-ȗxz*fFwgV+=?M OsKw8}k=MsZ5ԃPo3%Ԫ䜏/ϧJœjŏE:_&E:_&E?uoM2_,H\I] V8##ME67˦?u?lʹYL%76`rچj7sɩa? ܷC]Ne)&w;W8!61ܬa[_ko?՚ES]VZm\UL(5v;.E(e1Ψm-j7F槦Z' 6'vsR6VKo+Xٕ2p70\vc~ܥ"'c _#g=)/K{Eý| O4u?sOӺխm.ټ'q.B[h8W)W o)=kf 빵ۛOs9$:`&"3MUNTf ~®V$4hKWEOynHcA5+I57Ӓ]12pצyu欇RXPJltK?h,+ Ao_JojgAVIB>q8Le&Z(Wu Z~o6py,dzgK6]q0'|- FneFP~uZ=(X8wk(`F)gjQWD)Kk`yQ)g+ҫGZ xY~4], I@ǩn]cixCi2Fw8ڟ4ܮi]hiEYi5e! JU# UCA<\ŵ.٘VH3>J府8[l[iJۤ%V>Spmo$#K1<j\Y@,r^hXY7cpq4`^ >SpOJŻ[0#Y5KDx?)JJV^_ CzsAFʦVDp;3 =G-`VA8&4g pN24bx}$gVt0bAZjpXIX`vW<Z)I>߃6`-RuF:Y~IdoWߞriNFYclx|_]x-\ q$c$䖈ɨjo+e ЃUSMM4]$x;leyHF9gR:i|1c'sH}3Cn┚^zm~#ɿ!YLQ 'ԑꖲRin#]6vv1G*I)IA!#Su#8fM7u#DfBo^1ҥJW׿o/.ypk6GPy<7ymv3~1W[SDPO;׌AN vT[mϷ֬nʹo&kLzb0{zQg]5/'e p RFgl <@$&5p0*玝Oc%YJYգsTSIϱwu3nR͵K;fMʌdU}^4k-M,,䑎aƉml"1k8m[ dg d4&b۳Hسl :4vЪ4"pֹۍ6Dhe{y#e`G,9ϥDt9V)4{W6׭,6c9azݤ?2U'myKO #tb^jVpL$ +V&esVo/$6( iQU2FYJ5ŎM6IJ2yjY6p[җ<-tt]EVؒPJ pqן^j;-F\qy6q? pUH#p~4Zdq'{s?/ȹMٳ[9LZXEVnN /70ҡiWo( o<֜sGIy~jo6J/Kԯvǘol*uÕ=mE j]Ry 2_~1v[ėW#E {$ɒA?1sz9;]VTo!%F dTup@,2ԫǵaz5͍hi#s8GVm#z@vǵJNfe w$L8ܹ#V`Qu=ίi:L3T@=kz-˧&Aw@ʼnIJ_ǜj觱#cd;`QT߅M%^͘=mڧ~ZUTKVk;QL z͎q$3Hw(aeI03]׋?dծ*"Ko{n–u$Z7W:4FHE@k4fMm9l 6?dubvHhX5&[H\:]s),q0TQt8 ~uh K{飶-эf6]ĖZMvwF@U!$tzkP;i5*-It5+DlmiHssW뀸L[_Zp n"ua('mkHhAݰl,y=1W4OԤ##ZTW>l&;qpwcϮ8ϥs zzy7pJFGZ.Gu66 }[Oi3.89ݼzd,l䪀1 F+EVjom*Z\3圠$uRMr-f{{9#hnٴ 曌/$/d56/ tUv Q|UeZ;H.+NLO<𶟨=-Vv$DF$C+] ie:ŀ`^?AJjܙ(+nZz #CnGX _òjhVk jG/$bx)Y#qGzQ-]_c/Mmyq-˕pNEX[ҥ=JUJմue;tg['#*JKŹY$V܅+2O9`U]T`4^)TXe cΡ\/\um9ٖ퀉F%>W#jvig=H"UFNѥ3Iɹlai'ޫMw)Ҏ{:i#]eQSetᶕo n$;&OǵdhEer|<_ޠ׶b%3[A۵z9Ywe>Ta-;G33rSSzZ#<4R+"# r Ma>6.bq7NA<~mkqg{e3NWl麴Q_ b]4nYG8ǿ Fњ6:ޗ[=ŕwI1}?qm*-*Q;m|FcT5I&` XaU<9<<Cmj+#Τ(- scMWw-5vF-kxN%P>l vn"9i%pRiA=($V Yw<<ڙ ?osnןj-wn(H=={С9)sE|[b@m7yqjߨE7n#Ϯ8T՜Rq 9o"m[lS 8p 4!ԭ%2$0:XN[:^.#= Phԭ/4aw&4Oj\evQH.z~$kvt~ ѵ UԺ @@k%ЭM2ԗ1n b\Fvh r՚rGtcgZgZ6a筿TKVjjjy (jԓza{|b$/!!psHZW%ɽMN8fбO+'3cNA3A0yFH¡BݱKLhuC#Sppwd[x;TY\ܙ,KPx6Fyj} TMrR-;N:󣨺eV,bʅ1eeԼO6ga#A幔I]njs݆,xF.^"0Ӏz$a5WNеkkBKR{KI!ͣpJo0QڙcJk?jAa%%FSj;@l}/<4*D*)/u*y8Ma-S$HRLBTsqbCet-KLXqx$"iHN P]x*Y:qK1Z jБK.џIԣM(H!P-t*mF<#/UnJ.4 Bxl~l{֥[DݴU!ceQԕ߹/2xCcZ 0%$c>1С?duy7+ɷp'dsTm<-áAa6m$֓,֓-P ?:E:_ sjnY,X*<̏2I4u;MZ]YJd\2AXUF`xcg ?ܰeY|`zVʹrksL˴.'})-Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@V9ojV9oit'jm3l-BxmuHTKVjjjy (6ZզtRZEb@8r]ho'KӔoGNz}+R7{qq FF'',/`8m 5ah/d&lTw| d{Q:nOmcwڢtӦU0HCI}ߩQs{[ 'PPh$X}ԗ~).&{(@0_ HOo5${h`8X# u*{lPV 29Rp(((((((((((((((((((((((_ǜjV9oit''*m7l-B8.t_[l_ko?՚QE0Ynjq?*(((((((((((((((((((((((((_ǜ5f_ǜit'LF9qЇ_Ǵ ,0qSickjjVS_-Y>;!ES]x\Wڻ+? 袊((((((((((((((((((((((((*yFkFwB{/~6?kn6?k G9o?՚mڧ~Z^|v:(ڻ+?7vVs_@EQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEUkFk89SS%a__l?9o?՚mڧ~Z^|v:(ڻ+?7vVs_@EQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEUkY6ԩzq `ToZ|NFY#ܤ= G9o?՚mڧ~Z^|v:(ڻ+?7vVs_@EQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQET71uʓȩ9/֓zUg17E6nAI'X~SrmjĒ8;o?՚mڧ~ZJ; (`?*{Weg05T=Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@G7EԕICMEgCtS_-Y%4QLvVs_\ojʀ'(((((((((((((((((((((((((n_˄A?MU6劐5œY&; +!p Y{дE`\c{}k<#nab ݼjBG#>JbE"Sn00qn0-%{ŗbH&ko΀5|ko>m>5:UB@(oMsh94yI<$7&(G(oMsh94yI<$7&(G(oMsh94yI<$7&(G(oMsh94yI<$7&(G(oMsh94yI<$7&(G(oMsh94yI<$7&(G(oMsh941JS(96pRVVR0({$traitsui-4.1.0/docs/source/traitsui_user_manual/images/file_editors.png0000644000175100001440000004470411674463545027503 0ustar ischnellusers00000000000000PNG  IHDRI~ IDATx}kufH _%IJeq]8$DP;$5Z!JXG X@b7k!B)K1c"}WTW~LϝӼh:u^u}V3w~X'M!p4J"A2.c! IR5<( \F`2) 'O ?|:W].+l?X$Ih~9?t`0ؠ?%I5xi?ّR.2#J}Z$eE@~sD;DqB1 e" ILt8#z]=l;ٽlڰc4u<6E@/bvyfUqFҼ1b] 0NI #wƷ^n\mA]r+.*OfLq0r&/21)ed?'{ٜcuhg&5uwhp -6kh^2'AvAe<$a!`B.ff 4X3`Bg&х97UyRFcT}>0EU-ƒg L'EIХC ;`2G5i.loUљLsIL ype{!ڳ$;LeZI4,|ʀ Gt$ǐԛ%EKf!I%#8`YHg16Vq$xjL 5u!o4!ipL!- 6]"xV)mNZ6zN' CBRt8+хMF褥Y{ V8k' +ib}ҲUY1TgNd3Mp8$)¸PuC-|nWda"HE LÓGQ>+x5!,E#kYӑ٠J[Rߪ߷;td"J42 hϊg/ܕ$H1A7d;pd7|Ѹ80BML~38`:I.1\%Çl䙓H.`M{ltj*L3v`>?$I]^L' ]{ɠޕ8\4d6|&8 Ci|%{ #`z#fXEzG^6&_hBF0{uսqHRI J 0Ŝ0"ٞS7w*.Qd6uܓZjfLREG; 0l$5Q$-pOjl LHG mt#I*a![5Ѭ^uv%I*e&F &k@TI{P9Qlȍs! HZŧ 8# I*@@z.>AIRP u) ,<嬻T́ B皙E!@9%b@N$e 95WV+T#&LD-B@T#&LD-B@T#&LD-B|V9yGGb+yoX_Xt/~ݦ$) ?> ҂Gf(pm풤 Oj Xz2*6aud1aV i(LzIh^qű pb8Y'C.3I%GZA8aeHFŽQL}"rI.ӈ-aߐX4(t#P}T"k(f’i-7\+ʔ/3n_B_8Lopc:A kd 1 ;`2G*<|V9vя{޳< 0!I(@yv+G'O`2{7f&''gNm25lL7&'&QٜO<# @BD5"ǟPWRy SsK.ee(x V 8vƮɔ퍟_xiqZRgOtۭVW=8}WqNÄ~!B܊]sPG?0 u1IR 4QM V sR=~?S^GS^S_Ʒ|2 %U85B{RG88}(8S#CYH.J9 < <^<==EKPOY7Q@gXtLrXDW8=t=W]<9}q|갔J1$I*|l/`#X1zKKKxy^YFRЛL' Z䅻)s('r3 $]UFlRpFRCZ'0(IfpyG/s.Ҟk;(+OSzCsTY91+z_+e~ N)o$IYa-O_"[%=T~K/C*Sx /] @ĪܴG%٭M+b_>eCa=Zl 0`ڸ׺ Ͼ2wSlfw\LH%*#bb`+ ̩|AOd?Q%_eON4vmBԱߝJ*J%mPIMNLh %E@笕T *#hb;h{,U?+<:Qr-AnċX-3#n $UFv+#أ""L OM W_ؑ|2T$R@N;F: Vi9M أU>#yyn6_#O[ϑ[ӓMr9ZڠњI2νlof3z=+rɈ. /.j;4)G닀TRo\<+{ Vd;hq֓&hztRz-G/nɄ΄jUiRI{p<`\0Aa)}bk yjqqrZjmRt9Abݛ(]%! T)WHY@OL{0[-!TN[V)Eui#q#H_w"_RI;U+qKKSi)oT mJ@AFGǔ"1X1U}y̋Jb>J#gb\/$I;ؑ$$&p tRw (#0+ HToЋe:J RT2eW[\}S49ۛ鋥eK֡w[nCa5? aUFHTG|Cwў=ѭFssH+vbl&>^]bp_-kzD?cRi[Ҕw%%b!Tb;h{DAm#"?}[Ӎxc?8+77'h/7'>|'1n=dyxjt,+&M9r=VӃ/.GG'br͗v'RF (x2(ږDqqΰY*#ub;h{,OY)U}@3:?{q*Fs{A3uSlb$c[IqAH2ʫ22uUHP:цmn>Z?܃>E=yn }0 :u vDxf#.ݗ*CR]}1c?X7u"ZSꊏ)d 񌕜v6d%Gƌ dCzðY,+S'qd.NJUhn!냝#.WIkho 0$؎ Q}yUPGzTNEgE@y1V2=T&QzۜeVA:{붝Wlݱ33J v | 8:07d%6sVUPGz44?oR*ĉqE3SqŌq(@eANXa m|* -ay~x ]WAoJ*9ZqF i+X"F55?Bb"޽#h'k1 ٜe!uZvnm옝ܱ}r玩'w욝9;mWn:} 7˭NZZ 0XHsfp$?cيN&<*T?.d2Ʈg 1tk-Xb%tz1ޞP]_ߏS 1etfA'wx'Ŕ1nE9>GWz(O@whsS$*2 P]<{(wJw{xy)F֛TǍ&uO sqt䁕<(>pGp6'*HÿO,o(:۫ڻ9q*|c|'nD!a=0I8 Me$NxK`h Xޕ-'XSZs.˔ m$ 3-+)b,]J #I~Ս;xi] %GҐ/MPGz<8Q'N, e_VaNLúN:c]&I8z|7{(d ?AR)u9TR 4K2 C%_|q~ĭ'NΟRs'NE{a8K!g!+!Mxɨ<,:-| wڍ^gnt;7]UK[_>eC`gO>&n,_ڋRnH-A:pd|g \]i8Tnfzο^mk]g_)j6z;_zr ʄ5VVk.`#aYe077Vi)(C @ ;P1ŗ7m{ԏ]X栃򩋋ju1Dc׶WZI%xԧ 5A`w;ɩ+mWcYBZ7 `_M[HAVao56} agtWƒL[{pWثނ̄^aj[V)} '  + nqo܀ wvlSi鲒ұq롅-rXkOcl:}u[hARY^!T}[|T3j@,68z;6q}zQIJA8H( IDATVQ ˡ;n g;zXk ~Ԍz:(VAl߱Gc3NU6V lwpoyO?H3ȘSƗ)I1SlƒHOذy蛝xeBu&g`n +ujE6w ɕE;{`Zb#Wa^5&Θ?L}G[(mh`K.c5cA3:plk`Qڢ+n O*:dNsǦ7Sl_֩RIAO~qz!Fnڃy}AyNKLn:vWsKDvAJc81)ŸV_0'0o Π-xS)OM0i};{Swj[%IYa` .1 F5"K}LݩRq#2ce/mMlFÎeE;m Dc;ذwq* }fGԛg48;v/ƧNL+kzQ?hoGn쀔UG- U%\qr_.`RIF W|kzё{ G?~0>+&<<21z|  {^+pK l֋;<ߘ=r+!Y:!$IAO" [ZQ;EjM/TRP2gSbY/Tɣ%^TgyIRyS85}a7JRI>jU!/ ' + LE܏rrsP7pe`W[kƅXd$I٠aM.8Q>m5@;s5-}L*d|M}u[Vpbm`m<ܾS[w65ΰg\IRIL<8aM/EG-ďqQApOM[T".I*7vƚ^0_}Y/j_:qͦ-_C֩׸ 5m,z ZA,z?'-A@ȋ,zA[ՅGr(SL_+쓶 2Z! ju8$A@0$e""mA@ju8$A@0$e""mA@ju8$A@0$e""mA@# Üu>:E`ÜwlGwީxO'G'TO>mG҃a0=+D%2c9}ՍƤX EU$Za ΃(n8^=;w!jzv/L-O7V=7@]x%^vaJk(y)UF`0w 8RwNG(d[;f'wlܹcjݳ3fwN}[NU/.~c/BlRIY@ 2c[G]lu?s"^?#F egM"5@ŽڭSWuߑ"Q~w}d6$UTAr'}+&M9r#y]W&1-!n-qP}}G{ Q<tie/T)夵:VZsaV%*A CX^gL ;A娞ō= /=2T_e(J-YeZ .ƭ2e{>onė0[;ܘ@e-٤!CLuvA3Cń?,}U{c#q![Sܭ40#QxĉLe͹əS۶LM53ͩ鉉Fl6''&>S,τBl 0=P.Q ?x'T=էTB\-=+,ya ^#𨦝k2_{.^Z\j-w:Vgy}iYS3vUzw\09_Epל3ԑテ(`)/Ll|gEH1MTaATBT5׾/!HINͻP(ԑ#Nq D/>PAV"˽Rq@yBq+/.OOymEKTOY7Q@gXtLrXDW8=0T:xw=uqONxa,:,R IJ&V E**믹ljz-C&IV&y.vʉ̶Bd#<)I5DgWQ(#QԄ/ 3 J2)\+K܅KN{1S'T^GkvD̊@6ǗxJ!C'0ƒSxzF@IRVX2}|`#_1Kd4qJzTe{ gG0+9)7P?7QhvkӊXdz! IQey ;K ay|%& ]LE@T)e(<`^^42TE26hX^J$)/\} |`e+} ߱|@z|܅/[o,yWrׅvx =&oxTݿ¶xXe@Dm Uv~͝ۦV "A-E},Vl}NH'5)T)S*}ꁦ{3g_T:{K˖CX0ʎ^if%Z&Xz0UXiʦט5.@܂ɩ'#hϞ[kT7(Nl D@fsD l]Q]F b!@ *ax GAm"0ьi4ԋp5w/+^4я&z+^6r~|vaFdIS`(>K/>qщ"?7nXA/t|'ݸ\Vf(42I:dStB[+ԫ&Zi0fӘ(`ŴHF=xm}>G{g4Rt]‚)bB8"\ob݉醔 km6yV2̥5Gji&i >pXŒ]i&XޗP!{,O Y 538ڿ*9%'mFQS9Z?ys7 aԄ)`EMݾM.\@%E1ѰSz}A1WeU mHO棅=SS̞>&00ӾXװkG J XSqp 9%k:RTuVHU#] T*ygEE{ F蔺z Ylm4䬰6b|:^,`Iby`;)`bf"[%=T$I܀: yRUt<[`/"_[F$)ĝL.h*F/7c])f& ]aL%HeB9824`i0>AM1>m⅓+яʈ* ([8+vTIQ +1XqdmCJ Wy'NDǏ+/fF9aAs@0cu1~ ??~4_XR}2{R4@.K+F`!=-GFi}yuwY҇D zeJ&]9( K 1;cSO5;sv ۦ2ulo,ڗ[H\ع2 *j+ *@Q),BL\q!H b*Z"-Fb=;xcA7cK#SJ2`a{ Vt N{#3Q0vmlE'OޙrO@C[#v֬V۝~ocUzV' w  KKXв$RBXB(| p&s PDy=nJ$ v7[3ƝWkEVGqGx }RGT).V F`EPk&nvz$+4yX7G~as͘VP2|~*ͻTRi[ .ƭ2e{lwz2=7M.F ;m hS+383zY ]:AASaLun:Sc hu:FcX } n[ԳQ2Ѕ[pc ?& ܼ$X188g#L{[KS˗{R_lRt{DFWT]zG@.gEva{o:˃R§iڠqu&zFsU4ux*TR H`'Qxg~Z"2lP9mYS3$kե#c0Dv˻}۲fϾ2o))`DdQ-KKP)yt>xE) 2 g1Y+T`=s.,_zsA_6u<ɉƮmog81O6?Nz} iw;ɩ+fw\ڹU=F#ؾj,yW|U܍ ^؉eS.,&:$$I0mAM[{pWثނ @Usj[m4põ R/TD9E I !ZxzѢ9X+GkOW:}u[hARY^!'*~릚Vpe gq^]NmKql>Q ˡ;n g;zXkDt|?P>cQgl8n֝ z αg̠49^O/REH<ģSq7Sd&C HR^HJ Vَ+;ȏx0kzA/eTBƹhii!=ܯ`K ͏YYl3SWo`YUە%Ր$ē=ZxIB% .q6%s%mh>'(U8x,b ,u87 аǃi7K4=6pcvj>Tɣ%}"{WN-I-,zrM?>n-A1|nf8 xf860\YlplˋTnնf;,`$De'ܓ"[t㩇QM{Դ{MW2X}*7:qͦ-_C֩ dѻ@݇np @ E&Jj;luQV_L$I8NUDL~v! $)oDAD@Th/A@F@7d U" IJŗ x# I2Q*0A3U(T́QĹHkfg 90Q/>\Z{R: H2 xu$ !  P?$IHD ! IJCHA@#n sIDATÜ5=0G`Ü|wԟ8O'(TO>!- 7&T@$U!@IRIL +QϣGm'WMvfћGW7UftC˶ݫ-I$ y 4Q(R4/i,[U:K?98t' -iCub^U׼KGg?}^ord @0pSA O0&/:G3bP]8')5IM cR2 ˠ~ON9)5$LjHZlҽX#d&Oza#Pg gyILC ]4~ /,ig>vMyq2'<{1n-S,ø&bD8Jm=,$X2#-bOGTչ7)OR4ztu2쀯{a1O^NDUE 4I!V z0Z7a9G@H-i9#IB@J2$FՂZ.[fGb+$>|)G4D], .PSgZ IOyw.g "0]$Y Z57WHFǰ4?$I]^L' ]{ɠޕ8\4d6|&8$9:=RWf:II1:VI2rMF|:=ͱB͠\Rs 0̩!aF;RqTM3ΩnX p22 d6uaCQvA&He'DY8 PC$IHH pܻ/UktyA@@@T8Y]X9[A $Iڹj  |YA@IRC.AIR>h T$! $)DV*G@T吋CA@A|a)"|?YZ皙E#"@9%b@N$%(:*@9%b@.' @Q$U6b_r! I*|,e# Ilž B@T.DYF@T}A@ȅ$\ $ LR.au6Շm'WMvfћGW7UftC˶ݫ%) ?zt֌08f5yIWB5Ӽ'Iwyy$ kUљt/k,wy`t;݂NY3 7hؗ8!0 1DuLRVq;<@%+^j2i|vD$a;hN:I,@M].f .Lwb{7IjIC2YMTF=9 ]+t°őTt4wq&l[&2g+ּ7 OV/0}V`z2 EbXXf+)Fd}A9$䀯3I't˰IW be.9vc tiƓRuϊgNAi%atYt[ye$߈YgMVaa@*g[6zcR8ɽᅚVI]3w~X'{q ON9G&]2͗_Y/^~r5w⪏LԺyDR)6SQ|17Q}eEo RI% TRq^$A@XW$I+\F! IjB/늀q./]C Azo| =IENDB`traitsui-4.1.0/docs/source/traitsui_user_manual/images/text_editor.jpg0000644000175100001440000000525511674463545027357 0ustar ischnellusers00000000000000JFIF``C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222!&" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?+7%5}:jN ƥe-D#x R{J$-nZOBj+u PEF>EmQG,{_#R{Oo"#R{Oo"=^/Ͻ7GϽ7[TQsԿԿ(`׹j_i Qj_i Vrǰk5/(5/+j9c5bCyCE1|K}?!ڟ٢b8uF=륪ٖm~+jJ\܊ՙ|+kL#,NISS'{>Ҿ _%s`RoQn:Ia>6K Z17n?ZTGU9ʫܪrroSA7JZmۿb݌gMQ̰oGeߥ Ʀ&U~7/> fXύ_2|mgΆ翳,?/Qa>6Žx\eߥ ?,?/Q:+̰oGeߥ 9gCEsٖm~(̰oG6Ks,Ά翳,?/Qa>6Žx\eߥ ?,?/Qg_F$qG b8QE_ŠkMC袊c ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (?traitsui-4.1.0/docs/source/traitsui_user_manual/images/ui_for_ex16.png0000644000175100001440000001344111674463545027153 0ustar ischnellusers00000000000000PNG  IHDR»3IDATx] u;-2?BHEBJ जؔWY$E$T LBE"#DZp?ĉ"E KFJ!P,Np9tgٷml~Sׯ_==;s}zSG_P8d/<>LV$ Rxߜ1yr^I?u@g/2ǿJ$ X՗,m5ꇱgM o8)$4ٳy쓘̫,4D󌀿W Je1U4Xyp/lpLYkH}V_+ҍʂWg,]8A?|Zt|]٢>Mq3Ӑ8w56 "ߍziw52>s.i:ټuD ~FѡCso7,֏ ?s ױ[kN'cΏv}FsǏpQ#&8r;W]D1xf-5? I99rg,]ɑ>)Nso1i|~ޱCECUV40whGz#` |)ΚO'yU]s_ČX vjk-ZNݥ;5>;p-zmk^ӆ{{B%G*z KÒ#|^9+;G_b05]}W>cfᎈgnHyivL|3G'zjXsLe_{_ $Ӛ~^7x b/]f=~5kμJ޶uǬW--fƯEـZ6r[,bL" —lZ7m'LK}>d03/|5[E ο?˷6=z'Ч^g13?|ݨֳL`~g Lǟal1#e0uj;h9m?+,:Q ˉɭO?/x뚗'}[n^yc1Bu%rBjZjҰ"-IcN+C;a [? } G9{w7.B6ejmOx'FDT.> ]J]76VQ=n7BDh&&YyL2 }#Nhi-kkOwnmw{e~+FO5{34Ԙc^zM̓xL Tv:Mh{[`ph;k[l^DG͗kgcdLECWm}4Ik}}}돯oR?2c;pBK}ņuOnypÔf&6LP4b`'s+gy2KdtYۘ5bF&i'? 3t'ƴH84@K)S2?S~dt0PaNySWlo߱k=ؑR3m;)¦Gn[vy6=Ck Mfzc((Mt_$kN0یdch4);6)n90݅ r븖&q"Cwg]:b:k xKvy,[ogpU$"Hblji6Od9qBP/^Ll0hg 5w|B&bmtN_xGXO+/ֺHd/!g|~p /K|GԘ;~iEA3_oXG}"Kv'캜hOnfn˳O3_~pX}ވ74Bk':Ӊb0{$)'=K7&}?8,]5N X _4tZN5#@ER/x.['v-+XnJĨPzT.҄vmkbT&a7mLk=͞îh7-Bw$tNr3ohx`%]GRuѕ TY՜R®T#n ? #_S{j%1!;z8PKbB? yC 0s&1Ap4_nm߸.J.J? Hy8;cEI e{Rkm{hRC G$^BkY@HlFg\-S0TdkI*D _GvSd"biVv'^r}~"kMg(@H8a0Rج%'Z 8<6I;/ Rq8zHL|rmT%c}M̄&.Бe։UK:%yB21 XhԮԧ&"7gN'Adی4d z0֖$k'e[aE21t@H&ؤ*BF4ʇ@H AI4~a J zR {֕ $2GފًYBYĚ8+obĉA GY!gq^Ufëd̊=)k#L (SWJ?lYrX 8K8yL1e@Gw#')<H2.y@1ǔbK9͎1~~?<9h4Z2L tno6}EXD"J 8vwm G"m> a@_@L C \Ð>w"vH1Xx,i-zj a gߩZ'sU1$!L5FT1W[ؐ q(8Q>؂JELr ` ѱBV.́~0JTβ -t4*A-9H,βm5̀=4".|DSƝrYH0c{H_3P䥡4A^z2q:~7-Q6x[$hF^*Jb-Wrۤ$NعJ݉JMw9 s^+5*R]JvxPY7(x[lm[XB8k  H\YCmmpPD@"bnC$n""qsцAvD=Vnk4Ro:H/DaDm 0I183$y!Ł7ś dn}}-z wЄA?u hjcH@EnZ*DtK)zz]dYu%Զԩ@fbȺkYTD;OP)lւԒG-w Ȃx՜U M4(HE(l[/@H`άL K;L&Qq<ʊ]Q`aѓP[Rn*c qD.TQɬWV60̸zdNhm鞒7FH[ V3/L&kĩ؈BLv&sG$26q0o rg7$z!EŒЈ^{?{P ݊h% ˇ+(<~F"DZ!RѽgU|$1F0p,v^hIjfx-gPwAb$Ѹ[?=AMB qnvĦ,>vxP] jfb?NZъ] 4bf,ˇ@_LJoݜă0⏌Uep]N P0(l @!oǍHaDm 0I18'^?ETDUiv2w 8Tӗ;cnl]QYJJ -zā)%ѲVg6;ܔ(8,ʰx$v"Nv]EmXFbX[8&Fc6YmMG'U6;ϾH) l85R!)@HFp7S{̦Z N!c#L<} czbg5-HRQ @ 'fcM&e qYf+C# qG`w@H"Z}~odϟ<>7rมAd@CmL .ɆR  b1:4@<$K>IENDB`traitsui-4.1.0/docs/source/traitsui_user_manual/images/themed_button_editor.png0000644000175100001440000001016311674463545031232 0ustar ischnellusers00000000000000PNG  IHDRfq2:IDATx]}U_YʪBժXmT ƒRi֚SKgSMV$XPb5+6JKA hKą{ܹ}l^^Μ93ٹs;7O11)("vh50%r ZF٘\n'߭O`r𑾊AA4LG0,ؼeȱhFM`9m0jK<~ e1=OmQ0Y< {ns+ 7s#9ҿChzwޏw䦜]97Ck@0a6b2VfLLV-䆣WlJk<m۶ڵ$S6BUx"^<4UyMR,5,d[ŊicLέJqMKSGLnJLMkZj0Yʹ `&V\8<7@)tbe#puedU-%"OԢ:Z9Z /MW30y\ ~ vfM5ʼV㠕S%}[e˵w9qjxWKASeϿ% vn( ' 7v3bۮ[#@iT3ڰZa!sK-XjJK-@xlw]/a@4";b'pGX!]P{(ÙZXvʾ9߶Gy{;OA 'o{TEȍyȈ_Z1rA`2olY9YkSc]an{`gYOo=nMtvL×"ֺG ^[_DB?ƶ]ln 7--8w iM4x"'8l&cߧ%fHP %Y1} H28E ^ '0m("vh5--u.'*sih)ЇW|蜻 j~"s\ԫ nڅ(.|Xީwmښ-8}Hߵ(4弉3Mڵ{o[Omڷ}(OXkz3g^V;܈h}C[:&tO"j=Q0M~W]i#9펛³`_L*D,Ԏ/D;cLu*"O=}'7=GW;:;m9JnHݫ%wiKPr{>@^ww= %ZqΈ+p=%׏\4F";Q<rgko7H@`2_ysAu;) t6դS/[j@ Jle6-9l7dk~Ay6r6~)lD% KLߧ%߻^ ^RjC0y~c%H䨙Ake6_3&'@9]Y0@gÒ6g#c,pUyMg(9I5 , _G35q&e7nxaRl/Gc J1s5Dg y$f^Y%4%rNC"YMh?Lyl/ HΈ"8Ho@>0ﳙ;/fOp.rUV޸e;b>9I^Lu(Mj2IJ*VVR66>M*G4l"we`ǁUY&}9:i8 U|t[S*"1V*fn&S!lִ>M!``YkVX1kn5Lwz=?&Ӽs%CwEpˏ׹-Ӓ]CC5TǜA^a׉QNba2g|'7Ï[S8#id jsxDR:m89Ta)hcO:Rj67_ 71M=&f,mڶ2q`8*j~gbu>cup- I^.mEm LY_P0cKh^1h瓂xIuC<R+-Ν bid{U@gk5xI熿k_1xӏsG;Yjz HFm6'UYI^OLOcBWc[# zz(r}O50sڴwojmgI-D~XrTrq¹ɼAHkL"GhMHҠy5~Hޕ=pkC-ڝnܬo% [\>\ftF#`;HTߍsuB㞔9iI;W/?.8&fDvXx/ՌV/av}K7Dm )Y!Kfb\ɭKo\Con$ ozs=*jO2#JQ `g𸯁zU:=>kڅ޷-$s姻EBbId0kwj/ 쪱b44FL @S\.;Ȱq _\wȯϽQJz/WG.K/QJ=nO\+_% (a=nO\+_% (a=nO\+_% (a=nO\+_% (a=nO\+_% (a=nO\+_% (a=nO\+_% (a=nO\+_% (a=n\av`c"$8=+B '饕o 8f;5֖]YgQA%9Oq") >I!FO$1>%Ȳ+ *AW+3i65.2\MNgE'%Uj(*E5nyZ襨4Kq.ݏF:ӕOO'UZ<=!V?"CzʮQKbT}CU(Ar؇?bUr9P\!=\_/"K~1]s697J횺`nc5PJ2Lڱ%p.,g ː (qAKDn{i#L[9gMb륚yS/ Zx]PҘ8ʉYLcm̛~E#;g<5:,cǾG'K*9` ”ef)a՛.? c~VZR?Ox?hէ>.? c~VZR?Ox?hէ>.? c~VZR?Ox?hէ>.? c~VZR?Ox?hէ>.ujW+\tA@^vc n.8[-t:Ww$Ŀ ME;y_]覢N' *E-?+ZO'UZ<=!V?"(((\־|+=wem'4.#-2OzF=urZXO(/W{M2{tny+1pUֹ",^7XHhˀZI6y ay#Yy׏5x=G뢴 X涒9 u AR#OEPEPEPEPEPEPEPEPEPEP^{ ~WWw_wTxIu9 J{ NoϨ+QvWws:G' ?k?cTWws:G' ?k?cTWws:G' ?k?cT/'LU(\T.;=uki1uGF-;%eG G G X*>VaӌIuη|@G$mefmNO,}֘8]b"!B7弈|1Uչkw&3@;3@w&3@;3@w&3@;3@w&3@;3@w&3@;3@w&3;ѾBKm|.5!V "cJhs"\-bфiџa%ZV'd, -?Nb8VGX[*TPVaIAb8Śqnwa` , [-ڱ޲ ާ\;6P.Bա[b†a-T gj.zvrudžVBc77#PqCqqL-4xYU7@m(Z06b=} 9 ͍-;<ݞNBeVi5hIfYArPoAZ&"֋hr-BO+b9LODPLh! %:o:ڰ)ζu*%p4I_9 N>|iBx, +Y$x.Z/+$L4y#Br#X'= 򔧴Yi%g9ήAErҫΣl@Mh*J`i}WD7`P44/r5!/^>}$:aX2u%m/\h-",/KAΨ,ǰ#3\He.1[q@( hfE5pe< ħ:F ٻt΢a`%4Fv\b}:Xr:1 W1Јv@"VA;ހ ;=vR4[ĺ[V②>Pz|aDbழHԓVԣEMxm- K 6~v`aiBpZ͞ٽw ЪfU%pW'T&YdFvZZdGl?+5mSY cjKOAO\ѱn SvmFxX;%Swcuwöo,{ښVט"-$/M]kvʺ&>3m6,gس*-0Zŀɳ-Jli l Ȉ1;Z(&cפp$k9:q!J(J6.{Cd PĕD1l\(q*+bظ P U2?ӻ}*w KҘ8rB%"AQp 3:H/(}E]!86dB0@&,1@\(D%(; Qv9v4/]!bA;mS$QIVi솁<'{)lq}N};b_.xRCbXBXPq5y3i6zzSJP6v#Q JvVl˫szW<ž @,cJ.s8>E8P[j)Ĥ*="Gԓ c֘B "EmuxS*GR%(2E6V։HA-⛢\#)k<5UdN` WU]z栍!Y,WhMaX.S֘cEXb gy$;2pӉ;;c"ن7?'ގ/sZg( D1EapF1AQJ8N$$5EesxNDa"S9EYlXȈbX9 f2=D8[Z*6~Ȓq˫ :"@P}S՘ 2 BWn<:"'C7y3?"(>yъ%c֎ VW-/,Gܪ=IZ{2VqrЬΪ+W[UO2a9I2Q:[9qˇoJR/ud)~y>0mld9ɬ:aEyQ 4aE;QdD(!Hs L" uOΏ =Ƭ8*V/Ts~I yz({cK~ѧy(YT:_.7%Hng)GojI PǗPeO3'=|%d s#ѓ< ?umŏ<{e 6QMy=4 g^v|4 XB$lKrNgDV,#Ph@C~ʘl8~͋F!.)_E}]@+~ڪD & uRrF ?%Du}^qʹbV[QiL1Ǧg gbZwDGuH H~LŐ!* 1U;C~TtT^Lmϵg]03ďQ;gC(yvȃRJ<(!Cy!@~xF~䇇m9!~cnT>\7n |?OdUDxPF~3þsL1h06'?,Tn~eq[/"ΠvlѮ;r(!#9,n'E(=LO h3Ԫr;M)9䀂5AV+"kNi 4[#^8\JBɞ=¦qp93k5  EdhMU)Yg@CJha2%b;zu/K%dC <jx\Ez*~ۺhScӝsա2 ?lkȏjPNՊ"?A9e cʶV+唁Bo|5<;M])?F4JftcN!J) w䁇CAx:䀇@'QXp~.t|?GMWyAIAx1ŠxdۜG4e5'PXNO;M)C$8"^;Uڧ8@Hp| pJ-8~C֦C4jOC scAyX R<B'N~L ;¤|?T;OqU!@~xF~䇇m9!@~x~sC}!rJI1uQ,5C}\w%yPJ%dC <rCС <rCzVTOl !~DhH@v,:.5A>hl+fgIbJmN,Rê)\ Uª]Ʈ;?rl!k3*Ud5eDsjvn!@ r LYNI搇ͭ4iP'&vr!\1`)/Jb_ -imըUD!~$]hwS+|=&Kێ/`n-d8.M~䇇m9!@~xF~䇇m9!@~xF~䇇m9!@~xF~䇇m9!P'Oy*ɏȝc^z|y9 g!Bt9MC?B3t&ȏ3u{{wY? wŘ{+ń5x$IENDB`traitsui-4.1.0/docs/source/traitsui_user_manual/images/move_up_icon.png0000644000175100001440000000113611674463545027505 0ustar ischnellusers00000000000000PNG  IHDRh6%IDAT(c?)M1P{Oω͛211ٲ2!A%JKw?~i֠]BY5 tOMϺ.+_U@h8pࡻʿ?m?ۙ&V]jx[^}g?E?f3j}WZ-}3D#bܯ&_l_>~Y#ʫ;M g~%%QoA"߿~O [ag^?~ٽv+y/}7 Ԋ.̾͛O^ˁ7FI.0~UqsؘY^Yq _iX5ݛolMmG˷_Ϗ5_AQ ^VVƯ~|o_>s13Ie!%i?N?3L1F_ q"6~do<]PTFG(!8d>A6 rJLS~IENDB`traitsui-4.1.0/docs/source/traitsui_user_manual/images/theme_image2.png0000644000175100001440000004722411674463545027361 0ustar ischnellusers00000000000000PNG  IHDR~ IDATx=mYwRs N@&D@%DPʨ *2W/ rlS!)a4P040=o^gYݥҐ'}~>'xyo?yr:?V0(\a{XO ?QckFnr:1>pgk":HBɅ`!~zi侜NOMv-]'nԱ69+~-ֳVu~w$35Tُ~uRq큳}+s<[2ؾ ')=\^y74mQj-x|9p8NЬъkGp>?tr..7^?o݆?^(꺽67/\RVj-Kk\>n17NwØd\g؞_,fO _ G g]e88pZǸuxtwG l5ZF>V #Tx}B[WͿ;^^?^~çÇz}t8|?ǫtWe{\ۗBV?"_^?rojo'z><WO//n'Wđt =gէtED?\/NljOǛ}Dhp|NE(l~O_ժjή+?H8OǛtG{(W?{;"z ܊ö{a՚(g 﫺QWGB 8 %;']+q.]&;p $HD種n7Nwuv}?W|t,=>3z IKhdE;Ž[ IGV(ڗ&|/߼\ߌpRk,aiX?y5Qihup:jyFۛ:V iCY&J\Vc]oc ++VDteD1Cm{8UQu4F:E7ccLt|)t 4Zu-mul*1LΆE =Wbqq̎ǧ~p}UORpm?Fh<ȭt"ɏZ>F>$5]~($eƊ; A:|x5;4@%J؆H/z|Br b;my AU=ޱq$eXY|jw=T5Fu]WF{<[('ܢwV`ِy1`Eo:\n:p4C|󑫎2Gc@)r1 *mP*!S_AKB-ѮJ~{aDεn;G9*\R+%ţ"r[}Y6=6D(/tl RRh  ށdIX" !YFC "b`9酤1FnZޕ@zFh/kyt-췢e~tԨZVF=F ".NU"wgL`$hmg RB*kPنrc$Ёvq:cB˟u?J;QNjC?ُZwITDK|0ƺrZy  pM40f?ʐKF?]}GY4A+%VlM;`n8v)`ꔈOT`e< BhIRj%,{pb O º8 Ѫdav5kf<:C>/l5: {f/hCDr[:I-W!:( a]h{TL"\Uu-2#{բ#TJwDZULL ^rhdn2`ըDb'Z ]r0 @X:[ >՝ cFW`ɮY^E[-P x'! */7iڥŧ0ц˜GyÙQF]a@~[* #~">qw:iWMV$N^k0T- kNYz62r vqb5Zѳ>Σk~l EamD{Fce$Җsg/sSьF-;MCژ8IWyk.nZ+<ᰒh"DpڰU[xXv$B̧hBVzBHreً,n3j anm?Wvyn]sS|pc~4gFG4-gbe%֊m.*$essdλtK{#s@6çHLo&2JU\ߢma&ĭ& /6CևlQ e~)̋h+cGIYY떤. < HNscB1J&0h8Gu^ W0+Q+Hp %43<Xgٱ"dûUJ0 W<H˭FKv?{yvFN|X%(a7K; kk ̩+vhbj hLxDo1gPX]nrl9tCUn.9ܺ=V1P#3{Oj4SaިQ>{9SB؏Σ/nXgD rV2y[uG=7hkkFKyI4,S]J(J=i1 8q"T5ʆ0G2u4-%xۮ!D(T:g 6g}ޜG`PR5=7{Fk[Z_j4He 1H, nh!ISnu ]i՛S̲WjE 80{kTsL s+BٷVE6 55ZXkg/y4bnA+#5KbZnXf4|] {jyɍۤ. &L w Vn6AHE( B" l^f)1L8kPAhahE >GDAGF<62ֺ=n5 d XseT2ˀ\78AEF *l2s}ʋ^(*cNF{f/6 >1mxJbh.n}Ʀ︦DuP~3@t0 bޣ 98⯁R˘$i% WeuXLg@Qzn|c6*u93Q׺䲞|hY ]omBdmX›+2|0[O p֚6N6̭#h\uTԜʠjdI.pYF<[\{9{ΌuG{^Ό3 S^$]6J"c[A :DmB2^s?>:? fq81ꖪBL tr(* |C!)sYFYոߏzfT ID;ֺu5v :*çZb`/UcMHzrz4LgS$\-RoWaPb TC|$Q rkUI%R r/K L>^Z`~(' 컀̣ 9WKAQmqQFÍBlk Aeu8@SJU2!5X 'Chd5&6!ɠi,/{JhM5LWag4~sGNW iyv֫D ,}SbLήn]}9*1d+gVV5c䦒BDDUHD@hr|ddk] ͹.x5tZ\wݹt׺psϣ&/H4N U1C2Em!W8UGt"CmB}H_9ц֫FPlVY+䶂1N?d E[]@k40Pyt[fG6 yvUϜ/#yZzͬJ= 19k+z+uM8 "A^is7D@c82@yI2b2(1W3cɸS94 S؉z6eދ~"Z' y=^Hmh3;K mBZ 4To|9*T]a "R3ܼ^VIK &y&?!TU;VNSku`v 8>Y HVWч[1iYgTy4eS("lFQd(?Cun! ;2ltzQ-51\+.zrE>=N5riX1BO)2z"(^FwA{|cMDC[<e@m#( 2zpmJw 9SY!֘ScvqrKY9F|a"s4 5+< ޣ˕9Xz;YMC>~渞zsqNBt2.&AÞ*6V#MR=,G&`}VxD0BBe MSgAeQ?hPlGYcOԃD 1 &"B"=n(@όJ:=2}s| A5lsʡs(z a@y=:ŚάZa"P(s<nf>{fSUJ^FL IDAT wV  Z; !:3ר!\k#/|b9#磵2yt0F,^G X#O~zw#TV "3@@8G㋕6c~Aй0*` k% l倒Ǣ۫n?byY <8W3u':kxhY3(5Im DWEבs8‡XV5-g-z}-[ZJ'Z*ZIl,BnTdNេDɨr[ch1nxrATǘowh~nݴwrrVJVFΣ\nL]31r5ߓe\  ށ+7h}dΈPB^ +UED24<ؖD*2 [5 Ԧ#$ݓ&g>CyA|fΣlQ]2 :ؐ]t.1>lw9$Hwp]]?XoZ@@t%Q3 u 9/U-HHP f]NbF%Bꄕ8LV488tէݿSdFGȞ~dHQ]$y n1OA \uyYCwhѐ)]HM%LqvPŔC<}x];k 6pEe;KkijΉ1]cKNW5ZHYv.Gl52ʹ.$JkX3 r$v`OTS8k[4D@+)D JH/m1**UI;t<刅XUU7@ p~hNw4Bh?%s]VF=T] e~-QѹzaH`r+s NBCD$¡zwsxjF= Uu(sbT BR=2$ꬆC:ũm+`^^DQ=kok]y}ʰ`wz.~yԅQ5 Ҝ[@ou\zn]16sLYzPδu"a -Z T4t ZB%:BTU]%R5T,bmi\evmnc/MV{l5mgu|?e?Z E#t7JnMLe72͘..Y 8<-Lt.mT V`]Jmh9V] 􁶄P \i6׺;+`R[SC.T0I[e?gME{;@@ƧQjPU^96 ܑ@L4$@V&) 31i{ox;yޟڪֈp˙:2bM7 {Ka8.6KJ/8N|\Vi+$D7qւOt[*uPρ9ՀvEa]hcX_1wxzl۝)j99ų:{,G!bm*LmMmŸ`5R%գh\J+-v*JV^uVpgLCJo Rx*"4  6idU h? Zuwa&; }£纓M;G,ՋrIO-e}U`!cn:`+`e8}g!TCVhkU VsԀJZC>]/<ѤrC uS0 qB$T5-;Yk8>ُ7~3#Cų\AP?q0@.@i% b<%*# z(9TBnUspX lxP B[6v9prֺMC<G4h8335I*zt5IyZTT?$#̭/Dvc Lp[_x^p_@*Li]R%YWUF$0]@++J |RiE3\y46Ro^ ̣uG*5㠡W39]nJgqKzB"rR4pH4KY=K|W%TDk}>mHj,B2š12ZPeSG^hK=tn7Q^ q?3#uS&]<Fzrh58U(sgsqr< +x4R| _Q`uQ='Zw:!$ZhlV=cN919!KDžQdeC~hu/ U #eW7S(ZA \FkV*+zࢡG? V&X8L8mpgXG202h>x8~qHPggnu -0ܔVh/pu <{FW0=ڏ~(HZll(5T S\e@ !WY|ZPӘ=c* Nvg@М&` 8q բPa,#Ma܏Ε3*`ީ\1%E6jE *BPd5KH`+\5ΕM:*i^Nݢ8G=WouYNV\d9ֺً l5 W!y\)L 9!Vna!W Mdb FRd-U]EhKoͣ) b#enZS?(oâj>3Y4Mkhh5>;:7^S 16<2m`u>WЖ+Q!͆E/Nֲ?l[QX)Nf!ABgqKo?ڊ3F'zXk{P㍵.}+S_Gd?Jm7@q3-uAzMgWC+n8Ul_ZTeA(q>I^YJdt" !Q Í!`nF3ҶC KP0xk{Fo<{磗gofm=%Q!YQG.0# 95Ui[0t|z_qYflgB*g !W)+Ѐ<:Ӗר+iPc2>h?G(78c[~tֽx3)osov&+Q i Wzҏ H:3j a VX [rZVnB)!BًB48JΪY^j{F]O} xvֻ^3t93✟C]%\,Okh44Iq:p6npΧ B5§Ys{@/̘L(4zk*rB! r+jKjU \hshn .}ݼ {/ghqo\ IY_,II+=#g/u!xUsfT Ok}@M4#K<(ˇ@ L4 3d8"TѢʲ;GhpT&YVGHόwȱJ4hO[Ό. 5Z>}k"tFKJ9nZӹː$fY@`0Ӆ# (8M/lSgt)(59 pXyF#iqhQ+gVJ ُͣgQ׺U瓖5vBMO)&LrAk>ʽGO sl,YuJU&/=0$_94W2 q¨Qu,ױ,<:8P(qIC_]_j4J4\6WΑ|Oti-@HVPqKmێsk:HXϧaeA"E<Ձ&by[zeF|>TZ粩yԏg/ CI>{stl;]8UwS|ĵ,+$rup0ZCYm2uLhu,Ll`z.Wg 5ܲp1Ȥ@m[eOUU %oQM]dgFEB*4iu7Mk_$Ryޢ1 #!_(\u+[9"[˭s80p9ǹ:(8P ȳEIiΎ=+YK 0XߜJ/|(a$yaΣgFp=};-~yҿKv9K`tBFNbȴX;R+ ݽpƿ1 ؀Q$!,5,ԫQ˅<SNHϱ6(Ē;=hɁ|}uKPMI @_{GӳWp-@7T11A&eN x[^րInEnֆVs,SJ]\u# "M/IJd ѷu ?2s:aa C^ѹjOf *\`Ty5$]Y,HSU Zy ^+UR &5D렲:iȫ%ٵ\hڽKoGZyi r&澉TUڧ /0TFZ+[{PlrЃE(z+N &v[wQkGP(Q%h ]yy%Gc}*%pZ-$2ÚݧU0,farJn)·_UD$ )&Ć0WUF=t9 SfWuWgE@yFWϣ^>BUA3̣uypm=1!MPQX3H Ya)A0+ DHcƑ+=bkoW`/ *%S$ROV6[ ]U0s@ҫߝ8J{cu蝃jAC8p9$еmީz0+UCIDATQ{F@f hLu'Pћ ] βrk) ApFa(LLNsHVGі$C/BC[J>37ZMV"h~+/ީ ڿwE>9]așQ 9A$TNi\3G"\Puu[?@ c| i # BjKdnd]v!)5wD8xfPt(Pk4McL}.۲PaJ_k|Nֿl"4 $u#2K]]0 N9^PÕ^l?ȵ7Mࠂ8 3"h9s8c3@%i0_Ds],]ϝ&qQIt7VG ?{=>M6N^F9* ų30fc3 4">N'屌L&OVUN\![ΊNy ^@Kg7Sզ9"[b!׫P᎑7KY!3l+yztBO/f Nsd2u*]a|«"*hC<{)$ܺ*x_,:FYcXƘ766CkHM}В"_ԭXa4FC$йu7T3@¼iXKZS!T MWAFr{8ç>8y4{owo~"x_5I #$@3+kHnbWb-|;- zCLX,CnZ< 1 ˬm!86@Ka RCM:grf4:l q1z#ad&ȒA٥+ uz%OeeMԬlXOkf*ɊsmeUF<}mhC{iZ%ժD%1xvVi,(uDظ\o~^z_ÇO8]}o?]p>n>tYx?|/i[7׫ +]Ol?At*] {u\fWq[Ox %[H &<W8~m?^_| A>E jhu4GZ$?^Z9=O0t+'Oy/?|!!~ruuʈficGΌyBM%?x ћ2tR[+ ]hvV{ rVFn!#{`t[%r -=T@8@ n;ƜU=EDjTZ]3ֺuۿ.@RϳuƴHο;tH^ .Atk8*HCꖷSy2]@.oswhu&=CITmo+:3jtCceUkL/F6]+f\ ].oIaAUsڰm?.Z2XoY\VA*ٕ[Ūmׅ|SϨd>W̛ap\SO}*b`]giLߺܞsS_]]dGw> ]iUL?@?RuqS%z+\&;V'Pи.pʡ]uUk-Cq[tuP]mVՃOn-!Z|aE0 S4Uo?n]~ϖg^x?7u?B{寎e/dݹ OAgKK|^s6wP`D@4s}{{D׵W8꿾~:?>黫W̡N|qwv`_}^6@/84+Λm8UrCsŅ>'ߋ0|S\ h ^"~_>sͧ~ӛ< =Cc1,|k*g*ptϟ$xZ-) 'Ҋ(S2#7#l~cf<9i?]}ɕ18] 9}-Cg9W?7<|tZE?UMm@]1ʆ8zDψ'xgl'9_G#XXZ׹2.yeB{hm5@O'#E>vW+cPom..ZoǵrZv]xsTԦ2U/D#m'N>j0x,Dv}8+`]:zQϝiE>vV{GҢ&{o-[v vN ̷uh.b]TY$Tr(I7t}W%VniE>vQߡVG5n'6,~RK\ĻcnAlh9J_W["02<Ƒ`vx柷>§giE>vQߡSx_R[E N̐.@f8L,l' *Hp>m١Vwk1]&MSx̷UCw/Z̹ж6PKdK}ۀCSx3Wr]o=ҋ|УN/B'Ze1"R276Jx+ ӵ'[hn"cRg?7/2TTfgi>vQߡM<ZWGn˅8##VټQ.J|ٛxTRIءݗ{|QӋ|УN/BFoOiZ(Ba`XEcZiNQ8"t$-?8 ?;o+3bii>vQߡYr4Χ[ߡIZߡYrQϥiE>Vf(rQϥi=pAn͚&!HU#<`dz)|9pm-oח#.P6N215^(k5Q6.HeVϠ=4˩rv4iZ_aon^_t{\?I6+xcӭ|fh\[2q>3hoQnj2~#qn<s+*ޯd۩0olnl(%h&Ү Pȯ 72qj{O^]w VU<.XZٯxMXrIP.~oZܰ4廍vHհH<}?\9i[ F2c,ʨJ3{>w9 ۼju;m..>drB̪pIFz%Ь$mVPh@y99xz~9}+/eD-T' ʘtjNtzw=|FAu9^*jҢVkMsq`:Q^rOE{27;͍YOVd^GwAcED z]My'V4r[qpNEyfY+$FO>ND27+lJ%mѫ}oO߄/|Q K5l]QBc2;b[-B+/kkE+~[ Wc%A I?24ž ??kL5\ gVܖe;saᆐfip qRtno!1ZZ!dBlg"~ a|?G"~ a|?DMSO68,t4Ql_^".Щ,~o{&#IEo)Ta'4'5-^_pEch-U/4Zb(wa.PcP@U}O&t}GGs;ȩ.7O#_}M}MoGQ4*ttDUYG?eyA:Ŧ[.se8u[MC[h-~=ܼ2TH`GcU?_.qwg{~ |UgAVm"S6TbI?5%-Ib[H%CP+u G??5eEYTU%h}O[k-] q3d b[kpi޳Ӭ5F <1rO!xڠO???O&'/-|6^iќic#'% }^#[ ޡrQW<=g?ϰ$hO??ږaN5L&.Y{{"~ a|I?5~">SDA>?ϰ$hQ)`kk?ϸ$i?'G~!G7G[?}?Ϻ4jk~ {uޡO?ğM[1ʓQM.ߞ(Pj')u~z~ѨF?9iѨZO{W_o/ѨF?9iѨZO{W_o/ѨF?9i-ӓtw@y>HMp1q=u/x7@#;H;ѿ:bf^^]u|d~byeϋ,"k22w T/W[>g?G"/UqNڳXM 6*H纙k;Vۏ+\MP}Q;y!e)v(L63 >Rk)ϙQ>g?[4RÖ=oE4_??f=cM|*E4_?٢i>9cSE3M|*hOX1SE3(Ö=oE4_??f=cM|*_ϥ^^ak"XJR;ߙ-%%c??dc?J4< >xE}K_<(_2@J'/k/^1 w&r22GEpͦ܍sfY} q/k~+XZ:q7< ߹< ߹â*/k~(?/k~+>T=M߷Xr>V4>LX#f9$&EaR;ɖwǧxWhBO1c >Uȿem\Ґ7I%YrsMO ׭]JrK=ٝ&o+Q >UW' \J{1}}7}?M{+?O ע{0&o+Q >UW' \Eai;MW}7}?⫏O ף?/^vy|G&o+W \G%rG_م?7_*MW??/^J>z/G OoϽUy|\%rG_@}^fsM{?7_*J>z?+?->a >ToϽUq@}W'z=Z}}7}?⫖Zu%rG_C{[ l) ;K`gZJj1OPQwM2앙Z,Xx}K񢋯E}ܾ&yQez?-EO_ף Rf_u=N/bQEpX$-ooׇ!#!bYTlwGh"X"6a {1]Xz s؇eu?QǩXY4??}qBXXP, $2z=kNY*͜v|i 5G͜v|i fϩQ)c(Ku)kKNKKt%֟Vei̱o%ruRh>x_w/d~{/?^%KQxATYOS Q\'Aj^ ,Sz)e'2>zkym˙ 3G=ǽcmV!sf1$Eu@]1ЉØLQY8wJђ`Adcް}F!gYc3m2+N8gS}NG:_Mnpn#پ5T{wpyIn{ֵrmsʪ˴.to_ӯNN8EY tZk$,Q}Ou+&T$P_ .+ <PAt`UZ]~EB-!I䁞( NFF~'N s, $&;G{}^RůhL$}*/i6A{7L4. <yYpA!%fnf=$W7i{?*b ip1ӿj_;L,@?g Q!b~]NHVT18Fn"<ſv65`bO < ~>2U6W~{?sHȬp]?ehCsk3iTNJm4y`bO < ~>as>[*C*m#PYw%NFw dӵ`b/'$[{Ӿѧq0}{G繹'!W0۟-z@ZiyMspUFI铓kw /;ۏi?Ù;-%wLe4*pG..Zy#k0n$RXG˵]Ce!$~=k^%Jk}6kcV#ҭW}0z>=Ο /.ǧ^a_? /`{:_0c-R>e ssYPԍF -6l5_9%+nhOe|+2X4QuRh2? = G *Z,ׅ Bh*s2JA ~dOBF@\RX[+u)'(z7?]-e#/#&FI5n#Yϔeu?Qǩ&KuٕO,qAu8H dp$j;v׊.{-?,_z/=P.f0vCh*GSx̀Emi6ȯk* 3 TWP瑡Ǩ?,_z.m%1Η H7qc^+|Rtlzpi%'i!h$yAfD $TZ9)RDb2Y!%Tp ֹq+5p66.dh{I 3z?8wk/! F!l+0G# 9cr)>ߥs쎋?8'u*-|H#2*D֣sB=wt9hڈ4p&3[b9=k E$t_d𿮱G[h`FV:0[[|n4 Ionܜ+?h⢢ĺnLDzHWS8 dBs3^I fmđ;O ף?/^/fZY..pO!FpU]@}W'б]2s?/^J>z^a{&SW' \Gף=)W?+?O ףɔ諟@}W'dtUJ>z?+?{e:*%rG_@}}z=2s?/^J>z>NTC?+?^XKfv6LTm[#EwuİD l?04%+cγU.Ɠ.;-?,_z/=LbYe ʲHQdM1hi|+t^Ugf "=ZwSX-?,_z]sNiZ?ۿ.ѲgpF܌3*Am$'XQc Gfݜ!]0zR"O ˴-^yv~ʑ9Vmbdi!h$yAfD $TZ9)RDb2Y!%Tp ֹ1+5p6iz~!L$@QA<ύ=AH_O+%UVl33;~Q'TʔVˠ(wq4gƞ ֖kog[xXs$22,B?Xj Ӯu#,pYCyLe+`C688?_p<كzF|i v4QgzF|i v4QgzF|i v4QgzF|i v4QgzF|i v4QgzF|i v4QgzF|i v4QgzP׋ᦌwk2ZFInٔb1铞3)%Ցߊ݂ѳ<֩ϩQ)c(KsGխK[;H*='E-soՊ䖋O1A֧3Z,Y2nx}K񢋯E}ܾ&yQez?-Eh2O D(S29V2{,ׅ K6NbI[l\Ub=A=j1"+ Ɔ!L,q̊#=qd# M62iDs7SӞz/&u8~R}h=4(y\?8qU.;52^\N e0 xsC>}NG:_MMoCMm65MyQB;\XyU@yv{u8?j^ɖ-$$(7K+}_SyJou @U JBO9d!PVu_p)J@/,_axg1a˶McjpE}It!”&cӧzɾ-U8|+$$obnn<1[a$G]1rYWpPWtMN(wVYV|>q#gogɾ-P%zM v1j<b{:g +by75Ũ1tϱW75ŨokQc9c(?okQgs>ǠQ^gɾ-G}@ɾ-G}C] ZcAEy}C] Z&??΃=[]SOk;ʑdazP75ŨokVay;ˡwLk;kXDQGAaȥ}-:g[:\Dio6N tVVejN y3sn_]Կ+3̏Oi8p*KWth׀6щ }Asz΍כ֫*ORՕ8hx_~_GE5sxu-/Xx>ާ?>?#??#??#??#?  'y}}  6- !"#$%&'()*+,.</0123457P89:;=Q>?@ABCDEFGHIJKLMNORp`STUVWXYZ[\]^_aqbcdefghijklmnorstuvwxz{|}~Root Entry 1@2 Catalog 4JFIF``C     C   \`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?a+◁ujzs2ZV8Us'W<;kˣ&Ig%Jn${b|Q_ONxLws(kFr|xt0HȏV66BAnJ8 aj,F.gnY.}{K(tp徼ޕiv-H GFyAwH4vUӴ13<%vp;U|%Eӆck fh~觷țEӥ4̊;w! p;0u)1R/}^9tԤ맺o8Ȯ?nkW\&u7 FvE9'F^:R:I]Mmx/pgJk}-?KC6s1_G|cA/%/1th?-;i/{K ]΃-?6i'y,-BHチ^=~ҵ/٫Cj?KkgIi#G-m]}Hº^Zg->r骳Ymw}ьnSmΏ$b%?2Yn##Pg$+_Ok+7oG۟ǃv#-g@me}=fLFRIbqWAoÞ&{Ȯ+0]Di<§n0xU`߇e+TO2̏_zʛ>_˽G?.,t:@UdBeUl$&#'* |K`W1nm#ߚ_i~Ɨbɦ0w܅F:{`W>0u)ov#Iy6&7˓QEo}=SLKԙ62 w9돡O]Kر^?~u :}`kGu|-za?/ΏYz'Eg> Gu|-qsO"|_߳GĈ-'Iti9:}`W͵ك9'G%Jr/Ppґ{{)[3f!^ r3^^o7 Wc<?zt!ZDINoʳ~#r M&hiFdːi gMHK{F#\!%rY}E:<=i- eyDp'Ϣڼn`The. $ zsO}KWBTLg!!#??  )|VMG-mz3+1  )BCCJlS~Z??騵/ᨿ^KYTҿf2^CPyX!G?64aԬ%::3޾>ܑ˫X"2=jF,X|69i#o(ŗbRtقӞ|ԣ~o/./i:}̶b&wٟ˄ g bxtg_qxb餌20\rt>+ϿW\!/_jQ?L!ۡ4o2gw¼?_ _ >dtF~+w :/~ |9ǡ&[ٴ-;5݁?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvyz{|}~  JFIF``C     C   =`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?~~>1厯܇DQcUrwoo®8skMhkK{9tf#,l8j];G[ı_[s71WUenO{KtK^u "MJo;Rr#1gn1zv*K0ZQiᢧE%h}UP`ԥ]s;uͫ7-QY]_ZZ%nHHV!$|yqM3UL-B0Zy =?ugitoiVF&efbɛ⥰_:n4h_xPInl[I2A*@8}|q9֝ZIY=^p2jwm^/ar[`AUct)xWXhVw!x=FG#^ǽF-F!h `!Y~-m.PA+ CӼUoeCk ;KdknGNrr6:W }T90~ʝWuţPC/W^Ú6a,hcTM[%F|#23潗Jtk+G0-n aGyY^UJqQi>;w{ѧ'54JͧoȋMP'k’ 1r^J`sӭv?>xCԵ&/ƞ0Wh~# VԬV7mȠI|"7s/ibUB,ںIY%$* 09ߥ|yb>oS-ui.iS\ߑxs֓SLujpr,8x !TOS^wl_| .toh & .}A{vM}}k6Ij4T*Eyo.uې\."dGp1\&3$púRN/=wv~ÔrZi{eN-Z_}Oٓz1̲B33(Ty p+c:0+D3)@W9趚+vIY3 w ˗9nr+8 H gy%69L<-=>k_xfN-M)}5+O3T98=)|FPqҹoگ@Eվ%d 8Cn3i#53FƹQ|[ux>º]oIq Ĭ޻p\%RRJ2MdLN[G JFIF``C     C    "JFIF``C     C   E`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz3:.4x.56 w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?M>?eauJkfhUX l@8KLJAogF{>]k2MY IaA+<$* {Rh3'f3msl-cr~wƷ37៊-k}KN-c#lc+&o^>"4߶~Q{kf{~Wr[#?Gxn5[1C+Miwm*ƻ~Kl`[}L3kjKx+K?) Ml7bM|Z GF"/ͳ,֝6Ox>fiWc[%Hƌ6|FP|<ަ=c2mV3{FhՄQ 2q:x_|J7Q g,PUL2+W~2Y ]Y%}DU nz<:DŽ>=r5OC]_Qk=W"y>>=r5OC]_Qk=WZc|}g/#W~˨/OE/N6ȃ|a<{ d֧Z+?ۖd{.QF5S>woiŶ%{'YǽtСe+ eNJ >>8 !*B?UСe+Vɿ}O / TӼUB(Vɿ}zwPG=;_(Yoj?l__8ӼUB?*BUQdaO=;_(Yoj?C?|Z@-bEw`_'e8֫W۩qWz`^"4 "JFIF``C     C   E`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?M>?eauJkfhUX l@8KLJAogF{>]k2MY IaA+<$* {Rh3'f3msl-cr~wƷ37៊-k}KN-c#lc+&o^>"4߶~Q{kf{~Wr[#?Gxn5[1C+Miwm*ƻ~Kl`[}L3kjKx+K?) Ml7bM|Z GF"/ͳ,֝6Ox>fiWc[%Hƌ6|FP|<ަ=c2mV3{FhՄQ 2q:x_|J7Q g,PUL2+W~2Y ]Y%}DU nz<:DŽ>=r5OC]_Qk=W"y>>=r5OC]_Qk=WZc|}g/#W~˨/OE/N6ȃ|a<{ d֧Z+?ۖd{.QF5S>woiŶ%{'YǽtСe+ eNJ >>8 !*B?UСe+Vɿ}O / TӼUB(Vɿ}zwPG=;_(Yoj?l__8ӼUB?*BUQdaO=;_(Yoj?C?|Z@-bEw`_'e8֫W۩qWz }!1A JFIF``C     C   P`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?:|a[-_Q"hz;W`b>$x C֟ıj֗W*r/Y N:q3<-N2^s7)$2+ +KƿtK]u #N_;]*KPvAQ\AjҋO >H-W?'C'RZu6Ǜv),n-`{YD2;B)#Va8KKjw{Ũ=EC@ƺ3ΏYivфY$wbS73-BLq I]uw TوXT͒y=N8}|q9֝ZIQjOWo#xL wk;%t8qW[BmWv=O=^ciXVE܅xz?Hodx`  eden?)yv%Q3Y^:mY$rܳyl,mp/ڧ'.X6ƺW N.3S8P ½Ѵk gdGo* ޼OQm2٬|_ #2ݔ3M+6my\k\ yZ*S]Iۻ/NNjihNߑMzO:O$2"b4*Z~ |">jMs_gimuxd3-{-Bٵ 1urآ$0\DnkW^/mt-^Yu?1"̩)!D@P~U/-?]V,/t1xs֓SJZR!8x !TOS^wl_| .4oh7 & ;n\+ƻk2nO-,ZM#U#9Q^]ƶ>-5ېQ_2ISqVcLgWHWu$_zkl~ÔrZi{eN-Y{5o=;_5mRcoameeϷ32ԁ]ڙ:|D*1y)qlC|8Jg ]<g{ۤswQQENkGCy1I x1щ$w5y%69L}Ve~F ^AmmftÌE'$H`S" xVd]Fvol;J+5m)4'Kh3o.6%GM`9xh4hD܅iN2Dʹ|\mڼ6vS[cSѯ'tUdr30=|6XdSkƫ e#T0qzBxPյ9Ȕ|VZ_V?-}Q m_ZùG>~'g Kmu5?U[e=WQ m_ꟴq= QRz+·#q]fQ C&Hs澈>-}¿n fS!NNJrE4a^?Cf쟢eA7y~kWCIF5gSB iUx 8ScèEF ,Fn_ ?;=#i .ZKׄZy0DKYXS%Z|jyge3 i#In1H\H]aO_o.?yFɻv. f{*y[7߿>wGSèEFg}N 'a5.I*I$9\RW;F WVuܷ{Lv?R3yw{ڍ\'fyzo9GSܵ~ʟNxJo/W+Ŀlɮ ԕLЄ*i9s zYeNl}fjRfX|/zGgڧ_ [JԼyڽWmbrF@Ip⫯63 DBM9ץ58+#=&Ah$%SqwOLך>=Elt-ң뫦n !\q6\W5á5.*[|:Y<=YVc@eG_h:>{0}_覯sE.*j=sIӮ~2M{ךK)oa?}f9k >!-ʴkD"^_b}xޭ`|->cAW$yI=r?T᭾d ^W>G3[ǰ׈;G:Sc̀Pi'L+yq| U:4ceWR1 m?Y<>y:sTZ99h:>ߵ_ض1?᭾gK'`?hៈ|Ex^4GP9 {G+1PI%(I)+ٟ JFIF``C     C   P`"      !"#$%&'()*+,-./0123^6789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]`abcdefghijklmnopqrstuvwxyz{|}~ }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?:|a[-_Q"hz;W`b>$x C֟ıj֗W*r/Y N:q3<-N2^s7)$2+ +KƿtK]u #N_;]*KPvAQ\AjҋO >H-W?'C'RZu6Ǜv),n-`{YD2;B)#Va8KKjw{Ũ=EC@ƺ3ΏYivфY$wbS73-BLq I]uw TوXT͒y=N8}|q9֝ZIQjOWo#xL wk;%t8qW[BmWv=O=^ciXVE܅xz?Hodx`  eden?)yv%Q3Y^:mY$rܳyl,mp/ڧ'.X6ƺW N.3S8P ½Ѵk gdGo* ޼OQm2٬|_ #2ݔ3M+6my\k\ yZ*S]Iۻ/NNjihNߑMzO:O$2"b4*Z~ |">jMs_gimuxd3-{-Bٵ 1urآ$0\DnkW^/mt-^Yu?1"̩)!D@P~U/-?]V,/t1xs֓SJZR!8x !TOS^wl_| .4oh7 & ;n\+ƻk2nO-,ZM#U#9Q^]ƶ>-5ېQ_2ISqVcLgWHWu$_zkl~ÔrZi{eN-Y{5o=;_5mRcoameeϷ32ԁ]ڙ:|D*1y)qlC|8Jg ]<g{ۤswQQENkGCy1I x1щ$w5y%69L}Ve~F ^AmmftÌE'$H`S" xVd]Fvol;J+5m)4'Kh3o.6%GM`9xh4hD܅iN2Dʹ|\mڼ6vS[cSѯ'tUdr30=|6XdSkƫ e#T0qzBxPյ9Ȕ|VZ_V?-}Q m_ZùG>~'g Kmu5?U[e=WQ m_ꟴq= QRz+·#q]fQ C&Hs澈>-}¿n fS!NNJrE4a^?Cf쟢eA7y~kWCIF5gSB iUx 8ScèEF ,Fn_ ?;=#i .ZKׄZy0DKYXS%Z|jyge3 i#In1H\H]aO_o.?yFɻv. f{*y[7߿>wGSèEFg}N 'a5.I*I$9\RW;F WVuܷ{Lv?R3yw{ڍ\'fyzo9GSܵ~ʟNxJo/W+Ŀlɮ ԕLЄ*i9s zYeNl}fjRfX|/zGgڧ_ [JԼyڽWmbrF@Ip⫯63 DBM9ץ58+#=&Ah$%SqwOLך>=Elt-ң뫦n !\q6\W5á5.*[|:Y<=YVc@eG_h:>{0}_覯sE.*j=sIӮ~2M{ךK)oa?}f9k >!-ʴkD"^_b}xޭ`|->cAW$yI=r?T᭾d ^W>G3[ǰ׈;G:Sc̀Pi'L+yq| U:4ceWR1 m?Y<>y:sTZ99h:>ߵ_ض1?᭾gK'`?hៈ|Ex^4GP9 {G+1PI%(I)+ٟQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdef  JFIF``C     C   (`"75 8 _ 91 01 o  }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?i:‹ ay/%% 6ܟgr+nAڢ@2;g5-OH/^k }!G.=CW#3P*|7RI8-k%wݟV>u7^"l]W -J9pOIv7%ڍŇwꠞ=W~/xYKA&ɖ#X) }\ݗm vpU'r+ާƙx*԰z;tM9Ս%ɟkLvW/ G%D wn=ۮѯS{_n*.baIۀ0ҽ_'25KG*.A^.z.lFԍX/\1NԱ y(?G~s~g5ψ5v6:v8;?wqx@Tm<} c! R+"7R#%?/Z]>vղ;ƫڊNtڿE5Xiγ-^\;l2prýWDc ̛y$o83OCY.XN k hzQMN9蚆f]BY2F- v0V">n&Ö >עIm5PJȮ>o3=Ho%N[@/g8O,~σq}+i&3eA#w` u(q_'jz4-Mko#ܺYQNhUCA;}5T}Ub$}_Z_i"Sy4rB@=;*%^U>myrM`GM!}Xz7\U_KgC0_Eωȍ&Oqo.#tl7Ak_?SE7sؑ@]Oݡ ~w L} OJ5e&2/Jc]Bm|ż ,>n Q> /HBbR|dAvRiIYE'trߎJk /k(R[]< E$X M_O\RQd:Ia]NI0Mvvs_+߱ҞxIalPrftb˭B @ BOkO:k7:*M*7 ۛ{lq +?jN_}no~AU=WG<>:6h;jG9~/ϲʇo[ƾPH=?߮Tb5-壃H9]GN$w ꋢeiP{P˭@r[az`]Q]+Z$kpH%^qgI(ƠSBEL>6ǟYIpMz @ IQ]2*4],\^oghijstuvwxyz  JFIF``C  *    C   (`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?i:‹ ay/%% 6ܟgr+nAڢ@2;g5-OH/^k }!G.=CW#3P*|7RI8-k%wݟV>u7^"l]W -J9pOIv7%ڍŇwꠞ=W~/xYKA&ɖ#X) }\ݗm vpU'r+ާƙx*԰z;tM9Ս%ɟkLvW/ G%D wn=ۮѯS{_n*.baIۀ0ҽ_'25KG*.A^.z.lFԍX/\1NԱ y(?G~s~g5ψ5v6:v8;?wqx@Tm<} c! R+"7R#%?/Z]>vղ;ƫڊNtڿE5Xiγ-^\;l2prýWDc ̛y$o83OCY.XN k hzQMN9蚆f]BY2F- v0V">n&Ö >עIm5PJȮ>o3=Ho%N[@/g8O,~σq}+i&3eA#w` u(q_'jz4-Mko#ܺYQNhUCA;}5T}Ub$}_Z_i"Sy4rB@=;*%^U>myrM`GM!}Xz7\U_KgC0_Eωȍ&Oqo.#tl7Ak_?SE7sؑ@]Oݡ ~w L} OJ5e&2/Jc]Bm|ż ,>n Q> /HBbR|dAvRiIYE'trߎJk /k(R[]< E$X M_O\RQd:Ia]NI0Mvvs_+߱ҞxIalPrftb˭B @ BOkO:k7:*M*7 ۛ{lq +?jN_}no~AU=WG<>:6h;jG9~/ϲʇo[ƾPH=?߮Tb5-壃H9]GN$w ꋢeiP{P˭@r[az`]Q]+Z$kpH%^qgI(ƠSBEL>6ǟYIpMz @ IQ]2*4],\^o  % JFIF``C     C   D`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?-gľ3ƻ`CMwvMakgns3f>ŗx~]MNWEF' wc&E5\ =G_]6r~,IKDR^0^'n!/VNa왎ڙ.o Fzy8| b/IԼQA\3ThʁS[pxP2WʢzQou%+a*T6NWМkƟA,'{tW7:UbI2@'kaIZF׺{ sѱ,v~ W g=K÷Z[[oҭtXu!~FIq|֭]|qcxv/"{U1K%bFwbQJBv0vK qrfMߵk/tMi]2B+<V8t[k'Gn5 mo(/A県4燳tU.ޞ}Hiӛ^>дjOo*?t2zua^\ZE\^1ImR1 gW|͇4-zvDZMfdi-$c @-Oİ+ ^5;?gu嵭nXޗZչߥo>gDRygFc?i#2dV;FX{{ Gc-(.f tQ(vR2v_o 4EdQӦ!HR*, \M{7S֡eD+HB]r0Z7kbҙQ $m,+~P@&\(궒%P,&Her {5Tk(Ƞ((׾"7j%{Ex&Q+?e?s?G<+|}fUK ӖեJdr$] +(T0*Fkt/B𻵕ė:+l[0*H :* x"mrXOe?iUd:?*Qa𥿇?ɮ[]52L\<#6W$fl nYbsխ`ԡ*K6H:sYĚtz50n8CR~5Tw"[R~4jYƲE*WhԲ?[R~4jYƋf_^`ږ__ﭮ?fR9Iڎ X1R9?<d,MjrzK?Ͼ i(c.TH}1],O fsbcsH OtV&jg\Ͳ5Xdp~ }_t6V1)]Ѻa'\uo[{{cs'$,S(QT/Ds83O9=%j^5}Jg[Y,X"bxk6a:ukmVk'8Ѳ6rhƥ|J}Zis]mRK,U@IxG+{Fr\QoiOe&̊xE6:),uJ+[:U , B8,t<(ċq?;E?o|7?Q&xK-dhؠ3[DHVMԁĜJ՛,'dWQm.ñ,w9 `}'^aR,K1ys(<5A_7-5_.gKcڠ>T3׫_G 8H~> gg~Ӽ?^iQipz5GHbQ$A#Ec ?Z?I:G y'ƿ,J(-h O?X+52]+RɸHlAN@ҖUӜg <M4ctŗx~]MNWEF' wc&E5\ =G_]6r~,IKDR^0^'n!/VNa왎ڙ.o Fzy8| b/IԼQA\3ThʁS[pxP2WʢzQou%+a*T6NWМkƟA,'{tW7:UbI2@'kaI~*Rn3JFpym|J6>=0NRń֖].=VH_l\l)W_u9<Ȟnxy RxؾnR>*%eF\uw߉heӎ]7lgƐxgмCa@ڿ2n@ʐq^{xwDld\N#L^qxs<vcrO'+۬>'xp׺N5+Z^jfP^H9XoN&kK;vo :'Qrt|9h ԞyVOIFGip*W[^|7umQѵT4Z2N: ;䈵.ZIHq[aq|W_k}]Ւw~kZmt1K/c(i/i=۫s_K.|#Fž5Ȍ~#\/,Fd*2v?Ǭ[P\͢A*K8Qe<- i:&M%C,HUsYF8;nB<-WB:.H`n4i/'3/tHx[u8I]pG5-P4/In`,tK y\ƒy7r ((((+l5 ډ^^/fɯ|DoJa)OF GCoe?icIyBJ ]3KЬ<.eq%Ί[n 1ʳ;g<j'\:keYOD,ivkK^C1ǭz,O f 5KMgWK%,$ld~uR9?|||YtTZu~\+&rO$y&#(+eY}Jmqۿtͤ>5GHbQ$A#E>[@#FZ?I:G y'ƿ,J(-h O?X>5GHbQEoC֫|kģI:G (>_~?<_t%s?>+|JnnLJԡnG+xaӐ(eM5?OZJnެw!1AQaq"2B #3Rbr $4%&'()*5 % JFIF``C     C   D`"11341 215+o 31Ib4167}`      !"#$%&'()a,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`cdefghijklmnopqrstuvwxyz{|~ }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?-gľ3ƻ`CMwvMakgns3f>ŗx~]MNWEF' wc&E5\ =G_]6r~,IKDR^0^'n!/VNa왎ڙ.o Fzy8| b/IԼQA\3ThʁS[pxP2WʢzQou%+a*T6NWМkƟA,'{tW7:UbI2@'kaIZF׺{ sѱ,v~ W g=K÷Z[[oҭtXu!~FIq|֭]|qcxv/"{U1K%bFwbQJBv0vK qrfMߵk/tMi]2B+<V8t[k'Gn5 mo(/A県4燳tU.ޞ}Hiӛ^>дjOo*?t2zua^\ZE\^1ImR1 gW|͇4-zvDZMfdi-$c @-Oİ+ ^5;?gu嵭nXޗZչߥo>gDRygFc?i#2dV;FX{{ Gc-(.f tQ(vR2v_o 4EdQӦ!HR*, \M{7S֡eD+HB]r0Z7kbҙQ $m,+~P@&\(궒%P,&Her {5Tk(Ƞ((׾"7j%{Ex&Q+?e?s?G<+|}fUK ӖեJdr$] +(T0*Fkt/B𻵕ė:+l[0*H :* x"mrXOe?iUd:?*Qa𥿇?ɮ[]52L\<#6W$fl nYbsխ`ԡ*K6H:sYĚtz50n8CR~5Tw"[R~4jYƲE*WhԲ?[R~4jYƋf_^`ږ__ﭮ?fR9Iڎ X1R9?<d,MjrzK?Ͼ i(c.TH}1],O fsbcsH OtV&jg\Ͳ5Xdp~ }_t6V1)]Ѻa'\uo[{{cs'$,S(QT/Ds83O9=%j^5}Jg[Y,X"bxk6a:ukmVk'8Ѳ6rhƥ|J}Zis]mRK,U@IxG+{Fr\QoiOe&̊xE6:),uJ+[:U , B8,t<(ċq?;E?o|7?Q&xK-dhؠ3[DHVMԁĜJ՛,'dWQm.ñ,w9 `}'^aR,K1ys(<5A_7-5_.gKcڠ>T3׫_G 8H~> gg~Ӽ?^iQipz5GHbQ$A#Ec ?Z?I:G y'ƿ,J(-h O?X+52]+RɸHlAN@ҖUӜg <M4ctŗx~]MNWEF' wc&E5\ =G_]6r~,IKDR^0^'n!/VNa왎ڙ.o Fzy8| b/IԼQA\3ThʁS[pxP2WʢzQou%+a*T6NWМkƟA,'{tW7:UbI2@'kaI~*Rn3JFpym|J6>=0NRń֖].=VH_l\l)W_u9<Ȟnxy RxؾnR>*%eF\uw߉heӎ]7lgƐxgмCa@ڿ2n@ʐq^{xwDld\N#L^qxs<vcrO'+۬>'xp׺N5+Z^jfP^H9XoN&kK;vo :'Qrt|9h ԞyVOIFGip*W[^|7umQѵT4Z2N: ;䈵.ZIHq[aq|W_k}]Ւw~kZmt1K/c(i/i=۫s_K.|#Fž5Ȍ~#\/,Fd*2v?Ǭ[P\͢A*K8Qe<- i:&M%C,HUsYF8;nB<-WB:.H`n4i/'3/tHx[u8I]pG5-P4/In`,tK y\ƒy7r ((((+l5 ډ^^/fɯ|DoJa)OF GCoe?icIyBJ ]3KЬ<.eq%Ί[n 1ʳ;g<j'\:keYOD,ivkK^C1ǭz,O f 5KMgWK%,$ld~uR9?|||YtTZu~\+&rO$y&#(+eY}Jmqۿtͤ>5GHbQ$A#E>[@#FZ?I:G y'ƿ,J(-h O?X>5GHbQEoC֫|kģI:G (>_~?<_t%s?>+|JnnLJԡnG+xaӐ(eM5?OZJnެ ?o JFIF``C     C   ``" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzفV w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?^"umF @[@rw'ook/yԜ=Sw' *O2y3?6I4mqA; ky3Þw' *O29y3k TG&?Ƹ(?9;?M?'Rcj_[/bPީm%ð@ N9V-s?x?5kzFSucy=ook0XO㗫9ՅQRHQEQEQEW?}#/iV ~?jF>?5?F+~j75V3gՅQRHQEQEQEW?}#/iV ~?jF>?5?F+~j75V3gՅQRHQEQEQEW?}#/iV ~?jF>?5?F+~j75V3gՅQRHQEQEQEW?}#/iV ~?jF>?5?F+>jwv @RIs dW?'-)ʅG)5rUME΂}?'-*~SEz΂}?'-(OVtW?П_)?]lG(}^򳠢xwnO e >SCs?x?5hwO[/RiZWuUºպê$H$H[ѣR5hޅ ?ٕ-2@+|_ua/,R/^y TJFIF``C     C   R`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ? _xKWPb\lv I 0W6zSE b&B7AD#j|/׃4IlY,gr*2Mn§ _RǸ<"i{Ut:9SQB\׹տ-je홂V8|cZMĉL19}ȍe@T޾OsWԱ'YQWE N}-=7_q*$yxሬn[oGy +.lIU8ÌVI'uy5+$˞3_AxP iߑ&[ XcU$qkJ)Ju% ӋPpu7{?:ۿiRu"(C,%NF)-\䧄CHY:9+-O/+?a3ݬĕ>&[cp%V'aι#98Z|vJ٤wؿm9:]A<:Wicn+V\p#kot;#8;ۣ#/VM:ܢoүAXiS_[_\g)_=R Ҹ9VA ֤Ue2" pG>֛ۼn=+⯂,RƷ~mOLG|ɏyq'- k]Y$ɕ[,1dr$T?a%O_ X)0Z,hi=q^ yg5e[YXצLd_ igaD&gc4hG_r¾^v?w䵤,Ra##m yu)QFMg;@[rCH?"h*in[i\`Z?k_0_:!wS .#'Ӛsit  G\GO[Xf,?Mvұ8n#ӠhxE[GAL+ GдVveƚY A7Mo#NcM6"v2z) mA<xvEz$;oymWi|ga7:^ʥ  ,zp3ԋCQ{!dٱ# ɮeOܟDy : ??\mWd'EeoGؖku$T>'<&>pG~8x2BS0xil,vdS@xֺ7 ml k22S]1QjfNrL۟ ]Yy;X钞Ƹ:7?|{liH0F1؎k_|oZYX_gc>B:<|25?? m&ba#=+| # Ƃۣ+go/ XI`_]ض&X~ 8B͌#`"]1&7Tp%A'nw;L'LJ=䎲-^ ?Xn8 'mEdh഑",հ 2++OS|1.[ &q>\ m8j6He]d$A9We}c XKiTTbFArk6UPwm;`\=7Qմv/NdyrhNY2MUƗ|Ϳ?-+o"Eе//Q BԿJ.]Ɨ|Ϳ?-+o"Eе//Q BԿE\(-+o"o:w|}j!鳤A"H (i|!j0pV=gO+k ^| shJEC#gOoi څ/Jdǧ?@} Vo| bX3ao+089կB,,J{ǿ*ZGAR–#\_15? i;Ǫ͓AsǞ8W]|I̢N$[~B |"[Vw W,I96a|#-׺|!SYf>sC~O{ {MςdX.h%(@qK '4_1gd|]CN?dk3TQXw : fuQE,ӭo*Y>.ZUP '4_1Oiֿc7Ew : f⪶[\V RJQ[TK?٨eh`¡Wp(H& JFIF``C     C   D`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?a sox#ԴkfaH[ª mns^g)xFJOiaUY"KBʲ@ڙ~,#F1ª܌ ^xzy8*\V.kxۿCцKM7M[{??C4sTM2Rh?ǸFq+A鷟,[U&]7ĺou{ .p`gA}ccu%>&іI%[&>`]5_o6Uͮl`aK|ϞճLF7㯆n)zqI?~\1EIg{{X~ϟD`ؿzy (ʙTpq85~KKDnc/3ɼ-2@+|_ua/,R/^y-RhZ6PF ¸[oEk>#gf5ז`e^'quPcn>5غ~!m~̓%V-iH)8y4{D$c9 O*I ^Y/vEt]Ns/^~^+9ɡxB4K;.%21e0;mw{/'(_3c\_#/j7:A -S!;-gŸ /|7èϮU(Z$BIA>]3]3H>7G}S5՟i(.?֣G{S5eRXt%f83&CWi}"Ky4ϟ^UF10?@ABCDEFGHIJKLMNOPQRTUXWYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|};F9π?|n'tرA뵿4{cŔ+pSv~^+4V+_4  &,f2H\Ü:[j6VO<+.| }Rhe{Ybx H*l.ZWKJ%!g׍JznfCiiQ#cwY2~N>\.O֗{_Ϳ‹ծS q^10 Xly+8l6sF?VK*V!#tr4"wl2̅LY6ԓrzOu&,JA/{TGo|<'A^AUKYn(1RҶ|&hܠeQY%X玆Ú̲A"`pqTFG7]pVM~Fm_Csu˧æ~?_P$!'ׁ~6oĈ_Λ.sνLۇz—OA|$n[m$+9=@=( B{Y3[ʩ8eXq\ST%;˧'ʠ˴;{dѢI]D`d#n&rҙW#|'a+K.AY]BN|ϣu`:vKKB% 9{m=O^SP;7oKFY](R ڬrH8䁌fi7h{5m_,T(?3}kS"?*=y,jj&%Q'Zi~bia>#6/QO)Yw"?*Xpϡi="i~b0‡}GW~Zk_oċA\)Vt[ >m3m3[??WuNReӭQA%'Q!V짂 %B?ke^?>^a|N/ tQO7>!#g|N/ t>'ϗX(7>!oW;|5>^a袏=_{??.?/ jphi+X`y ve8W(ъii'sEMfI =y+ Ꮔ>Z57 uޓc~X|=6+ JFIF``C     C   H`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?ׅ4Mko닿\2˗ds c^bmæ)/XɌ)#bgD?}ej3Iuqqg<#"nMx VMԫ+VQ_ʯ'\-BM{mwesO4[w4lW*g}uU/Gc4Hro![ruLW-<0N3]$u?zoXU;%}/{}KHچggЕP~i'dz?y7VO_|cw{o!GTؚv dN[iɧ$ byoCX'޺!H$GqF!੺^f/ĬBJa~1c%)w_A;. 6Ee'$..|VeIu_Ei—qKdUdI>l~zs8?l Ns˩iLJ,,Q]OnC1WUYeXji4iM9-5tӺCY}<X5:|\YVqzntzol KQi.x5:a&UUoYcz|l5LV:)'Jj9v_J O.0臗V6mݐ1=+Ӵ9洕S* ʺHg[* RʖfG[s{2_A=ke =ꖊpwxoZqƝ$R:IsDZ57 uޓc~X|=6+wßտ_c{,G/Hirȟ*xey?80E$,T?zp:s6(Q?-[jɓ^ /z?<9=[?Gaܿ('mVAReE'j6+&Wtm5>~>,[yM>i*q_t!5DTMz9fpЯRj^Jɥovq*N--i} 7E6t[Q/"D1A,hs\gӽci.x5A#˘,Ky~k[BS+"o4^k7whbT˸ 8yW7xHC)6^zOkXZg {w˴FʼnlskOd!0{.7M>ckoqz dXnUMO5o~?д]0[_Z^ }آ|pOAץ[_&qFwk60 x ߐ.u}{~HC3&ψ}kl|VaG]4USYgG;4Ok}j`q'V~޷~(| `yB-S~'Pu/GsƝyi5X̕ި *6tBtjYs3)8#~zIw3v]f<Q͸|c/9g#t#?gD$|s3f=^մuwk$(6[Ae'x?ȳC$.!ʲ=׆waߝitDZҜ?̗BT}+)f1'c5m7VeEK_N?ҹ?Agh:l$@$UKRj eW͓ 1q]+IO{M_socN#ķSoIn[\S]lDpdvkl,rc9 i5iS#ס/%ͣDY8\U]W.y׾ixZ񵶭$:N&;j ۽Xӵ=к 6+l3lzUæk;_oH NןCN oX{cN#xPmJte'_35~Qv?½/{t:?.'KghkݟC\{3^t ^]ڔ?t=xG ߏ1>(DXnUFnv|W-?SP>$VeU'?p8k/╴@1c6IjeWPQ\n*+Oߎ<5/tOi6v֑OtЌ{~w šwx>퓣Mv=p7~:E8W(Tw]6{8;/,phz}մ ෆdF f'NVSʣR.36".IE}OG)maoeOmnŢ[sx մ hY6QIhPnO"?O̗J-/Z aCh.ȇ'~?V9i֏m+kEb}r}g=~~MѻFr:=޼7_? ^quC;Ekot2r$u=Q]trN)Jr|[nHx($3٧8r l֟5? JFIF``C     C   ``" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?Oe 1~<-Yn.J?iOx#7LR7Xwx"axVyyٞI [׮~E_w,q_ٞ?z?<3q~;_g "P [ף3>]3g~W(w,q_ٞ?z?<3?k Yߕ Og "P?i xm! ˰=ko⿅d_,ut'Z _X (uGf\vSOO vf?A4??WfȊZgATQ@Q@Q@Q@O׌RO^Io׊~ɟ+I?l~ٟ"ֻ_D=#cEq_g'wHX@EPEPEPEPIo׊~ɟ+I?{_&" ^)&ȯe]$tfȊZgA~ٟ"ֻ_D=#cEzQ@Q@Q@Q@&" ^)&ȯe]$u& x"t")kC??WfȊZgAtQEQEQEQEp_& x"t׵nk/@5⟲g_O@=˯x5/:*("8y<~:hN]}f<.Np8kkh?_GI|ob<92D }qր;M_]MC%ǜ ϔw Zo' 1i^) ϔ ϔw Zo' 1i^) ϔ ϔw Zo' 1i^) ϔ ϔ.|!yhWij`Xո$N2BBw D.,s~.z؁ |cZ'+ּ 85xM2P!`_h* 7Wcsla*8fg'^7 E^o9/ȡa\Sڃ?d/ȡa?N|§?&iOEYhrqsK#Lc=h}!ʎ1SKi=iqր9ќ_zQzu#9HOsyTJ=:@Z{5|!w]_C?ʹ?To1޿CG,"G?6[_ _$( B5~' s GR6p*zCdS~;#ԐzQǯ?J?}JOQןڿ)2vx)OR::h2A:t`N^`}=uЎJ=}GJ^`sRK@PNA%J 8:!Jt~?o_x#tUn#-lkTq btMMs g^t Oړ#֮H _Щ{i!{x{\뎁uvף\*\?P~Q==[Au@9(¡O[!{?x{\&]ӌ#!-zy_P=G5uJ)|e-[hd8BNq^=E >0 t+cwJ~ RkEmlrDž7>Nڭd~ +1,ü>G .&|gkʕL@ 6++ޛZ^c)'a}+[?Gö1H?B0\(WVdz=U^5Q&ﺴ\p7Oj .7x@!m#yo@ ܅JϨo:%:U'͑e8Ċ@~@pteզ{Gqd|eӖҮ'f,:+(̰sbBexꔗ2m4gugel.u$+/wݲj|= u+++衙Le`3КotoW,b7. m`J4guvg?EAaN":&`f[:E`д< ntτ>Ҵ8axP̭&2Tv 98\ zTm~F6YiY&žps Z: oėlPH N3 H2py"|cxsPWe.E (fޜaڬxKúΧ$͚SoXyYV2*v\;W% x&>cq'wbˑ1"Ok57QqǛ_O!' u,^5wFcuWdS0?Q/W' tmO # '(Q cy*[28:MJ/fKO!Ϳi=OZ;:%2l-±5?@]S oOj~ t`tKOnѨm܊Z?29iEP\|!E4rzd "PkYQتuWOl߆:gt6^'дsk{F,1W?m?z|prr˨Fc/@7+gÙ\]Y–R{ǿɇQER]t~wywl8d%dڤsT0[?>kv,ˌ\1m#O}/\yѹ I3'5,nw+4~;:/!ec*N ivg5_4#oz^zc]A)ch\!#VXx}=_rC2K> QoA w:2C4#nMw`|B^|51w߃>biRds/lyoc Lٻ&vqqǽ|yU_ zS&p3/; Ī\|U_ z[^aW,dFN}JW - Y%(X3v7tȫw/.63Yi1Ⱦfa*iTA6=}#a"Ei/\L\..]d0|VWiEľ?nyEҡE @bqF:%aO2XLì/>q[GowCwkmo,l d% 0GU<5;Ym/컔{8C+3*#% 9;M}]~i{s|Sg]9p[9pOAXOii\76| е:=z^XW0$h 6O9c^{} Ϊ'־*3RTm۵e\>X6L,`3dKszt-Plf[66.O3ҰugOfӼ'-Yn ȌM&.<8S ⵣQZ5H<6#2 ]2"YP>~HX73{qu5ծpK LSDU*.w 4 JFIF``C     C   +`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?4_|#\MZ\>[ppAּ#^=a8̂Fr@T'W__ NUyg!Gn`\AyDѨt=%p&d(;ۿOUTšZD6v&1y*Q"w}ÞW6Ǔ%}Ka$q4J#Vr~_RxuOPS>:| 6oƗh*M;\]c,yq3,~ էMsGu5ii5f>,Q˰ؘ0Nq|Zͩ+47GoãKmd_ (i;(mL&xbDDHFɂ=j]_ dёxʤ{6"X^!]庝cq`KdaI _/͞5mm<`j%j7?.F}y:.!TմlQ! oo'+M7N O_XAD/9~/ͥE5_."Hecv<`玭i߅Z8z~I}E|'>)U:<9\|;}k cH9t0{ÅpT2sQ_ >ڧ h}OI֟;?#ouQ_ >ڧ $h}u_c?'AY}O~x)|ZEգ绎; a#=,_|- |mAc!v&De  W:C1L#pw^9<=ҿlOziXx%VDQ9=*6(o<^XՅ]]},֕:q%b*Q?у{. p8$ 䃁H+MCSZ.륈Yz a1vN>C~7@x?_<nׇȚlQW-fgb`s$RH]!! 5|GY֢$߈tSuuiyg7to"mj?~7@{7K!c?a?.Ql4{D[,ec4lx=x3m>񯣏zRG.MͿlK)@p18?&>7@x?_<nC~"n"mWZ߈,e?Tdg+sQ5/AmFKqs3g Nx_ۏ(?@x?//D?(+8,M-ЌxG+ @PNߓg5U{71 wU 06rl|mP/7T5[/R֟y qAFS#Һ0ZeVOytwReQ\y^%)1yeKI~" gTeW?=>ᯇk JFIF``C        !"#$%&'()*,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_abcdefghijklmnopqrsuvwxyz{|}~    C   `" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?w1G Ἥ>I$7341$^o;__X=fj^ oAݾЛQ܅CP*Y|HG>r+f\d3s~ ,?F 5Դ.b?1GzX|KYOQ% ҈Й67~^;ZUR30Qq(Jgjb޷bzX$Ѵu%Z[}ialgpAWq3]*t  )k+Mig"KYLSHH;{`DTێj9ܳtKɡuyC>c%U#-t^$>6ߞ9ʾM5mE~a}E TU!wtw4'Y0j2^^h{v&cOvi7&dj[[rҬY'TҼ?=ٗX;<i" $9]혼H& VxY7 Ӯ!6Y|b,xpqĩ[^(KMBՊOFEQ\q?"8 Òzm-Qwxpn i`)ۉcן¸oG1؛7qUJM+HwVs;m"h]v+ H9<Cj_E*Q!I :G `W]z{;XKa,_#Q`Ń-lgsE(w·/mj-V 9Hpdǜi{~HAGR1t<ύR1cf%UxO*SlA X䓜m k]J_3<7 GxszQE9Sؓ :G מH/Aa^x #Կ_~٧#6^aou+<%{# :QWQgٮ@P_C+_ JFIF``C     C   `" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?0>jn9b$is` zt+k &'ɉ <`׃nu'/*F>Tjj(p6][c F0<񎳪mK[[Lb[Ml_n60Ei>`YcXqZ۹phsDGqo$j[ y H}VR h-$3<'Y|.l4V:o%ė>$1+}FF0&gNjI}+K}GL]-rV-CCb`ec򟛅5|+h"kCu3,@S8!g4OQv ,JFxR(' yN4^C?5?F+~  JFIF``C     C   `N" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?:CO,l$X;j#NH—>vb_,V|-ɿ҄[wlp:>yrVW{tE@׼%bE=1 B=r1~]&PhcjJTogsMTΗ4ZՂ^<ɧw1$ Pдljut3niP*8_XrG*f }\ceoGs$19}2 :ۉfB I"pĖ,g<Ժ>H#_Xך|xO Yr׋䓏+ؾySu?–BH y3rwbk˫M){{i-* h຃8{+SΏz/Y _G?Mq׽xu/WTԭa,1̻273<ksE'MT.H6;f_yg 8eG<ŴnKVi dT@T*ohM ֱj4+Kr,s p.Y6Z!)Y^FtOߴ ͷ^Ԧ;KGbc>-W\}bFmLiίI#f>k FtOߴ ?K/Cj2>\+:"'Ls/BދZ\]iQ<W_(%Ʊ,~{ŧa,JJmlbNOWZ~"6obV `,jF$וtJE^uXFkcQ^aE+OO%weN|O$v>_G8ZhcG%ZL*k^:) ЇR͢ȕy6=9隻zdor䇊Y17dr=]L1s냎3Iufp}|`F\ j&f%[K5vM0ag%Jy%FXJ3]X@4͉y.G˟㯽XmhSmMx)k^AlVYg.Hx^a?M(ͬK4j4ay1=eŤr]Y;o'0<`5jlO[9r>\g}crLYyט|tJE^<<䊞ڡӓrW>lu'sb#f]֊Ni~ar\\[w؅aڬ┸(4; ""a#8EhqkHWtag!zAޝqr֡W{9ÑkШooe_40~@ tkG[ͤ@nfm1NCӵQ񎖶=cI{6,׈H>ccIzx}1X _t qa bu{}O~C8Zd-*vbߏƱόWE'ۗV/cX^獋5<i {[ͤ@nfm1NCӵPkK#܋|ǧ=zѧK{D7Ɠ'$b>3 5]7n_7g{ߥ/aWC:j󯎟)Z+AޝqyhX{^\8S+Uci^/~N>ZyyZs^/J4*9JN?fֵ JFIF``C     C   `" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*532)42+ 52`628/t4@6789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?\tH4/32_Y집t1%&Q֪I{;}:o!#Uvpq o[x##:vh4.y :|WdRu ۽_ ?=&9;&jcе z6ֲJΎ ϛ;zϫ&u[ow%*fU`[x$ )Q\V/OoI4Y^f= |1i.%- F NV+? 7#V7/OoI4GpMV~oG7M?zx?zOtI0MV~oG7M?zx?zOtIa?5@/U%𦓠^^KcdK{y. @:'iRON5G7M䚎~VqeairiEY$4"8"ؓq$ZSW/ȡa\Sڃ?d/ȡa?N|§? (JFIF``C     C   `" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?TƇ,hgLv?z bfhz5v+K}2'(;PKyr+'^.GO Ơ4 $@ zj!pxd=[ue֞.{.yɡIΝX|׶9qR)R+15 E[ktVQAiЈ?g'WM S1u? y:8+<oo1]}3 ? ??B ]75Oÿ^/N?C'U}('q(?B G4D3+w@kT;5b>q(I[0ɣE#)n fa1*ƞl1=,-+PFL)eO ۿ~ VVsת8o|9o_(|ڭ a](?zO.Z?PG5W-EXl?}ԿYE+jxw?='G(?zO.bl?}Կl?}Կ⪿]?S|Hw?='G(?zO.bl?}Կl?}ԿǡAtAGў!?F68wyhoaWú~WF̬dhrJ$pkhI:Uo^x|[xUUIo,8rϊPhNWkGRK:rSݾ˯_Wq_,xkk[Fu&I"[W~sƷ~kNuB􏢫ԥԼKj5 %ӕ5gw]2;t8wA;? oڛFU>vq`,̣aӈ''">Ug]ME>ۢ-3櫐nUPA:+? Z>jO=$±P?O|5=|?ڗ+(:+n _v?|5=|?ڗ+(:+n _v?|5=|?ڗ+(:J/n _vʯ#|oyi&i6vFbHP+3i p8PO e JFIF``C     C    `" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?Ğ-ξ-\ r劀p?8YnkeRv99fF}F{+O/Դ*Fh  Gx桨|_\KxWVL@eH܌9,EEH?ȯWg~91w^֛, Oo/VxO\Hcsrw_:G?\ 1"A_P=G5uui-z.͆V<V e&RmwZ$Dc5~%S5KHɐuqf0Y$jBA>ɗ\$G!?*ڟ^_?r@ѵ lҴD d`FaT |y6Oo9KEihdKg1Sh{׳N<})m-?*  JFIF``C     C   `N" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?:CO,l$X;j#NH—>vb_,V|-ɿ҄[wlp:>yrVW{tE@׼%bE=1 B=r1~]&PhcjJTogsMTΗ4ZՂ^<ɧw1$ Pдljut3niP*8_XrG*f }\ceoGs$19}2 :ۉfB I"pĖ,g<Ժ>H#_Xך|xO Yr׋䓏+ؾySu?–BH y3rwbk˫M){{i-* h຃8{+SΏz/Y _G?Mq׽xu/WTԭa,1̻273<ksE'MT.H6;f_yg 8eG<ŴnKVi dT@T*ohM ֱj4+Kr,s p.Y6Z!)Y^FtOߴ ͷ^Ԧ;KGbc>-W\}bFmLiίI#f>k FtOߴ ?K/Cj2>\+:"'Ls/BދZ\]iQ<?hBCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefgjklmnopqrstuvwxyz{|}~qM[+Ig9B|r:jڜWm0G+^ ?/<9֧嵂ӯ:"']2w\IL۲5SV'V'Ykӎ:}\V%v^_G8Z_@/Xy.O9 U ;C8ke3z4u;3E ]6Fo;ykipkZLJ*#k~tp#qrrd'h{WA=kVm{|o6)-5?훋+hD &2A,͸cb-KIL PG 1۷  䎣# g{qKi*KF[8Ǹia-^;ŅO;gUe˷.. kS35DwP7 f[j7VJ=@LeYp8[Uصqk6q >W_(%Ʊ,~{ŧa,JJmlbNOWZ~"6obV `,jF$וtJE^uXFkcQ^aE+OO%weN|O$v>_G8ZhcG%ZL*k^:) ЇR͢ȕy6=9隻zdor䇊Y17dr=]L1s냎3Iufp}|`F\ j&f%[K5vM0ag%Jy%FXJ3]X@4͉y.G˟㯽XmhSmMx)k^AlVYg.Hx^a?M(ͬK4j4ay1=eŤr]Y;o'0<`5jlO[9r>\g}crLYyט|tJE^<<䊞ڡӓrW>lu'sb#f]֊Ni~ar\\[w؅aڬ┸(4; ""a#8EhqkHWtag!zAޝqr֡W{9ÑkШooe_40~@ tkG[ͤ@nfm1NCӵQ񎖶=cI{6,׈H>ccIzx}1X _t qa bu{}O~C8Zd-*vbߏƱόWE'ۗV/cX^獋5<i {[ͤ@nfm1NCӵPkK#܋|ǧ=zѧK{D7Ɠ'$b>3 5]7n_7g{ߥ/aWC:j󯎟)Z+AޝqyhX{^\8S+Uci^/~N>Zps Z: oėlJz??@ѿ?MhiwG,B4p&*Brqk; h&  JFIF``C     C   A`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?#1~5W$M kT¢)ǙgtzGJv`3Hyߌ1o.5B)5YRYYƻRW#`?gBvvv1?f=PY."9B)%I(;,exr=z>"tu5 k>y(¢)ǙgtzGJv`3Hyߌ1o.5B)5YRYYƻRW#`?gBvvv1?f=PY."9B)%I(;,exr=z>"tu5 k>y(C89<WM Rehw4EvSWzC:»ԿswY?]_9,-@W5[xvM!}jO7RZ7|2FSOw4C4R.{STHu4jj[{o3 _FV Fw/,,+(&Y|yBMS1yQb8'Jb nOO=3_K:;*+stfP~R/ߵ Ͼ2 G[ &(wN*%yQw ߵ"k}_/J_E( O j3LEkrԌݕݍ YAv@h1YcoY"!(LpS5ԛ[#wQk1_"koE~([r/X_g/G%yR ߵ"kCS%K:5ث5GGEQ=?X%k۩dTN^Nُz5 Z*6WbK>O?'SC8xzO^- G\{4)l*8n"Q!/",$\i]e`&A#AFӵc}ep؞SmHqI*'O)֭#fAyf9€Xu#|[㛽oKEa"w&䧖C3"$68Ghǎ|u$P:x )-&dbK0:F+]U@tW-o ]̰\LEHggd*TopKgnXIkX^Z$> 8#M]*zOJ,l$y؏@QE&}R4 npFvV >RSJH[inAZ)\T|UpF QE;&~gG[-&iYC&=q*I{[o&ą#ȌISH^=I$,|/qy=Γ]#Q6b0~QT> x&X<=lE n8 rr:(|vrmsbK;#9%&|Ķ#$Nz3NHm,-[{XRFO~Q{f(:-%S*Ģ%H _ 4`X*};㏃b},jf XcYLPb=,X-*j~i.[ q*  JFIF``C     C   4`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz 13* 23+A 33,i 43-# w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?ǟ۠hH//rwwy_'P߱/gc b\;~]ƽ5Xn=C&Hf6*c8~nACpyAY[12O"$"rsӊ;M=Y#d֬5 mo[h LU³AVo+K?E#;M=G!oO^]_9,/]_f@GM;úm7%#*f@#rK A,xN"2oSiMG>C89<WM Rehw4EvSWzC:»ԿswY?]_9,-@W5[xvM!}jO7RZ7|2FSOw4C4R.{STHu4jj[{o3 _FV Fw/,,+(&Y|yBMS1yQb8'Jb nOO=3_K:;*+stfP~R/ߵ Ͼ2 G[ &(wN*%yQw ߵ"k}_/J_E( O j3LEkrԌݕݍ YAv@h1YcoY"!(LpS5ԛ[#wQk1_"koE~([r/X_g/G%yR ߵ"kCS%K:5ث5GGEQ=?X%k۩dTN^Nُz5 Z*6WbK>O?'SC8xzO^- G\{4)l*8n"Q!/",$\i]e`&A#AFӵc}ep؞SmHqI*'O)֭#fAyf9€Xu#|[㛽oKEa"w&䧖C3"$68Ghǎ|u$P:x )-&dbK0:F+]U@tW-o ]̰\LEHggd*TopKgnXIkX^Z$> 8#M]*zOJ,l$y؏@QE&}R4 npFvV >RSJH[inAZ)\T|UpF QE;&~gG[-&iYC&=q*I{[o&ą#ȌISH^=I$,|/qy=Γ]#Q6b0~QT> x&X<=lE n8 rr:(|vrmsbK;#9%&|Ķ#$Nz3NHm,-[{XRFO~Q{f([hU # (Pg@8r$$NM]g=k}&8_3pb뵚C`F <馥  JFIF``C     C   B`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?hnU6hՁ 3^d gm2V1%^|bJq q^6N$@;ZMHV:J-cZ|/oq2z˂ɂJ݀8Z׾#|Ai+2l.vWh&0W8'o#hrYݩuO L~(O60 $dM.ݟ$(ڵ-Vj:31i_ByD|r3!o%ތ){xFo;~\9bzՍW׋bmoa 1AFgL^0DewCdt տ;? տ;)t=cڼits*7ncD R~P>w7-L',~'6ۛxB MHghCuo?Cuo?Jh9G݄)V;K]0]>lZƞCZ$Z"H;x 6ay,#8sv픍mFyx"@KD qOv 9pH?C$i4$[fJyE2ۼ xTV1x81ƀ*@s\^"ŠEYRXdbW%'|Y6k$ż-"+Tb>nxcŶukS\e"60K <IoG$tR;"$[:(EIoH4R#aNjs˸YQY((((((((((({/%k +<;aӅǢ  JFIF``C     C   53.# 6373083 B`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?hnU6hՁ 3^d gm2V1%^|bJq q^6N$@;ZMHV:J-cZ|/oq2z˂ɂJ݀8Z׾#|Ai+2l.vWh&0W8'o#hrYݩuO L~(O60 $dM.ݟ$(ڵ-Vj:31i_ByD|r3!o%ތ){xFo;~\9bzՍW׋bmoa 1AFgL^0DewCdt տ;? տ;)t=cڼits*7ncD R~P>w7-L',~'6ۛxB MHghCuo?Cuo?Jh9G݄)V;K]0]>lZƞCZ$Z"H;x 6ay,#8sv픍mFyx"@KD qOv 9pH?C$i4$[fJyE2ۼ x JFIF``C     C   `X" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdef"      !>$%&'()*+,-./0123456789:;<=1d@ABCDEFGHIJKLMNOBQRSTUVWXYZ[\]^_`abcqyfghijklmnopqrstuvwx{|}~ghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?Ӭ-T=3UKt5u0ABjodimS|ýb4]^ Y^Zq\2R3i+<+CJL֞|=~c_?9:=4}=5{|G'4s˳RucĞ#ӅnQoXw3~b/RlR_POtzQ]qkݿ~ޝ oTz/넟 ]b{ =-bĉpx|Iikxږm}TV1x81ƀ*@s\^"ŠEYRXdbW%'  JFIF``C     C   /`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?m F,tqЃ1Q۞k6-wI{xv8T6!7~e6k!kQI<|Ȧ;BԮTYD;G!"eR~ѫS';⌐P9,tz㧱ŷk,o"IU'r2@:_ N߼ק{o^9STl w.~RWo}_3iVw¶/#z~S -??[x7P[[ySv3tJ|b{Dѧдk!6-ab-,NM^y[NZ4M_3c&5xzk{=?ZT·Go O*I6QaỷdmrBΧt3ˎs?>*]\hqkͫItRͲ*:|4g|>#[x7G+⫉2kM>I-=$ma#0?A[X"]m<  6>lu3\tJ3 jKn}GWp6'voUfxΙ/Vڦu4N2{-%xY_XZ1$Yd?.szjm&[2>LI+* fiRl=߱+2Xt&3KozY:6U6Ol۟γ ?6u=ViҮ9`{ֺMR4k<|ȧvi9xAR k$Q9Riu_ }4¶?3/&]%?yů}CuoY\_.·ROg.FT/x~#uE"8d%H8ןtIoL:^QG] w4aja%w|Y6k$ż-"+Tb>nxcŶukS\e"60  JFIF``C     C   /`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdef932# 04?14P24e ghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?m F,tqЃ1Q۞k6-wI{xv8T6!7~e6k!kQI<|Ȧ;BԮTYD;G!"eR~ѫS';⌐P9,tz㧱ŷk,o"IU'r2@:_ N߼ק{o^9STl w.~RWo}_3iVw¶/#z~S -??[x7P[[ySv3tJ|b{Dѧдk!6-ab-,NM^y[NZ4M_3c&5xzk{=?ZT·Go O*I6QaỷdmrBΧt3ˎs?>*]\hqkͫItRͲ*:|4g|>#[x7G+⫉2kM>I-=$ma#0?A[X"]m<  6>lu3\tJ3 jKn}GWp6'voUfxΙ/Vڦu4N2{-%xY_XZ1$Yd?.szjm&[2>LI+* fiRl=߱+2Xt&3KozY:6U6Ol۟γ ?6u=ViҮ9`{ֺMR4k<|ȧvi9xAR k$Q9Riu_ }4¶?3/&]%?yů}CuoY\_.·ROg.FT/x~#uE"8d%H8ןtIoL:^QG] w4aja%wK <IoG$tR;"$[ JFIF``C     C   F`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?fޏi{{9g2x LՈr0y'^$gQJ>FSUyf=v. W=:IVAG%)!i }9^jsĿdk^u JFIF``C     C   F`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?fޏi{{9g2x LՈr0y'^$gQJ>FSUyf=v. W=:IVAG%)!i }9^jsĿdk^uZ*G7jj+;<>5_<8[4cVZ=w_K_{GQqӯ}!D.lzw[xG&54;{ 5w\}ku~u)駳} ؕBjtSv4e鏆Rt{Um?|m& [Akm;+Պfb@%V<-АnrfJCUqk6",Bf] 61АGk4K@ֵ4NԾ4a{Y0fߵ0y5wGG ȭ[kǸ \C˱REHW*%$I\9/oCsƪZVW;u$J]p"''hfn~gsߧ9W`v@[`4FcZDѰ]Ůt`\fa+T~V|۱4&HM'ˑ/w%ʻ1ԧӠѭ4//^͖,FHW3O2P@5'6e# e}<7c/ _ZK_ZC.,B?#ӜcZo^[Ein"FU}73[Ӛ'ZWڿ?T\&>iyKm&߲wnGN?Sk;Ğ3uV֗0O(((((((((,Nimage050.j  JFIF``C     C   K`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz34z 44 54p 64%C  w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?EbM&>Rt{Um?|m& [Akm;+Պfb@%V<-АnrfJCUqk6",Bf] 61АGk4K@ֵ4NԾ4a{Y0fߵ0y5wGG ȭ[kǸ \C˱REHW*%$I\9/oCsƪZVW;u$J]p"''hfn~gsߧ9W`v@[`4FcZDѰ]Ůt`\fa+T~V|۱4&HM'ˑ/w%ʻ1ԧӠѭ4//^͖,FHW3O2P@5'6e# e}<7c/ _ZK_ZC.,B?#ӜcZo^[Ein"FU}73[Ӛ'ZWڿ?T\&>iyKm&߲wnGN?Sk;Ğ3uV֗0O(2)ќyKNO׼0<|?='Ƹj/}Gd>cc8ע ;6v.Z)+?EI<_XNz?$7;/;}-ٚwZߵ >sɿ4}ckvٚwZߵ ?4k}chu&4kfik~+u&M})i:$5UdPOO5=FڽЯutu/8um VC6'=qn.~'`G>*|? a^"-@*aS~+?|/6 q]EgK!a6p)3UfPZZ\]-PY$3 88jYK}Ra۱an:=EZ3KOEUu`M89ǨJ-n!k-YcB3(`•'ጜ kj.Dm*6azM}NFTO.&#*Ip 3OM:85U6ڀD" Cy{?O~ieZ\j~tطlrIintbg8s꧌`uZSΆ$v *: c DU YxKhX><w?Od5ĺ2i..kdqp*ƹ MCMU?zبz o ,pc5k:Ĩ`E V[S.L@UB]/#4O׼7(6_׷F_ %dt2J ` -ǥA2ܵly2FrIUtUHuLp\B,m%z?AzVK1%[3 ya#-zȺ 6HX;U_kcqbgXDD4g ~e3MկKKm4$.P:?=yjJἾfFYVhU g-v?f^kZ u!ڿOț-gOe[yŵYR8˴d$Ēi* 3Ji!Sye7 Y pE(Gþ'i5kKye3:yqxN@X? ׼ :<>,[ٵ #3\x-&qYTA?NMkk?O"hxWk}n Hdb, zg$|oQV]U3EH6 JvKdx .??jXHbr}EBvw,D>%^]tHmr21׷Q\/$K8HgeeZ5q>6{euP Op@<([!hЫDb3rH^}][q(tD' #}Gν^F  JFIF``C     C   0`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?4KCKwx&|+}:w-|G|Q:Ng."k٤Jw 1<ܘГTzQ| Fm%>gJLJ\|$$ 3D2##sn܎3JQ90}8/УR}-KVRMȹu"KU߷_¾R#?&|)hKy[Udf8oCo_LƐ?ק^:ҥ/\y f *K :u_ڞ-9wh )* @9=<:W*4Ӗ%3__Wv(?fs /7;~o:tqۨ\}H]fR\!t-o"DX1$|0heljl`eIY Ka9^2:W/O'TIAU? 5ˈUO+$tRQRo|E״{\U]f$t(|cC=V qe"vsmzWo4O_K_ҵ4Y{Cm8^| Ug+jF_j6m鉩捧~c~0Zz3CDm+6с{a6&X8\o5[OQ'Vx_C'i6od^<{ٜ;/2g8k$Lu}bjЃHf𮩨D >l멋F讙w$zEm>VӵY-COunYJ?+[{m>^( ռŰQp!zf%ϞzƕnZ]BmR8R5q@ :U--6-s ފ\`s]_u|K6[(Κ-…8$qN1ךϞ=,RFvCʓTMN6ǧ\pMu^ {8%eV#88' Gd[/\T8##0'<@S'|uo3JEM-n,\ r7`jv .;ؙ͸ci '{u江ۭ7[]ϙ31T 9<qTWtxb^kO,ЊK7 p=<.uo3|==u=ͭhg?ɔLrlcAuhޠ9@6k'NscjoCl3un.MRwH\|D?P_4BdmǘOcN3Mt?񯣏zRG.MͿlK)@p18?&>7n6jV[9ϽoOLtQ%}"}r[?{y5&7!^ ej'^I;׭9i]wAƨ`25Z?wG$H-#$|?M0~W>Mđok?ii5MψB7O|N{OO*qx\\]/F>]L0Xdh;Vu[ߕ 7qIH""7(;[^&Ӵc(?'=<)o 2YHk7}~l-4[ 1lyk؝J6yGZ$z/ѿGѿ\W'4{|\Կ}~֞|>֞|=~c_?9     % !"#$&3'()*+-H./0124I56789:;<=>?@ABCDEFGJd]KLMNOPQRSTUVWXYZ[\^o_`abce{fghijklmnp|qrstuvwxyz~:=4}=5{|G'4s˳RucĞ#ӅnQoXw3~b/RlR_POtzQ]qkݿ~ޝ oTz/넟 ]b{ =-bĉpx|Iikxږm}h-]Liklxoy9ėűۏxʴM^sF6W1dc6KqF@o?v |&_4ZfaHgWa=9^:%8;3(W%Etii߳֍nk׭C]2Ieb s 1Kඛjy&w4p^iG :}}jû9F%)``aS$`i %Ӯė#W1ʄ\@'=ƺe5yTmlI ?~$WyZ wYF--R8.\LUyY\cyu S8b~?7?OQt'* <FS hgd 0vyebl=0!Il ; OQm!<.[S_ڷb'YB+gğ?#EJ;襆%s:w!MPɥ 4(}eX |}j\RhL2Fׅ/4 9&2^ۘQ> qҽհl<­ ?qB^i?P?` >N>/c#y؈ģ s3Ӣ8^uhҳsI^ו\Joݸ1;# zO9ŵۿ qsOrOMt=k-=}^ oy2uvG̵ 'ܫQSi)u m-ʒ(gY#AH(g44=O-=}^G5Z???ih_FI %Z;?q$E;Q;m:YX\]=N\ᵿVz+[#/ڟrievxv4w!Q?&I|L[(a1/?,{h*v޸[o>9е6캞8PB9!wzR^ջynsWܟ7-3*S2ujw*n>#i;C<̄Kee$OB?1[w/BZn”#Ϫ֬\x7by@_sIR/R2)MOQ EjrXDx^5%YD]ʨ#=}A> _,ӿ)MOQ Mjr\ʑ4YHbiHKG3hXn?LrSw#DiZ-=pBG89?4U0;vo-jVľ w<7n$.P68=}*rݮ݃j`G ǎJkamK-W{Ѩ6w}Iwn2/$^Mly5{U1i^X,-`Ŏye^s1Ҳ-quIDw*?w35x*GYl˸!#xOL[m!vbQ,ƍǡ# .Ah_/>ۗOSK ܶv&>R#5+xCJ{[vv/,2IROLJ_ƏIt Ei{o?ľiw"Bnc|<9+iY0ȣK+)C7_Z .Ah_/uS݉=oğ?#Epon3hs*Lv^qEuFnxNw63ZI|RҹBX6Boyϑ?@ACDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnorstuvwxyz{|}~:}}jû9F%)``aS$`i %Ӯė#W1ʄ\@'=ƺe5yTmlI ?~$WyZ wYF--R8.\LUyY\cyu S8b~?7?OQt'* <FS hgd 0vyebl=0!Il ; OQm!<.[S_ڷb'YB+gğ?#EJ;襆%s:w!MPɥ 4(}eX |}j\RhL2Fׅ/4 9&2^ۘQ> qҽհl<­ ?qB^i?P?` >N>/c#y؈ģ s3Ӣ8^uhҳsI^ו\Joݸ1;# zO9ŵۿ qsOrOMt=k-=}^ oy2uvG̵ 'ܫQSi)u m-ʒ(gY#AH(g44=O-=}^G5Z???ih_FI %Z;?q$E;Q;m:YX\]=N\ᵿVz+[#/ڟrievxv4w!Q?&I|L[(a1/?,{h*v޸[o>9е6캞8PB9!wzR^ջynsWܟ7-3*S2ujw*n>#i;C<̄Kee$OB?1[w/BZn”#Ϫ֬\x7by@_sIR/R2)MOQ EjrXDx^5%YD]ʨ#=}A> _,ӿ)MOQ Mjr\ʑ4YHbiHKG3hXn?LrSw#DiZ-=pBG89?4U0;vo-jVľ w<7n$.P68=}*rݮ݃j`G ǎJkamK-W{Ѩ6w}Iwn2/$^Mly5{U1i^X,-`Ŏye^s1Ҳ-quIDw*?w35x*GYl˸!#xOL[m!vbQ,ƍǡ# .Ah_/>ۗOSK ܶv&>R#5+xCJ{[vv/,2IROLJ_ƏIt Ei{o?ľiw"Bnc|<9+iY0ȣK+)C7_Z .Ah_/uS݉=oğ?#Epon3hs*Lv^qEuFn:}-y-ïψhdX!wH\ȅ@HՂ Cu0L䵭3mnEN5?|S1XMUT,ܮ-~3O xvxOFb2hf3 , F3L4kXi1(,O^϶^Ig]**nN&{?fmq87O?7^ux2޺J2ZZ.ϗ?>"ΝK/=|Ǚ6XDw|Wcg32mmz{էB@nCg$#ޭ-d3 `NsJ8I~sMJr%M]Gbpyu[9&5}D2B7(O*eitADf8/ֽ6EuC7_o?5a|Y࿍4sd/P&&˓&:8? R9T+kQ_b2-eguȇCBXf1a}G6kWKyQ"ΝK/=|Ǚ6XDw|Wcg32mmz{էB@nCg$#ޭ-d3 `NsJ8I~sMJr%M]Gbpyu[9&5}D2B7(O*eitADf8/ֽ6EuC7_o?5a|Y࿍4sd/P&&˓&:8? R9T+kQ_b2-eguȇCBXf1a}G6kWKyQ5_<8[4cVZ=w_K_{GQqӯ}!D.lzw[xG&54;{ 5w\}ku~u)駳} ؕBjtSv4e鏆Snj<'oW!&@nƳk<&p_fKs8k(N54ogk5wu?q8?ߩЫ7o5ˣ](&4+MOacl麟 z\lAyq yJ'í6?Z^e&hYssp~~eaq>~,|.otfjpJJc_gXc^Mz+=9ms998ӊKZ)^ˠNEzjw0xUO3vwm:כhz>&-{B# 8ฒM?6 ~fH|]q' Ҝ\x~)ΙݱfB/I j+VWKSy,z_p:q;nVJ_)Rԅyw_b{5e_CkbKx7bovFN,Ű`"BklY|4kI>,h$6-ϝݾ̏7^)k7ۦ/4yh|!Nڮ_sMnŴ߯O#R/j~}ȭN-skY|շ_}rydx?ʾj=U?ξܞu^)k*F_ _W=#*gԶoF4kk&|2Xo5Eύ׷w>/yS,mb#24F8 cxZiR߇oүmq6s+j>k:w?AK]MoFH!Ʒo^xVnxqbt`0̡[n5+駶.hssb(NJg}+jK4CCqѝLWc{lTv嵵{x%GA;e_-xm iǒ-N25D?w?ld_oS߳%cq8 3L}?}kq'& IV l/8>&ண+Rz&Nܬ &7?5w\x?InhNHwW[9`db8Vt,#گKϼlqkB)# f ˸c|w~,{U?/YV K|ek\d=?$gm˧,Q[K!e鄨gokZG++`n-{=Z/^ږya Iun-^_`ȯ VCJGKؚXRb}e\PY&ҭr˖ ?u >~B<͜B6gJjU<7i2S.m]`+kVy?o7n1(G^.O*NcoQN~oca|YS <) K sr}W*r5.##o39'T&bQܶ-pڒnGY$g<ܞwV)h5{on%lISfln|)餲mrYVF#<ʶ9Jf=VkK8o8y(prswJCKۋ2 =;+`O<ԟ*W%?o/n>*6vI 9sdL4?%Mx'xa ZAzErfiw7? ? (?p_4^Ko(1Exﱃ8,O {O#%Uio Dr.yQ] -'TP F0E/oaD߀")RP%"# ^7Eٸ__l?> ӼI*pZBrs7<'_ SE^iZ@u,D@EӅѯNJ:u}י27  JFIF``C  _rp>Snj<'oW!&@nƳk<&p_fKs8k(N54ogk5wu?q8?ߩЫ7o5ˣ](&4+MOacl麟 z\lAyq yJ'í6?Z^e&hYssp~~eaq>~,|.otfjpJJc_gXc^Mz+=9ms998ӊKZ)^ˠNEzjw0xUO3vwm:כhz>&-{B# 8ฒM?6 ~fH|]q' Ҝ\x~)ΙݱfB/I j+VWKSy,z_p:q;nVJ_)Rԅyw_b{5e_CkbKx7bovFN,Ű`"BklY|4kI>,h$6-ϝݾ̏7^)k7ۦ/4yh|!Nڮ_sMnŴ߯O#R/j~}ȭN-skY|շ_}rydx?ʾj=U?ξܞu^)k*F_ _W=#*gԶoF4kk&|2Xo5Eύ׷w>/yS,mb#24F8 cxZiR߇oүmq6s+j>k:w?AK]MoFH!Ʒo^xVnxqbt`0̡[n5+駶.hssb(NJg}+jK4CCqѝLWc{lTv嵵{x%GA;e_-xm iǒ-N25D?w?ld_oS߳%cq8 3L}?}kq'& IV l/8>&ண+Rz&Nܬ &7?5w\x?InhNHwW[9`db8Vt,#گKϼlqkB)# f ˸c|w~,{U?/YV K|ek\d=?$gm˧,Q[K!e鄨gokZG++`n-{=Z/^ږya Iun-^_`ȯ VCJGKؚXRb}e\PY&ҭr˖ ?u >~B<͜B6gJjU<7i2S.m]`+kVy?o7n1(G^.O*NcoQN~oca|YS <) K sr}W*r5.##o39'T&bQܶ-pڒnGY$g<ܞwV)h5{on%lISfln|)餲mrYVF#<ʶ9Jf=VkK8o8y(prswJCKۋ2 =;+`O<ԟ*W%?o/n>*6vI 9sdL4?%Mx'xa ZAzErfiw7? ? (?p_4^Ko(1Exﱃ8,O {O#%Uio Dr.yQ] -'TP F0E/oaD߀")RP%"# ^7Eٸ__l?> ӼI*pZBrs7<'_ SE^iZ@u,D@EӅѯNJ:u}י27    C   2)ќyKNO׼0<|?='Ƹj/}Gd>cc8ע ;6v.Z)+?EI<_XNz?$7;/;}-ٚwZߵ >sɿ4}ckvٚwZߵ ?4k}chu&4kfik~+u&M})i:$5UdPOO5=FڽЯutu/8um VC6'=qn.~'`G>*|? a^"-@*aS~+?|/6 q]EgK!a6p)3UfPZZ\]-PY$3 88jYK}Ra۱an:=EZ3KOEUu`M89ǨJ-n!k-YcB3(`•'ጜ kj.Dm*6azM}NFTO.&#*Ip 3OM:85U6ڀD" Cy{?O~ieZ\j~tطlrIintbg8s꧌`uZSΆ$v *: c DU YxKhX><w?Od5ĺ2i..kdqp*ƹ MCMU?zبz o ,pc5k:Ĩ`E V[S.L@UB]/#4O׼7(6_׷F_ %dt2J ` -ǥA2ܵly2FrIUtUHuLp\B,m%z?AzVK1%[3 ya#-zȺ 6HX;U_kcqbgXDD4g ~e3MկKKm4$.P:?=yjJἾfFYVhU g-v?f^kZ u!ڿOț-gOe[yŵYR8˴d$Ēi* 3Ji!Sye7 Y pE(Gþ'i5kKye3:yqxN@X? ׼ :<>,[ٵ #3\x-&qYTA?NMkk?O"hxWk}n Hdb, zg$|oQV]U3EH6 JvKdx .??jXHbr}EBvw,D>%^]tHmr21׷Q\/$K8HgeeZ5q>6{euP Op@<(/kڴ}=snnl/S .??_/U7uaW4KHf.5i&#,v.Wh:z\o$K8I; ViZ QkZ2IU $ <~s@{%Կ_//5(z}SsUש/c0`"/kڴ}=snnl/S .??_/U7uaW4KHf.5i&#,v.Wh:z\o$K8I; ViZ QkZ2IU $ <~s@{%Կ_//5(z}SsUש/c }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?4KCKwx&|+}:w-|G|Q:Ng."k٤Jw 1<ܘГTzQ| Fm%>gJLJ\|$$ 3D2##sn܎3JQ90}8/УR}-KVRMȹu"KU߷_¾R#?&|)hKy[Udf8oCo_LƐ?ק^:ҥ/\y f *K :u_ڞ-9wh )* @9=<:W*4Ӗ%3__Wv(?fs /7;~o:tqۨ\}H]fR\!t-o"DX1$|0heljl`eIY Ka9^2:W/O'TIAU? 5ˈUO+$tRQRo|E״{\U]f$t(|cC=V qe"vsmzWo4O_K_ҵ4Y{Cm8^| Ug+jF_j6m鉩捧~c~0Zz3CDm+6с{a6&X8\o5[OQ'Vx_C'i6od^<{ٜ;/2g8k$Lu}bjЃHf𮩨D >l멋F讙w$zEm>VӵY-COunYJ?+[{m>^( ռŰQp!zf%ϞzƕnZ]BmR8R5q@ :U--6-s ފ\`s]_u|K6[(Κ-…8$qN1ךϞ=,RFvCʓTMN6ǧ\pMu^ {8%eV#88' Gd[/\T8##0'<@S'|uo3JEM-n,\ r7`jv .;ؙ͸ci '{u江ۭ7[]ϙ31T 9<qTWtxb^kO,ЊK7 p=<.uo3|==u=ͭhg?ɔLrlcAuhޠ9@6k'NscjoCl3un.MRwH\|D?P_4BdmǘOcN3Mt?  JFIF``C     C   >`" }!1A     C !"#$%&'()*+,-./0123456789:;<=>?@ABEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~Qa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?GlNdM&ڸ C?m[P -.,x6j&>)(/4/z_*K? je*׈VFqI 6>}G>dRYcP{/G%5z 6>}G 6>}GoT?IgACMϻQtMϻQt{h)BU ^\=yygzE}nkzdVdPec##+bR{yFX̲?\։keepK01%R v5rhiY*AV$QBI'ZKim."x' b\wzZΏLWեŕZ]]v0G\3΢ڄ׷ $&S+%F/6i۝Gk#mgm \dt(n,{…t%F7~x{z,!o`1\9`A;B8@|>;缐A,;[nL태Q|"0{Wye;KE;!gx y|sgs<[iO°/eK a8 \')? mf@P㷘mu4vy3|!S'giC֛fou[F'1*0l 1g5ȿŘ sbRܴ]$EW1컆ʂ@=zͤ-VGnT'08ㆳ/ﲵbs1pͰ,|`|r?)jk -RxiBDNntܠe>^w 8cF>bgSK|f_<1̫#A ~sHQ񻩭j5[nC@ʩ0e:#vϴlk+r/؏T\ ]ubpU u)2y.팎*yM\-νDdzJLt""/ߗ?G~Ph"qiIm%vpX#Gd182H}ds'P[#D0-22 wȟŚME']G$H5hnk|D7$,J`d)z߇|wU4觳i%!Ę,wfDC݉0f??0f?ېrOېrO`\1?"*ܓGܓE>;4M'<9L}袓rI񪺮 ]jx]F@*}νD?Vf{*ě?!Óx>I7xA-&$>a֬Kw  JFIF``C     C   >`" }!1A74 84D9405)G Qa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?GlNdM&ڸ C?m[P -.,x6j&>)(/4/z_*K? je*׈VFqI 6>}G>dRYcP{/G%5z 6>}G 6>}GoT?IgACMϻQtMϻQt{h)BU ^\=yygzE}nkzdVdPec##+bR{yFX̲?\։keepK01%R v5rhiY*AV$QBI'ZKim."x' b\wzZΏLWեŕZ]]v0G\3΢ڄ׷ $&S+%F/6i۝Gk#mgm \dt(n,{…t%F7~x{z,!o`1\9`A;B8@|>;缐A,;[nL태Q|"0{Wye;KE;!gx y|sgs<[iO°/eK a8 \')? mf@P㷘mu4vy3|!S'giC֛fou[F'1*0l 1g5ȿŘ sbRܴ]$EW1컆ʂ@=zͤ-VGnT'08ㆳ/ﲵbs1pͰ,|`|r?)jk -RxiBDNntܠe>^w 8cF>bgSK|f_<1̫#A ~sHQ񻩭j5[nC@ʩ0e:#vϴlk+r/؏T\ ]ubpU u)2y.팎*yM\-νDdzJLt""/ߗ?G~Ph"qiIm%vpX#Gd182H}ds'P[#D0-22 wȟŚME']G$H5hnk|D7$,J`d)z߇|wU4觳i%!Ę,wfDC݉0f??0f?ېrOېrO`\1?"*ܓGܓE>;4M'<9L}袓rI񪺮 ]jx]F@*}νD?/g7d3s8)Cm2ze XWt)'3^ۤM}]@"9ҒQB C :),m5<5r6Fv݁9`JzWNvcԊf{Cyi&%?0㑁ȩe%k!&Otb<4K´S VV:ܖ_,~X3.@ >AwBH7\*ުJE,xm4x^H팥Djrsڲjp{3[FG$6LzGƫhxR_ܽʐ4xg'R_"1._nuvL.\dcg_Z_,I%|/^?'i N }Q[˴MUu >x21Ϩ\"nTܶ "7N G ;ݰe6O͂p2wľjkާMńwp E!`kb\"-?2o&]۪My,G|ҍ?xTaNXwt rѹ#STM#{.ySk)fbgEO*>{q>8e\3~uQOXeRR a^"U %:=䯫gkʩS? Y'52{4dxX4{{گ*;Ɵh7ջ\dV3n@Y::F~MzR<{5֑0 s'&ZݿهsWfjیO=U/3Yyi|>Td߭z_Y+s'>*hw|,ahnb4Z |r=+}T[Z4ۨ彋s.s럨kZ!ӯ7ZO䈭|Ǔ7`θgmsTZ]]Yv[u8Tȸ-zW .QVzަ}b#f*[8䞝}~kIxY;V/k;1is85Żàjm!-D|g;kBD"rU q'kۉMC/Bw*$;@sޤ_S/=oJj?iC%ż#8U4Þk)X_>X&]ēdN1}k>)DY <,.hn<>>" |vg<E?DRp`u>Օ/oRFMUDAԐ8ܐ*喯{]2eMv8%0g͕x9E׍/-×ӻ|{ 1,8 댭ߍ."I+۞!g" dn LgP_m$lH&U98`vbrÎW5;SS.ag3DK)F'Bs0NjxXWt)'3^ۤM}]@"9ҒQB C :),m5<5r6Fv݁9`JzWNvcԊf{Cyi&%?0㑁ȩe%k!&Otb<4K´S VV:ܖ_,~X3.@ >AwBH7\*ުJE,xm4x^H팥Djrsڲjp{3[FG$6LzGƫhxR_ܽʐ4xg'R_"1._nuvL.\dcg_Z_,I%|/^?'i N }Q[˴MUu >x21Ϩ\"nTܶ "7N G ;ݰe6O͂p2wľjkާMńwp E!`kb\"-?2o&]۪My,G|ҍ?xTaNXwt rѹ#STM#{.ySk)fbgEO*>{q>8e\3~uQOXeRR a^"U %:=䯫gkʩS? Y'52{4dxX4{{گ*;Ɵh7ջ\dV3n@Y::F~MzR<{5֑0 s'&ZݿهsWfjیO=U/3Yyi|>Td߭z_Y+s'>*hw|,ahnb4Z |r=+}T[Z4ۨ彋s.s럨kZ!ӯ7ZO䈭|Ǔ7`θgmsTZ]]Yv[u8Tȸ-zW .QVzަ}b#f*[8䞝}~kIxY;V/k;1is85Żàjm!-D|g;kBD"rU q'kۉMC/Bw*$;@sޤ_S/=oJj?iC%ż#8U4Þk)X_>X&]ēdN1}k>)DY <,.hn<>>" |vg<E?DRp`u>Օ/oRFMUDAԐ8ܐ*喯{]2eMv8%0g͕x9E׍/-×ӻ|{ 1,8 댭ߍ."I+۞!g" dn LgP_m$lH&U98`vbrÎW5;SS.ag3DK)F'Bs0NjxWX cJ痽̸F:(Kq* qw#@RuIXQw̢RUնQ':Y׈?玟~֧arij ? /G*0T]VkO?xx',§K ? /U:O3G#^ :Ih;,K?#@Ru⯆Ӽ3\&RAY?xx':ͮu1]=ujs:Q{IM;t7^JcOt k77//#b?g{/ٮd)-?%( -|sdL+U@HBqG]XHcB80-—R8 u  {--+*[@'#WBI;낦[.B1ZvW5 Z_^huy Ċזᐩ79okU\XYw:Vvvh03́㵃 s*ӵRvA4ԹspLe=S P:"rH8⻽6{RӭnƩ $ʛN*4-JՋC 7S5O s*\1fA_o;^yV}GumqٌX39>AVN^ZhϥIle|\\emIv$ФaiD>ARgPH;֓7 m9@>7wD&k"bWFU 2QIUkWO̺~$zF5GLFJœW-EԸ|(㴷VXbg#qFdb@=SUlt]Mm9l$d]0g II<ZX3oP;n=J'GB,C~A9AMT;#Ggfggq#)FǞN@9=t_\Ϡיҵ;|E[ WT.F2UG$(^},A˟翴ChҋOY%??14Ys>\_Qu!4{I #}?ƲS9<3Be8Rҋ:ZliAZS78D.V X>ɫЅu,z!C=Ùkgii盧{B  JFIF``C     C   .`"15 H 25! 35"JE 45#K         D                   ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C ~ F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | }  }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?m^c}-F($9瓌qˮkuNl)U;BeIR3{ WX cJ痽̸F:(Kq* qw#@RuIXQw̢RUնQ':Y׈?玟~֧arij ? /G*0T]VkO?xx',§K ? /U:O3G#^ :Ih;,K?#@Ru⯆Ӽ3\&RAY?xx':ͮu1]=ujs:Q{IM;t7^JcOt k77//#b?g{/ٮd)-?%( -|sdL+U@HBqG]XHcB80-—R8 u  {--+*[@'#WBI;낦[.B1ZvW5 Z_^huy Ċזᐩ79okU\XYw:Vvvh03́㵃 s*ӵRvA4ԹspLe=S P:"rH8⻽6{RӭnƩ $ʛN*4-JՋC 7S5O s*\1fA_o;^yV}GumqٌX39>AVN^ZhϥIle|\\emIv$ФaiD>ARgPH;֓7 m9@>7wD&k"bWFU 2QIUkWO̺~$zF5GLFJœW-EԸ|(㴷VXbg#qFdb@=SUlt]Mm9l$d]0g II<ZX3oP;n=J'GB,C~A9AMT;#Ggfggq#)FǞN@9=t_\Ϡיҵ;|E[ WT.F2UG$(^},A˟翴ChҋOY%??14Ys>\_Qu!4{I #}?ƲS9<3Be8Rҋ:ZliAZS78D.V#%-^GN{O U$tii5QQҷs JFIF``C     C   M`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?+' q1pW[ O.f.j?Lj7?k?yQi s[G3Ouo]~k~xd!r ~+6O ~+o3$pr oK O.f.?MjG4yv7OG=y/6_K$ ~K%Of.j??>.й^H3ͪ\Ldsa "caOJv<:iM3m!0CUK۲R[ԟȟ~|Fy.F)!؉tQl#8Տg j:oJ[۔e>` #Ҿ^mv}%aPvcp2قy}}+i&~'[ʑh&9\p+qN?9PU%Rm^k;꺞,p(;_[|CZᴿ]z7-mHs.O2p1Y:]E[_'Hc%+ARç/4,DimՉČp p ꢣђoU vlwN祘hI Y7>hXjUs]Vq|O+38>O. ` )JMj65+譜J@BcU 3Od[O _qrx#Ҵsqiy`$$q#,NJ `0'<~ԯ<5 ?ڗiu̖Y.,>zό<= կ}Y6Ie C^7u$KʎM&^7TM|-;+{D総G %OK1Ri+d4i,-*_?WW}FX8j6OF2goUs^4S_'AOZֶkMrV݊P%(Wgx[} 7#ۚh_]z=:jFTbLL}ёn+FwB2@纫Ͷ ;r./R5*M[Dײ59Z GyiҙB?w 2yw1'=s\%eke9NK%+w}qҽp`i%SB/zI6#˩xSJ.L0+&'pm4vI8$\ʬN0D i /o FWV4iKZ(,U`?h0xn&dDòNSoM{KXy"ׇtfc.o-.ed 1;r_눯[_-7&Yq[h,=:sUmZ;;qm')"`qVvb]DC{BXd7J4#}k/\JfgV2D2 +(5Ho#mSSI>CZBg;ɴk?|I6z_%QϼpG9V/ϵZ_k&iʋ: :7M؉}6NGҫ |Fo]ˀ7pp "߳0f8EXNz%^R#HJ Jה՟n ?^^SVɸ|E4 t? Ϳ ß v ؓ*M&&5#n9ۜ{~ux?=ZE5,ZRm9bǶU_Z²7藱lNq͕FsǵV&.UgKHGţQ[u [gf3_jVlN{(y(<ԉ]7|L[hm?~eR6@湡s*\U;Pm!Lo&EϩUďj(,2+#\7'-S'udgwhp8k 5tmw2/}P[jKVcI1;`犽i6Ԣ;bH?.A*+Ο|'(Ο|')O p˿ҟ-DIk""4G~UZ |wq03IIs5M?g_O׫W՟n ?]oDV:L>ҭzgM_xk 5#M{7kn89q5??N?gZr jy 2SNvli/y'-W0ӏ5s9ɡh}sc 6aӃYo}N)cN1q_)S53 +VS=MH_G7Z~_Z~_OWcT+OUϿMH__7[ywU*q=EgizUhֈ"NUA?N?w|+8:}G?g_O a$+\gO(,( `ӱ?g}@"p\+QR:Q[k0҃v^ pp̻FG_&~S+3 h&~U/Ѓ JFIF``C     C   M`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?+' q1pW[ O.f.j?Lj7?k?yQi s[G3Ouo]~k~xd!r ~+6O ~+o3$pr oK O.f.?MjG4yv7OG=y/6_K$ ~K%Of.j??>.й^H3ͪ\Ldsa "caOJv<:iM3m!0CUK۲R[ԟȟ~|Fy.F)!؉tQl#8Տg j:oJ[۔e>` #Ҿ^mv}%aPvcp2قy}}+i&~'[ʑh&9\p+qN?9PU%Rm^k;꺞,p(;_[|CZᴿ]z7-mHs.O2p1Y:]E[_'Hc%+ARç/4,DimՉČp p ꢣђoU vlwN祘hI Y7>hXjUs]Vq|O+38>O. ` )JMj65+譜J@BcU 3Od[O _qrx#Ҵsqiy`$$q#,NJ `0'<~ԯ<5 ?ڗiu̖Y.,>zό<= կ}Y6Ie C^7u$KʎM&^7TM|-;+{D総G %OK1Ri+d4i,-*_?WW}FX8j6OF2goUs^4S_'AOZֶkMrV݊P%(Wgx[} 7#ۚh_]z=:jFTbLL}ёn+FwB2@纫Ͷ ;r./R5*M[Dײ59Z GyiҙB?w 2yw1'=s\%eke9NK%+w}qҽp`i%SB/zI6#˩xSJ.L0+&'pm4vI8$\ʬN0D i /o FWV4iKZ(,U`?h0xn&dDòNSoM{KXy"ׇtfc.o-.ed 1;r_눯[_-7&Yq[h,=:sUmZ;;qm')"`qVvb]DC{BXd7J4#}k/\JfgV2D2 +(5Ho#mSSI>CZBg;ɴk?|I6z_%QϼpG9V/ϵZ_k&iʋ: :7M؉}6NGҫ |Fo]ˀ7pp "߳0f8EXNz%^R#HJ Jה՟n ?^^SVɸ|E4 t? Ϳ ß v ؓ*M&&5#n9ۜ{~ux?=ZE5,ZRm9bǶU_Z²7藱lNq͕FsǵV&.UgKHGţQ[u [gf3_jVlN{(y(<ԉ]7|L[hm?~eR6@湡s*\U;Pm!Lo&EϩUďj(,2+#\7'-S'udgwhp8k 5tmw2/}P[jKVcI1;`犽i6Ԣ;bH?.A*+Ο|'(Ο|')O p˿ҟ-DIk""4G~UZ |wq03IIs5M?g_O׫W՟n ?]oDV:L>ҭzgM_xk 5#M{7kn89q5??N?gZr jy 2SNvli/y'-W0ӏ5s9ɡh}sc 6aӃYo}N)cN1q_)S53 +VS=MH_G7Z~_Z~_OWcT+OUϿMH__7[ywU*q=EgizUhֈ"NUA?N?w|+8:}G?g_O a$+\gO(,( `ӱ?g}@"p\+QR:Q[k0҃vɺ<O/0JlIs&I b1 } JFIF``C      C   `7" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?? ~wz4BMn&71|]t2LdnO Bü gA&NҰGw}kK< 2][i6d|$c=skᨭlQh%jdzܹn8:RP{$HȲJT~oϐOS~:%.:a gM';WQ.WٺV֦u($\k$? m3Ի|FOIS@xjZ2]И6!ْ~֢>#OCxw+TiƟGQMoVoinе kdPeTڬ%|=J;OvҘ3\eJ*NwroE]e85%(A-"{.KEoe[ >lHmI|r}9;=2('&@g 8b{ұ<|ᗆthMٕ$#ymƎ%Хb85n#TzMv 8Z}վF8=rf4 (<OvҘOvҘиw_<Hsl,ϗܭ{c 玳ATR;heF}<GL^0 +uvr98Ǧ1tv6ZqZ9 8ϰϯ__֟*CUiR}ӫH:?G_Mndm~V00~JqZҼoqgLy&&z6yjGuxU.eDBH<[ߛZ7K/Vc$$F!0IFyoS=ml/mo{(?"GE~Ñ%ͧ$y5*rM[gWw>#&eA'易?}7,'-Vu n2"ێ e/߅7mx8OR?@GK%|dCL%VU,iZ~WЎZSȃIiY_"q yc A .K;U4(FN#9$}tZ߮GќAC Qs.0}+9K]/4iW܉4tE ͥ#a1ok_-:AWo<"SĦHiw:'jFqyӵBW6aF0O\uG3?cOWy7m _D#fەP|EIOJbAWg#1U39!OmT q[=:c77rm.RX2:.Oc{׆o@~Y{m=q }#id#: 9 oAu?W?ztjfW  g$`幖2n`Kw op*kŸh=SL +ۼ;CI -液 ،-uRrqvNX8~߆B'T|1 iu.qb}@SǂnпeG-ݡ/*=_s6sO[ B_U<Cv(=_sx9{HSҿ-Zӭ5.H_̂ V/2xҩ,?6QuC } JFIF``C     C   `7" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz55$ 65 75&N 851O j  w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?? ~wz4BMn&71|]t2LdnO Bü gA&NҰGw}kK< 2][i6d|$c=skᨭlQh%jdzܹn8:RP{$HȲJT~oϐOS~:%.:a gM';WQ.WٺV֦u($\k$? m3Ի|FOIS@xjZ2]И6!ْ~֢>#OCxw+TiƟGQMoVoinе kdPeTڬ%|=J;OvҘ3\eJ*NwroE]e85%(A-"{.KEoe[ >lHmI|r}9;=2('&@g 8b{ұ<|ᗆthMٕ$#ymƎ%Хb85n#TzMv 8Z}վF8=rf4 (<OvҘOvҘиw_<Hsl,ϗܭ{c 玳ATR;heF}<GL^0 +uvr98Ǧ1tv6ZqZ9 8ϰϯ__֟*CUiR}ӫH:?G_Mndm~V00~JqZҼoqgLy&&z6yjGuxU.eDBH<[ߛZ7K/Vc$$F!0IFyoS=ml/mo{(?"GE~Ñ%ͧ$y5*rM[gWw>#&eA'易?}7,'-Vu n2"ێ e/߅7mx8OR?@GK%|dCL%VU,iZ~WЎZSȃIiY_"q yc A .K;U4(FN#9$}tZ߮GќAC Qs.0}+9K]/4iW܉4tE ͥ#a1ok_-:AWo<"SĦHiw:'jFqyӵBW6aF0O\uG3?cOWy7m _D#fەP|EIOJbAWg#1U39!OmT q[=:c77rm.RX2:.Oc{׆o@~Y{m=q }#id#: 9 oAu?W?ztjfW  g$`幖2n`Kw op*kŸh=SL +ۼ;CI -液 ،-uRrqvNX8~߆B'T|1 iu.qb}@SǂnпeG-ݡ/*=_s6sO[ B_U<Cv(=_sx9{HSҿ-Zӭ5.H_̂ V/2xҩ,?6QuCen8줻KD"UE;ymk>Ƈ̒~t}™ JFIF``C     C   0`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?nj% aV$rI'\S^˘oޛ}xC,"hϩj&1*IMV*x#D1Dݜ:>8җ}NhF_֢Iq?ZI$T+ j,]JOO7O]>Has8 Ч.ddxj;7w~ o5-ġI| F8 h~,d=Jյ@Z1" H8]I -# ꝍΙw-kİmR4Pճ_r!'?QF>?{w/n俚Þ]ȣF>?B?SL𮧨Z\3qhȤ >kK [5#K#+Zb;C:ZӓrWbiX4NdCp9V:⳿id|яsCJ|1dgX%U<_gvqV'uqF\qҦlvz$Ayq <O_4v\ڋwFNBl^FjYOa, B$7T?MMjW6ty22lr rZM%{'9\j6Pj~{0O9V9>jZZ#plO^H]"w=4'w?1NYj$h7Pڳ<:f&lY5#15h ݞAfPkN~cǿƏD?{hKaFQM^MмAu=-4{]MB0r0}JLn%U^9Aj7G-[]$j:߇΅! X\gYڸk}td}9~Dhkx;/2~![me.{ƣQSm])E쭡hjZbYJgoN+uw3.ZGwoen`OާcPdOzηQk嘵UO3:3bd"ܛ-b0|VGM'iKi#Q|E@*?* 1iS=ӱ[{K}P;0iI'n;Gb&?*Ư"$ZyAڣ{5/A75mؤOv .2p3WtݺΑm5ޛs 2IU5@#PMoND)]DJYo xG" 6$b  @ vdz`ymm _%紿q<C1T_ ZVt|UigO'%'[gG#r'eῆh=C&< JFIF``C     C   0`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdef                         V ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~  ghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?nj% aV$rI'\S^˘oޛ}xC,"hϩj&1*IMV*x#D1Dݜ:>8җ}NhF_֢Iq?ZI$T+ j,]JOO7O]>Has8 Ч.ddxj;7w~ o5-ġI| F8 h~,d=Jյ@Z1" H8]I -# ꝍΙw-kİmR4Pճ_r!'?QF>?{w/n俚Þ]ȣF>?B?SL𮧨Z\3qhȤ >kK [5#K#+Zb;C:ZӓrWbiX4NdCp9V:⳿id|яsCJ|1dgX%U<_gvqV'uqF\qҦlvz$Ayq <O_4v\ڋwFNBl^FjYOa, B$7T?MMjW6ty22lr rZM%{'9\j6Pj~{0O9V9>jZZ#plO^H]"w=4'w?1NYj$h7Pڳ<:f&lY5#15h ݞAfPkN~cǿƏD?{hKaFQM^MмAu=-4{]MB0r0}JLn%U^9Aj7G-[]$j:߇΅! X\gYڸk}td}9~Dhkx;/2~![me.{ƣQSm])E쭡hjZbYJgoN+uw3.ZGwoen`OާcPdOzηQk嘵UO3:3bd"ܛ-b0|VGM'iKi#Q|E@*?* 1iS=ӱ[{K}P;0iI'n;Gb&?*Ư"$ZyAڣ{5/A75mؤOv .2p3WtݺΑm5ޛs 2IU5@#PMoND)]DJYo xG" 6$b  @ vdz`ymm _%紿q<C1T_ ZVt|UigO'%'[j;1r8᳃:Ӽ<K"@q?+C˗{\U+O^߹yV>]6DyVd{UV#|3+m_O īN#p  >/*OЩA~ڧ2# Ot-NK;jyȏm2~f\ɌB@Iz-WL:ot`́ñ>)u=SOH@i"MRkltmOE6{moRi7[-jw~h5kRBۭh\'79WiDIm[|nX>w#o xŶvP\ew ぀Ǩ%6[K ]]O iȬBއ54InUyK#(vg-߹#8\zw亚R=wiB|I Y\߹ TF*=W\0h$1NѤ,-1ц 8)+kv%|D/QT~!p$I U;r;`Fh(xƲn= lXFFF ЃP]/\]KLִxS4%$}W|n %۷te9*YGzѪxZ檖͕k)[e2AcۚҜwDy,:vS_gIVi$1!XJ*^- x $$;ߴ>nOY'M $r"\3ڰ4˿鷗-$qb',}h,О;VKB4:LXxWˊ?Dt*41~T@$NYzQE`X<=M>$,b WFxNN֗,Jɇ*Ap@?Q( A4_ 4de2>HEA6 II>l~~xfBGJ(DAʷ= 3F C ~O#4qcWm0@& +Tn?3t}MV_#1Kgo<7kU3]cj.cɺ<O ^ JFIF``C  95(PW j 061626 *     C   D`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?El ::zʐ-y 0:w*oJ>j;1r8᳃:Ӽ<K"@q?+C˗{\U+O^߹yV>]6DyVd{UV#|3+m_O īN#p  >/*OЩA~ڧ2# Ot-NK;jyȏm2~f\ɌB@Iz-WL:ot`́ñ>)u=SOH@i"MRkltmOE6{moRi7[-jw~h5kRBۭh\'79WiDIm[|nX>w#o xŶvP\ew ぀Ǩ%6[K ]]O iȬBއ54InUyK#(vg-߹#8\zw亚R=wiB|I Y\߹ TF*=W\0h$1NѤ,-1ц 8)+kv%|D/QT~!p$I U;r;`Fh(xƲn= lXFFF ЃP]/\]KLִxS4%$}W|n %۷te9*YGzѪxZ檖͕k)[e2AcۚҜwDy,:vS_gIVi$1!XJ*^- x $$;ߴ>nOY'M $r"\3ڰ4˿鷗-$qb',}h,О;VKB4:LXxWˊ?Dt*41~T@$NYzQE`X<=M>$,b WFxNN֗,Jɇ*Ap@?Q( A4_ 4de2>HEA6 II>l~~xfBGJ(DAʷ= 3F C ~O#4qcWm0@& +Tn?3t}MV_#1KgU~ WF?U3]chsp^&^Iw~U?ۚx_H_YxwKxm#GC _?~ӿnkaɏ\[  JFIF``C  JFIF``C     C   \`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?#_|Zѯ|EmExkoX5mW}ʹڦ߂IJmgmH6q%P^x8?+x~4u=>);kC; XsWYof$nH#X38S0Ms>XR\GT޽4~Y<*4,.թz;#K-oInu+5ǘWdHeݼ3\  )u ]d^|܃姗 q dc88~ҮEşċ{,|ʒ##|2ÏZ4VI%uo" #&w?} -I("NZXv8謼wcQȵ}&O;3]".Bn$~N@# L }kЕ1# o'$i$pΦ^mw!i%2|YvHGk/jz/Z1id_?` r$ƙ`Wcsz S ?'MJ-W.eOW˰yEzXx%n׊|\wz/C?Hw? mzy x!B Ƶ W}8瘯OG3 O+8_+׼C>C9!vlF|ϛp'>>bzޫhkN[$$)97u8瘧-HAȯ6Q~!- >";1ͥmLw,@G_V%<0YXa\ z^eMj76V1&DC')e V.@5¾sѧte͞ RNra3.RVΊ Wc 5bW(?WVzu'{vB)B;#|? &]sjغ" ˞b|/Ro1$h7cXt:vkM0¼|LY÷Jԟ(_VKJݟtE Hw? mza?/)vQ^arß _PVcX|%ՁmLrH oxcA|Aqih[-ט7g>UTztQk>E8=3SrzD1rSS@y }@#[JbLG+'%Qj.1MgE(\Si"XӬ|K{F6nٞYOkU*WD'} YzV#^%}K5__ԿNYatmm|+ 'X@G߈NڟWy} Qh$up1F*KAfUO'cѣi,6ۖ-';bxZ+̹bxZ'=gObGRpAJ/厄5æoCӋ5$dݜ;-%Hn6I"T||qEynL]ddIG/#h^;MCs6ϬT+L_yt]m5/m%M+!ﱋ 'WEN5]'ŧZ?-?֟Oa(U念:Gh7H 8+ݿ-?׋~71~Ͽ'?\Z_t}ѝ_N"x,WW~vVXbr7\o_SڟWMEC[(-X8:'R ;ÇU:dH϶v1ǂr؉@̊ Ⱦ+kֆO)UTu%Nz.no7_ܷSx/F- i[Nd!@ÂbBZFY_ ݿ9Xg pC).fh;=REOHDhZE4Q2%iU-/y#pFAºg7?"?TksKփ>?^MU֚ 88z'X@ C'/šFacƲӭqO5> }N?񕱕Fq<6>(B-=_E~Y~-χ?o=G _Q㿞{CFgO);kC; XsWYof$nH#X38S0Ms>XR\GT޽4~Y<*4,.թz;#K-oInu+5ǘWdHeݼ3\  )u ]d^|܃姗 q dc88~ҮEşċ{,|ʒ##|2ÏZ4VI%uo" #&w?} -I("NZXv8謼wcQȵ}&O;3]".Bn$~N@# L }kЕ1# o'$i$pΦ^mw!i%2|YvHGk/jz/Z1id_?` r$ƙ`Wcsz S ?'MJ-W.eOW˰yEzXx%n׊|\wz/C?Hw? mzy x!B Ƶ W}8瘯OG3 O+8_+׼C>C9!vlF|ϛp'>>bzޫhkN[$$)97u8瘧-HAȯ6Q~!- >";1ͥmLw,@G_V%<0YXa\ z^eMj76V1&DC')e V.@5¾sѧte͞ RNra3.RVΊ Wc 5bW(?WVzu'{vB)B;#|? &]sjغ" ˞b|/Ro1$h7cXt:vkM0¼|LY÷Jԟ(_VKJݟtE Hw? mza?/)vQ^arß _PVcX|%ՁmLrH oxcA|Aqih[-ט7g>UTztQk>E8=3SrzD1rSS@y }@#[JbLG+'%Qj.1MgE(\Si"XӬ|K{F6nٞYOkU*WD'} YzV#^%}K5__ԿNYatmm|+ 'X@G߈NڟWy} Qh$up1F*KAfUO'cѣi,6ۖ-';bxZ+̹bxZ'=gObGRpAJ/厄5æoCӋ5$dݜ;-%Hn6I"T||qEynL]ddIG/#h^;MCs6ϬT+L_yt]m5/m%M+!ﱋ 'WEN5]'ŧZ?-?֟Oa(U念:Gh7H 8+ݿ-?׋~71~Ͽ'?\Z_t}ѝ_N"x,WW~vVXbr7\o_SڟWMEC[(-X8:'R ;ÇU:dH϶v1ǂr؉@̊ Ⱦ+kֆO)UTu%Nz.no7_ܷSx/F- i[Nd!@ÂbBZFY_ ݿ9Xg pC).fh;=REOHDhZE4Q2%iU-/y#pFAºg7?"?TksKփ>?^MU֚ 88z'X@ C'/šFacƲӭqO5> }N?񕱕Fq<6>(B-=_E~Y~-χ?o=G _Q㿞{CFgO^|AaJ^+}䃑QG3Q]74Zmx'eTBGPL9Gj a?/ l?kZZj[N̂H2sRd?G3Pӹ a?/ l?Nd?G3Pӹ!K;Y'ԅcq_kMFVIiz[Q[K@@HVܧ8\}Zu*rJoaA,kiQzVq׹-k:*ipj开l'ʆ\ di0Gs )<7#A*+ Ğlg%Lnvo',/췒ٹK\?/L{r棵'o! s:$Oqwӌ솶e/s1n7Ɵ2!_{t zs5Q厫eވ峻ӯ忩I揳 /(3$~5$(}8c* 6 =>o`cQ+lY ՟/Q̻Af_D8a$(*" ˿?&< Ϥ_G(] 417.ߘ1>;_?/ow˿?&TsNj5\!ZʪqGE_ D"> xT* -I4ͭ(-VǚY]mW[gDvҕ؁ߏ}=?Ʊu(n!YWSD?s<c@5FJ'2\wqOus/iMchZzeu68c6 = O 8M2'NF7~7Jy5>֞GckwLm4h.tˈTL 8k{X߷6_1?7Ə6o4}b=ٳۭk^OnGlqk Wٝݏ5c?Zjf샑SoDEqUa jQbT6 Q@Da? ݭt3Y1\FQđy{s[z6k!tvdiSqg1Aagx| >( xѼ+}jV4+ -⸂Byѱ`{~|< Q&ֵ)JRm I$}E|M55Eɴ|'@gmggخd}E|M55Eɴ|'@gm}l_|'@gm_ 3YD_G`G4W_ 3YD_G< Q&g9q?H\O "oᏏ-{ia[u5PmD)ąkJt]dG G>؆ C {AsZmOs5Aӵ̰B,*$T;h  JFIF``C     C   ^`" }!1A36 46 56+ 669W] Qa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?wG Z}Infi"rO;,,Oľizx~œLNz]mwLճ0B*Mm\- HunigQU$KeX1b2pb/O_}1D8C5R6FX/vq?\WBoZnCee-ϐ`l3no 9ϕ,}ζr|1bC@$EF퓞^.QxOi #hL2N=1zb2>^|AaJ^+}䃑QG3Q]74Zmx'eTBGPL9Gj a?/ l?kZZj[N̂H2sRd?G3Pӹ a?/ l?Nd?G3Pӹ!K;Y'ԅcq_kMFVIiz[Q[K@@HVܧ8\}Zu*rJoaA,kiQzVq׹-k:*ipj开l'ʆ\ di0Gs )<7#A*+ Ğlg%Lnvo',/췒ٹK\?/L{r棵'o! s:$Oqwӌ솶e/s1n7Ɵ2!_{t zs5Q厫eވ峻ӯ忩I揳 /(3$~5$(}8c* 6 =>o`cQ+lY ՟/Q̻Af_D8a$(*" ˿?&< Ϥ_G(] 417.ߘ1>;_?/ow˿?&TsNj5\!ZʪqGE_ D"> xT* -I4ͭ(-VǚY]mW[gDvҕ؁ߏ}=?Ʊu(n!YWSD?s<c@5FJ'2\wqOus/iMchZzeu68c6 = O 8M2'NF7~7Jy5>֞GckwLm4h.tˈTL 8k{X߷6_1?7Ə6o4}b=ٳۭk^OnGlqk Wٝݏ5c?Zjf샑SoDEqUa jQbT6 Q@Da? ݭt3Y1\FQđy{s[z6k!tvdiSqg1Aagx| >( xѼ+}jV4+ -⸂Byѱ`{~|< Q&ֵ)JRm I$}E|M55Eɴ|'@gmggخd}E|M55Eɴ|'@gm}l_|'@gm_ 3YD_G`G4W_ 3YD_G< Q&g9q?H\O "oᏏ-{ia[u5PmD)ąkJt]dGb$%ԅ[7-xpb3F$U$ gח_Kq;ﶧi  JFIF``C     C   Q`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz                           ! " # $ % & ' ( ) \ , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ ^ _ ` a b c d e f g h i j k l m n o p q r s u v w x y z { | } ~  w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?md枺LzMHK5 Wh:>]rFQ4f qX^gDb4kO{W7SןRޯsHrxnQHnJeD[ p0 =3x.O:UЌo;#=YP̳591$)Ǔp~SZjG]O—6 R{ڻg:UcF<6#}_Ila9ccw w눂G;˿ˌgV.s# 0F꩙Og=[](HLŹ!78W/&O a}ވkygX̘ąp '?"vLy!Fhpo S: Q4s%oE| <"T+_>NC3T_MNC3T_M{[_Us/4Kknz};gx,{?nfo ::8o.~n;`2kjUji8FQ:;&w$~cC dp -׋/??U|o67:5mBxN&Ko(Fl`Ax_>u.-5RDyE";pJ-Q,22E R ןS]{)DN@?o_kz???oYo:3Xןk^N@?o_kz??Vm}[~k/3TOeg&]!T?ן J]RGM髅d..̩CIE$$*vrp:U |7nʯp-įKll}*Yh*(UNɢo p1dqKŒżH$+(4)lcF@׷i15 srl[y0fSۖ>=7뤵}$a4|Lvu u!^s/51(ǰQ7$ס(ERYnf]yn,4H5kS>y rOJu9'E)k,vP8eamo$]IkO.7@cXͷ{{K񣪌#u.] 9>FKktM]#r g*ҿF?o /vs_پGoi_kWK@Y_U7EQvs_پT =Pk-R@#]eU|5\!2c!~SZ cE5{'o:41ĔRLG"xlF1¼.^2H"FNJ-R@t;mU?:rH99Gy5J՜LMap߯+;&E2}+lxd|b-{iaXMyخlfim7`| ^蛬&[k7dF֓kvPz]VQ]I23:G"?4-j ήlcj{Qy=+;ȏy(#i|ڼm^c #i|<"yw #Gj{Vuk I\[H#i|ċ"y9ZSֽIќ|Qock 0wQQ$0@8v5c}Ksmϣ"en]8}5E\e bo~|Bexkw%>\V7.~!6-$:`1rɐw7#[~o5zhdf!~gujuO+/;vi~&յIeq%[o\aO^d@?4/РŵڊnkbG?*[Tuڽ}*'Z2Hj-2Q\fEPTj'jR? ׼ )q&[3GEpOU(gR#𠢊+2((( ()qg?>ڟkc'Mfޮ\ߘ A(9r0.|h5  JFIF``C     C   Q`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?md枺LzMHK5 Wh:>]rFQ4f qX^gDb4kO{W7SןRޯsHrxnQHnJeD[ p0 =3x.O:UЌo;#=YP̳591$)Ǔp~SZjG]O—6 R{ڻg:UcF<6#}_Ila9ccw w눂G;˿ˌgV.s# 0F꩙Og=[](HLŹ!78W/&O a}ވkygX̘ąp '?"vLy!Fhpo S: Q4s%oE| <"T+_>NC3T_MNC3T_M{[_Us/4Kknz};gx,{?nfo ::8o.~n;`2kjUji8FQ:;&w$~cC dp -׋/??U|o67:5mBxN&Ko(Fl`Ax_>u.-5RDyE";pJ-Q,22E R ןS]{)DN@?o_kz???oYo:3Xןk^N@?o_kz??Vm}[~k/3TOeg&]!T?ן J]RGM髅d..̩CIE$$*vrp:U |7nʯp-įKll}*Yh*(UNɢo p1dqKŒżH$+(4)lcF@׷i15 srl[y0fSۖ>=7뤵}$a4|Lvu u!^s/51(ǰQ7$ס(ERYnf]yn,4H5kS>y rOJu9'E)k,vP8eamo$]IkO.7@cXͷ{{K񣪌#u.] 9>FKktM]#r g*ҿF?o /vs_پGoi_kWK@Y_U7EQvs_پT =Pk-R@#]eU|5\!2c!~SZ cE5{'o:41ĔRLG"xlF1¼.^2H"FNJ-R@t;mU?:rH99Gy5J՜LMap߯+;&E2}+lxd|b-{iaXMyخlfim7`| ^蛬&[k7dF֓kvPz]VQ]I23:G"?4-j ήlcj{Qy=+;ȏy(#i|ڼm^c #i|<"yw #Gj{Vuk I\[H#i|ċ"y9ZSֽIќ|Qock 0wQQ$0@8v5c}Ksmϣ"en]8}5E\e bo~|Bexkw%>\V7.~!6-$:`1rɐw7#[~o5zhdf!~gujuO+/;vi~&յIeq%[o\aO^d@?4/РŵڊnkbG?*[Tuڽ}*'Z2Hj-2Q\fEPTj'jR? ׼ )q&[3GEpOU(gR#𠢊+2((( ()qgUT3i-m!K0T۝+(/<5;'M'S{ݼ""' O֯]s JFIF``C     C   `" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ? A]b-feG?7:j4K%Z>*2%#k aj4Holnݖ1dwTx@۴ק< "]3O&o"X")RH%cϩ^m:tRfrql{M49\Xzǽ:_IefK鯡z_!AzB*DIE&hl4D5&12!;i qkoHy?^!Az9#.;DfmC[;g#n:wWKRjb >q |rKٮHy?^!Aznw mn=lZIş%ƙ;8G㤒̯&kRNZbOפ5(y> /Geq̐:N:i'{rڋy)[sN)n]ɭCmfxeq` XDo3L?# 6ݛִ$4g~c+$0-X]fYkmc 9I&mOfOW4,imOS'Yg~c(?5K4O߳Y?1}4O߳Y?1}4Oj:V.7)*鬟 kچ2HFA}hV JFIF``C     C   `" }!1A76t 86 $ 96 $ 07=Q  # Qa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ? A]b-feG?7:j4K%Z>*2%#k aj4Holnݖ1dwTx@۴ק< "]3O&o"X")RH%cϩ^m:tRfrql{M49\Xzǽ:_IefK鯡z_!AzB*DIE&hl4D5&12!;i qkoHy?^!Az9#.;DfmC[;g#n:wWKRjb >q |rKٮHy?^!Aznw mn=lZIş%ƙ;8G㤒̯&kRNZbOפ5(y> /Geq̐:N:i'{rڋy)[sN)n]ɭCmfxeq` XDo3L?# 6ݛִ$4g~c+$0-X]fYkmc 9I&mOfOW4,imOS'Yg~c(?5K4O߳Y?1}4O߳Y?1}4Oj:V.7)*鬟 kچ2HFA}hV<I?¸?xSOw6 `{f:л0¾s n"  JFIF``C     C   D`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?_#dzB:6J{W*7=wc9_-n~/lkXLfX7x&1H9<xrw Z T:z4FB|-AU.gGVzk +Wx;,R [!%rvgcs36:E{ }Im|sEX<}si`!FlJỤn[ӡO?%ծk&0.p(8TWVOK)(6秾9Gs3u-|?meM5?guzx;MQMA y+lg^=s3ο+{@_^={gk^7WWZz-{a:ֽnTkBbLշcI?5TQc݇3<\_/=/8;B >kl|]vï2Fᡖ=%G.\nۛZ)`;G MGLҬg\4*^=>'**RO޸ >kմ<6~0pH8TM͌ ėwU58e&KeK * @.˹ 01_cO?۝ǹ85b ( (<Ķ^;] QaF& dC6!gQWK7VOl|dC`(r28MwH|UKx: vڍ*bFbs"FJiSZĺş$c0WH5kb\m؉d#h.rA{.Z="_jVz"VeĂk#EiM;HM6ݑྲྀv|Q=<+ QF|9[$n< Gm3LծumDׅ# a;Uw{u){hmLS!=Qz3>PGCD `aw8Ҹ}g>蠽T2\(6pTHiuud+[hw<>1_JpAqKXe-.R$e,g'oEPEPEPEPEPEPEPEPEPǏsI!OLթI-Y u$ ?.s$^{oZ5k+;k:$  JFIF``C     C   D`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?_#dzB:6J{W*7=wc9_-n~/lkXLfX7x&1H9<xrw Z T:z4FB|-AU.gGVzk +Wx;,R [!%rvgcs36:E{ }Im|sEX<}si`!FlJỤn[ӡO?%ծk&0.p(8TWVOK)(6秾9Gs3u-|?meM5?guzx;MQMA y+lg^=s3ο+{@_^={gk^7WWZz-{a:ֽnTkBbLշcI?5TQc݇3<\_/=/8;B >kl|]vï2Fᡖ=%G.\nۛZ)`;G MGLҬg\4*^=>'**RO޸ >kմ<6~0pH8TM͌ ėwU58e&KeK * @.˹ 01_cO?۝ǹ85b ( (<Ķ^;] QaF& dC6!gQWK7VOl|dC`(r28MwH|UKx: vڍ*bFbs"FJiSZĺş$c0WH5kb\m؉d#h.rA{.Z="_jVz"VeĂk#EiM;HM6ݑྲྀv|Q=<+ QF|9[$n< Gm3LծumDׅ# a;Uw{u){hmLS!=Qz3>PGCD `aw8Ҹ}g>蠽T2\(6pTHiuud+[hw<>1_JpAqKXe-.R$e,g'oEPEPEPEPEPEPEPEPEP7+^~\,Q;ckK\9O7IR=ȶ|  JFIF``C     C   @`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?cEljD֮H`fL NzωL *yQ!y'<]~R~8dU&?濕pT>wݓU緾c  &1\~4ZvFIgB>S20[c搁a+?k>UoCZأU9QU<ɏyGv][X m6q3҈9h77 >zкi!UT'sgV0_򏞜9*Gò)#Mf"[U kckVlu7K,g*@sMaeثx'L3\I[ȮayY:|+IobrJSt;bpkOɏyTuؑt=DP~' kzxEz(A@cY![ɂ{ty ,[& }t,ʺ=!>Oj篣 7QG WM8״b<7wt}J?/@վخqj'F>[z?T('[\R"J:7<)_NQqޝQ,gq8RHZow^]^elyz?M%sͦkCsQb%fb2v={b‘F~PkOտ=}o:o'ڮTLEt{]AE\L_:*1o+?]$GCԭ\TLߕߨ=yuomR sY" ٔsWt]8j]\WPFÌ8_ }15me[ilfG<`VofXc$+3Ȣ/TQ_ s"?_ s"?/GڗX/h/jڗKecDDj_֏/GdoƨkhIjMlN-a5?ڗ:¶&N?&UnleAXE&ٓL2P}rZo؝tKi@~^I梺̒yY3E;fQj+/ -i|WAi>.uYBc#y+s UMb_ UC_HX7;VxLOïFֹp~ё@ g8=>x4}Ƹ{]_^6jA; cw=w~sup_Y";#n8{>x4}ƹq1L,x=*,OsE/h!?G|7>Gk/Z{fͻF mm=Fx=XgYL?ENneَG}Xo}!f /K5${|'qީT]otct}JtlzȖxKRT:me},ÞMtBQtKٟMqt<\?5?28׽׷Wӿnk厥~1ZOM  JFIF``C     C   17>R  27?S$  37@TI  47AUo                           ! " n % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m p q r s t u v w x y z { | } ~  @`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?cEljD֮H`fL NzωL *yQ!y'<]~R~8dU&?濕pT>wݓU緾c  &1\~4ZvFIgB>S20[c搁a+?k>UoCZأU9QU<ɏyGv][X m6q3҈9h77 >zкi!UT'sgV0_򏞜9*Gò)#Mf"[U kckVlu7K,g*@sMaeثx'L3\I[ȮayY:|+IobrJSt;bpkOɏyTuؑt=DP~' kzxEz(A@cY![ɂ{ty ,[& }t,ʺ=!>Oj篣 7QG WM8״b<7wt}J?/@վخqj'F>[z?T('[\R"J:7<)_NQqޝQ,gq8RHZow^]^elyz?M%sͦkCsQb%fb2v={b‘F~PkOտ=}o:o'ڮTLEt{]AE\L_:*1o+?]$GCԭ\TLߕߨ=yuomR sY" ٔsWt]8j]\WPFÌ8_ }15me[ilfG<`VofXc$+3Ȣ/TQ_ s"?_ s"?/GڗX/h/jڗKecDDj_֏/GdoƨkhIjMlN-a5?ڗ:¶&N?&UnleAXE&ٓL2P}rZo؝tKi@~^I梺̒yY3E;fQj+/ -i|WAi>.uYBc#y+s UMb_ UC_HX7;VxLOïFֹp~ё@ g8=>x4}Ƹ{]_^6jA; cw=w~sup_Y";#n8{>x4}ƹq1L,x=*,OsE/h!?G|7>Gk/Z{fͻF mm=Fx=XgYL?ENneَG}Xo}!f /K5${|'qީT]otct}JtlzȖxKRT:me},ÞMtBQtKٟ7tX9%dP2n=A@4\|=ؐOa!ReM!IH^  JFIF``C     C   G`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?'M 4x['L PYUCWͶ[*,/(BwuAvL? |)Iy{X\{s+$ ?'ČzyW99?wSYxXRX8][AKyuudH4``Б ].3?(Yx}?Oze&o"Cswm EvJi'TRBāpUO k_ iZNLQ8\WyWvFHmZ2G@5xIVKS^mxYY#dFVRH#?>M-N7!  ;dעWP$B vT}j5>,`HjZx K#8Qm^{U7-7<caqw⇏)@"n 0uͫwo~?z\MiyQz(]ܓ^oN2K_df+tR-IAXtkït+kA:'A¬ <kԴ :m\Gskhȹ ui劜js[Kz[\6m;@cn|X%m~wŠ([M3qs7~'[Y\>Xq52\K1*GIs^(V4gLi%*cH{םWe!ƥ-7`@=p3U=ީ{3tYV=ϛn=UhO4HdԬʂϏ߽Y ^j4P|: lE/;(Bdz}Gbdz}G2فVbx;@cn|D~7QEB1uhOڠkKq tR+H}@#?r]sqa4{AR?{y~6R6)8wZw(D1*DzX,amH¨{VlXFu]V88KA( }U}Tfg?G[uVPEUWtOZn+&gZ~$Y9JБ ].3?(Yx}?Oze&o"Cswm EvJi'TRBāpUO k_ iZNLQ8\WyWvFHmZ2G@5xIVKS^mxYY#dFVRH#?>M-N7!  ;dעWP$B vT}j5>,`HjZx K#8Qm^{U7-7<caqw⇏)@"n 0uͫwo~?z\MiyQz(]ܓ^oN2K_df+tR-IAXtkït+kA:'A¬ <kԴ :m\Gskhȹ ui劜js[Kz[\6m;@cn|X%m~wŠ([M3qs7~'[Y\>Xq52\K1*GIs^(V4gLi%*cH{םWe!ƥ-7`@=p3U=ީ{3tYV=ϛn=UhO4HdԬʂϏ߽Y ^j4P|: lE/;(Bdz}Gbdz}G2فVbx;@cn|D~7QEB1uhOڠkKq tR+H}@#?r]sqa4{AR?{y~6R6)8wZw(D1*DzX,amH¨{VlXFu]V88KA( }U}Tfg?G[uVPEUWtOZn+&gZ~$Y9JoA<'ۚ<)Kd\v3}:P :=9Um+y0<+Vem԰&[|cYRxN[ir+%ƻ]]lY[J̤H8qZ6MQp;E8[?N*IA5et24ӗ8s?OJгH:,[Onǁ}}u2M!9,тs?Ht=>eXErP}G'=!K k&{LT[@3w7~Bdfks$a9uحY–W h-ڱcpfj^n+酬#MH|%wgpw7;FEjV1#Uݎǎ^hn4s]Xq,{J4+:֟]ºpЏi/SmGU5{CUͿʹQE0 ( ( ( +O kzTڪ,EGwoBJEx4-g_Aq-P:QEqsAiߡ1{4QO}?~E1{4}?~(`iߡ1{4QG;L bxYnLsmؤuқDc2%O;C724Ey&U|_Lc8'3H??bE57BV 67 77DX 87EY JFIF``C     C   '`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?1UI=^z^KHdy*ky qfHxW&4M4aPD,OLp=|-$סyb$1\ǐ9Qkُؖ}M8$KcN lާ%kSiG[oNJ``zիW2>oA<'ۚ<)Kd\v3}:P :=9Um+y0<+Vem԰&[|cYRxN[ir+%ƻ]]lY[J̤H8qZ6MQp;E8[?N*IA5et24ӗ8s?OJгH:,[Onǁ}}u2M!9,тs?Ht=>eXErP}G'=!K k&{LT[@3w7~Bdfks$a9uحY–W h-ڱcpfj^n+酬#MH|%wgpw7;FEjV1#Uݎǎ^hn4s]Xq,{J4+:֟]ºpЏi/SmGU5{CUͿʹQE0 ( ( ( +O kzTڪ,EGwoBJEx4-g_Aq-P:QEqsAiߡ1{4QO}?~E1{4}?~(`iߡ1{4QG;L bxYnLsmؤuқDc\ܯ*+7A@((?\.iQY JFIF``C     C   `^" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?7Ad 4-y-Go fQϧ|30-*XC&j?.Hp;E }G‘JdxVok 0$djo:au B f+ $8$@pz#VRwmRJȺU\i(ebCntυr2OG9{ |܃eXdqWH~h6K^oL"ҭ1 -:[6vGyayUgce'Ӗ m*HliqpAU/x?M{qM<6ѷ\mI]R%nK3>XU2Fb@IF <?f_t{mUMZIXUM6S}d T UXi?{${/7Z^\[IhD ƠA^YEx;@MzluRZF.^2{wOTe<(ڼc6|oxc}(ITo ^ T!yh= &KҴ˻#hy8|I!W8w5tAZVym5Plr0pAEx8o'fl4sG戃.Wtc>>53M,1M ,(VY1T]f߃ ?PC-Id 9rr\NO'&3ƞ5O/8w1u!]O#sActR=v퇊- 4KI^yoh:Lju,-Hj3qSϮ J -"qȱIDsԑ956gyVpr#E %8 郦!Y/ Q e?j%^I׫+Hd25G+%\z?%^jAi+:wsIFּ#_g\-?澈Lnz_g\-?{!LZ7.fynN&vuR}:}-֟o~W+ɮh6բt٬y1\+VncgQUgڹZgu s ·qܣo|c` 84;FIuh3kWB=feu: }VXs3ȿ1K:i>zF[# nf6I'}3ȿ>?"ha\펊6!pyX1ż>Pp1Yܙ`2J˱O,b;T7?]0X_f}On f}ٿi=cnjO_/~ӟ녧׸VSY"ׇ~ӟ녧קOIl<t6헡 (ɟ5mb'`e݀p:c;u[-R]ߘMInBDI:uK(K)ry 'B)Q 'B)R tVg$ _G$ _G'\ӯ? O\K+hcq8"ol$VVrI|½[K?O JFIF``C     C                           ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~  `^" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?7Ad 4-y-Go fQϧ|30-*XC&j?.Hp;E }G‘JdxVok 0$djo:au B f+ $8$@pz#VRwmRJȺU\i(ebCntυr2OG9{ |܃eXdqWH~h6K^oL"ҭ1 -:[6vGyayUgce'Ӗ m*HliqpAU/x?M{qM<6ѷ\mI]R%nK3>XU2Fb@IF <?f_t{mUMZIXUM6S}d T UXi?{${/7Z^\[IhD ƠA^YEx;@MzluRZF.^2{wOTe<(ڼc6|oxc}(ITo ^ T!yh= &KҴ˻#hy8|I!W8w5tAZVym5Plr0pAEx8o'fl4sG戃.Wtc>>53M,1M ,(VY1T]f߃ ?PC-Id 9rr\NO'&3ƞ5O/8w1u!]O#sActR=v퇊- 4KI^yoh:Lju,-Hj3qSϮ J -"qȱIDsԑ956gyVpr#E %8 郦!Y/ Q e?j%^I׫+Hd25G+%\z?%^jAi+:wsIFּ#_g\-?澈Lnz_g\-?{!LZ7.fynN&vuR}:}-֟o~W+ɮh6բt٬y1\+VncgQUgڹZgu s ·qܣo|c` 84;FIuh3kWB=feu: }VXs3ȿ1K:i>zF[# nf6I'}3ȿ>?"ha\펊6!pyX1ż>Pp1Yܙ`2J˱O,b;T7?]0X_f}On f}ٿi=cnjO_/~ӟ녧׸VSY"ׇ~ӟ녧קOIl<t6헡 (ɟ5mb'`e݀p:c;u[-R]ߘMInBDI:uK(K)ry 'B)Q 'B)R tVg$ _G$ _G'\ӯ? O\K+hcq8"ol$VVrI|½[K?OG$C)Q PH??bE.iWӿnk?$ 1O"7mڬI8Up0k'VR8 JFIF``C     C   `^" JFIF``C     C   `^" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?k xGдVveƚ^Y# H=ϽtP|:}[ēN̨~20MR~X Cn`3< A8Tng ]L,Q&Ca3rFdtn85ZeN䎋c_b@Gd]?1U.hk+i!ҡmۆ =\f?麢j:{a4)g\>X6L,`3dKs{ "=ZB^Y#?>qbzW-IJqsѴRI}g˧|:׮RFH#"0ϗ ݸ ՛MK4b$dE_<^8k.xb_ڸTc\K;A* LĊG;r+WnkXn4StgHҘ\$IJSΏo/2FFkh,%֕;B3MxŊY35R`Al7ĚGC-SI%8n ?3 Bï-źCiwm~H_.YNhdKg1Ӕh{VWV/yن*[tAZZiZe4vм F ܜp;:?qI{dM\Q9F8e "\WvR}?ғP}6[uV9DA+Hw cvr1NGXK&ES+,n* .F}oچZKJ9. 'q'WlcOiI';f.'l ?iWzXotK'بfy#0QH$ ¶;Nbs"cֽxLF&88aYV'Vb$R##֋*HJohɧH\6ƄV~x끜L5͹<- :|I4oݪ% sWĞ,KKWyn[pV% 8z6gM hY)3 tx_HI|[Z0UTCU|ԅidžgui';^(HBrBȲau2G`kd25UOxOolf%*LO/hmgc$5KLOԂ2W tuZɸ"?xG9Z}q2=?9ZzySr'~ǩ4a* Aڵ??Vg?A?MeƲR5_l 95g-}F/Xz^*okx" U-YA9V=عVXCm'?zïxc;O+[BG ̒F΍[FGF Xy;pjBS y#2GIъÙog彁fΚV{^QNs^ -nYf\D͸w=O'ׅ~ӟ녧ס+czطz=S &j_2 ?2#PkW?sQ5b?SOEAW(>?\5%a{?\j2Zۆ2\HX"_k5izEqk:X5,3&!kxԔU.)kVGזmm"&M;CMC{i kV5hy$3#ּom4mm"&VL9QA [rd @]" O?i5:wKح|Ap$1s3^]Ns^Nrb'z?A?MmٗU ! Ѡ V'_]y4C}#Q-Nd3 `TwLv[ r|_㫋VbK)QHuE?+ W&_`8l`z?'_]h|fu49SR>GƗ#^4 y( z6otgW!ptlϴ?]vSԿoinkF{)Jx,bkÿinkʧϏ\Z~d|A}Ꮓ:mkGdϚ2rqgEr~ѱN)q7EPNA_T0c#( :v6d[ŌASkgO/ S/?Vt}!oYǀXmoe#hcyA,\ Ae5{[X$/-УN폗`O/ S\I΋d7Ub vp UdzW7*4|@ͤjFY~F6ɵFF 9ǯ9hY oα20G]#f+YK*95ȦxM7x|l񒍂' >Тk䚟u]r@m*C:4+B t `32OzV|0uX6L,`3dKs{ "=ZB^Y#?>qbzW-IJqsѴRI}g˧|:׮RFH#"0ϗ ݸ ՛MK4b$dE_<^8k.xb_ڸTc\K;A* LĊG;r+WnkXn4StgHҘ\$IJSΏo/2FFkh,%֕;B3MxŊY35R`Al7ĚGC-SI%8n ?3 Bï-źCiwm~H_.YNhdKg1Ӕh{VWV/yن*[tAZZiZe4vм F ܜp;:?qI{dM\Q9F8e "\WvR}?ғP}6[uV9DA+Hw cvr1NGXK&ES+,n* .F}oچZKJ9. 'q'WlcOiI';f.'l ?iWzXotK'بfy#0QH$ ¶;Nbs"cֽxLF&88aYV'Vb$R##֋*HJohɧH\6ƄV~x끜L5͹<- :|I4oݪ% sWĞ,KKWyn[pV% 8z6gM hY)3 tx_HI|[Z0UTCU|ԅidžgui';^(HBrBȲau2G`kd25UOxOolf%*LO/hmgc$5KLOԂ2W tuZɸ"?xG9Z}q2=?9ZzySr'~ǩ4a* Aڵ??Vg?A?MeƲR5_l 95g-}F/Xz^*okx" U-YA9V=عVXCm'?zïxc;O+[BG ̒F΍[FGF Xy;pjBS y#2GIъÙog彁fΚV{^QNs^ -nYf\D͸w=O'ׅ~ӟ녧ס+czطz=S &j_2 ?2#PkW?sQ5b?SOEAW(>?\5%a{?\j2Zۆ2\HX"_k5izEqk:X5,3&!kxԔU.)kVGזmm"&M;CMC{i kV5hy$3#ּom4mm"&VL9QA [rd @]" O?i5:wKح|Ap$1s3^]Ns^Nrb'z?A?MmٗU ! Ѡ V'_]y4C}#Q-Nd3 `TwLv[ r|_㫋VbK)QHuE?+ W&_`8l`z?'_]h|fu49SR>GƗ#^4 y( z6otgW!ptlϴ?]vSԿoinkF{)Jx,bkÿinkʧϏ\Z~d|A}Ꮓ:mkGdϚ2rqgEr~ѱN)q7EPNA_T0c#( :v6d[ŌASkgO/ S/?Vt}!oYǀXmoe#hcyA,\ Ae5{[X$/-УN폗`O/ S\I΋d7Ub vp UdzW7*4|@ͤjFY~F6ɵFF 9ǯ9hY oα20G]#f+YK*95ȦxM7x|l񒍂' >Тk䚟u]r@m*C:4+B t `32OzV|0uA7Mo#NcM6"v2z5Oº~-Sc\ }`+[ʫY8Tng L,Q&Ca3rFdtn85ZeN䎋n@ ,ād]?:Kksqeǀm۷? =1{MR?{a4)g>\>X6L,`3dKszt-Plf[66.O3ҰugOfӼ'-Yn ȌM&.<8S ⵣQZ5H<6#2 ]2"YP>~HX73{qu5ծpK LSDU*.w%)1yeKI~" gTeW?=>ᯇkui-z.͆V<V e&RmwZ$Dc5~%S5KHɐuqf0Y$jBA>ɗ\$G!?*ڟ^_?r@ѵ lҴD d`FaT |y6Oo9KEihdKg1Sh{׳N<})m-?*Jz??@ѿ?MhiwG,B4p&*Brqk; h&ky7yrF`ᔂ _ǟKqMđok?ii5MψB7O|N{OO*qx\\]/F>]L0Xdh;Vu[ߕ 7qIxNw63ZI|RҹBX6BoyϑI7xA-&$>a֬Kw/g7d3s8)Cm2ze ɫЅu,z!C=Ùkgii盧{B#%-^GN{O U$tii5QQҷs^ pp̻FG_&~S+3 h&~U/Ѓɺ<O/0JlIs&I b1en8줻KD"UE;ymk>Ƈ̒~t}™? r#ΣA:@5>gG#r'eῆh=C&<'1'_zr;&~S(n?rK?$ۀxgWfQo<7kU3]cj.cɺ<OU~ WF?U3]chsp^&^Iw~U?ۚx_H_YxwKxm#GC _?~ӿnkaɏ\[ G>؆ C {AsZmOs5Aӵ̰B,*$T;hb$%ԅ[7-xpb3F$U$ gח_Kq;ﶧi?>ڟkc'Mfޮ\ߘ A(9r0.|h5UT3i-m!K0T۝+(/<5;'M'S{ݼ""' O֯]s<I?¸?xSOw6 `{f:л0¾s n"ǏsI!OLթI-Y u$ ?.s$^{oZ5k+;k:$7+^~\,Q;ckK\9O7IR=ȶ|Mqt<\?5?28׽׷Wӿnk厥~1ZOM7tX9%dP2n=A@4\|=ؐOa!ReM!IH^ x~fEo23jAOuI S?6z_ÏJ?v26 2%O;C724Ey&U|_Lc8'3H??bE\ܯ*+7A@((?\.iQYG$C)Q PH??bE.iWӿnk?$ 1O"7mڬI8Up0k'VR8pg k JFIF``C     C   9`" JFIF``C     C   `Z" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?^[ÚQ:E&"IN~AZ_T w?ZV Pkj^*"Ƽލmi$ך^Mik7}.9FjƛWK]'~6rEl*@9y#&P[wL~ -X-FF+ݛvr\nܹw0>lT~InhdqcWW?=eT>>Yg˗Nm#Q]BG.O ׯd](sG'O/XpdAԿƿw ~_?/^d3\>xHY T pA—w zw5_<,TRcN'xg-?GƇREj7 ;g\t-5s^ᯆ^oi>K ;z9#_:~M槉UI屔!ʮwKu>,f|wV5*;8-N@/="5mGp2LQ # w~kIHZUWjgG9YJ}ݸP']ש9xմ4>LnervS#c8;4}Ҩ,&N mhi+6D={miBԦqW:lY$~O^Xr_lA,@+Ö?x}Dž$G#>m.o#{Ly>f7ygv0|'M?Vba+Nx#'Ө߮([ ͕Q3ov)'8< %`Jƥpjj6#'W!/<1zP,RW@+ojQjaV%/랧 ꎎ@p*_$m̓psQU{9v /K^;Eη-}uD|M,6l1:jF7?b:y?yyHլzI/bs)瓖x8{9v 3J׮m]AiݷBdbl5山Ʊ{+hD 7,A$S5[kóh^dGve 3.;u=tdH?g|W8끜\|JE3@ˈbIc u |5/`ՑIQj%]p9`q&VGe{Fze.|֩\&Y #-*if<ұy$6gcH?!\&$ך^Mik7}.9FjƛWK]'~6rEl*@9y#&P[wL~ -X-FF+ݛvr\nܹw0>lT~InhdqcWW?=eT>>Yg˗Nm#Q]BG.O ׯd](sG'O/XpdAԿƿw ~_?/^d3\>xHY T pA—w zw5_<,TRcN'xg-?GƇREj7 ;g\t-5s^ᯆ^oi>K ;z9#_:~M槉UI屔!ʮwKu>,f|wV5*;8-N@/="5mGp2LQ # w~kIHZUWjgG9YJ}ݸP']ש9xմ4>LnervS#c8;4}Ҩ,&N mhi+6D={miBԦqW:lY$~O^Xr_lA,@+Ö?x}Dž$G#>m.o#{Ly>f7ygv0|'M?Vba+Nx#'Ө߮([ ͕Q3ov)'8< %`Jƥpjj6#'W!/<1zP,RW@+ojQjaV%/랧 ꎎ@p*_$m̓psQU{9v /K^;Eη-}uD|M,6l1:jF7?b:y?yyHլzI/bs)瓖x8{9v 3J׮m]AiݷBdbl5山Ʊ{+hD 7,A$S5[kóh^dGve 3.;u=9r pkQ񗊣H|Eo@d4 s,s8O(rANN0W9,D{}&UIim#v\N$2+ymDXdZ?$`l$=6J{bĶ:ndu++-caLDp98շU9.#,Epp @;[@}YY$|tz=Xsdv͝:]ٳ^?0,̣`bV9'_79bLUg~ǙVO}E+ë?:qwwoS/'( 8-M4$|Si mί;Ea4Y. a9gN+RĖ7w1EVxsbAݸUx L4ljo )DMTomo`Z}_1߬;ȬQyb$}k(8Y33S+#U%m~(ǰ+oW( m~(ǰ+oW( m~(ǰ+oW( w_Ҭ_YǨZo6-*}x#Y)XH]60;>mZ.cVAh`1S IM$(cpA99לּKci,X”c瑿ֳ:Mz+&Ś&{]b4FW;`ңƾdh=5Gv)9;[4EcK-T[ћfI;q}OCs ه3xL"G@VEtKbVy[b,МtV4{LՙVPfUerS8݀zgtK,E.~i#ͼk,HlTIj:z]۲y fppSYWIKYl Xp-Q/ XխݧOd% #%ft Ov9ٳw&$xwG%kZw_/m (`H!~9[|_ l/h~&cqx?gSZWr} !:#6ims*לTAS4 YN#qH 99f?(+] ?,vpfL =F *)дҨAPl Б٢2+Y̓[i6VңoWC^\y4-7O{]>D)`2G^*i ~$CfXJ \*g-#Ly%U&'*iN|4CAg=]W1lf yn T2vDeU\mF-Dq{s+a@ -QEQEQENen k JFIF``C     C   9`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?ǿ `񏂭,%)$K(T>9r pkQ񗊣H|Eo@d4 s,s8}E+ë?:qwwoS/'( 8-M4$|Si mί;Ea4Y. a9gN+RĖ7w1EVxsbAݸUx L4ljo )DMTomo`Z}_1߬;ȬQyb$}k(8Y33S+#U%m~(ǰ+oW( m~(ǰ+oW( m~(ǰ+oW( w_Ҭ_YǨZo6-*}x#Y)XH]60;>mZ.cVAh`1S IM$(cpA99לּKci,X”c瑿ֳ:Mz+&Ś&{]b4FW;`ңƾdh=5Gv)9;[4EcK-T[ћfI;q}OCs ه3xL"G@VEtKbVy[b,МtV4{LՙVPfUerS8݀zgtK,E.~i#ͼk,HlTIj:z]۲y fppSYWIKYl Xp-Q/ XխݧOd% #%ft Ov9ٳw&$xwG%kZw_/m (`H!~9[|_ l/h~&cqx?gSZWr} !:#6ims*לTAS4 YN#qH 99f?(+] ?,vpfL =F *)дҨAPl Б٢2+Y̓[i6VңoWC^\y4-7O{]>D)`2G^*i ~$CfXJ \*g-#Ly%U&'*iN|4CAg=]W1lf yn T2vDeryrǼjm҇@`S MդY/tJib A]yZ4lmKմl%CW1xG\csA_&=Ƨ0R(ɐKeI#5U~^O "L2r=ϭl Acj]1 $H',w"ޛIb\H 2 #qtW2NK;+彌Wy/̊%#' ”.ɝY30c<"c>tdH?g|W8끜\|JE3@ˈbIc u |5/`ՑIQj%]p9`q&VGe{Fze.|֩\&Y #-*if<ұy$6gcH?!\&Ց qkcgn/[7T 9_AsͳbS|O9Ͻ8q{KHZ&|7Tޟϊe6ӄҰERd'Uƶ$F /ug#qв??WDWg-k sX㤸뎽:ս+ XYxOAg^3W2KFp Tc$F#9F{V2=_ k)g;?5iTÿcCV_ha+a+?s_W>/>C1k^o*tW]&XT|aS,L-k/]'eaf]OGjg|?ܾ}KWӭ#_p>c* UIkVUY*b}g@?'Tq9Tgj&۱p8'眜dkc;POjPOj(Yt[04cm*IU=r)6HA8+6;*F|Nm藮MY`ӆ=?U?|9{蕮?O|/`_TKqAEW)QEQEQEW5;I?w^Z'6gnKNWDIIkV=JCOSO/Q\EPEPEP\&,Mzk$ş /]8o_?ᨥF[+#Dn,١*+1UZnwۿϒ:-  a4?QEsd4 4?Q 76h1?hw֧,١*YC?UQC?>>?f?0T  a⨢AA 76h1wG \|;LQxEWҮQ5Ibal7rhTh;nO7?s.jpg,*,Ni TJFIF``C     C   H`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdef78b `88c 98 09+ghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?-/kFu.<6Ow1-Xu{R'y\(wM};ΟkvʞoS׿J/Feu88RP[$9|*z&dw:Lp 8,A>Ց qkcgn/[7T 9_AsͳbS|O9Ͻ8q{KHZ&|7Tޟϊe6ӄҰERd'Uƶ$F /ug#qв??WDWg-k sX㤸뎽:ս+ XYxOAg^3W2KFp Tc$F#9F{V2=_ k)g;?5iTÿcCV_ha+a+?s_W>/>C1k^o*tW]&XT|aS,L-k/]'eaf]OGjg|?ܾ}KWӭ#_p>c* UIkVUY*b}g@?'Tq9Tgj&۱p8'眜dkc;POjPOj(Yt[04cm*IU=r)6HA8+6;*F|Nm藮MY`ӆ=?U?|9{蕮?O|/`_TKqAEW)QEQEQEW5;I?w^Z'6gnKNWDIIkV=JCOSO/Q\EPEPEP\&,Mzk$ş /]8o_?ᨥF[+#Dn,١*+1UZnwۿϒ:-  a4?QEsd4 4?Q 76h1?hw֧,١*YC?UQC?>>?f?0T  a⨢AA 76h1wG \|;LQxEWҮQ5Ibal7rhTh;nO7?,4]Nimage063 JFIF``C     C   5`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?!tř 06ˮ)l-n幾6"aneW'/xźon`~zE-I     !"#$%&'()*,-./0123456789;<=>?@ABCDEFGHJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnoqrstuvwxyz{|}~NWm$f*d/Y !k=pgjRZᷣxPvs>?|?=|wH[Ỷm*O?/`~u_gQT[6J:ϖ '_򣹇Ce2;AuX?|?~^GUX쭄/@`Oq߮{Smt[F 7yW ۷}""EcEgp"{IO z!֧\iQZI7OR60T'qU~+?(K}; d&fn% $bf29+ӾjΟ^@:~fn1֗""RA0N w>5k^bJw.6?\VB_PeC7O00}Y6NDd"x3N1Z$q7Yۂl#% ?};^d0iXm:*ʮH^W8=ֺف8eF_N\xji!o]cBTO~I]N;V5V.+QQ?\EQG(Eٿ?ӿL䎞ZvL:rD-={UQ{QgQ]K3מ}!u-%ӵ+_ eӤ{r[֝ dMgH$MuxFU x< 7cɰTdnj7YͷO~l/Xno ~GMgߣ4l/=.o ~GMgߣ4l/=.o ~GMgߣ4l/=.o ~PaKA"^Ɨ~n*GIk'ِnN1QFf$Tq|ߘ ({"qoqoQd8?8?Š( }[G}[EY>>,VR7prs&)Nimage056.j JFIF``C     C   5`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?!tř 06ˮ)l-n幾6"aneW'/xźon`~zE-INWm$f*d/Y !k=pgjRZᷣxPvs>?|?=|wH[Ỷm*O?/`~u_gQT[6J:ϖ '_򣹇Ce2;AuX?|?~^GUX쭄/@`Oq߮{Smt[F 7yW ۷}""EcEgp"{IO z!֧\iQZI7OR60T'qU~+?(K}; d&fn% $bf29+ӾjΟ^@:~fn1֗""RA0N w>5k^bJw.6?\VB_PeC7O00}Y6NDd"x3N1Z$q7Yۂl#% ?};^d0iXm:*ʮH^W8=ֺف8eF_N\xji!o]cBTO~I]N;V5V.+QQ?\EQG(Eٿ?ӿL䎞ZvL:rD-={UQ{QgQ]K3מ}!u-%ӵ+_ eӤ{r[֝ dMgH$MuxFU x< 7cɰTdnj7YͷO~l/Xno ~GMgߣ4l/=.o ~GMgߣ4l/=.o ~GMgߣ4l/=.o ~PaKA"^Ɨ~n*GIk'ِnN1QFf$Tq|ߘ ({"qoqoQd8?8?Š( }[G}[EY>>,VR7prs&)Nimage056.j JFIF``C     C   " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdeftable_editor.jpg,ZSʽNimage019.gif2[SʽNtable_prefs.gif,\SʽNimage020.jpgH]SʽNtable_column_selection.jpg,^SʽNimage022.gif,_SʽNimage021.gif4`SʽNmove_up_icon.gif8aSʽNmove_down_icon.gif,bSʽNimage023.gif*cSʽNno_soghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?/NUkt) ݙHn+;i€$h灅clxCz jM:KP!:Ȏ~{hBT+þ(|i]v[+jֺƗ W67:snvtN /nm~ɬ"|55O0T:*/IEYsr/u~]Ϩj7.nieWؒĒI9$h?5x/oÿ6ciⶍ$MJHʒ8$Q^[G,Ntext_edi JFIF``C     C   " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz19:29I 39p 49 w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?/NUkt) ݙHn+;i€$h灅clxCz jM:KP!:Ȏ~{hBT+þ(|i]v[+jֺƗ W67:snvtN /nm~ɬ"|55O0T:*/IEYsr/u~]Ϩj7.nieWؒĒI9$h?5x/oÿ6ciⶍ$MJHʒ8$Q^[G,Nimage056.j  JFIF``C     C   H`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?<7;x>5'pזbwR\\+G/= 9{V^3Go)l~hj#<\˵PL +:{|maN8s}_-\797wn쿻~oE0x9xSVhm6u=s1\gWl5=~?IC_s?Hȟڧmios9d(|Y]_wIV[dR@ir+Sv /֋ČނtU'Kp59C%d.W{NWaf+>_Cז\xkOImny^Ɓ]npk >m%~g=^Wߧ/'|ZeG2wů\JU)_P?~?C5s[-_> +k=!Blҫxχ^#BKh%PUSll#15)_P?dw?(5+j??{Sx5v7] ̎N~rG}+u\UqWzH]4 Yڐ1sߌWS@6IsS@6I* QEwpψ]pψ]X_~3KЫ:-BWך~3$< 8BtRq'5l{'K*aI~>dd?5nj⫰T$ѤB ?6bO $ #8/cڕf#jdd?"̚Hg_臮ds *ȬN}?Ӆk_EK򟅿g6>1h$R[ Q E*$-[u,\"A G.?ie䁪Q\!4F\evo_㏀d6|[Ā袗ϲ7Oy^,ݨ[M>ۅoi[E5Ὶ_z "nMw#xn5 ՙ~8GGVtQGϲ3~#:W|$8a}|N=G,ŞTHFwr`@\N@Rh05ԥ]WC:5dpg,:]Nimage06  JFIF``C     C   H`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?<7;x>5'pזbwR\\+G/= 9{V^3Go)l~hj#<\˵PL +:{|maN8s}_-\797wn쿻~oE0x9xSVhm6u=s1\gWl5=~?IC_s?Hȟڧmios9d(|Y]_wIV[dR@ir+Sv /֋ČނtU'Kp59C%d.W{NWaf+>_Cז\xkOImny^Ɓ]npk >m%~g=^Wߧ/'|ZeG2wů\JU)_P?~?C5s[-_> +k=!Blҫxχ^#BKh%PUSll#15)_P?dw?(5+j??{Sx5v7] ̎N~rG}+u\UqWzH]4 Yڐ1sߌWS@6IsS@6I* QEwpψ]pψ]X_~3KЫ:-BWך~3$< 8BtRq'5l{'K*aI~>dd?5nj⫰T$ѤB ?6bO $ #8/cڕf#jdd?"̚Hg_臮ds *ȬN}?Ӆk_EK򟅿g6>1h$R[ Q E*$-[u,\"A G.?ie䁪Q\!4F\evo_㏀d6|[Ā袗ϲ7Oy^,ݨ[M>ۅoi[E5Ὶ_z "nMw#xn5 ՙ~8GGVtQGϲ3~#:W|$8a}|N=G,ŞTHFwr`@\N@Rh05ԥ]WC:5dpg,:]Nimage06 JFIF``C     C   " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?㗊IѬ4q/kYp&&ݹF2WE|ߏ:l%emwI?@G.vrq 6s{ftNv*tTM>ݲm5$vQC p㡢?WFIGXJB%J2)~WW)p]Om]׊+A5h>gp9ᑇ*zE)p5k xkvrZnjYs; 1It)Gi)zQ\editors.g FJFIF``C  59R69R7989{    C   " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?k)!LtTԮ CS'iE >5ǫC{uw^Y˨X.m$"+I K|Fĕ\G־:VkXE*;Cs1  =Q]Aeeѭ4>#)/#E"anI*F@fm_~mCƾ'}wge055.jpg4%,Ncode FJFIF``C     C   " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?k)!LtTԮ CS'iE >5ǫC{uw^Y˨X.m$"+I K|Fĕ\G־:VkXE*;Cs1  =Q]Aeeѭ4>#)/#E"anI*F@fm_~mCƾ'}wJ,Nsimple_enum_e JFIF``C     C   " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?㗊IѬ4q/kYp&&ݹF2WE|ߏ:l%emwI?@G.vrq 6s{ftNv*tTM>ݲm5$vQC p㡢?WFIGXJB%J2)~WW)p]Om]׊+A5h>gp9ᑇ*zE)p5k xkvrZnjYs; 1It)Gi)zQ\editors.g oJFIF``C     C   " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?cvs#ƚl+Ӭkȵ"P&S f/>kT{\|asy2"k,ʱ;011߆q\[2immK2Q$-ɯK|W#Ğ4N1>mf1G2Ņ1Aq8]lN7Fdڛo>T%'EȚvW2eOT,h7~&ּISŵߵI)¸a؞J-~#_xZ]GiC6B/,}'0ӓOM-.ރY&B<^J->;:KI2xfB׵IYl 9$l3 a@gr>&yScp9'#Z(,~*U10S{^cOP֓ttr Z<:66 ^e9Q\8  ~8Ly+ݭ][#eO`N6].{Mi oJFIF``C     C   "99'x{001l101ogl201pqN }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?cvs#ƚl+Ӭkȵ"P&S f/>kT{\|asy2"k,ʱ      "#$%&'()*+,-.0123456789:;<=>?@BCDEFGHIJKLMNOPQRTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{}~;011߆q\[2immK2Q$-ɯK|W#Ğ4N1>mf1G2Ņ1Aq8]lN7Fdڛo>T%'EȚvW2eOT,h7~&ּISŵߵI)¸a؞J-~#_xZ]GiC6B/,}'0ӓOM-.ރY&B<^J->;:KI2xfB׵IYl 9$l3 a@gr>&yScp9'#Z(,~*U10S{^cOP֓ttr Z<:66 ^e9Q\8  ~8Ly+ݭ][#eO`N6].{Mi `JFIF``C      C   " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?Own͏45д+ N+FNglČ Y{C"[{"Hf( oHƞ0ѾOVSAH& MURq&_NX+RD3mba$s1^xoz߫o%_moCQ^ |;(*y t}67֊)V(%,Ncode `JFIF``C     C   " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?Own͏45д+ N+FNglČ Y{C"[{"Hf( oHƞ0ѾOVSAH& MURq&_NX+RD3mba$s1^xoz߫o%_moCQ^ |;(*y t}67֊)V(%,Ncode BJFIF``C     C   " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?? /4?|aԴ:SG|&M+x'%>`v)A;Tdߏ>|#SN]4*}>>)kHତ1#id7➟?6O#_ ~΍m h43>7A rO_|-i~"m-;bS6.ჳ@#L$w?mage055.jpg4%,Ncode BJFIF``C     C   " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz 301fi!N401rs/H501hlAH601tuS w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?? /4?|aԴ:SG|&M+x'%>`v)A;Tdߏ>|#SN]4*}>>)kHତ1#id7➟?6O#_ ~΍m h43>7A rO_|-i~"m-;bS6.ჳ@#L$w?image060.gif4/,Nen <JFIF``C     C   " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?'4~ Ķ~.E^cmzAP!AΏe-ǟ<@ʃR cʯ?}%GY"%u OEznmF" 'kn"+r8 6$֋[|2}l>ֆONMZ]ڶڛ?RwG/i7b/2 P@,Eyo]~ɾ.v}*)|}4鶓x yr{tRsQ>YVz>NSsw+z SKh/?v@ӵ^XmֆONMZ]ڶڛ?RwG/i7b/2 P@,Eyo]~ɾ.v}*)|}4鶓x yr{tRsQ>YVz>NSsw+z SKh/?v@ӵ^Xm'k+-X\4N#%!s\`z:eݣn͸ RI{W'o;Pqhd]N?!v<M&eRi~G_h -t巷ҡٟ'Lַ,A&8L&P zr9~(k>"P&ծ<9qZD̄t9\8evϦ;CQ}c@Y<=fqv/,nOaKϿΞ#CEծ;w޹WrjFhcs;3=}Sh^{]bH)",?<| { ]e?m\l&cŸ1 ڜ}:+PDt(AΣ ~k1y Jg0Aǵz_Q)o+ӵ+N5;$ɜ`n+Vӵ~)r #j }kX5O}ح8Ʉ^Js㏮ygZϯi[w. X7h_cK'f=j}V[0 ] F展psڹXdYͻ9uXRwȠ/_Az`#_dS1('n5W0]<1,rE%ȃ,|x'? DFYD\MݣDfr @{֊YqtfG# ahz -#pcpGb wZmo}Y%kn{VMwQoNqq/ *,b1Ur,dž'oQ^{ɭpnMƻ,Nßn3Uhh..La͒^?\IF$[zl޸z(ׄZ̦$Bnlٌ\ڻ}2ym=/0Kuc00#Z5ׂMuKXB<%>^)ˢ_}|آJ LB-a W{n5x Ve=/ݐϣgTlk[\Z/m\cqp8\eIdIk^\8(_SYFi+ۿzns[ž##D(WOA޻ :=J)A"(pO!5P],t6;- 00lGҽ- oK#LU*"}9L3:nSl"D!\0@Te֜\*&D t~/SP +'k+-X\4N#%!s\`z:eݣn͸ RI{W'o;Pqhd]N?!v<M&eRi~G_h -t巷ҡٟ'Lַ,A&8L&P zr9~(k>"P&ծ<9qZD̄t9\8evϦ;CQ}c@Y<=fqv/,nOaKϿΞ#CEծ;w޹WrjFhcs;3=}Sh^{]bH)",?<| { ]e?m\l&cŸ1 ڜ}:+PDt(AΣ ~k1y Jg0Aǵz_Q)o+ӵ+N5;$ɜ`n+Vӵ~)r #j }kX5O}ح8Ʉ^Js㏮ygZϯi[w. X7h_cK'f=j}V[0 ] F展psڹXdYͻ9uXRwȠ/_Az`#_dS1('n5W0]<1,rE%ȃ,|x'? DFYD\MݣDfr @{֊YqtfG# ahz -#pcpGb wZmo}Y%kn{VMwQoNqq/ *,b1Ur,dž'oQ^{ɭpnMƻ,Nßn3Uhh..La͒^?\IF$[zl޸z(ׄZ̦$Bnlٌ\ڻ}2ym=/0Kuc00#Z5ׂMuKXB<%>^)ˢ_}|آJ LB-a W{n5x Ve=/ݐϣgTlk[\Z/m\cqp8\eIdIk^\8(_SYFi+ۿzns[ž##D(WOA޻ :=J)A"(pO!5P],t6;- 00lGҽ- oK#LU*"}9L3:nSl"D!\0@Te֜\*&D t~/SP +,0 u҃r>Ovݕ<ҽKW@u(IwFqJc7`9?Gګ{uo_dG1&K{K/}\CDd sFAݐxv|i?O %+}Ҁ}ɬwTm&yuk{OPA`m</mrWW}vx% ܖg!YhF3ktAQEIhjJ|rm |Ⱥڜ0.wZܳY-iV܃mIqiGj< =<\|_n ږeWNG+%WXr\85EP UJ UJ3uQE (7-"N`PmYU5ʺOO5OCa?iB?HO|{be08zs0EXoWܱ Am=3^\gM<]CA,˞]ǃuB (8mUmW?(QEዸ|7N&(pN d{յ (ZV2Ak=j_tQ?m:[_=Ƶ Ĉ #|oV哻llQEHŠ(t_menu. % JFIF``C     C   G`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ? ?KHbRKdL&W$=4;$)s)nSuOڇ2Fwl8s ץlz8K[NuҲ mFU#T2$_szq &4]W^woo+\rٜ-ᦲ>,0 u҃r>Ovݕ<ҽKW.uδ%T1ϸҺgzoGMH¶(@u(IwFqJc7`9?Gګ{uo_dG1&K{K/}\CDd sFAݐxv|i?O %+}Ҁ}ɬwTm&yuk{OPA`m</mrWW}vx% ܖg!YhF3ktAQEIhjJ|rm |Ⱥڜ0.wZܳY-iV܃mIqiGj< =<\|_n ږeWNG+%WXr\85EP UJ UJ3uQE (7-"N`PmYU5ʺOO5OCa?iB?HO|{be08zs0EXoWܱ Am=3^\gM<]CA,˞]ǃuB (8mUmW?(QEዸ|7N&(pN d{յ (ZV2Ak=j_tQ?m:[_=Ƶ Ĉ #|oV哻llQEHŠ(t_menu.  JFIF``C        !"$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~    C   G`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?\|skZ82BCĥO~ M|O i{f.nFwxq+{A@u-n !;F|͎ztѿ:Qes3sAۀ{(34Ů1"?OE`EnC"DgL?GһF@>9ӆl,$sӁqt<138[[חncșR#!\O-𑊬ś\^KU^ 7Q8>̉ue#Zy{y r@͕[#/r=VOm>gڪe pVh7$D9zH[ĺE-je3̄X;to\φ@D02,_lHp?xѿ5[Wtcңk 9;ty|b6r>lX7OyA>sv8ShYB܅B2Wnx@:5XrۖA v׭Fk}G4TƭٴjJv|#F8z8^y>KKIΏ%I Hgb|I4Wziytp,r@p"SnHB,%鈢M/ge')vEMdDIgkh[)`d纕f?<˺ۛI?u*fcӁqgQz7׮kQlNM#̭GzX-դw:>S;^[Z;dc/p șcޜ|'^8ڼn][s)Ѡ0:9 to27g>a즎I2Pb zVsؤC-O\" T cyR[GbN18}uK]7]n`Xm rKn+^lH|5·wE|rwxCѺ{^q5o=$AB"L9b~S;&o)mmy;~R@R8+@_zjPKbdQ12vd SmtoGP)_]H-X vϺVB*a<صJ0=ɦ"Uaq B p?'͉2>g:\-4e9-գ)՜)I6@<\輑c[s98ú-}뀓PǶVjPs4VOGeݎA [${WmduKbFzgn,A1w2O͸Ѷt4@SbH1~M#qx?S}kKKmPIw#Ð8jg111z# 211{W 311| 411}p ghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?\|skZ82BCĥO~ M|O i{f.nFwxq+{A@u-n !;F|͎ztѿ:Qes3sAۀ{(34Ů1"?OE`EnC"DgL?GһF@>9ӆl,$sӁqt<138[[חncșR#!\O-𑊬ś\^KU^ 7Q8>̉ue#Zy{y r@͕[#/r=VOm>gڪe pVh7$D9zH[ĺE-je3̄X;to\φ@D02,_lHp?xѿ5[Wtcңk 9;ty|b6r>lX7OyA>sv8ShYB܅B2Wnx@:5XrۖA v׭Fk}G4TƭٴjJv|#F8z8^y>KKIΏ%I Hgb|I4Wziytp,r@p"SnHB,%鈢M/ge')vEMdDIgkh[)`d纕f?<˺ۛI?u*fcӁqgQz7׮kQlNM#̭GzX-դw:>S;^[Z;dc/p șcޜ|'^8ڼn][s)Ѡ0:9 to27g>a즎I2Pb zVsؤC-O\" T cyR[GbN18}uK]7]n`Xm rKn+^lH|5·wE|rwxCѺ{^q5o=$AB"L9b~S;&o)mmy;~R@R8+@_zjPKbdQ12vd SmtoGP)_]H-X vϺVB*a<صJ0=    C   !`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?Og=˫-&0`6̌ ^7 kh?m]AkB.+Bw>Ch}Ou]mO]A汎S2pn0I9Ax'Zx~o&/cK6c;Xgϝ~0&KN$g֝(\0rjr[x_tk׺v dv =H湡3GLN7(%ـ39ϭWG_>$/m4/ӵ"](.) W-,uJjJJj_g֎3ݚrTѾ}t떟+[]t? C1MNS}+Ɵ6x).Gٙvms^i;w}7Ty湛^,OxƪXkr|6zR4=An]0\/ 5*Uƭ쬛KO8t`q^ִ^2Z\j6Rq]Ϥ֥euse(I (18u"vSj4&v*n[ q[v$(!V2 n֊(.q1z::wrcuo+[ɲ6dc2H8H[x[,;y1nrTezn $,r N~^cU rindhg[q3;韘 Z KHǕcz 񞝺QÕ~]GsIbs|(u]rWmlm= vآRwI2s  JFIF``C     C   G`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdef/4I,m剝A R2*jJjY˥ݗa[ڨ?bKm''|'⑩&f4#Slnp98\/P'xMn~K߳?D]9Vܱ_C,28]gڻzlZ~:mYVh\(8׃K^xȸuweV >b]+Sxhnkw|5x<6ov8>fh/"Y]b5&gsP'L{ [:5F}CRct7nHzdOb?_IS ]7N^ဖrJWkm?#|Ogqx^K$s}pmй+xZVwh5($:7.ſmۻkoSs-ƅƺ=ī屷&epJOoًPGZp-2#'p+pS\|Ok[Vˍbt\pwֶ[}<ޏYޟcs}jIi~AXMgghPDLn9/3u]y|3ŧ>XŒ։4qNNu}~ϟ|%[/Ch}Ou]mO]A汎S2pn0I9Ax'Zx~o&/cK6c;Xgϝ~0&KN$g֝(\0rjr[x_tk׺v dv =H湡3GLN7(%ـ39ϭWG_>$/m4/ӵ"](.) W-,uJjJJj_g֎3ݚrTѾ}t떟+[]t? C1MNS}+Ɵ6x).Gٙvms^i;w}7Ty湛^,OxƪXkr|6zR4=An]0\/ 5*Uƭ쬛KO8t`q^ִ^2Z\j6Rq]Ϥ֥euse(I (18u"vSj4&v*n[ɦ"Uaq B p?'͉2>g:\-4e9-գ)՜)I6@<\輑c[s98ú-}뀓PǶVjPs4VOGeݎA [${WmduKbFzgn,A1w2O͸Ѷt4@SbH1~M#qx?S}kKKmPIw#Ð8jg q[v$(!V2 n֊(.q1z::wrcuo+[ɲ6dc2H8H[x[,;y1nrTezn $,r N~^cU rindhg[q3;韘 Z KHǕcz 񞝺QÕ~]GsIbs|(u]rWmlm= vآRwI2s  JFIF``C  /4I,m剝A R2*jJjY˥ݗa[ڨ?bKm''|'⑩&f4#Slnp98\/P'xMn~K߳?D]9Vܱ_C,28]gڻzlZ~:mYVh\(8׃K^xȸuweV >b]+Sxhnkw|5x<6ov8>fh/"Y]b5&gsP'L{ [:5F}CRct7nHzdOb?_IS ]7N^ဖrJWkm?#|Ogqx^K$s}pmй+xZVwh5($:7.ſmۻkoSs-ƅƺ=ī屷&epJOoًPGZp-2#'p+pS\|Ok[Vˍbt\pwֶ[}<ޏYޟcs}jIi~AXMgghPDLn9/3u]y|3ŧ>XŒ։4qNNu}~ϟ|%[/i`1=v'm&Bd \mA*F/Ox/ 7 ATo9ÃxmVEU})i1%2Ee1޿f2prOQMy?'/U~kc<xV-Xqd<}E|~! _~ ~ hcN-tݽ&P7$⼟7DE58ܯ0^NWR++%o~ISzh}ˬc$ۿiknCA[^ GU?4O꿔_^Ы)_cMW>a־7-%܉M働N𧍝9JsP]I GJc0Frx$^=E}Q GU?4O꿔_X< m-T?2,? *L"FySn{2fAWhL?#Qn:>1"x,?V7eⷈlZI5ͥ \Aɚ'u_/_ׇC{yd^ned%J8LԒeJ<9ig:0Rso.֔R׻zo=qK^o vnko-%B|=' zĐ79`I iqdv̇q<D]ޓt?L!HH"% T2?kFu7bͨy$??~E6CO~/Eיb?dy.úU6uoױb+J>]`յx\>![[M-ZX.M 018¶`25_RVTPj$TgPXt{և~/q5R|,g7RqoM#Tir^k9Xy#w0 `0NyU.~!x"+-F$Ȭ(Vܬt{??痄?>yxC|Mmڔ"X ̿-?Ěs}m$w܇V?]??痄?>yxC>J!wkfKuΙsq3퍙_g_iA 811q]     !"#$%&'()*+,-./0123456789:;<=?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnoprstuvwxyz{|}~w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ??4? N<]\"eagVݿjl2k2㇂.[Z_. 6 UA=5Zn/ov>i`1=v'm&Bd \mA*F/Ox/ 7 ATo9ÃxmVEU})i1%2Ee1޿f2prOQMy?'/U~kc<xV-Xqd<}E|~! _~ ~ hcN-tݽ&P7$⼟7DE58ܯ0^NWR++%o~ISzh}ˬc$ۿiknCA[^ GU?4O꿔_^Ы)_cMW>a־7-%܉M働N𧍝9JsP]I GJc0Frx$^=E}Q GU?4O꿔_X< m-T?2,? *L"FySn{2fAWhL?#Qn:>1"x,?V7eⷈlZI5ͥ \Aɚ'u_/_ׇC{yd^ned%J8LԒeJ<9ig:0Rso.֔R׻zo=qK^o vnko-%B|=' zĐ79`I iqdv̇q<D]ޓt?L!HH"% T2?kFu7bͨy$??~E6CO~/Eיb?dy.úU6uoױb+J>]`յx\>![[M-ZX.M 018¶`25_RVTPj$TgPXt{և~/q5R|,g7RqoM#Tir^k9Xy#w0 `0NyU.~!x"+-F$Ȭ(Vܬt{??痄?>yxC|Mmڔ"X ̿-?Ěs}m$w܇V?]??痄?ghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?-tYh=5O%쮘sJ~!PO=>mr]N5f(neT |\rEu%Q54i( .>ӣ*1}rrRzrtOxoFu˯N8"I$fFWpc#$dUMg'4kˋm⼖1, &2bJ=uxHdBrJM (ZA*aVlL -^?P_RΟ\6 j2]^[#>.gh]M>i,gMő0FjU=MhmbX`G(ªUŠ(( [j{ݲϤ~O $u<}oVN:f]O \X]׻|HfO D_2E%G$n2zvlU4TKAF8z}wϞL"մK7naIxϾ Y"Ϟ?|/OU(e=Kl'_.Q|/OQW@<,QM|C˻ knu?.7yd3X"w\tj_\_14 55l$1SH@c#*a w6sBv{w&4X)/]HKɖ,rO7fcogmsvQQ2NOղ^1-QUle?Ơe*[?l*[(+,Dž&-gQҴfR%p0 GYG2|M?]|TAL_GZ5Xei%mP?JL.[ EՕFg8[ݼSʡDJA _ Xi^ҭ^vZX%i'S")1z=ύ5χ^MԤDzdwBwuDE=HU3\8$b0($Һ-i`j¢ަC^|PaaCE㢸aQ>^y#;͎@Yi Znʢ@9 Ezpח6$Iß)UEYX?kK>ß)9?nI/{25 Ih62nBdsTouo?ٖZjvnA+#AOЍQ _LEv簶k͗%3,s79kK>ß)9?=;5/?QZj7W6|Vw >L[s}n^ _LEk𔒾i;1#XYqJNj  d JFIF``C     C   ;`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz A^[__𯟵?/O_ui;fk-o,`Jq egF1c_5`_hFn݋X"c-!9QJǡex?ex?xHf3ٻ>!!?#go96\?o뺗=F5?]y_ J{;eq|)šwmEIEG3;#4[wZ elk3Qk=NkI|[nL7٤H#ZsgO0a .vb)EB,;AnFUnಊů J%(ڥc8U{]/Z,5j֖aoI<60w,`pJó\??rhQ hS躧KFfN[y%i #FT#%=NkCNt l,-<ϳ±؁8;QUGPgO0a .+yWKG}cq~v7g8Ҵe-2Vb-<Iȟ(W;as(ó\-*=QEp<.ߍtq1i7r;,%OIn]~XJ~ C +"c--ف>Fšnxc4 9k}V$8 y<-x㥊O UFm#{9{vU̴sC Z^#}޺ѷڞ4QKoEu8ҴkFS+O-OZ u{k/y*ݵ),M糕qL^eԧ ukmvGf8# >H:sj e`E" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?-tYh=5O%쮘sJ~!PO=>mr]N5f(neT |\rEu%Q54i( .>ӣ*1}rrRzrtOxoFu˯N8"I$fFWpc#$dUMg'4kˋm⼖1, &2bJ=uxHdBrJM (ZA*aVlL -^?P_RΟ\6 j2]^[#>.gh]M>i,gMő0FjU=MhmbX`G(ªUŠ(( [j{ݲϤ~O $u<}oVN:f]O \X]׻|HfO D_2E%G$n2zvlU4TKAF8z}wϞL"մK7naIxϾ Y"Ϟ?|/OU(e=Kl'_.Q|/OQW@<,QM|C˻ knu?.7yd3X"w\tj_\_14 55l$1SH@c#*a w6sBv{w&4X)/]HKɖ,rO7fcogmsvQQ2NOղ^1-QUle?Ơe*[?l*[(+,Dž&-gQҴfR%p0 GYG2|M?]|TAL_GZ5Xei%mP?JL.[ EՕFg8[ݼSʡDJA _ Xi^ҭ^vZX%i'S")1z=ύ5χ^MԤDzdwBwuDEA^[__𯟵?/O_ui;fk-o,`Jq egF1c_5`_hFn݋X"c-!9QJǡex?ex?xHf3ٻ>!!?#go96\?o뺗=F5?]y_ J{;eq|)šwmEIEG3;#4[wZ elk3Qk=NkI|[nL7>yxC>J!wkfKuΙsq3퍙_g_iA^y#;͎@Yi Znʢ@9 Ezpח6$Iß)UEYX?kK>ß)9?nI/{25 Ih62nBdsTouo?ٖZjvnA+#AOЍQ _LEv簶k͗%3,s79kK>ß)9?=;5/?QZj7W6|Vw >L[s}n^ _LEk𔒾i;1#XYqJNj   JFIF``C     C   `E" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdef٤H#ZsgO0a .vb)EB,;AnFUnಊů J%(ڥc8U{]/Z,5j֖aoI<60w,`pJó\??rhQ hS躧KFfN[y%i #FT#%=NkCNt l,-<ϳ±؁8;QUGPgO0a .+yWKG}cq~v7g8Ҵe-2Vb-<Iȟ(W;as(ó\-*=QEp<.ߍtq1i7r;,%OIn]~XJ~ C +"c--ف>Fšnxc4 9k}V$8 y<-rt.gif,dSʽNimage024.gif>eSʽNsearch_table_icon.gif,fSʽNimage025.gif<gSʽNinsert_item_icon.gif,hSʽNimage026.gif<iSʽNdelete_item_icon.gif,jSʽNimage027.jpg8kSʽNtabular_editor.jpg,lNimage028.gif2mNtree_editorw!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?fPԵ v ‰hI5? ?it WQɮ_ OKst; Օ5|z4]WϹi6ݐ72p1kK o j²ޅ*ªN} `-Z[;5)EY75 ?G 0e¾O C??W"gcW o j±O3kewkj\\B VcК+x\t]:/tq T`e@cb3Iԍ ,4]Nimage063 8JFIF``C     C    `" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdef911jD021]121D221 oIsΆ;\d#E\t1[Ux+vbΧd[y&H'.++v%3ͨlڏ689W<(8I 4e^EOף<( cm (*Q KLwZMEgiY8R%9ns>58Ag]񇑧uA *O-~ǝ,ϛ[ >6X|N٠k>:Θ5ql~f|ʞDǝVMƀIhd4o?%9}7\njυh~>:rN/ .ZoG֛eQP3  JFIF``C     C   ghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?Gѵk:: בVy>+gm * iwp:K)Eܱ>V>i9X&)*Q _C3cq(3L|˰V߫BESYB]g22=]Nui_for_ex16.gif,> QJFIF``C     C    `".gif,nNimage029.jpg>oNarray_view_editor.jpg,pNimage030.gif0qNled_editor.gif,rNimage031.gifDsNthemed_button_editor.gif,tNimage032.gifHuNthemed_checkbox_editor.gif,vNimage033.gif,wNimage03 }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?fPԵ v ‰hI5? ?it WQɮ_ OKst; Օ5|z4]WϹi6ݐ72p1kK o j²ޅ*ªN} `-Z[;5)EY75 ?G 0e¾O C??W"gcW o j±O3kewkj\\B VcК+x\t]:/tq T`e@cb3Iԍ r_ex16.gif,> 8JFIF``C  x㥊O UFm#{9{vU̴sC Z^#}޺ѷڞ4QKoEu8ҴkFS+O-OZ u{k/y*ݵ),M糕qL^eԧ ukmvGf8# >H:sj e oIsΆ;\d#E\t1[Ux+vbΧd[y&H'.++v%3ͨlڏ689W<(8I 4e^EOף<( cm (*Q KLwZMEgiY8R%9ns>58Ag]񇑧uA *O-~ǝ,ϛ[ >6X|N٠k>:Θ5ql~f|ʞDǝVMƀIhd4o?%9}7\njυh~>:rN/ .ZoG֛eQP3 QJFIF``C     C    `" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz     C    `" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?Gѵk:: בVy>+gm * iwp:K)Eܱ>V>i9X&)*Q _C3cq(3L|˰V߫BESYB]g22=]Nui_for_ex16.gif,> JFIF``C     C   "`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?mM*kۑ#Vrwc($=نFT"\)5C>"gW #,l5URGBIt[+Wk%°?Q ]P\ڿo̮X'.J*+AE2dFd'cX52 0QnNE͌mԫV꿯\.4.j=N _Ey8]zzD1-+G|ϩ7+ wyCE'ZE*:O]@Q Xk(a(Z%<Ո6]@,=V-3sn09g {ל[UW!8.du,O lY HFu&2$ؽO-nѕ \eQU'95~ҷĒG<#ɱJr K?՜d?zψZ>=-/5[; a鐃 .AǯC\%@+ ?tF<2w0[$lY.FI鑜dgu>0xDWY*#G5~ YFEYGE?J>ѢxIUQF몽g-x|E= /+K?=G+K?=G'Q w_R´J´J{-x|E= /+K?=G+K?=G"3Ï[f7wp5;8.ca?@ABCDEFGHIJKLMNOPQRSTUVWXZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~"`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?/y8 JV #60.A$##&O?iXݖ'FmojZcg-P +;U[^E_[ᆤ0vy5䝏#-R? _OsE ( Mİ=x7 ?_t_[t :/ -*Iq[6AMs_4O6<:.mxW]+CK./SKmy]t]h7ׅaio k¿04CSKmy]t]h7ׅaio k¿04CSKmy]t]p}# Q"u"I^CE݉=_Qa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?mM*kۑ#Vrwc($=نFT"\)5C>"gW #,l5URGBIt[+Wk%°?Q ]P\ڿo̮X'.J*+AE2dFd'cX52 0QnNE͌mԫV꿯\.4.j=N _Ey8]zzD1-+G|ϩ7+ wyCE'ZE*:O]@Q Xk(a(Z%<Ո6]@,=V-3sn09g {ל[UW!8.du,O lY HFu&2$ؽO-nѕ \eQU'95~ҷĒG<#ɱJr K?՜d?zψZ>=-/5[; a鐃 .AǯC\%@+ ?tF<2w0[$lY.FI鑜dgu>0xDWY*#G5~ YFEYGE?J>ѢxIUQF몽g-x|E= /+K?=G+K?=G'Q w_R´J´J{-x|E= /+K?=G+K?=G"3Ï[f7wp5;8.camojZcg-P +;U[^E_[ᆤ0vy5䝏#-R? _OsE ( Mİ=x7 ?_t_[t :/ -*Iq[6AMs_4O6<:.mxW]+CK./SKmy]t]h7ׅaio k¿04CSKmy]t]h7ׅaio k¿04CSKmy]t]p}# Q"u"I^CE݉=_t_[u|Oޑ6t U-leYb0%TM \[kϷl< β4+Q\(Շ&>M;|-UؚwZߕ ?4+Q@&>M;|-Pυ_N _Ebik~W+KJmǼq?TDM]N U JFIF``C     C   /`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?kzl7׋u KQN%+K!q|`Wu Li;IDa'EK$Fđ8 'q?κ?oܴuv+FKE!\/U:g5MQ Lioܴu?iO %=tWsTaM2Wc.6\k> gs[+JkCR 66i>++` XٲIR)[`ؑv u޴r}o57M;|-UؚwZߕ ?4+Q@&>M;|-Pυ_N _Ebik~W+KJmǼq?T JFIF``C     C   "`" }!1A*U:g5MWc|\O?'Q= NAM{U~ O {,oI,nۛyC<ۛ_?iMr_3 LVj_:gOU®w ?_xgIy?H{xc]3l*/Gc3[Y<ŭm@G\p1z}CTҵL*Y&f,XI%Ky5CasxInc|莠##c+nMkZ[oujuDI+(尬,2%~P5*i3ťv?ݑ>y+I qݐ͸|1Zx{S+d ]`\ mS^tfॽԾak,*CH1_0| ?Q LVjtχ>4K<E+C[_Gæ.c sֺ?P^"#*|^z[?R&}wX/JYuWլ721Ya 821 921 031{w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?kzl7׋u KQN%+K!q|`Wu Li;IDa'EK$Fđ8 'q?κ?oܴuv+FKE!\/U:g5MQ Lioܴu?iO %=tWsTaM2Wc.6\k> gs[+JkCR 66i>++` XٲIR)[`ؑv u޴r}o57_3 LVj_:gOU®w ?_xgIy?H{xc]3l*/Gc3[Y<ŭm@G\p1z}CTҵL*Y&f,XI%Ky5CasxInc|莠##c+nMkZ[oujuDI+(尬,2%~P5*i3ťv?ݑ>y+I qݐ͸|1Zx{S+d ]`\ mS^tfॽԾak,*CH1_0| ?Q LVjtχ>4K<(M^I^*lƇb=HIڣq i:E9 /<ªqA\G--1mrHd}]HdU_:Ag8O =zTf( jI2Exu{i*]]TƉK}BXgGueue|u]F[Y<&*+'#} P^ Cuj$?,!(dl{Ќ_ScyݔduD@FO:PKS-ƓeI@8N:k;fV*!z=|@[V4/%s({+|%]j~&I&yWdcoHm/x`^U ^ƻ@|;@{_⸏Wrx+0XdN3E?Ğ!ӴHM%%Ie;`Wfh|Q}*#$Vi1rA3ڼ>~kk SS;X[?D"Vc(c ⻽z'Z"K^=w 4qƠ2$p{|2|#.G}eD2(v(U|'%_V-;_Nf?$=of?$=oRIa"fP5t>&/K/ G(IzJte`~&Z`~5y1 Q)6`h_rDh&d^kPb%P_O/U _}FVҒ{+g5+ZٶVwQ^ )^߫?Nm+~+xCNҬ4ɭ$g[y.@NwSxMJkgij? U JFIF``C     C   /`" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz  w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?ᦁk?^j^4մe/R4#jGw;\⹱ӧeΌpBޠwk>(M^I^*lƇb=HIڣq i:E9 /<ªqA\G--1mrHd}]HdU_:Ag8O =zTf( jI2Exu{i*]]TƉK}BXgGueue|u]F[Y<&*+'#} P^ Cuj$?,!(dl{Ќ_ScyݔduD@FO:PKS-ƓeI@8N:k;fV*!z=|@[V4/%s({+|%]j~&I&yWdcoHm/x`^U ^ƻ@|;@{_⸏Wrx+0XdN3E?Ğ!ӴHM%%Ie;`Wfh|Q}*#$Vi1rA3ڼ>~kk SS;X[?D"Vc(c ⻽z'Z"K^=w 4qƠ2$p{|2|#.G}eD2(v(U|'%_V-;_Nf?$=of?$=oRIa"fP5t>&/K/ G(IzJte`~&Z`~5y1 Q)6`h_rDh&d^kPb%P_O/U _}FVҒ{+g5+ZٶkT{\|asy2"k,ʱ;011߆q\[2immK2Q$-ɯK|W#Ğ4N1>mf1G2Ņ1Aq8]lN7Fdڛo>T%'EȚvW2eOT,h7~&ּISŵߵI)¸a؞J-~#_xZ]GiC6B/,}'0ӓOM-.ރY&B<^J->;:KI2xAL>E+C[_Gæ.c sֺ?P^"#*|^z[?R&}wX/JYuWլ 9P^"#(/i?º?X/JYu_B^_ξ._#? nѼc͡&@z|f~AxxB&02Hʷ?CWCnΥk l(=P{*qqi#[Yݣ$E%NCM''ҏo/_z_"| Iv%Pۦ[p*K_ڭZ5# Elve?B=k.[j`_w/lSl Aٷ]^::ٴdg.E"=}9|?P^"#(/i?º?X/JYu_B=}9|s= {mBRծtۖIm#*>VwQ^ )^߫?Nm+~+xCNҬ4ɭ$g[y.@NwSxMJkgij?  JFIF``C     C   `H" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdeffB׵IYl 9$l3 a@gr>&yScp9'#Z(,~*U10S{^cOP֓ttr Z<:66 ^e9Q\8  ~8Ly+ݭ][#eO`N6].{M.j``0SʽNui_for_ex1.jpg0SʽNui_for_ex2.jpg,SʽNimage004.jpg0SʽNui_for_ex3.jpg,SʽNimage005.jpg0SʽNui_for_ex4.jpg,SʽNimag]Nimage065.jpg@9]Nimage_enum_editors.jpg,:]Nimage066.jpgJ;]Nsingle_instance_editors.jpg,<]Nimage067.gif2=]Nui_for_ex16.gif,>]Nimage068.jpg4?]Nlist_editors.jpg,@]Nimage069.gifHA]Nlist_with_context_menu.gif,B]Nimage070.jpgDC]Nnotebook_list_editor.jpg,D,Nimage042.jpg@E,Nlist_string_editor.jpg,F]Nimage071.jpg6G]Nrange_editors.jpg,H]Nimage072.jpg0I]Nset_editor.jpg,J]Nimage073.jpg4K]Nshell_editor.jpg,L]Nimage074.gifDM]Ntext_editor_integers.gif,N]Nimage075.gifhemed_ui2.jpg2SʽNunthemed_ui.jpg0SʽNthemed_ui1.jpg4SʽNtheme_image1.gif4SʽNtheme_image2.gif2SʽNui_for_ex12.jpgB,Ndefault_text_editor.gif26w"ts02F?x-_.$zVѢYw$ ƛrB:dĜp0iN_Pj¬OȔ¬OȕA{,TIuk yqОM !k]k]7Y'r /i %2%*-0{G\RdzdZ-_z.Z9cvqq!bUuy7^&1iDmIi$0xqm&%r3ЃA O"o/פ֕~6f7ľ i)HlQ!`NY*#<}kŵ&Km;R'%0Ie4/*:+d'N~ghcQ~2‹͇(ο~?e=u_aǩWWw sȴqLQο~?ǚmK&/'Ҏ_@9.Y\Еk0g XUJ+75~ZSs:#4=bDaf#`2=O  Pߩ¹|CԼ"{&aH<9kЏߡ5鸷*fBB?/S'/-O}o>t/nEԐGy)X2VJH+"/X?ROB?;k`> Z^I#Y3cZ?WP ؖ6Ѱ`yG (G,_)C~ O^ZG/-O}o"$k,MZ-k_&P#'wS~$Q-d,lh@ܻA,Kp;^n;NE5?k=7S"7,iM eY %|Q}?KK;@k.y#(^3R&IҵIgqtc"ưK(;NOQ\ZV4S  JFIF``C     C   `H" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz``0SʽNui_for_ex1.jpg0SʽNui_for_ex2.jpg,SʽNimage004.jpg0SʽNui_for_ex3.jpg,SʽNimage005.jpg0SʽNui_for_ex4.jpg,SʽNimage007.jpg0SʽNui_for_ex7.jpg, SʽNimage008.gif, SʽNimage009.gif@ SʽNalter_title_before.gif> SʽNalter_title_after.gif4 SʽNtheme_image3.gif0SʽNthemed_ui2.jpg2SʽNunthemed_ui.jpg0SʽNthemed_ui1.jpg4SʽNtheme_image1.gif4SʽNtheme_image2.gif2SʽNui_for_ex12.jpgB,Ndefault_text_editor.gif2,Nui_for_ex13.jpg@,Ncustom_enum_editor.jpg2,NHTML_editor.gif,,Nimage051.gif<,Nread_only_editor.jpgN,Nsimple_enum_editor_closed.jpgJ,Nsimple_enum_editor_open.jpg2,Ntext_editor.jpg6,Narray_editors.gN_Pj¬OȔ¬OȕA{,TIuk yqОM !k]k]7Y'r /i %2%*-0{G\RdzdZ-_z.Z9cvqq!bUuy7^&1iDmIi$0xqm&%r3ЃA O"o/פ֕~6f7ľ i)HlQ!`NY*#<}kŵ&Km;R'%0Ie4/*:+d'N~ghcQ~2‹͇(ο~?e=u_aǩWWw sȴqLQο~?ǚmK&/'Ҏ_@9.Y\Еk0g XUJ+75~ZSs:#4=bDaf#`2=O  Pߩ¹|CԼ"{&aH<9kЏߡ5鸷*fBB?/S'/-O}o>t/nEԐGy)X2VJH+"/X?ROB?;k`> Z^I#Y3cZ?WP ؖ6Ѱ`yG (G,_)C~ O^ZG/-O}o"$k,MZ-k_&P#'wS~$Q-d,lh@ܻA,Kp;^n;NE5?k=7S"7,iM eY %|Q}?KK;@k.y#(^3R&IҵIgqtc"ưK(;NOQ\ZV4S oJFIF``C     C   " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz if,,Nimage052.jpg:,Nboolean_editors.jpg, ,Nimage053.gif8!,Nbutton_editors.gif,",Nimage054.gif>#,Nchecklist_editors.gif,$,Nimage055.jpg4%,Ncode_editors.jpg,&,Nimage056.jpg6',Ncolor_editors.jpg,(,Nimage057.jpgD),Ncolor_picker_windows.jpg,*,Nimage058.gif<+,Ncompound_editors.gif,,,Nimage059.gif>-,Ndirectory_editors.gif,.,Nimage060.gif4/,Nenum_editors.gif,0,Nimage061.gif41,Nfile_editors.gif,2]Nimage062.gif43]Nfont_editors.gif,4]Nimage063.jpgB5]Nfont_dialog_windows.jpg,6]Nimage064.gif<7]Nhtml_code_editor.gif,8]Nimage065.jpg@9]Nimage_enum_editors.jpg,:]Nimage066.jpgJ;]Nsingle_instance_editors.jpg,<]Nimage067.gif2=]Nui_for_ex16.gif,>]Nimage068.jpg4?]Nlist_editors.jpg,@]Nimage069.gifHA]Nlist_with_context_menu.gif,B]Nimage070.jpgDC]Nnotebook_list_editor.jpg,D,Nimage042.jpg@E,Nlist_string_editor.jpg,F]Nimage071.jpg6G]Nrange_editors.jpg,H]Nimage072.jpg0I]Nset_editor.jpg,J]Nimage073.jpg4K]Nshell_editor.jpg,L]Nimage074.gifDM]Ntext_editor_integers.gif,N]Nimage075.gifBO]Ntext_editor_strings.gif,P]Nimage076.gifHQ]Ntext_editors_passwords.gif,R]Nimage077.gif6S]Ntuple_editors.gif,T]Nimage078.gif4U]Nvalue_editor.gif,VSʽNimage017.jpg@WSʽNkey_binding_editor.jpg,XSʽNimage018.jpg4YSʽNtraitsui-4.1.0/docs/source/traitsui_user_manual/factory_intro.rst0000644000175100001440000003712111674463545026467 0ustar ischnellusers00000000000000.. _introduction-to-trait-editor-factories: ====================================== Introduction to Trait Editor Factories ====================================== The preceding code samples in this User Manual have been surprisingly simple considering the sophistication of the interfaces that they produce. In particular, no code at all has been required to produce appropriate widgets for the Traits to be viewed or edited in a given window. This is one of the strengths of TraitsUI: usable interfaces can be produced simply and with a relatively low level of UI programming expertise. An even greater strength lies in the fact that this simplicity does not have to be paid for in lack of flexibility. Where a novice TraitsUI programmer can ignore the question of widgets altogether, a more advanced one can select from a variety of predefined interface components for displaying any given Trait. Furthermore, a programmer who is comfortable both with TraitsUI and with UI programming in general can harness the full power and flexibility of the underlying GUI toolkit from within TraitsUI. The secret behind this combination of simplicity and flexibility is a TraitsUI construct called a trait :term:`editor factory`. A trait editor factory encapsulates a set of display instructions for a given :term:`trait type`, hiding GUI-toolkit-specific code inside an abstraction with a relatively straightforward interface. Furthermore, every :term:`predefined trait type` in the Traits package has a predefined trait editor factory that is automatically used whenever the trait is displayed, unless you specify otherwise. Consider the following script and the window it creates: .. _example-12-using-default-trait-editors: .. rubric:: Example 12: Using default trait editors :: # default_trait_editors.py -- Example of using default # trait editors from traits.api import HasTraits, Str, Range, Bool from traitsui.api import View, Item class Adult(HasTraits): first_name = Str last_name = Str age = Range(21,99) registered_voter = Bool traits_view = View(Item(name='first_name'), Item(name='last_name'), Item(name='age'), Item(name='registered_voter')) alice = Adult(first_name='Alice', last_name='Smith', age=42, registered_voter=True) alice.configure_traits() .. figure:: images/ui_for_ex12.jpg :alt: UI showing text boxes for names, slider for Age, and checkbox for voter Figure 12: User interface for Example 12 Notice that each trait is displayed in an appropriate widget, even though the code does not explicitly specify any widgets at all. The two Str traits appear in text boxes, the Range is displayed using a combination of a text box and a slider, and the Bool is represented by a checkbox. Each implementation is generated by the default trait editor factory (TextEditor, RangeEditor and BooleanEditor respectively) associated with the trait type. TraitsUI is by no means limited to these defaults. There are two ways to override the default representation of a :term:`trait attribute` in a TraitsUI window: - Explicitly specifying an alternate trait editor factory - Specifying an alternate style for the editor generated by the factory The remainder of this chapter examines these alternatives more closely. .. _specifying-an-alternate-trait-editor-factory: Specifying an Alternate Trait Editor Factory -------------------------------------------- As of this writing the TraitsUI package includes a wide variety of predefined trait editor factories, which are described in :ref:`basic-trait-editor-factories` and :ref:`advanced-trait-editors`. Some additional editor factories are specific to the wxWidgets toolkit and are defined in one of the following packages: - traitsui.wx - traitsui.wx.extra - traitsui.wx.extra.windows (specific to Microsoft Windows) These editor factories are described in :ref:`extra-trait-editor-factories`. For a current complete list of editor factories, refer to the *Traits API Reference*. Other packages can define their own editor factories for their own traits. For example, enthought.kiva.api.KivaFont uses a KivaFontEditor() and enthought.enable2.traits.api.RGBAColor uses an RGBAColorEditor(). For most :term:`predefined trait type`\ s (see `Traits User Manual `_), there is exactly one predefined trait editor factory suitable for displaying it: the editor factory that is assigned as its default. [15]_ There are exceptions, however; for example, a Str trait defaults to using a TextEditor, but can also use a CodeEditor or an HTMLEditor. A List trait can be edited by means of ListEditor, TableEditor (if the List elements are HasTraits objects), CheckListEditor or SetEditor. Furthermore, the TraitsUI package includes tools for building additional trait editors and factories for them as needed. To use an alternate editor factory for a trait in a TraitsUI window, you must specify it in the View for that window. This is done at the Item level, using the *editor* keyword parameter. The syntax of the specification is :samp:`editor = {editor_factory}()`. (Use the same syntax for specifying that the default editor should be used, but with certain keyword parameters explicitly specified; see :ref:`initializing-editors`). For example, to display a Str trait called **my_string** using the default editor factory (TextEditor()), the View might contain the following Item:: Item(name='my_string') The resulting widget would have the following appearance: .. figure:: images/default_text_editor.png :alt: Text field showing text that contains HTML markup Figure 13: Default editor for a Str trait To use the HTMLEditor factory instead, add the appropriate specification to the Item:: Item( name='my_string', editor=HTMLEditor() ) The resulting widget appears as in Figure 14: .. figure:: images/HTML_editor.png :alt: Same text as Figure 13, styled as HTML Figure 14: Editor generated by HTMLEditor() .. NOTE:: TraitsUI does not check editors for appropriateness. TraitsUI does not police the *editor* argument to ensure that the specified editor is appropriate for the trait being displayed. Thus there is nothing to prevent you from trying to, say, display a Float trait using ColorEditor(). The results of such a mismatch are unlikely to be helpful, and can even crash the application; it is up to the programmer to choose an editor sensibly. :ref:`the-predefined-trait-editor-factories` is a useful reference for selecting an appropriate editor for a given task. It is possible to specify the trait editor for a trait in other ways: - You can specify a trait editor when you define a trait, by passing the result of a trait editor factory as the *editor* keyword parameter of the callable that creates the trait. However, this approach commingles the :term:`view` of a trait with its :term:`model`. - You can specify the **editor** attribute of a TraitHandler object. This approach commingles the :term:`view` of a trait with its :term:`controller`. Use these approaches very carefully, if at all, as they muddle the :term:`MVC` design pattern. .. _initializing-editors: Initializing Editors ```````````````````` Many of the TraitsUI trait editors can be used "straight from the box" as in the example above. There are some editors, however, that must be initialized in order to be useful. For example, a checklist editor (from CheckListEditor()) and a set editor (from SetEditor()) both enable the user to edit a List attribute by selecting elements from a specified set; the contents of this set must, of course, be known to the editor. This sort of initialization is usually performed by means of one or more keyword arguments to the editor factory, for example:: Item(name='my_list',editor=CheckListEditor(values=["opt1","opt2","opt3"])) The descriptions of trait editor factories in :ref:`the-predefined-trait-editor-factories` include a list of required and optional initialization keywords for each editor. .. _specifying-an-editor-style: Specifying an Editor Style -------------------------- In TraitsUI, any given trait editor can be generated in one or more of four different styles: *simple*, *custom*, *text* or *readonly*. These styles, which are described in general terms below, represent different "flavors" of data display, so that a given trait editor can look completely different in one style than in another. However, different trait editors displayed in the same style (usually) have noticeable characteristics in common. This is useful because editor style, unlike individual editors, can be set at the Group or View level, not just at the Item level. This point is discussed further in :ref:`using-editor-styles`. .. _the-simple-style: The 'simple' Style `````````````````` The *simple* editor style is designed to be as functional as possible while requiring minimal space within the window. In simple style, most of the Traits UI editors take up only a single line of space in the window in which they are embedded. In some cases, such as the text editor and Boolean editor (see :ref:`basic-trait-editor-factories`), the single line is fully sufficient. In others, such as the (plain) color editor and the enumeration editor, a more detailed interface is required; pop-up panels, drop-down lists, or dialog boxes are often used in such cases. For example, the simple version of the enumeration editor for the wxWidgets toolkit looks like this: .. figure:: images/simple_enum_editor_closed.jpg :alt: Closed drop-list editor Figure 15: Simple style of enumeration editor However, when the user clicks on the widget, a drop-down list appears: .. figure:: images/simple_enum_editor_open.jpg :alt: Expanded drop-list editor Figure 16: Simple enumeration editor with expanded list The simple editor style is most suitable for windows that must be kept small and concise. The 'custom' Style `````````````````` The *custom* editor style generally generates the most detailed version of any given editor. It is intended to provide maximal functionality and information without regard to the amount of window space used. For example, in the wxWindows toolkit, the custom style the enumeration editor appears as a set of radio buttons rather than a drop-down list: .. figure:: images/custom_enum_editor.jpg :alt: Radio buttons for a set of values Figure 17: Custom style of enumeration editor In general, the custom editor style can be very useful when there is no need to conserve window space, as it enables the user to see as much information as possible without having to interact with the widget. It also usually provides the most intuitive interface of the four. Note that this style is not defined explicitly for all trait editor implementations. If the custom style is requested for an editor for which it is not defined, the simple style is generated instead. The 'text' Style ```````````````` The *text* editor style is the simplest of the editor styles. When applied to a given trait attribute, it generates a text representation of the trait value in an editable box. Thus the enumeration editor in text style looks like the following: .. figure:: images/text_editor.jpg :alt: Text field Figure 18: Text style of enumeration editor For this type of editor, the end user must type in a valid value for the attribute. If the user types an invalid value, the validation method for the attribute (see `Traits User Manual `_) notifies the user of the error (for example, by shading the background of the text box red). The text representation of an attribute to be edited in a text style editor is created in one of the following ways, listed in order of priority: #. The function specified in the **format_func** attribute of the Item (see :ref:`the-item-object`), if any, is called on the attribute value. #. Otherwise, the function specified in the *format_func* parameter of the trait editor factory, if any, is called on the attribute value. #. Otherwise, the Python-style formatting string specified in the **format_str** attribute of the Item (see :ref:`the-item-object`), if any, is used to format the attribute value. #. The Python-style formatting string specified in the *format_str* parameter of the trait editor factory, if any, is used to format the attribute value. #. Otherwise, the Python str() function is called on the attribute value. The 'readonly' style ```````````````````` The *readonly* editor style is usually identical in appearance to the text style, except that the value appears as static text rather than in an editable box: .. figure:: images/read_only_editor.jpg :alt: Read-only text field Figure 19: Read-only style of enumeration editor This editor style is used to display data values without allowing the user to change them. .. _using-editor-styles: Using Editor Styles ``````````````````` As discussed in :ref:`contents-of-a-view` and :ref:`customizing-a-view`, the Item, Group and View objects of TraitsUI all have a **style** attribute. The style of editor used to display the Items in a View is determined as follows: #. The editor style used to display a given Item is the value of its **style** attribute if specifically assigned. Otherwise the editor style of the Group or View that contains the Item is used. #. The editor style of a Group is the value of its **style** attribute if assigned. Otherwise, it is the editor style of the Group or View that contains the Group. #. The editor style of a View is the value of its **style** attribute if specified, and 'simple' otherwise. In other words, editor style can be specified at the Item, Group or View level, and in case of conflicts the style of the smaller scope takes precedence. For example, consider the following script: .. _example-13-using-editor-styles-at-various-levels: .. rubric:: Example 13: Using editor styles at various levels :: # mixed_styles.py -- Example of using editor styles at # various levels from traits.api import HasTraits, Str, Enum from traitsui.api import View, Group, Item class MixedStyles(HasTraits): first_name = Str last_name = Str department = Enum("Business", "Research", "Admin") position_type = Enum("Full-Time", "Part-Time", "Contract") traits_view = View(Group(Item(name='first_name'), Item(name='last_name'), Group(Item(name='department'), Item(name='position_type', style='custom'), style='simple')), title='Mixed Styles', style='readonly') ms = MixedStyles(first_name='Sam', last_name='Smith') ms.configure_traits() Notice how the editor styles are set for each attribute: - **position_type** at the Item level (lines 19-20) - **department** at the Group level (lines 18 and 21) - **first_name** and **last_name** at the View level (lines 16, 17, and 23) The resulting window demonstrates these precedence rules: .. figure:: images/ui_for_ex13.jpg :alt: UI showing read-only text, closed drop-list, and radio buttons Figure 20: User interface for Example 13 .. rubric:: Footnotes .. [15] Appendix II contains a table of the predefined trait types in the Traits package and their default trait editor types. traitsui-4.1.0/docs/source/traitsui_user_manual/view.rst0000644000175100001440000006012411674463545024556 0ustar ischnellusers00000000000000.. _the-view-and-its-building-blocks: ================================ The View and Its Building Blocks ================================ A simple way to edit (or simply observe) the attribute values of a :term:`HasTraits` object in a GUI window is to call the object's configure_traits() [3]_ method. This method constructs and displays a window containing editable fields for each of the object's :term:`trait attribute`\ s. For example, the following sample code [4]_ defines the SimpleEmployee class, creates an object of that class, and constructs and displays a GUI for the object: .. index:: pair: examples; configure_traits() .. _example-1-using-configure-traits: .. rubric:: Example 1: Using configure_traits() :: # configure_traits.py -- Sample code to demonstrate # configure_traits() from traits.api import HasTraits, Str, Int import traitsui class SimpleEmployee(HasTraits): first_name = Str last_name = Str department = Str employee_number = Str salary = Int sam = SimpleEmployee() sam.configure_traits() Unfortunately, the resulting form simply displays the attributes of the object **sam** in alphabetical order with little formatting, which is seldom what is wanted: .. figure:: images/ui_for_ex1.jpg :alt: Dialog box showing all attributes of SimpleEmployee in alphabetical order Figure 1: User interface for Example 1 .. index:: object: View .. _the-view-object: The View Object --------------- In order to control the layout of the interface, it is necessary to define a View object. A View object is a template for a GUI window or panel. In other words, a View specifies the content and appearance of a TraitsUI window or panel display. For example, suppose you want to construct a GUI window that shows only the first three attributes of a SimpleEmployee (e.g., because salary is confidential and the employee number should not be edited). Furthermore, you would like to specify the order in which those fields appear. You can do this by defining a View object and passing it to the configure_traits() method: .. index:: configure_traits(); view parameter, examples; View object .. _example-2-using-configure-traits-with-a-view-object: .. rubric:: Example 2: Using configure_traits() with a View object :: # configure_traits_view.py -- Sample code to demonstrate # configure_traits() from traits.api import HasTraits, Str, Int from traitsui.api import View, Item import traitsui class SimpleEmployee(HasTraits): first_name = Str last_name = Str department = Str employee_number = Str salary = Int view1 = View(Item(name = 'first_name'), Item(name = 'last_name'), Item(name = 'department')) sam = SimpleEmployee() sam.configure_traits(view=view1) The resulting window has the desired appearance: .. figure:: images/ui_for_ex2.jpg :alt: User interface showing only First name, Last name, and Department Figure 2: User interface for Example 2 A View object can have a variety of attributes, which are set in the View definition, following any Group or Item objects. The sections on :ref:`contents-of-a-view` through :ref:`advanced-view-concepts` explore the contents and capabilities of Views. Refer to the *Traits API Reference* for details of the View class. Except as noted, all example code uses the configure_traits() method; a detailed description of this and other techniques for creating GUI displays from Views can be found in :ref:`displaying-a-view`. .. index:: View; contents object: View .. _contents-of-a-view: Contents of a View ------------------ The contents of a View are specified primarily in terms of two basic building blocks: Item objects (which, as suggested by Example 2, correspond roughly to individual trait attributes), and Group objects. A given View definition can contain one or more objects of either of these types, which are specified as arguments to the View constructor, as in the case of the three Items in Example 2. The remainder of this chapter describes the Item and Group classes. .. index:: widget, control object: Item .. _the-item-object: The Item Object ``````````````` The simplest building block of a View is the :term:`Item` object. An Item specifies a single interface :term:`widget`, usually the display for a single trait attribute of a HasTraits object. The content, appearance, and behavior of the widget are controlled by means of the Item object's attributes, which are usually specified as keyword arguments to the Item constructor, as in the case of *name* in Example 2. The remainder of this section describes the attributes of the Item object, grouped by categories of functionality. It is not necessary to understand all of these attributes in order to create useful Items; many of them can usually be left unspecified, as their default values are adequate for most purposes. Indeed, as demonstrated by earlier examples, simply specifying the name of the trait attribute to be displayed is often enough to produce a usable result. The following table lists the attributes of the Item class, organized by functional categories. Refer to the *Traits API Reference* for details on the Item class. .. index:: attributes; Item, Item; attributes .. index:: name attribute, dock attribute; Item, emphasized attribute .. index:: export attribute; Item, height attribute; Item, image attribute; Item .. index:: item_theme attribute; Item, label attribute; Item .. index:: label_theme attribute; Item, padding attribute; Item .. index:: resizable attribute, show_label attribute, springy attribute; Item .. index:: width attribute; Item, format_str attribute, format_func attribute .. index:: editor attribute, style attribute; Item, enabled_when attribute; Item .. index:: visible_when attribute; Item, defined_when attribute; Item .. index:: has_focus attribute, tooltip attribute, help attribute; Item .. index:: help_id attribute; Item, id attribute; Item .. _attributes-of-item-by-category-table: .. rubric:: Attributes of Item, by category +----------+---------------------+---------------------------------------------+ |Category |Attributes |Description | +==========+=====================+=============================================+ |Content | * **name** |These attributes specify the actual data to | | | |be displayed by an item. Because an Item is | | | |essentially a template for displaying a | | | |single trait, its **name** attribute is | | | |nearly always specified. | +----------+---------------------+---------------------------------------------+ |Display |* **dock** |In addition to specifying which trait | |format |* **emphasized** |attributes are to be displayed, you might | | |* **export** |need to adjust the format of one or more of | | |* **height** |the resulting widgets. | | |* **image** | | | |* **item_theme** |If an Item's **label** attribute is specified| | |* **label** |but not its name, the value of **label** is | | |* **label_theme** |displayed as a simple, non-editable string. | | |* **padding** |(This feature can be useful for displaying | | |* **resizable** |comments or instructions in a TraitsUI | | |* **show_label** |window.) | | |* **springy** | | | |* **width** | | +----------+---------------------+---------------------------------------------+ |Content |* **format_str** |In some cases it can be desirable to apply | |format |* **format_func** |special formatting to a widget's contents | | | |rather than to the widget itself. Examples of| | | |such formatting might include rounding a | | | |floating-point value to two decimal places, | | | |or capitalizing all letter characters in a | | | |license plate number. | +----------+---------------------+---------------------------------------------+ |Widget |* **editor** |These attributes override the widget that is | |override |* **style** |automatically selected by TraitsUI. These | | | |options are discussed in | | | |:ref:`introduction-to-trait-editor-factories`| | | |and | | | |:ref:`the-predefined-trait-editor-factories`.| +----------+---------------------+---------------------------------------------+ |Visibility|* **enabled_when** |Use these attributes to create a simple form | |and status|* **visible_when** |of a dynamic GUI, which alters the display | | |* **defined_when** |in response to changes in the data it | | |* **has_focus** |contains. More sophisticated dynamic behavior| | | |can be implemented using a custom | | |.. TODO: Add examples|:term:`Handler` see | | | here |:ref:`controlling-the-interface-the-handler` | | | |). | +----------+---------------------+---------------------------------------------+ |User help |* **tooltip** |These attributes provide guidance to the user| | |* **help** |in using the user interface. If the **help** | | |* **help_id** |attribute is not defined for an Item, a | | | |system-generated message is used instead. The| | |.. TODO: Add sample |**help_id** attribute is ignored by the | | | help screen |default help handler, but can be used by a | | | |custom help handler. | +----------+---------------------+---------------------------------------------+ |Unique |* **id** |The **id** attribute is used as a key for | |identifier| |saving user preferences about the widget. If | | | |**id** is not specified, the value of the | | | |**name** attribute is used. | +----------+---------------------+---------------------------------------------+ .. index:: Label class, Heading class, Spring class pair: Item; subclasses .. _subclasses-of-item: Subclasses of Item `````````````````` The TraitsUI package defines the following subclasses of Item: * Label * Heading * Spring These classes are intended to help with the layout of a TraitsUI View, and need not have a trait attribute associated with them. See the *Traits API Reference* for details. .. index: object: Group .. _the-group-object: The Group Object ```````````````` The preceding sections have shown how to construct windows that display a simple vertical sequence of widgets using instances of the View and Item classes. For more sophisticated interfaces, though, it is often desirable to treat a group of data elements as a unit for reasons that might be visual (e.g., placing the widgets within a labeled border) or logical (activating or deactivating the widgets in response to a single condition, defining group-level help text). In TraitsUI, such grouping is accomplished by means of the :term:`Group` object. Consider the following enhancement to Example 2: pair: configure_traits(); examples triple: View; Group; examples .. _example-3-using-configure-traits-with-a-view-and-a-group-object: .. rubric:: Example 3: Using configure_traits() with a View and a Group object :: # configure_traits_view_group.py -- Sample code to demonstrate # configure_traits() from traits.api import HasTraits, Str, Int from traitsui.api import View, Item, Group import traitsui class SimpleEmployee(HasTraits): first_name = Str last_name = Str department = Str employee_number = Str salary = Int view1 = View(Group(Item(name = 'first_name'), Item(name = 'last_name'), Item(name = 'department'), label = 'Personnel profile', show_border = True)) sam = SimpleEmployee() sam.configure_traits(view=view1) The resulting window shows the same widgets as before, but they are now enclosed in a visible border with a text label: .. figure:: images/ui_for_ex3.jpg :alt: User interface showing three fields enclosed in a border Figure 3: User interface for Example 3 .. indexx: pair: contents; Group .. _content-of-a-group: Content of a Group :::::::::::::::::: The content of a Group object is specified exactly like that of a View object. In other words, one or more Item or Group objects are given as arguments to the Group constructor, e.g., the three Items in Example 3. [5]_ The objects contained in a Group are called the *elements* of that Group. Groups can be nested to any level. .. index:: pair: attributes; Group .. _group-attributes: Group Attributes :::::::::::::::: The following table lists the attributes of the Group class, organized by functional categories. As with Item attributes, many of these attributes can be left unspecified for any given Group, as the default values usually lead to acceptable displays and behavior. See the *Traits API Reference* for details of the Group class. .. index:: object attribute; Group, content attribute; Group .. index:: label attribute; Group, show_border attribute, show_labels attribute .. index:: show_left attribute, padding attribute; Group, layout attribute .. index:: selected attribute, orientation attribute, style attribute; Group .. index:: columns attribute, dock attribute; Group, dock_theme attribute .. index:: group_theme attribute, item_theme attribute; Group .. index:: label_theme attribute; Group, image attribute; Group .. index:: export attribute; Group, springy attribute; Group .. _attributes-of-group-by-category-table: .. rubric:: Attributes of Group, by category +----------+---------------------+---------------------------------------------+ |Category |Attributes |Description | +==========+=====================+=============================================+ |Content |* **object** |The **object** attribute references the | | |* **content** |object whose traits are being edited by | | | |members of the group; by default this is | | | |'object', but could be another object in the | | | |current context. The **content** attribute is| | | |a list of elements in the group. | +----------+---------------------+---------------------------------------------+ |Display |* **columns** |These attributes define display options for | |format |* **dock** |the group as a whole. | | |* **dock_theme** | | | |* **export** | | | |* **group_theme** |.. index:: enabled_when attribute; Group | | |* **image** |.. index:: visible_when attribute; Group | | |* **item_theme** |.. index:: defined_when attribute; Group | | |* **label** |.. index:: help attribute; Group | | |* **label_theme** |.. index:: help_id attribute; Group | | |* **layout** |.. index:: id attribute; Group | | |* **orientation** | | | |* **padding** | | | |* **selected** | | | |* **show_border** | | | |* **show_labels** | | | |* **show_left** | | | |* **springy** | | | |* **style** | | +----------+---------------------+---------------------------------------------+ |Visibility|* **enabled_when** |These attributes work similarly to the | |and status|* **visible_when** |attributes of the same names on the Item | | |* **defined_when** |class. | | | | | | | |.. TODO: Does Item-level or Group-level take | | | | precedence? Find out and document. | +----------+---------------------+---------------------------------------------+ |User help |* **help** |The help text is used by the default help | | |* **help_id** |handler only if the group is the only | | | |top-level group for the current View. For | | | |example, suppose help text is defined for a | | | |Group called **group1**. The following View | | | |shows this text in its help window:: | | | | | | | | View(group1) | | | | | | | |The following two do not:: | | | | | | | | View(group1, group2) | | | | View(Group(group1)) | | | | | | | |The **help_id** attribute is ignored by the | | | |default help handler, but can be used by a | | | |custom help handler. | | | | | | | |.. TODO: The document needs to include | | | | material on organizing Views via Groups, | | | | including the implied top-level group of | | | | every View. If we do this earlier in the | | | | document, it will probably simplify this. | +----------+---------------------+---------------------------------------------+ |Unique |* **id** |The **id** attribute is used as a key for | |identifier| |saving user preferences about the widget. If | | | |**id** is not specified, the **id** values | | | |of the elements of the group are concatenated| | | |and used as the group identifier. | +----------+---------------------+---------------------------------------------+ .. index:: pair: subclasses; Group .. _subclasses-of-group: Subclasses of Group ``````````````````` The TraitsUI package defines the following subclasses of Group, which are helpful shorthands for defining certain types of groups. Refer to the *Traits API Reference* for details. .. index:: HGroup, HFlow, HSplit, Tabbed, VGroup, VFlow, VGrid, VFold, VSplit .. _subclasses-of-group_table: .. rubric:: Subclasses of Group +-----------+------------------------------+-----------------------------------------+ |Subclass |Description |Equivalent To | +===========+==============================+=========================================+ |HGroup |A group whose items are laid |:samp:`Group(orientation='horizontal')` | | |out horizontally. | | +-----------+------------------------------+-----------------------------------------+ |HFlow |A horizontal group whose items|:samp:`Group(orientation='horizontal', | | |"wrap" when they exceed the |layout='flow', show_labels=False)` | | |available horizontal space. | | +-----------+------------------------------+-----------------------------------------+ |HSplit |A horizontal group with |:samp:`Group(orientation='horizontal', | | |splitter bars to separate it |layout='split')` | | |from other groups. | | +-----------+------------------------------+-----------------------------------------+ |Tabbed |A group that is shown as a tab|:samp:`Group(orientation='horizontal' | | |in a notebook. |layout='tabbed', springy=True)` | +-----------+------------------------------+-----------------------------------------+ |VGroup |A group whose items are laid |:samp:`Group(orientation='vertical')` | | |out vertically. | | +-----------+------------------------------+-----------------------------------------+ |VFlow |A vertical group whose items |:samp:`Group(orientation='vertical', | | |"wrap" when they exceed the |layout='flow', show_labels=False)` | | |available vertical space. | | +-----------+------------------------------+-----------------------------------------+ |VFold |A vertical group in which |:samp:`Group(orientation='vertical', | | |items can be collapsed (i.e., |layout='fold', show_labels=False)` | | |folded) by clicking their | | | |titles. | | +-----------+------------------------------+-----------------------------------------+ |VGrid |A vertical group whose items |:samp:`Group(orientation='vertical', | | |are laid out in two columns. |columns=2)` | +-----------+------------------------------+-----------------------------------------+ |VSplit |A vertical group with splitter|:samp:`Group(orientation='vertical', | | |bars to separate it from other|layout='split')` | | |groups. | | +-----------+------------------------------+-----------------------------------------+ .. rubric:: Footnotes .. [3] If the code is being run from a program that already has a GUI defined, then use edit_traits() instead of configure_traits(). These methods are discussed in more detail in :ref:`displaying-a-view`. .. [4] All code examples in this guide that include a file name are also available as examples in the :file:`tutorials/doc_examples/examples` subdirectory of the Traits docs directory. You can run them individually, or view them in a tutorial program by running: :program:`python` :file:`{Traits_dir}/tutorials/tutor.py` :file:`{Traits_dir}/docs/tutorials/doc_examples` .. [5] As with Views, it is possible for a Group to contain objects of more than one type, but it is not recommended. traitsui-4.1.0/docs/source/traitsui_user_manual/advanced_view.rst0000644000175100001440000004537411674463545026415 0ustar ischnellusers00000000000000.. index:: View; internal, View; external, View; ways of displaying pair: View; context .. _advanced-view-concepts: ====================== Advanced View Concepts ====================== The preceding chapters of this Manual give an overview of how to use the View class to quickly construct a simple window for a single HasTraits object. This chapter explores a number of more complex techniques that significantly increase the power and versatility of the View object. * *Internal Views:* Views can be defined as attributes of a HasTraits class; one class can have multiple views. View attributes can be inherited by subclasses. * *External Views:* A view can be defined as a module variable, inline as a function or method argument, or as an attribute of a :term:`Handler`. * *Ways of displaying Views:* You can display a View by calling configure_traits() or edit_traits() on a HasTraits object, or by calling the ui() method on the View object. * *View context:* You can pass a context to any of the methods for displaying views, which is a dictionary of labels and objects. In the default case, this dictionary contains only one object, referenced as 'object', but you can define contexts that contain multiple objects. * *Include objects:* You can use an Include object as a placeholder for view items defined elsewhere. .. index: View; internal .. _internal-views: Internal Views -------------- In the examples thus far, the View objects have been external. That is to say, they have been defined outside the model (HasTraits object or objects) that they are used to display. This approach is in keeping with the separation of the two concepts prescribed by the :term:`MVC` design pattern. There are cases in which it is useful to define a View within a HasTraits class. In particular, it can be useful to associate one or more Views with a particular type of object so that they can be incorporated into other parts of the application with little or no additional programming. Further, a View that is defined within a model class is inherited by any subclasses of that class, a phenomenon called *visual inheritance*. .. _defining-a-default-view: Defining a Default View ``````````````````````` .. index:: default view, View; default It is easy to define a default view for a HasTraits class: simply create a View attribute called **traits_view** for that class. Consider the following variation on Example 3: .. index:: configure_traits(); default view example, default view; example .. index:: examples; default view .. _example-5-using-configure-traits-with-a-default-view-object: .. rubric:: Example 5: Using configure_traits() with a default View object :: # default_traits_view.py -- Sample code to demonstrate the use of # 'traits_view' from traits.api import HasTraits, Str, Int from traitsui.api import View, Item, Group import traitsui class SimpleEmployee2(HasTraits): first_name = Str last_name = Str department = Str employee_number = Str salary = Int traits_view = View(Group(Item(name = 'first_name'), Item(name = 'last_name'), Item(name = 'department'), label = 'Personnel profile', show_border = True)) sam = SimpleEmployee2() sam.configure_traits() In this example, configure_traits() no longer requires a *view* keyword argument; the **traits_view** attribute is used by default, resulting in the same display as in Figure 3: .. figure:: images/ui_for_ex3.jpg :alt: User interface showing three fields enclosed in a border Figure 5: User interface for Example 5 It is not strictly necessary to call this View attribute **traits_view**. If exactly one View attribute is defined for a HasTraits class, that View is always treated as the default display template for the class. However, if there are multiple View attributes for the class (as discussed in the next section), if one is named 'traits_view', it is always used as the default. .. index:: View; multiple, multiple Views .. _defining-multiple-views-within-the-model: Defining Multiple Views Within the Model ```````````````````````````````````````` Sometimes it is useful to have more than one pre-defined view for a model class. In the case of the SimpleEmployee class, one might want to have both a "public information" view like the one above and an "all information" view. One can do this by simply adding a second View attribute: .. index:: pair: examples; multiple Views .. _example-6-defining-multiple-view-objects-in-a-hastraits-class: .. rubric:: Example 6: Defining multiple View objects in a HasTraits class :: # multiple_views.py -- Sample code to demonstrate the use of # multiple views from traits.api import HasTraits, Str, Int from traitsui.api import View, Item, Group import traitsui class SimpleEmployee3(HasTraits): first_name = Str last_name = Str department = Str employee_number = Str salary = Int traits_view = View(Group(Item(name = 'first_name'), Item(name = 'last_name'), Item(name = 'department'), label = 'Personnel profile', show_border = True)) all_view = View(Group(Item(name = 'first_name'), Item(name = 'last_name'), Item(name = 'department'), Item(name = 'employee_number'), Item(name = 'salary'), label = 'Personnel database ' + 'entry', show_border = True)) sam = SimpleEmployee3() sam.configure_traits() sam.configure_traits(view='all_view') .. index:: traits_view attribute, configure_traits(); view parameter As before, a simple call to configure_traits() for an object of this class produces a window based on the default View (**traits_view**). In order to use the alternate View, use the same syntax as for an external view, except that the View name is specified in single quotes to indicate that it is associated with the object rather than being a module-level variable:: configure_traits(view='all_view'). Note that if more than one View is defined for a model class, you must indicate which one is to be used as the default by naming it ``traits_view``. Otherwise, TraitsUI gives preference to none of them, and instead tries to construct a default View, resulting in a simple alphabetized display as described in :ref:`the-view-and-its-building-blocks`. For this reason, it is usually preferable to name a model's default View traits_view even if there are no other Views; otherwise, simply defining additional Views, even if they are never used, can unexpectedly change the behavior of the GUI. .. index:: View; external .. _separating-model-and-view-external-views: Separating Model and View: External Views ----------------------------------------- In all the preceding examples in this guide, the concepts of model and view have remained closely coupled. In some cases the view has been defined in the model class, as in :ref:`internal-views`; in other cases the configure_traits() method that produces a window from a View has been called from a HasTraits object. However, these strategies are simply conveniences; they are not an intrinsic part of the relationship between model and view in TraitsUI. This section begins to explore how the TraitsUI package truly supports the separation of model and view prescribed by the :term:`MVC` design pattern. An *external* view is one that is defined outside the model classes. In Traits UI, you can define a named View wherever you can define a variable or class attribute. [7]_ A View can even be defined in-line as a function or method argument, for example:: object.configure_traits(view=View(Group(Item(name='a'), Item(name='b'), Item(name='c'))) However, this approach is apt to obfuscate the code unless the View is very simple. :ref:`Example 2 ` through :ref:`Example 4 ` demonstrate external Views defined as variables. One advantage of this convention is that the variable name provides an easily accessible "handle" for re-using the View. This technique does not, however, support visual inheritance. A powerful alternative is to define a View within the :term:`controller` (Handler) class that controls the window for that View. [8]_ This technique is described in :ref:`controlling-the-interface-the-handler`. .. index:: View; methods for displaying .. _displaying-a-view: Displaying a View ----------------- TraitsUI provides three methods for creating a window or panel from a View object. The first two, configure_traits() and edit_traits(), are defined on the HasTraits class, which is a superclass of all Traits-based model classes, as well as of Handler and its subclasses. The third method, ui(), is defined on the View class itself. .. index:: configure_traits(); method .. _configure-traits: configure_traits() `````````````````` The configure_traits() method creates a standalone window for a given View object, i.e., it does not require an existing GUI to run in. It is therefore suitable for building command-line functions, as well as providing an accessible tool for the beginning TraitsUI programmer. The configure_traits() method also provides options for saving :term:`trait attribute` values to and restoring them from a file. Refer to the *Traits API Reference* for details. .. index:: edit_traits() .. _edit-traits: edit_traits() ````````````` The edit_traits() method is very similar to configure_traits(), with two major exceptions. First, it is designed to run from within a larger application whose GUI is already defined. Second, it does not provide options for saving data to and restoring data from a file, as it is assumed that these operations are handled elsewhere in the application. .. index:: ui() .. _ui: ui() ```` The View object includes a method called ui(), which performs the actual generation of the window or panel from the View for both edit_traits() and configure_traits(). The ui() method is also available directly through the TraitsUI API; however, using one of the other two methods is usually preferable. [9]_ The ui() method has five keyword parameters: * *kind* * *context* * *handler* * *parent* * *view_elements* The first four are identical in form and function to the corresponding arguments of edit_traits(), except that *context* is not optional; the following section explains why. The fifth argument, *view_elements*, is used only in the context of a call to ui() from a model object method, i.e., from configure_traits() or edit_traits(), Therefore it is irrelevant in the rare cases when ui() is used directly by client code. It contains a dictionary of the named :term:`ViewElement` objects defined for the object whose configure_traits() (or edit_traits()) method was called.. .. index:: context .. _the-view-context: The View Context ---------------- All three of the methods described in :ref:`displaying-a-view` have a *context* parameter. This parameter can be a single object or a dictionary of string/object pairs; the object or objects are the model objects whose traits attributes are to be edited. In general a "context" is a Python dictionary whose keys are strings; the key strings are used to look up the values. In the case of the *context* parameter to the ui() method, the dictionary values are objects. In the special case where only one object is relevant, it can be passed directly instead of wrapping it in a dictionary. When the ui() method is called from configure_traits() or edit_traits() on a HasTraits object, the relevant object is the HasTraits object whose method was called. For this reason, you do not need to specify the *context* argument in most calls to configure_traits() or edit_traits(). However, when you call the ui() method on a View object, you *must* specify the *context* parameter, so that the ui() method receives references to the objects whose trait attributes you want to modify. So, if configure_traits() figures out the relevant context for you, why call ui() at all? One answer lies in *multi-object Views*. .. index:: multi-object Views, View; multi-object .. _multi-object-views: Multi-Object Views `````````````````` A multi-object view is any view whose contents depend on multiple "independent" model objects, i.e., objects that are not attributes of one another. For example, suppose you are building a real estate listing application, and want to display a window that shows two properties side by side for a comparison of price and features. This is straightforward in TraitsUI, as the following example shows: .. index:: examples; context, context; examples, examples; multi-object Views .. index:: multi-object Views; examples .. _example-7-using-a-multi-object-view-with-a-context: .. rubric:: Example 7: Using a multi-object view with a context :: # multi_object_view.py -- Sample code to show multi-object view # with context from traits.api import HasTraits, Str, Int, Bool from traitsui.api import View, Group, Item # Sample class class House(HasTraits): address = Str bedrooms = Int pool = Bool price = Int # View object designed to display two objects of class 'House' comp_view = View( Group( Group( Item('h1.address', resizable=True), Item('h1.bedrooms'), Item('h1.pool'), Item('h1.price'), show_border=True ), Group( Item('h2.address', resizable=True), Item('h2.bedrooms'), Item('h2.pool'), Item('h2.price'), show_border=True ), orientation = 'horizontal' ), title = 'House Comparison' ) # A pair of houses to demonstrate the View house1 = House(address='4743 Dudley Lane', bedrooms=3, pool=False, price=150000) house2 = House(address='11604 Autumn Ridge', bedrooms=3, pool=True, price=200000) # ...And the actual display command house1.configure_traits(view=comp_view, context={'h1':house1, 'h2':house2}) .. FIXME: This is a bit assymmetrical. Can we clean it up without complicating the example overly? The resulting window has the desired appearance: [10]_ .. figure:: images/ui_for_ex7.jpg :alt: UI showing side-by-side groups. Figure 6: User interface for Example 7 For the purposes of this particular example, it makes sense to create a separate Group for each model object, and to use two model objects of the same class. Note, however, that neither is a requirement. .. index:: extended trait names; Item name attribute Notice that the Item definitions in Example 7 use the same type of extended trait attribute syntax as is supported for the on_trait_change() dynamic trait change notification method. In fact, Item **name** attributes can reference any trait attribute that is reachable from an object in the context. This is true regardless of whether the context contains a single object or multiple objects. For example:: Item('object.axle.chassis.serial_number') Because an Item can refer only to a single trait, do not use extended trait references that refer to multiple traits, since the behavior of such references is not defined. Also, avoid extended trait references where one of the intermediate objects could be None, because there is no way to obtain a valid reference from None. Refer to the `Traits User Manual `_, in the chapter on trait notification, for details of the extended trait name syntax. .. index:: object: Include .. _include-objects: Include Objects --------------- In addition to the Item and Group class, a third building block class for Views exists in TraitsUI: the Include class. For the sake of completeness, this section gives a brief description of Include objects and their purpose and usage. However, they are not commonly used as of this writing, and should be considered unsupported pending redesign. In essence, an Include object is a placeholder for a named Group or Item object that is specified outside the Group or View in which it appears. For example, the following two definitions, taken together, are equivalent to the third: .. index:: pair: examples; Include .. _example-8-using-an-include-object: .. rubric:: Example 8: Using an Include object :: # This fragment... my_view = View(Group(Item('a'), Item('b')), Include('my_group')) # ...plus this fragment... my_group = Group(Item('c'), Item('d'), Item('e')) #...are equivalent to this: my_view = View(Group(Item('a'), Item('b')), Group(Item('c'), Item('d'), Item('e')) This opens an interesting possibility when a View is part of a model class: any Include objects belonging to that View can be defined differently for different instances or subclasses of that class. This technique is called *view parameterization*. .. rubric:: Footnotes .. [7] Note that although the definition of a View within a HasTraits class has the syntax of a trait attribute definition, the resulting View is not stored as an attribute of the class. .. [8] Assuming there is one; not all GUIs require an explicitly defined Handler. .. [9] One possible exception is the case where a View object is defined as a variable (i.e., outside any class) or within a custom Handler, and is associated more or less equally with multiple model objects; see :ref:`multi-object-views`. .. [10] If the script were designed to run within an existing GUI, it would make sense to replace the last line with ``comp_view.ui(context={'h1': house1, 'h2': house2})``, since neither object particularly dominates the view. However, the examples in this Manual are designed to be fully executable from the Python command line, which is why configure_traits() was used instead. traitsui-4.1.0/docs/source/traitsui_user_manual/factories_basic.rst0000644000175100001440000013472711674463545026737 0ustar ischnellusers00000000000000 .. _the-predefined-trait-editor-factories: ===================================== The Predefined Trait Editor Factories ===================================== This chapter contains individual descriptions of the predefined trait editor factories provided by TraitsUI. Most of these editor factories are straightforward and can be used easily with little or no expertise on the part of the programmer or end user; these are described in :ref:`basic-trait-editor-factories`. The section :ref:`advanced-trait-editors` covers a smaller set of specialized editors that have more complex interfaces or that are designed to be used along with complex editors. .. NOTE:: Examples are toolkit-specific. The exact appearance of the editors depends on the underlying GUI toolkit. The screenshots and descriptions in this chapter are based on wxWindows. Another supported GUI toolkit is Qt, from TrollTech. Rather than trying to memorize all the information in this chapter, you might skim it to get a general idea of the available trait editors and their capabilities, and use it as a reference thereafter. .. _basic-trait-editor-factories: Basic Trait Editor Factories ---------------------------- The editor factories described in the following sections are straightforward to use. You can pass the editor object returned by the editor factory as the value of the *editor* keyword parameter when defining a trait. .. _arrayeditor: ArrayEditor() ````````````` :Suitable for: 2-D Array, 2-D CArray :Default for: Array, CArray (if 2-D) :Optional parameter: *width* The editors generated by ArrayEditor() provide text fields (or static text for the read-only style) for each cell of a two-dimensional Numeric array. Only the simple and read-only styles are supported by the wxWidgets implementation. You can specify the width of the text fields with the *width* parameter. .. figure:: images/array_editors.png :alt: 3x3 integer; integer read-only; 4x4 float; float read-only Figure 21: Array editors The following code generates the editors shown in Figure 21. .. _example-14-demonstration-of-array-editors: .. rubric:: Example 14: Demonstration of array editors :: # array_editor.py -- Example of using array editors import numpy as np from traits.api import HasPrivateTraits, Array from traitsui.api \ import View, ArrayEditor, Item from traitsui.menu import NoButtons class ArrayEditorTest ( HasPrivateTraits ): three = Array(np.int, (3,3)) four = Array(np.float, (4,4), editor = ArrayEditor(width = -50)) view = View( Item('three', label='3x3 Integer'), '_', Item('three', label='Integer Read-only', style='readonly'), '_', Item('four', label='4x4 Float'), '_', Item('four', label='Float Read-only', style='readonly'), buttons = NoButtons, resizable = True ) if __name__ == '__main__': ArrayEditorTest().configure_traits() BooleanEditor() ``````````````` :Suitable for: Bool, CBool :Default for: Bool, CBool :Optional parameters: *mapping* BooleanEditor is one of the simplest of the built-in editor factories in the TraitsUI package. It is used exclusively to edit and display Boolean (i.e, True/False) traits. In the simple and custom styles, it generates a checkbox. In the text style, the editor displays the trait value (as one would expect) as the strings True or False. However, several variations are accepted as input: - :samp:`'True'` - ``T`` - ``Yes`` - ``y`` - :samp:`'False'` - ``F`` - ``No`` - ``n`` The set of acceptable text inputs can be changed by setting the BooleanEditor() parameter *mapping* to a dictionary whose entries are of the form *str*: *val*, where *val* is either True or False and *str* is a string that is acceptable as text input in place of that value. For example, to create a Boolean editor that accepts only yes and no as appropriate text values, you might use the following expression:: editor=BooleanEditor(mapping={"yes":True, "no":False}) Note that in this case, the strings True and False would *not* be acceptable as text input. Figure 22 shows the four styles generated by BooleanEditor(). .. figure:: images/boolean_editors.jpg :alt: simple: checkbox; custom: checkbox; text: text field; read-only: read-only Figure 22: Boolean editor styles ButtonEditor() `````````````` :Suitable for: Button, Event, ToolbarButton :Default for: Button, ToolbarButton :Optional parameters: *image*, *label*, *orientation*, *style*, *value*, *view*, *width_padding* The ButtonEditor() factory is designed to be used with an Event or Button [16]_ trait. When a user clicks a button editor, the associated event is fired. Because events are not printable objects, the text and read-only styles are not implemented for this editor. The simple and custom styles of this editor are identical. .. figure:: images/button_editors.png :alt: simple: button; custom: button; text style unavailable; read-only style unavailable Figure 23: Button editor styles By default, the label of the button is the name of the Button or Event trait to which it is linked. [17]_ However, this label can be set to any string by specifying the *label* parameter of ButtonEditor() as that string. You can specify a value for the trait to be set to, using the *value* parameter. If the trait is an Event, then the value is not stored, but might be useful to an event listener. CheckListEditor() ````````````````` :Suitable for: List :Default for: (none) :Optional parameters: *cols*, *name*, *values* The editors generated by the CheckListEditor() factory are designed to enable the user to edit a List trait by selecting elements from a "master list", i.e., a list of possible values. The list of values can be supplied by the trait being edited, or by the *values* parameter. The *values* parameter can take either of two forms: - A list of strings - A list of tuples of the form (*element*, *label*), where *element* can be of any type and *label* is a string. In the latter case, the user selects from the labels, but the underlying trait is a List of the corresponding *element* values. Alternatively, you can use the *name* parameter to specify a trait attribute containing the label strings for the values. The custom style of editor from this factory is displayed as a set of checkboxes. By default, these checkboxes are displayed in a single column; however, you can initialize the *cols* parameter of the editor factory to any value between 1 and 20, in which case the corresponding number of columns is used. The simple style generated by CheckListEditor() appears as a drop-down list; in this style, only one list element can be selected, so it returns a list with a single item. The text and read-only styles represent the current contents of the attribute in Python-style text format; in these cases the user cannot see the master list values that have not been selected. The four styles generated by CheckListEditor() are shown in Figure 24. Note that in this case the *cols* parameter has been set to 4. .. figure:: images/checklist_editors.png :alt: simple: drop-list; custom: checkboxes; text and read-only: str() of the list Figure 24: Checklist editor styles .. TODO: Change the demo and update the figure accordingly. The (value, label) option should also be demonstrated. CodeEditor() ```````````` :Suitable for: Code, Str, String :Default for: Code :Optional parameters: *auto_set* The purpose of a code editor is to display and edit Code traits, though it can be used with the Str and String trait types as well. In the simple and custom styles (which are identical for this editor), the text is displayed in numbered, non-wrapping lines with a horizontal scrollbar. The text style displays the trait value using a single scrolling line with special characters to represent line breaks. The read-only style is similar to the simple and custom styles except that the text is not editable. .. figure:: images/code_editors.jpg :alt: simple, custom, and read-only: multi-line, numbered, text field; text: single line text field Figure 25: Code editor styles The *auto_set* keyword parameter is a Boolean value indicating whether the trait being edited should be updated with every keystroke (True) or only when the editor loses focus, i.e., when the user tabs away from it or closes the window (False). The default value of this parameter is True. .. _coloreditor: ColorEditor() ````````````` :Suitable for: Color :Default for: Color :Optional parameters: *mapped* The editors generated by ColorEditor() are designed to enable the user to display a Color trait or edit it by selecting a color from the palette available in the underlying GUI toolkit. The four styles of color editor are shown in Figure 26. .. figure:: images/color_editors.jpg :alt: simple and text: colored text field; custom: color picker; read-only: colored field Figure 26: Color editor styles In the simple style, the editor appears as a text box whose background is a sample of the currently selected color. The text in the box is either a color name or a tuple of the form (*r*, *g*, *b*) where *r*, *g*, and *b* are the numeric values of the red, green and blue color components respectively. (Which representation is used depends on how the value was entered.) The text value is not directly editable in this style of editor; instead, clicking on the text box displays a pop-up panel similar in appearance and function to the custom style. The custom style includes a labeled color swatch on the left, representing the current value of the Color trait, and a palette of common color choices on the right. Clicking on any tile of the palette changes the color selection, causing the swatch to update accordingly. Clicking on the swatch itself causes a more detailed, platform-specific interface to appear in a dialog box, such as is shown in Figure 27. .. figure:: images/color_picker_windows.jpg :alt: MS Windows color selection dialog box Figure 27: Custom color selection dialog box for Microsoft Windows XP The text style of editor looks exactly like the simple style, but the text box is editable (and clicking on it does not open a pop-up panel). The user must enter a recognized color name or a properly formatted (*r*, *g*, *b*) tuple. The read-only style displays the text representation of the currently selected Color value (name or tuple) on a minimally-sized background of the corresponding color. **For advanced users:** The *mapped* keyword parameter of ColorEditor() is a Boolean value indicating whether the trait being edited has a built-in mapping of user-oriented representations (e.g., strings) to internal representations. Since ColorEditor() is generally used only for Color traits, which are mapped (e.g., 'cyan' to wx.Colour(0,255,255) ), this parameter defaults to True and is not of interest to most programmers. However, it is possible to define a custom color trait that uses ColorEditor() but is not mapped (i.e., uses only one representation), which is why the attribute is available. CompoundEditor() ```````````````` :Suitable for: special :Default for: "compound" traits :Optional parameters: *auto_set* An editor generated by CompoundEditor() consists of a combination of the editors for trait types that compose the compound trait. The widgets for the compound editor are of the style specified for the compound editor (simple, custom, etc.). The editors shown in Figure 28 are for the following trait, whose value can be an integer between 1 and 6, or any of the letters 'a' through 'f':: compound_trait = Trait( 1, Range( 1, 6 ), 'a', 'b', 'c', 'd', 'e', 'f') .. figure:: images/compound_editors.png :alt: simple: slider for numbers, drop-list for letters; custom: radio buttons for both Figure 28: Example compound editor styles The *auto_set* keyword parameter is a Boolean value indicating whether the trait being edited should be updated with every keystroke (True) or only when the editor loses focus, i.e., when the user tabs away from it or closes the window (False). The default value of this parameter is True. CSVListEditor() ```````````````` :Suitable for: lists of simple data types :Default for: none :Optional parameters: *auto_set*, *enter_set*, *ignore_trailing_sep*, *sep* This editor provides a line of text for editing a list of certain simple data types. The following List traits can be edited by a CSVListEditor: * List(Int) * List(Float) * List(Str) * List(Enum('string1', 'string2', `etc`)) * List(Range(low= `low value or trait name`, high= `high value or trait name`)) The 'text', 'simple' and 'custom' styles are all the same. They provide a single line of text in which the user can enter the list. The 'readonly' style provides a line of text that can not be edited by the user. The default separator of items in the list is a comma. This can be overridden with the *sep* keyword parameter. Parameters :::::::::: *auto_set* : bool If *auto_set* is True, each key pressed by the user triggers validation of the input, and if it is valid, the value of the object being edited is updated. `Default:` True *enter_set* : bool If *enter_set* is True, the input is updated when the user presses the `Enter` key. `Default:` False *sep* : str or None The separator of the list item in the text field. If `sep` is None, each contiguous span of whitespace is a separator. (Note: After the text field is split at the occurrences of `sep`, leading and trailing whitespace is removed from each item before converting to the underlying data type.) `Default:` ',' (a comma) *ignore_trailing_sep* : bool If *ignore_trailing_sep* is True, the user may enter a trailing separator (e.g. '1, 2, 3,') and it will be ignored. If this is False, a trailing separator is an error. `Default:` True See Also :::::::: ListEditor, TextEditor DefaultOverride() ````````````````` :Suitable for: (any) :Default for: (none) The DefaultOverride() is a factory that takes the trait's default editor and customizes it with the specified parameters. This is useful when a trait defines a default editor using some of its data, e.g. Range or Enum, and you want to tweak some of the other parameters without having recreate that data. For example, the default editor for Range(low=0, high=1500) has '1500' as the upper label. To change it to 'Max' instead, use:: View(Item('my_range', editor=DefaultOverride(high_label='Max')) DirectoryEditor() ````````````````` :Suitable for: Directory :Default for: Directory :Optional parameters: *entries*, *filter*, *filter_name*, *reload_name*, *truncate_ext*, *dclick_name* A directory editor enables the user to display a Directory trait or set it to some directory in the local system hierarchy. The four styles of this editor are shown in Figure 29. .. figure:: images/directory_editors.png :alt: simple: combo box with '...' button; custom: folder tree Figure 29: Directory editor styles In the simple style, the current value of the trait is displayed in a combo box to the left of a button labeled '...'. The user can type a new path directly into the text box, select a previous value from the droplist of the combo box, or use the button to bring up a directory browser panel similar to the custom style of editor. When the user selects a directory in this browser, the panel collapses, and control is returned to the original editor widget, which is automatically populated with the new path string. The user can also drag and drop a directory object onto the simple style editor. The custom style displays a directory browser panel, in which the user can expand or collapse directory structures, and click a folder icon to select a directory. The text style of editor is simply a text box into which the user can type a directory path. The 'readonly' style is identical to the text style, except that the text box is not editable. The optional parameters are the same as the FileEditor. No validation is performed on Directory traits; the user must ensure that a typed-in value is in fact an actual directory on the system. .. _enumeditor: EnumEditor() ```````````` :Suitable for: Enum, Any :Default for: Enum :Required parameters: for non-Enum traits: *values* or *name* :Optional parameters: *cols*, *evaluate*, *mode* The editors generated by EnumEditor() enable the user to pick a single value from a closed set of values. .. figure:: images/enum_editors.png :alt: simple: drop-list; custom: radio buttons; text: text; read-only: read-only Figure 30: Enumeration editor styles The simple style of editor is a drop-down list box. The custom style is a set of radio buttons. Use the *cols* parameter to specify the number of columns of radio buttons. The text style is an editable text field; if the user enters a value that is not in enumerated set, the background of the field turns red, to indicate an error. You can specify a function to evaluate text input, using the *evaluate* parameter. The read-only style is the value of the trait as static text. If the trait attribute that is being edited is not an enumeration, you must specify either the trait attribute (with the *name* parameter), or the set of values to display (with the *values* parameter). The *name* parameter can be an extended trait name. The *values* parameter can be a list, tuple, or dictionary, or a "mapped" trait. By default, an enumeration editor sorts its values alphabetically. To specify a different order for the items, give it a mapping from the normal values to ones with a numeric tag. The enumeration editor sorts the values based on the numeric tags, and then strips out the tags. .. _example-15-enumeration-editor-with-mapped-values: .. rubric:: Example 15: Enumeration editor with mapped values :: # enum_editor.py -- Example of using an enumeration editor from traits.api import HasTraits, Enum from traitsui.api import EnumEditor Class EnumExample(HasTraits): priority = Enum('Medium', 'Highest', 'High', 'Medium', 'Low', 'Lowest') view = View( Item(name='priority', editor=EnumEditor(values={ 'Highest' : '1:Highest', 'High' : '2:High', 'Medium' : '3:Medium', 'Low' : '4:Low', 'Lowest' : '5:Lowest', }))) The enumeration editor strips the characters up to and including the colon. It assumes that all the items have the colon in the same position; therefore, if some of your tags have multiple digits, you should use zeros to pad the items that have fewer digits. .. _fileeditor: FileEditor() ```````````` :Suitable for: File :Default for: File :Optional parameters: *entries*, *filter*, *filter_name*, *reload_name*, *truncate_ext*, *dclick_name* A file editor enables the user to display a File trait or set it to some file in the local system hierarchy. The styles of this editor are shown in Figure 31. .. figure:: images/file_editors.png :alt: simple: text box with 'Browse' or '...' button; custom: file tree; text: text box; read-only: read-only Figure 31: File editor styles The default version of the simply style displays a text box and a :guilabel:`Browse` button. Clicking :guilabel:`Browse` opens a platform-specific file selection dialog box. If you specify the *entries* keyword parameter with an integer value to the factory function, the simple style is a combo box and a button labeled :guilabel:`...`. The user can type a file path in the combo box, or select one of *entries* previous values. Clicking the :guilabel:`...` button opens a browser panel similar to the custom style of editor. When the user selects a file in this browser, the panel collapses, and control is returned to the original editor widget, which is automatically populated with the new path string. For either version of the simple style, the user can drag and drop a file object onto the control. The custom style displays a file system browser panel, in which the user can expand or collapse directory structures, and click an icon to select a file. You can specify a list of filters to apply to the file names displayed, using the *filter* keyword parameter of the factory function. In Figure 31, the "Custom with Filter" editor uses a *filter* value of ``['*.py']`` to display only Python source files. You can also specify this parameter for the simple style, and it will be used in the file selection dialog box or pop-up file system browser panel. Alternatively, you can specify *filter_name*, whose value is an extended trait name of a trait attribute that contains the list of filters. The *reload_name* parameter is an extended trait name of a trait attribute that is used to notify the editor when the view of the file system needs to be reloaded. The *truncate_ext* parameter is a Boolean that indicates whether the file extension is removed from the returned filename. It is False by default, meaning that the filename is not modified before it is returned. The *dclick_name* parameter is an extended trait name of a trait event which is fired when the user double-clicks on a file name when using the custom style. FontEditor() ```````````` :Suitable for: Font :Default for: Font A font editor enables the user to display a Font trait or edit it by selecting one of the fonts provided by the underlying GUI toolkit. The four styles of this editor are shown in Figure 32. .. figure:: images/font_editors.png :alt: simple: text box; custom: text box with drop-lists for typeface and size Figure 32: Font editor styles In the simple style, the currently selected font appears in a display similar to a text box, except that when the user clicks on it, a platform-specific dialog box appears with a detailed interface, such as is shown in Figure 33. When the user clicks :guilabel:`OK`, control returns to the editor, which then displays the newly selected font. .. figure:: images/font_dialog_windows.jpg :alt: MS Windows font selection dialog box Figure 33: Example font dialog box for Microsoft Windows In the custom style, an abbreviated version of the font dialog box is displayed in-line. The user can either type the name of the font in the text box or use the two drop-down lists to select a typeface and size. In the text style, the user *must* type the name of a font in the text box provided. No validation is performed; the user must enter the correct name of an available font. The read-only style is identical except that the text is not editable. HTMLEditor() ```````````` :Suitable for: HTML, string traits :Default for: HTML :Optional parameters: *format_text* The "editor" generated by HTMLEditor() interprets and displays text as HTML. It does not support the user editing the text that it displays. It generates the same type of editor, regardless of the style specified. Figure 34 shows an HTML editor in the upper pane, with a code editor in the lower pane, displaying the uninterpreted text. .. figure:: images/html_code_editor.png :alt: formatted and unformatted HTML text Figure 34: Example HTML editor, with code editor showing original text .. NOTE:: HTML support is limited in the wxWidgets toolkit. The set of tags supported by the wxWidgets implementation of the HTML editor is a subset of the HTML 3.2 standard. It does not support style sheets or complex formatting. Refer to the `wxWidgets documentation `_ for details. If the *format_text* argument is True, then the HTML editor supports basic implicit formatting, which it converts to HTML before passing the text to the HTML interpreter. The implicit formatting follows these rules: - Indented lines that start with a dash ('-') are converted to unordered lists. - Indented lines that start with an asterisk ('*') are converted to ordered lists. - Indented lines that start with any other character are converted to code blocks. - Blank lines are converted to paragraph separators. The following text produces the same displayed HTML as in Figure 34, when *format_text* is True:: This is a code block: def foo ( bar ): print 'bar:', bar This is an unordered list: - An - unordered - list This is an ordered list: * One * Two * Three ImageEnumEditor() ````````````````` :Suitable for: Enum, Any :Default for: (none) :Required parameters: for non-Enum traits: *values* or *name* :Optional parameters: *path*, *klass* or *module*, *cols*, *evaluate*, *suffix* The editors generated by ImageEnumEditor() enable the user to select an item in an enumeration by selecting an image that represents the item. .. figure:: images/image_enum_editors.jpg :alt: simple: single image button; custom: multiple images: text: "top right"; read-only: image Figure 35: Editor styles for image enumeration The custom style of editor displays a set of images; the user selects one by clicking it, and it becomes highlighted to indicate that it is selected. The simple style displays a button with an image for the currently selected item. When the user clicks the button, a pop-up panel displays a set of images, similar to the custom style. The user clicks an image, which becomes the new image on the button. The text style does not display images; it displays the text representation of the currently selected item. The user must type the text representation of another item to select it. The read-only style displays the image for the currently selected item, which the user cannot change. The ImageEnumEditor() function accepts the same parameters as the EnumEditor() function (see :ref:`enumeditor`), as well as some additional parameters. .. NOTE:: Image enumeration editors do not use ImageResource. Unlike most other images in the Traits and TraitsUI packages, images in the wxWindows implementation of image enumeration editors do not use the PyFace ImageResource class. In the wxWidgets implementation, image enumeration editors use the following rules to locate images to use: #. Only GIF (.gif) images are currently supported. #. The base file name of the image is the string representation of the value, with spaces replaced by underscores and the suffix argument, if any, appended. Note that suffix is not a file extension, but rather a string appended to the base file name. For example, if *suffix* is ``_origin`` and the *value* is 'top left', the image file name is :file:`top_left_origin.gif`. #. If the *path* parameter is defined, it is used to locate the file. It can be absolute or relative to the file where the image enumeration editor is defined. #. If *path* is not defined and the *klass* parameter is defined, it is used to locate the file. The *klass* parameter must be a reference to a class. The editor searches for an images subdirectory in the following locations: #. The directory that contains the module that defines the class. #. If the class was executed directly, the current working directory. #. If *path* and *klass* are not defined, and the *module* parameter is defined, it is used to locate the file. The *module* parameter must be a reference to a module. The editor searches for an images subdirectory of the directory that contains the module. #. If *path*, *klass*, and *module* are not defined, the editor searches for an images subdirectory of the traitsui.wx package. #. If none of the above paths are defined, the editor searches for an :file:`images` directory that is a sibling of the directory from which the application was run. InstanceEditor() ```````````````` :Suitable for: Instance, Property, self, ThisClass, This :Default for: Instance, self, ThisClass, This :Optional parameters: *cachable*, *editable*, *id*, *kind*, *label*, *name*, *object*, *orientation*, *values*, *view* The editors generated by InstanceEditor() enable the user to select an instance, or edit an instance, or both. Editing a Single Instance ::::::::::::::::::::::::: In the simplest case, the user can modify the trait attributes of an instance assigned to a trait attribute, but cannot modify which instance is assigned. .. figure:: images/single_instance_editors.jpg :alt: simple: button; custom: editors for instance traits; text and custom: str() of instance Figure 36: Editor styles for instances The custom style displays a user interface panel for editing the trait attributes of the instance. The simple style displays a button, which when clicked, opens a window containing a user interface for the instance. The *kind* parameter specifies the kind of window to open (see :ref:`stand-alone-windows`). The *label* parameter specifies a label for the button in the simple interface. The *view* parameter specifies a view to use for the referenced instance's user interface; if this is not specified, the default view for the instance is used (see :ref:`defining-a-default-view`). The text and read-only styles display the string representation of the instance. They therefore cannot be used to modify the attributes of the instance. A user could modify the assigned instance if they happened to know the memory address of another instance of the same type, which is unlikely. These styles can useful for prototyping and debugging, but not for real applications. Selecting Instances ::::::::::::::::::: You can add an option to select a different instance to edit. Use the *name* parameter to specify the extended name of a trait attribute in the context that contains a list of instances that can be selected or edited. (See :ref:`the-view-context` for an explanation of contexts.) Using these parameters results in a drop-drown list box containing a list of text representations of the available instances. If the instances have a **name** trait attribute, it is used for the string in the list; otherwise, a user-friendly version of the class name is used. For example, the following code defines a Team class and a Person class. A Team has a roster of Persons, and a captain. In the view for a team, the user can pick a captain and edit that person's information. .. _example-16-instance-editor-with-instance-selection: Example 16: Instance editor with instance selection :: # instance_editor_selection.py -- Example of an instance editor # with instance selection from traits.api \ import HasStrictTraits, Int, Instance, List, Regex, Str from traitsui.api \ import View, Item, InstanceEditor class Person ( HasStrictTraits ): name = Str age = Int phone = Regex( value = '000-0000', regex = '\d\d\d[-]\d\d\d\d' ) traits_view = View( 'name', 'age', 'phone' ) people = [ Person( name = 'Dave', age = 39, phone = '555-1212' ), Person( name = 'Mike', age = 28, phone = '555-3526' ), Person( name = 'Joe', age = 34, phone = '555-6943' ), Person( name = 'Tom', age = 22, phone = '555-7586' ), Person( name = 'Dick', age = 63, phone = '555-3895' ), Person( name = 'Harry', age = 46, phone = '555-3285' ), Person( name = 'Sally', age = 43, phone = '555-8797' ), Person( name = 'Fields', age = 31, phone = '555-3547' ) ] class Team ( HasStrictTraits ): name = Str captain = Instance( Person ) roster = List( Person ) traits_view = View( Item('name'), Item('_'), Item( 'captain', label='Team Captain', editor = InstanceEditor( name = 'roster', editable = True), style = 'custom', ), buttons = ['OK']) if __name__ == '__main__': Team( name = 'Vultures', captain = people[0], roster = people ).configure_traits() .. figure:: images/ui_for_ex16.png :alt: Dialog box for a "team", with drop-list selection for "Team Captain" Figure 37: User interface for Example 16 If you want the user to be able to select instances, but not modify their contents, set the *editable* parameter to False. In that case, only the selection list for the instances appears, without the user interface for modifying instances. Allowing Instances :::::::::::::::::: You can specify what types of instances can be edited in an instance editor, using the *values* parameter. This parameter is a list of items describing the type of selectable or editable instances. These items must be instances of subclasses of traitsui.api.InstanceChoiceItem. If you want to generate new instances, put an InstanceFactoryChoice instance in the *values* list that describes the instance to create. If you want certain types of instances to be dropped on the editor, use an InstanceDropChoice instance in the values list. .. TODO: Need an example here. ListEditor() ```````````` :Suitable for: List :Default for: List [18]_ :Optional parameters: *editor*, *rows*, *style*, *trait_handler*, *use_notebook* The following parameters are used only if *use_notebook* is True: *deletable*, *dock_style*, *export*, *page_name*, *select*, *view* The editors generated by ListEditor() enable the user to modify the contents of a list, both by editing the individual items and by adding, deleting, and reordering items within the list. .. figure:: images/list_editors.jpg :alt: simple: single text box; custom and text: multiple text boxes; read-only: read-only list Figure 38: List editor styles The simple style displays a single item at a time, with small arrows on the right side to scroll the display. The custom style shows multiple items. The number of items displayed is controlled by the *rows* parameter; if the number of items in the list exceeds this value, then the list display scrolls. The editor used for each item in the list is determined by the *editor* and *style* parameters. The text style of list editor is identical to the custom style, except that the editors for the items are text editors. The read-only style displays the contents of the list as static text. By default, the items use the trait handler appropriate to the type of items in the list. You can specify a different handler to use for the items using the *trait_handler* parameter. .. TODO: Add an example of a trait handler. For the simple, custom, and text list editors, a button appears to the left of each item editor; clicking this button opens a context menu for modifying the list, as shown in Figure 39. .. figure:: images/list_with_context_menu.png :alt: list editor with context menu Figure 39: List editor showing context menu In addition to the four standard styles for list editors, a fifth list editor user interface option is available. If *use_notebook* is True, then the list editor displays the list as a "notebook" of tabbed pages, one for each item in the list, as shown in Figure 40. This style can be useful in cases where the list items are instances with their own views. If the *deletable* parameter is True, a close box appears on each tab, allowing the user to delete the item; the user cannot add items interactively through this style of editor. .. figure:: images/notebook_list_editor.jpg :alt: tabbed instance editors Figure 40: Notebook list editor ListStrEditor() ``````````````` :Suitable for: ListStr or List of values mapped to strings :Default for: (none) :Optional parameters: *activated, activated_index, adapter, adapter_name, auto_add, drag_move*, *editable, horizontal_lines, images, multi_select, operations*, *right_clicked, right_clicked_index, selected, selected_index, title*, *title_name* ListStrEditor() generates a list of selectable items corresponding to items in the underlying trait attribute. All styles of the editor are the same. The parameters to ListStrEditor() control aspects of the behavior of the editor, such as what operations it allows on list items, whether items are editable, and whether more than one can be selected at a time. You can also specify extended references for trait attributes to synchronize with user actions, such as the item that is currently selected, activated for editing, or right-clicked. .. figure:: images/list_string_editor.jpg :alt: list box displaying strings Figure 41: List string editor NullEditor() ```````````` :Suitable for: controlling layout :Default for: (none) The NullEditor() factory generates a completely empty panel. It is used by the Spring subclass of Item, to generate a blank space that uses all available extra space along its layout orientation. You can also use it to create a blank area of a fixed height and width. RangeEditor() ````````````` :Suitable for: Range :Default for: Range :Optional parameters: *auto_set*, *cols*, *enter_set*, *format*, *high_label*, *high_name*, *label_width*, *low_label*, *low_name*, *mode* The editors generated by RangeEditor() enable the user to specify numeric values within a range. The widgets used to display the range vary depending on both the numeric type and the size of the range, as described in Table 8 and shown in Figure 42. If one limit of the range is unspecified, then a text editor is used. .. _range-editor-widgets-table: .. rubric:: Table 8: Range editor widgets +-----------------------------+-----------+-------------+----------+-----------+ |Data type/range size |Simple |Custom |Text |Read-only | +=============================+===========+=============+==========+===========+ |Integer: Small Range (Size |Slider with|Radio buttons|Text field|Static text| |0-16) |text box | | | | +-----------------------------+-----------+-------------+----------+-----------+ |Integer: Medium Range (Size |Slider with|Slider with |Text field|Static text| |17-101) |text box |text box | | | +-----------------------------+-----------+-------------+----------+-----------+ |Integer: Large Range (Size > |Spin box |Spin box |Text field|Static text| |101) | | | | | +-----------------------------+-----------+-------------+----------+-----------+ |Floating Point: Small Range |Slider with|Slider with |Text field|Static text| |(Size <= 100.0) |text box |text box | | | +-----------------------------+-----------+-------------+----------+-----------+ |Floating Point: Large Range |Large-range|Large-range |Text field|Static text| |(Size > 100.0) |slider |slider | | | +-----------------------------+-----------+-------------+----------+-----------+ .. figure:: images/range_editors.jpg :alt: slider with text box; radio buttons; text box; static text; spin box; large-range slider Figure 42: Range editor widgets In the large-range slider, the arrows on either side of the slider move the editable range, so that the user can move the slider more precisely to the desired value. You can override the default widget for each type of editor using the *mode* parameter, which can have the following values: - 'auto': The default widget, as described in Table 8 - 'slider': Simple slider with text field - 'xslider': Large-range slider with text field - 'spinner': Spin box with increment/decrement buttons - 'enum': Radio buttons - 'text': Text field You can set the limits of the range dynamically, using the *low_name* and *high_name* parameters to specify trait attributes that contain the low and high limit values; use *low_label*, *high_label* and *label_width* to specify labels for the limits. RGBColorEditor() ```````````````` :Suitable for: RGBColor :Default for: RGBColor :Optional parameters: *mapped* Editors generated by RGBColorEditor() are identical in appearance to those generated by ColorEditor(), but they are used for RGBColor traits. See :ref:`coloreditor` for details. .. _seteditor: SetEditor() ``````````` :Suitable for: List :Default for: (none) :Required parameters: Either *values* or *name* :Optional parameters: *can_move_all*, *left_column_title*, *object*, *ordered*, *right_column_title* In the editors generated by SetEditor(), the user can select a subset of items from a larger set. The two lists are displayed in list boxes, with the candidate set on the left and the selected set on the right. The user moves an item from one set to the other by selecting the item and clicking a direction button (:guilabel:`>` for left-to-right and :guilabel:`<` for right-to-left). Additional buttons can be displayed, depending on two Boolean parameters: - If *can_move_all* is True, additional buttons appear, whose function is to move all items from one side to the other (:guilabel:`>>` for left-to-right and :guilabel:`<<` for right-to-left). - If *ordered* is True, additional buttons appear, labeled :guilabel:`Move up` and :guilabel:`Move down`, which affect the position of the selected item within the set in the right list box. .. figure:: images/set_editor.jpg :alt: set editor list boxes with buttons Figure 43: Set editor showing all possible buttons You can specify the set of candidate items in either of two ways: - Set the *values* parameter to a list, tuple, dictionary, or mapped trait. - Set the *name* parameter to the extended name of a trait attribute that contains the list. ShellEditor() ````````````` :Suitable for: special :Default for: PythonValue The editor generated by ShellEditor() displays an interactive Python shell. .. figure:: images/shell_editor.jpg :alt: interactive shell pane Figure 44: Python shell editor TextEditor() ```````````` :Suitable for: all :Default for: Str, String, Password, Unicode, Int, Float, Dict, CStr, CUnicode, and any trait that does not have a specialized TraitHandler :Optional parameters: *auto_set*, *enter_set*, *evaluate*, *evaluate_name*, *mapping*, *multi_line*, *password* The editor generated by TextEditor() displays a text box. For the custom style, it is a multi-line field; for the read-only style, it is static text. If *password* is True, the text that the user types in the text box is obscured. .. figure:: images/text_editor_integers.png :alt: simple: text box; custom: multi-line text box; text: text box; read-only: static text Figure 45: Text editor styles for integers .. figure:: images/text_editor_strings.png :alt: simple: text box; custom: multi-line text box; text: text box; read-only: static text Figure 46: Text editor styles for strings .. figure:: images/text_editors_passwords.png :alt: same as above, but with value obscured by asterisks Figure 47: Text editor styles for passwords You can specify whether the trait being edited is updated on every keystroke (``auto_set=True``) or when the user presses the Enter key (``enter_set=True``). If *auto_set* and *enter_set* are False, the trait is updated when the user shifts the input focus to another widget. You can specify a mapping from user input values to other values with the *mapping* parameter. You can specify a function to evaluate user input, either by passing a reference to it in the *evaluate* parameter, or by passing the extended name of a trait that references it in the *evaluate_name* parameter. TitleEditor() ````````````` :Suitable for: string traits :Default for: (none) TitleEditor() generates a read-only display of a string value, formatted as a heading. All styles of the editor are identical. Visually, it is similar to a Heading item, but because it is an editor, you can change the text of the heading by modifying the underlying attribute. TupleEditor() ````````````` :Suitable for: Tuple :Default for: Tuple :Optional parameters: *cols*, *editors*, *labels*, *traits* The simple and custom editors generated by TupleEditor() provide a widget for each slot of the tuple being edited, based on the type of data in the slot. The text and read-only editors edit or display the text representation of the tuple. .. figure:: images/tuple_editors.png :alt: simple and custom: color editor, range editor, text box Figure 48: Tuple editor styles You can specify the number of columns to use to lay out the widgets with the *cols* parameter. You can specify labels for the widgets with the *labels* parameter. You can also specify trait definitions for the slots of the tuple; however, this is usually implicit in the tuple being edited. You can supply a list of editors to be used for each corresponding tuple slot. If the *editors* list is missing, or is shorter than the length of the tuple, default editors are used for any tuple slots not defined in the list. This feature allows you to substitute editors, or to supply non-default parameters for editors. ValueEditor() ````````````` :Suitable for: (any) :Default for: (none) :Optional parameters: *auto_open* ValueEditor() generates a tree editor that displays Python values and objects, including all the objects' members. For example, Figure 49 shows a value editor that is displayed by the "pickle viewer" utility in enthought.debug. .. figure:: images/value_editor.png :alt: tree of Python values, including dictionaries, lists, and tuples Figure 49: Value editor from Pickle Viewer .. rubric:: Footnotes .. [16] In Traits, a Button and an Event are essentially the same thing, except that Buttons are automatically associated with button editors. .. [17] TraitsUI makes minor modifications to the name, capitalizing the first letter and replacing underscores with spaces, as in the case of a default Item label (see :ref:`the-view-object`). .. [18] If a List is made up of HasTraits objects, a table editor is used instead; see :ref:`tableeditor`. traitsui-4.1.0/docs/source/traitsui_user_manual/intro.rst0000644000175100001440000002020011674463545024726 0ustar ischnellusers00000000000000============ Introduction ============ This guide is designed to act as a conceptual guide to :term:`TraitsUI`, an open-source package built and maintained by Enthought, Inc. The TraitsUI package is a set of GUI (Graphical User Interface) tools designed to complement :term:`Traits`, another Enthought open-source package that provides explicit typing, validation, and change notification for Python. This guide is intended for readers who are already moderately familiar with Traits; those who are not may wish to refer to the `Traits User Manual `_ for an introduction. This guide discusses many but not all features of TraitsUI. For complete details of the TraitsUI API, refer to the *Traits API Reference*. .. index:: MVC design pattern, Model-View-Controller, model, view (in MVC), controller .. _the-model-view-controller-mvc-design-pattern: The Model-View-Controller (MVC) Design Pattern ---------------------------------------------- A common and well-tested approach to building end-user applications is the :term:`MVC` ("Model-View-Controller") design pattern. In essence, the MVC pattern the idea that an application should consist of three separate entities: a :term:`model`, which manages the data, state, and internal ("business") logic of the application; one or more :term:`view`\ s, which format the model data into a graphical display with which the end user can interact; and a :term:`controller`, which manages the transfer of information between model and view so that neither needs to be directly linked to the other. In practice, particularly in simple applications, the view and controller are often so closely linked as to be almost indistinguishable, but it remains useful to think of them as distinct entities. The three parts of the MVC pattern correspond roughly to three classes in the Traits and TraitsUI packages. * Model: :term:`HasTraits` class (Traits package) * View: View class (TraitsUI package) * Controller: :term:`Handler` class (TraitsUI package) The remainder of this section gives an overview of these relationships. .. index:: HasTraits class; as MVC model .. _the-model-hastraits-subclasses-and-objects: The Model: HasTraits Subclasses and Objects ``````````````````````````````````````````` In the context of Traits, a model consists primarily of one or more subclasses or :term:`instance`\ s of the HasTraits class, whose :term:`trait attribute`\ s (typed attributes as defined in Traits) represent the model data. The specifics of building such a model are outside the scope of this manual; please see the `Traits User Manual `_ for further information. .. index:: View; as MVC view .. _the-view-view-objects: The View: View Objects `````````````````````` A view for a Traits-based application is an instance of a class called, conveniently enough, View. A View object is essentially a display specification for a GUI window or :term:`panel`. Its contents are defined in terms of instances of two other classes: :term:`Item` and :term:`Group`. [1]_ These three classes are described in detail in :ref:`the-view-and-its-building-blocks`; for the moment, it is important to note that they are all defined independently of the model they are used to display. Note that the terms :term:`view` and :term:`View` are distinct for the purposes of this document. The former refers to the component of the MVC design pattern; the latter is a TraitsUI construct. .. index:: Handler class; as MVC controller .. _the-controller-handler-subclasses-and-objects: The Controller: Handler Subclasses and Objects `````````````````````````````````````````````` The controller for a Traits-based application is defined in terms of the :term:`Handler` class. [2]_ Specifically, the relationship between any given View instance and the underlying model is managed by an instance of the Handler class. For simple interfaces, the Handler can be implicit. For example, none of the examples in the first four chapters includes or requires any specific Handler code; they are managed by a default Handler that performs the basic operations of window initialization, transfer of data between GUI and model, and window closing. Thus, a programmer new to TraitsUI need not be concerned with Handlers at all. Nonetheless, custom handlers can be a powerful tool for building sophisticated application interfaces, as discussed in :ref:`controlling-the-interface-the-handler`. .. index:: toolkit; selection .. _toolkit-selection: Toolkit Selection ----------------- The TraitsUI package is designed to be toolkit-independent. Programs that use TraitsUI do not need to explicitly import or call any particular GUI toolkit code unless they need some capability of the toolkit that is not provided by TraitsUI. However, *some* particular toolkit must be installed on the system in order to actually display GUI windows. TraitsUI uses a separate package, traits.etsconfig, to determine which GUI toolkit to use. This package is also used by other Enthought packages that need GUI capabilities, so that all such packages "agree" on a single GUI toolkit per application. The etsconfig package contains a singleton object, **ETSConfig** (importable from `traits.etsconfig.api`), which has a string attribute, **toolkit**, that signifies the GUI toolkit. .. index:: ETSConfig.toolkit The values of **ETSConfig.toolkit** that are supported by TraitsUI version 3 are: .. index:: wxPython toolkit, Qt toolkit, null toolkit * 'wx': `wxPython `_, which provides Python bindings for the `wxWidgets `_ toolkit. * 'qt4': `PyQt `_, which provides Python bindings for the `Qt `_ framework version 4. * 'null': A do-nothing toolkit, for situations where neither of the other toolkits is installed, but Traits is needed for non-UI purposes. The default behavior of TraitsUI is to search for available toolkit-specific packages in the order listed, and uses the first one it finds. The programmer or the user can override this behavior in any of several ways, in the following order of precedence: .. index:: ETS_TOOLKIT, environment variable; ETS_TOOLKIT, toolkit; flag .. index:: toolkit; environment variable #. The program can explicitly set **ETSConfig.toolkit**. It must do this before importing from any other Enthought Tool Suite component, including traits. For example, at the beginning of a program:: from traits.etsconfig.api import ETSConfig ETSConfig.toolkit = 'wx' #. The user can specify a -toolkit flag on the command line of the program. #. The user can define a value for the ETS_TOOLKIT environment variable. .. _structure-of-this-guide: Structure of this Manual ------------------------ The intent of this guide is to present the capabilities of the TraitsUI package in usable increments, so that you can create and display gradually more sophisticated interfaces from one chapter to the next. * :ref:`the-view-and-its-building-blocks`, :ref:`customizing-a-view`, and :ref:`advanced-view-concepts` show how to construct and display views from the simple to the elaborate, while leaving such details as GUI logic and widget selection to system defaults. * :ref:`controlling-the-interface-the-handler` explains how to use the Handler class to implement custom GUI behaviors, as well as menus and toolbars. * :ref:`traits-ui-themes` described how to customize the appearance of GUIs through *themes*. * :ref:`introduction-to-trait-editor-factories` and :ref:`the-predefined-trait-editor-factories` show how to control GUI widget selection by means of trait :term:`editor`\ s. * :ref:`tips-tricks-and-gotchas` covers miscellaneous additional topics. * Further reference materials, including a :ref:`glossary-of-terms` and an API summary for the TraitsUI classes covered in this Manual, are located in the Appendices. .. rubric:: Footnotes .. [1] A third type of content object, Include, is discussed briefly in :ref:`include-objects`, but presently is not commonly used. .. [2] Not to be confused with the TraitHandler class of the Traits package, which enforces type validation. traitsui-4.1.0/docs/source/traitsui_user_manual/factories_advanced_extra.rst0000644000175100001440000016331511674463545030621 0ustar ischnellusers00000000000000 .. _advanced-trait-editors: Advanced Trait Editors ---------------------- The editor factories described in the following sections are more advanced than those in the previous section. In some cases, they require writing additional code; in others, the editors they generate are intended for use in complex user interfaces, in conjunction with other editors. CustomEditor() `````````````` :Suitable for: Special cases :Default for: (none) :Required parameters: *factory* :Optional parameters: *args* Use CustomEditor() to create an "editor" that is a non-Traits-based custom control. The *factory* parameter must be a function that generates the custom control. The function must have the following signature: factory_function(*window_parent*, *editor*[, \*\ *args*, \*\*\ *kwargs*]) - *window_parent*: The parent window for the control - *editor*: The editor object created by CustomEditor() Additional arguments, if any, can be passed as a tuple in the *args* parameter of CustomEditor(). For an example of using CustomEditor(),examine the implementation of the NumericModelExplorer class in the enthought.model.numeric_model_explorer module; CustomEditor() is used to generate the plots in the user interface. DropEditor() ```````````` :Suitable for: Instance traits :Default for: (none) :Optional parameters: *binding*, *klass*, *readonly* DropEditor() generates an editor that is a text field containing a string representation of the trait attribute's value. The user can change the value assigned to the attribute by dragging and dropping an object on the text field, for example, a node from a tree editor (See :ref:`treeeditor`). If the *readonly* parameter is True (the default), the user cannot modify the value by typing in the text field. You can restrict the class of objects that can be dropped on the editor by specifying the *klass* parameter. You can specify that the dropped object must be a binding (enthought.naming.api.Binding) by setting the *binding* parameter to True. If so, the bound object is retrieved and checked to see if it can be assigned to the trait attribute. If the dropped object (or the bound object associated with it) has a method named drop_editor_value(), it is called to obtain the value to assign to the trait attribute. Similarly, if the object has a method named drop_editor_update(), it is called to update the value displayed in the text editor. This method requires one parameter, which is the GUI control for the text editor. DNDEditor() ``````````` :Suitable for: Instance traits :Default for: (none) :Optional parameters: *drag_target, drop_target, image* DNDEditor() generates an editor that represents a file or a HasTraits instance as an image that supports dragging and dropping. Depending on the editor style, the editor can be a *drag source* (the user can set the value of the trait attribute by dragging a file or object onto the editor, for example, from a tree editor), or *drop target* (the user can drag from the editor onto another target). .. _drag-and-drop-editor-style-variations-table: .. rubric:: Table 9: Drag-and-drop editor style variations ============ ============ ============ Editor Style Drag Source? Drop Target? ============ ============ ============ Simple Yes Yes Custom No Yes Read-only Yes No ============ ============ ============ KeyBindingEditor() `````````````````` The KeyBindingEditor() factory differs from other trait editor factories because it generates an editor, not for a single attribute, but for an object of a particular class, traitsui.key_bindings.KeyBindings. A KeyBindings object is a list of bindings between key codes and handler methods. You can specify a KeyBindings object as an attribute of a View. When the user presses a key while a View has input focus, the user interface searches the View for a KeyBindings that contains a binding that corresponds to the key press; if such a binding does not exist on the View, it searches enclosing Views in order, and uses the first matching binding, if any. If it does not find any matching bindings, it ignores the key press. A key binding editor is a separate :term:`dialog box` that displays the string representation of each key code and a description of the corresponding method. The user can click a text box, and then press a key or key combination to associate that key press with a method. .. figure:: images/key_binding_editor.jpg :alt: Dialog box with fields for key presses corresponding to operations Figure 50: Key binding editor dialog box The following code example creates a user interface containing a code editor with associated key bindings, and a button that invokes the key binding editor. .. _example-17-code-editor-with-key-binding-editor: .. rubric:: Example 17: Code editor with key binding editor :: # key_bindings.py -- Example of a code editor with a # key bindings editor from traits.api \ import Button, Code, HasPrivateTraits, Str from traitsui.api \ import View, Item, Group, Handler, CodeEditor from traitsui.key_bindings \ import KeyBinding, KeyBindings key_bindings = KeyBindings( KeyBinding( binding1 = 'Ctrl-s', description = 'Save to a file', method_name = 'save_file' ), KeyBinding( binding1 = 'Ctrl-r', description = 'Run script', method_name = 'run_script' ), KeyBinding( binding1 = 'Ctrl-k', description = 'Edit key bindings', method_name = 'edit_bindings' ) ) # TraitsUI Handler class for bound methods class CodeHandler ( Handler ): def save_file ( self, info ): info.object.status = "save file" def run_script ( self, info ): info.object.status = "run script" def edit_bindings ( self, info ): info.object.status = "edit bindings" key_bindings.edit_traits() class KBCodeExample ( HasPrivateTraits ): code = Code status = Str kb = Button(label='Edit Key Bindings') view = View( Group ( Item( 'code', style = 'custom', resizable = True ), Item('status', style='readonly'), 'kb', orientation = 'vertical', show_labels = False, ), id = 'KBCodeExample', key_bindings = key_bindings, title = 'Code Editor With Key Bindings', resizable = True, handler = CodeHandler() ) def _kb_fired( self, event ): key_bindings.edit_traits() if __name__ == '__main__': KBCodeExample().configure_traits() .. _tableeditor: TableEditor() ````````````` :Suitable for: List(*InstanceType*) :Default for: (none) :Required parameters: *columns* or *columns_name* :Optional parameters: See *Traits API Reference*, traitsui.wx.table_editor.ToolkitEditorFactory attributes. TableEditor() generates an editor that displays instances in a list as rows in a table, with attributes of the instances as values in columns. You must specify the columns in the table. Optionally, you can provide filters for filtering the set of displayed items, and you can specify a wide variety of options for interacting with and formatting the table. .. figure:: images/table_editor.jpg :alt: Table editor with toolbar and instance editor Figure 51: Table editor To see the code that results in Figure 51, refer to :file:`TableEditor_demo.py` in the :file:`demos/TraitsUI Demo/Standard Editors` subdirectory of the Traits UI package. This example demonstrates object columns, expression columns, filters, searching, and adding and deleting rows. The parameters for TableEditor() can be grouped in several broad categories, described in the following sections. - :ref:`specifying-columns` - :ref:`managing-items` - :ref:`editing-the-table` - :ref:`defining-the-layout` - :ref:`table-defining-the-format` - :ref:`other-user-interactions` .. _specifying-columns: Specifying Columns :::::::::::::::::: You must provide the TableEditor() factory with a list of columns for the table. You can specify this list directly, as the value of the *columns* parameter, or indirectly, in an extended context attribute referenced by the *columns_name* parameter. The items in the list must be instances of traitsui.api.TableColumn, or of a subclass of TableColumn. Some subclasses of TableColumn that are provided by the TraitsUI package include ObjectColumn, ListColumn, NumericColumn, and ExpressionColumn. (See the *Traits API Reference* for details about these classes.) In practice, most columns are derived from one of these subclasses, rather than from TableColumn. For the usual case of editing trait attributes on objects in the list, use ObjectColumn. You must specify the *name* parameter to the ObjectColumn() constructor, referencing the name of the trait attribute to be edited. You can specify additional columns that are not initially displayed using the *other_columns* parameter. If the *configurable* parameter is True (the default), a :guilabel:`Set user preferences for table` icon (|preferences_icon|) appears on the table's toolbar. When the user clicks this icon, a dialog box opens that enables the user to select and order the columns displayed in the table, as shown in Figure 52. (The dialog box is implemented using a set editor; see :ref:`seteditor`.) Any columns that were specified in the *other_columns* parameter are listed in the left list box of this dialog box, and can be displayed by moving them into the right list box. .. |preferences_icon| image:: images/table_prefs.png .. figure:: images/table_column_selection.jpg :alt: Dialog box with two list boxes for selecting column names Figure 52: Column selection dialog box for a table editor .. _managing-items: Managing Items :::::::::::::: Table editors support several mechanisms to help users locate items of interest. .. _organizing-items: Organizing Items ~~~~~~~~~~~~~~~~ Table editors provide two mechanisms for the user to organize the contents of a table: sorting and reordering. The user can sort the items based on the values in a column, or the user can manually order the items. Usually, only one of these mechanisms is used in any particular table, although the TraitsUI package does not enforce a separation. If the user has manually ordered the items, sorting them would throw away that effort. If the *reorderable* parameter is True, :guilabel:`Move up` (|move_up_icon|) and :guilabel:`Move down` (|move_down_icon|) icons appear in the table toolbar. Clicking one of these icons changes the position of the selected item. .. |move_up_icon| image:: images/move_up_icon.png .. |move_down_icon| image:: images/move_down_icon.png If the *sortable* parameter is True (the default), then the user can sort the items in the table based on the values in a column by Control-clicking the header of that column. - On the first click, the items are sorted in ascending order. The characters :guilabel:`>>` appear in the column header to indicate that the table is sorted ascending on this column's values. - On the second click, the items are sorted descending order. The characters :guilabel:`<<` appear in the column header to indicate that the table is sorted descending on this column's values. - On the third click, the items are restored to their original order, and the column header is undecorated. If the *sort_model* parameter is true, the items in the list being edited are sorted when the table is sorted. The default value is False, in which case, the list order is not affected by sorting the table. If *sortable* is True and *sort_model* is False, then a :guilabel:`Do not sort columns` icon (|no_sort_icon|) appears in the table toolbar. Clicking this icon restores the original sort order. .. |no_sort_icon| image:: images/no_sort_icon.png If the *reverse* parameter is True, then the items in the underlying list are maintained in the reverse order of the items in the table (regardless of whether the table is sortable or reorderable). .. _filtering-and-searching: Filtering and Searching ~~~~~~~~~~~~~~~~~~~~~~~ You can provide an option for the user to apply a filter to a table, so that only items that pass the filter are displayed. This feature can be very useful when dealing with lengthy lists. You can specify a filter to apply to the table either directly, or via another trait. Table filters must be instances of traitsui.api.TableFilter, or of a subclass of TableFilter. Some subclasses of TableFilter that are provided by the TraitsUI package include EvalTableFilter, RuleTableFilter, and MenuTableFilter. (See the *Traits API Reference* for details about these classes.) The TraitsUI package also provides instances of these filter classes as "templates", which cannot be edited or deleted, but which can be used as models for creating new filters. .. TODO: Provide more detail on how these filters work. The *filter* parameter specifies a filter that is applied to the table when it is first displayed. The *filter_name* parameter specifies an extended trait name for a trait that is either a table filter object or a callable that accepts an object and returns True if the object passes the filter criteria, or false if it does not. You can use *filter_name* to embed a view of a table filter in the same view as its table. You can specify use the *filters* parameter to specify a list of table filters that are available to apply to a table. When *filters* is specified, a drop-down list box appears in the table toolbar, containing the filters that are available for the user to apply. When the user selects a filter, it is automatically applied to the table. A status message to the right of the filters list indicates what subset of the items in the table is currently displayed. A special item in the filter list, named :guilabel:`Customize`, is always provided; clicking this item opens a dialog box that enables the user to create new filters, or to edit or delete existing filters (except templates). You can also provide an option for the user to use filters to search the table. If you set the *search* parameter to an instance of TableFilter (or of a subclass), a :guilabel:`Search table` icon (|search_table_icon|) appears on the table toolbar. Clicking this icon opens a :guilabel:`Search for` dialog box, which enables the user to specify filter criteria, to browse through matching items, or select all matching items. .. |search_table_icon| image:: images/search_table_icon.png .. TODO: Add a screenshot of the dialog when it actually works .. _interacting-with-items: Interacting with Items ~~~~~~~~~~~~~~~~~~~~~~ As the user clicks in the table, you may wish to enable certain program behavior. The value of the *selection_mode* parameter specifies how the user can make selections in the grid: - ``cell``: A single cell at a time - ``cells``: Multiple cells - ``column``: A single column at a time - ``columns``: Multiple columns - ``row``: A single row at a time - ``rows``: Multiple rows You can use the *selected* parameter to specify the name of a trait attribute in the current context to synchronize with the user's current selection. For example, you can enable or disable menu items or toolbar icons depending on which item is selected. The synchronization is two-way; you can set the attribute referenced by *selected* to force the table to select a particular item. You can use the *selected_indices* parameter to specify the name of a trait attribute in the current context to synchronize with the indices of the table editor selection. The content of the selection depends on the *selection_mode* value: - ``cell``: The selection is a tuple of the form (*object*, *column_name*), where *object* is the object contains the selected cell, and *column_name* is the name of the column the cell is in. If there is no selection, the tuple is (None, ''). - ``cells``: The selection is a list of tuples of the form (*object*, *column_name*), with one tuple for each selected cell, in order from top to bottom and left to right. If there is no selection, the list is empty. - ``column``: The selection is the name of the selected column, or the empty string if there is no selection. - ``columns``: The selection is a list containing the names of the selected columns, in order from left to right. If there is no selection, the list is empty. - ``row``: The selection is either the selected object or None if nothing is selected in the table. - ``rows``: The selection is a list of the selected objects, in ascending row order. If there is no selection, the list is empty. The *on_select* and *on_dclick* parameters are callables to invoke when the user selects or double-clicks an item, respectively. You can define a shortcut menu that opens when the user right-clicks an item. Use the *menu* parameter to specify a TraitsUI or PyFace Menu, containing Action objects for the menu commands. .. _editing-the-table: Editing the Table ::::::::::::::::: The Boolean *editable* parameter controls whether the table or its items can be modified in any way. This parameter defaults to True, except when the style is 'readonly'. Even when the table as a whole is editable, you can control whether individual columns are editable through the **editable** attribute of TableColumn. .. _adding-items: Adding Items ~~~~~~~~~~~~ To enable users to add items to the table, specify as the *row_factory* parameter a callable that generates an object that can be added to the list in the table; for example, the class of the objects in the table. When *row_factory* is specified, an :guilabel:`Insert new item` icon (|insert_item_icon|) appears in the table toolbar, which generates a new row in the table. Optionally, you can use *row_factory_args* and *row_factory_kw* to specify positional and keyword arguments to the row factory callable. .. |insert_item_icon| image:: images/insert_item_icon.png To save users the trouble of mousing to the toolbar, you can enable them to add an item by selecting the last row in the table. To do this, set *auto_add* to True. In this case, the last row is blank until the user sets values. Pressing Enter creates the new item and generates a new, blank last row. .. deleting-items: Deleting Items ~~~~~~~~~~~~~~ The *deletable* parameter controls whether items can be deleted from the table. This parameter can be a Boolean (defaulting to False) or a callable; the callable must take an item as an argument and handle deleting it. If *deletable* is not False, a :guilabel:`Delete current item` icon (|delete_item_icon|) appears on the table toolbar; clicking it deletes the item corresponding to the row that is selected in the table. .. |delete_item_icon| image:: images/delete_item_icon.png .. _modifying-items: Modifying Items ~~~~~~~~~~~~~~~ The user can modify items in two ways. - For columns that are editable, the user can change an item's value directly in the table. The editor used for each attribute in the table is the simple style of editor for the corresponding trait. - Alternatively, you can specify a View for editing instances, using the *edit_view* parameter. The resulting user interface appears in a :term:`subpanel` to the right or below the table (depending on the *orientation* parameter). You can specify a handler to use with the view, using *edit_view_handler*. You can also specify the subpanel's height and width, with *edit_view_height* and *edit_view_width*. .. _defining-the-layout: Defining the Layout ::::::::::::::::::: Some of the parameters for the TableEditor() factory affect global aspects of the display of the table. - *auto_size*: If True, the cells of the table automatically adjust to the optimal size based on their contents. - *orientation*: The layout of the table relative to its associated editor pane. Can be 'horizontal' or 'vertical'. - *rows*: The number of visible rows in the table. - *show_column_labels*: If True (the default), displays labels for the columns. You can specify the labels to use in the column definitions; otherwise, a "user friendly" version of the trait attribute name is used. - *show_toolbar*: If False, the table toolbar is not displayed, regardless of whether other settings would normally create a toolbar. The default is True. .. _table-defining-the-format: Defining the Format ::::::::::::::::::: The TableEditor() factory supports a variety of parameters to control the visual formatting of the table, such as colors, fonts, and sizes for lines, cells, and labels. For details, refer to the *Traits API Reference*, traitsui.wx.table_editor.ToolkitEditorFactory attributes. You can also specify formatting options for individual table columns when you define them. .. _other-user-interactions: Other User Interactions ::::::::::::::::::::::: The table editor supports additional types of user interaction besides those controlled by the factory parameters. - Column dragging: The user can reorganize the column layout of a table editor by clicking and dragging a column label to its new location. If you have enabled user preferences for the view and table editor (by specifying view and item IDs), the new column layout is persisted across user sessions. - Column resizing: The user can resize a column by dragging the column separator (in one of the data rows) to a new position. Because of the column-dragging support, clicking the column separator in the column label row does not work. - Data dragging: The user can drag the contents of any cell by clicking and dragging. TabularEditor() ``````````````` :Suitable for: lists, arrays, and other large sequences of objects :Default for: (none) :Required parameters: *adapter* :Optional parameters: *activated, clicked, column_clicked, dclicked, drag_move, editable,* *horizontal_lines, images, multi_select, operations, right_clicked,* *right_dclicked, selected, selected_row, show_titles, vertical_lines* The TabularEditor() factory can be used for many of the same purposes as the TableEditor() factory, that is, for displaying a table of attributes of lists or arrays of objects. While similar in function, the tabular editor has advantages and disadvantages relative to the table editor. .. _tabular-advantages: Advantages :::::::::: - **Very fast**: The tabular editor uses a virtual model, which accesses data from the underlying model only as needed. For example, if you have a million-element array, but can display only 50 rows at a time, the editor requests only 50 elements of data at a time. - **Very flexible data model**: The editor uses an adapter model to interface with the underlying data. This strategy allows it to easily deal with many types of data representation, from list of objects, to arrays of numbers, to tuples of tuples, and many other formats. - **Supports useful data operations**, including: - Moving the selection up and down using the keyboard arrow keys. - Moving rows up and down using the keyboard. - Inserting and deleting items using the keyboard. - Initiating editing of items using the keyboard. - Dragging and dropping of table items to and from the editor, including support for both copy and move operations for single and multiple items. - **Visually appealing**: The tabular editor, in general, uses the underlying operating system's native table or grid control, and as a result often looks better than the control used by the table editor. - **Supports displaying text and images in any cell**. However, the images displayed must be all the same size for optimal results. .. _tabular-disadvantages: Disadvantages ::::::::::::: - **Not as full-featured**: The table editor includes support for arbitrary data filters, searches, and different types of sorting. These differences may narrow as features are added to the tabular editor. - **Limited data editing capabilities**: The tabular editor supports editing only textual values, whereas the table editor supports a wide variety of column editors, and can be extended with more as needed. This is due to limitations of the underlying native control used by the tabular editor. .. _tabularadapter: TabularAdapter :::::::::::::: The tabular editor works in conjunction with an adapter class, derived from TabularAdapter. The tabular adapter interfaces between the tabular editor and the data being displayed. The tabular adapter is the reason for the flexibility and power of the tabular editor to display a wide variety of data. The most important attribute of TabularAdapter is **columns**, which is list of columns to be displayed. Each entry in the **columns** list can be either a string, or a tuple consisting of a string and another value, which can be of any type. The string is used as the label for the column. The second value in the tuple, called the *column ID*, identifies the column to the adapter. It is typically a trait attribute name or an integer index, but it can be any value appropriate to the adapter. If only a string is specified for an entry, then the index of the entry within the **columns** list is used as that entry's column ID. Attributes on TabularAdapter control the appearance of items, and aspects of interaction with items, such as whether they can be edited, and how they respond to dragging and dropping. Setting any of these attributes on the adapter subclass sets the global behavior for the editor. Refer to the *Traits API Reference* for details of the available attributes. You can also specify these attributes for a specific class or column ID, or combination of class and column ID. When the TabularAdapter needs to look up the value of one of its attributes for a specific item in the table, it looks for attributes with the following naming conventions in the following order: #. *classname_columnid_attribute* #. *classname_attribute* #. *columnid_attribute* #. *attribute* For example, to find the **text_color** value for an item whose class is Person and whose column ID is 'age', the get_text_color() method looks for the following attributes in sequence, and returns the first value it finds: #. **Person_age_text_color** #. **Person_text_color** #. **age_text_color** #. **text_color** Note that the *classname* can be the name of a base class, searched in the method resolution order (MRO) for the item's class. So for example, if the item were a direct instance of Employee, which is a subclass of Person, then the **Person_age_text_color** attribute would apply to that item (as long as there were no **Employee_age_text_color** attribute). .. _the-tabular-editor-user-interface: The Tabular Editor User Interface ::::::::::::::::::::::::::::::::: Figure 53 shows an example of a tabular editor on Microsoft Windows, displaying information about source files in the Traits package. This example includes a column that contains an image for files that meet certain conditions. .. figure:: images/tabular_editor.jpg :alt: Tabular editor with columns for file name, size, an icon, time, and date Figure 53: Tabular editor on MS Windows Depending on how the tabular editor is configured, certain keyboard interactions may be available. For some interactions, you must specify that the corresponding operation is allowed by including the operation name in the *operations* list parameter of TabularEditor(). - :kbd:`Up arrow`: Selects the row above the currently selected row. - :kbd:`Down arrow`: Selects the row below the currently selected row. - :kbd:`Page down`: Appends a new item to the end of the list ('append' operation). - :kbd:`Left arrow`: Moves the currently selected row up one line ('move' operation). - :kbd:`Right arrow`: Moves the currently selected row down one line ('move' operation). - :kbd:`Backspace, Delete`: Deletes from the list all items in the current selection ('delete' operation). - :kbd:`Enter, Escape`: Initiates editing on the current selection ('edit' operation). - :kbd:`Insert:`: Inserts a new item before the current selection ('insert' operation). The 'append', 'move', 'edit', and 'insert' operations can occur only when a single item is selected. The 'delete' operation works for one or more items selected. Depending on how the editor and adapter are specified, drag and drop operations may be available. If the user selects multiple items and drags one of them, all selected items are included in the drag operation. If the user drags a non-selected item, only that item is dragged. The editor supports both "drag-move" and "drag-copy" semantics. A drag-move operation means that the dragged items are sent to the target and are removed from the list displayed in the editor. A drag-copy operation means that the dragged items are sent to the target, but are not deleted from the list data. .. _treeeditor: TreeEditor() ```````````` :Suitable for: Instance :Default for: (none) :Required parameters: *nodes* (required except for shared editors; see :ref:`editing-objects`) :Optional parameters: *auto_open, editable, editor, hide_root, icon_size, lines_mode,* *on_dclick, on_select, orientation, selected, shared_editor, show_icons* TreeEditor() generates a hierarchical tree control, consisting of nodes. It is useful for cases where objects contain lists of other objects. The tree control is displayed in one pane of the editor, and a user interface for the selected object is displayed in the other pane. The layout orientation of the tree and the object editor is determined by the *orientation* parameter of TreeEditor(), which can be 'horizontal' or 'vertical'. You must specify the types of nodes that can appear in the tree using the *nodes* parameter, which must be a list of instances of TreeNode (or of subclasses of TreeNode). .. figure:: images/tree_editor.png :alt: Tree control with instance editor pane Figure 54: Tree editor The following example shows the code that produces the editor shown in Figure 54. .. _example-18-code-for-example-tree-editor: .. rubric:: Example 18: Code for example tree editor :: # tree_editor.py -- Example of a tree editor from traits.api \ import HasTraits, Str, Regex, List, Instance from traitsui.api \ import TreeEditor, TreeNode, View, Item, VSplit, \ HGroup, Handler, Group from traitsui.menu \ import Menu, Action, Separator from traitsui.wx.tree_editor \ import NewAction, CopyAction, CutAction, \ PasteAction, DeleteAction, RenameAction # DATA CLASSES class Employee ( HasTraits ): name = Str( '' ) title = Str phone = Regex( regex = r'\d\d\d-\d\d\d\d' ) def default_title ( self ): self.title = 'Senior Engineer' class Department ( HasTraits ): name = Str( '' ) employees = List( Employee ) class Company ( HasTraits ): name = Str( '' ) departments = List( Department ) employees = List( Employee ) class Owner ( HasTraits ): name = Str( '' ) company = Instance( Company ) # INSTANCES jason = Employee( name = 'Jason', title = 'Engineer', phone = '536-1057' ) mike = Employee( name = 'Mike', title = 'Sr. Marketing Analyst', phone = '536-1057' ) dave = Employee( name = 'Dave', title = 'Sr. Engineer', phone = '536-1057' ) susan = Employee( name = 'Susan', title = 'Engineer', phone = '536-1057' ) betty = Employee( name = 'Betty', title = 'Marketing Analyst' ) owner = Owner( name = 'wile', company = Company( name = 'Acme Labs, Inc.', departments = [ Department( name = 'Marketing', employees = [ mike, betty ] ), Department( name = 'Engineering', employees = [ dave, susan, jason ] ) ], employees = [ dave, susan, mike, betty, jason ] ) ) # View for objects that aren't edited no_view = View() # Actions used by tree editor context menu def_title_action = Action(name='Default title', action = 'object.default') dept_action = Action( name='Department', action='handler.employee_department(editor,object)') # View used by tree editor employee_view = View( VSplit( HGroup( '3', 'name' ), HGroup( '9', 'title' ), HGroup( 'phone' ), id = 'vsplit' ), id = 'traits.doc.example.treeeditor', dock = 'vertical' ) class TreeHandler ( Handler ): def employee_department ( self, editor, object ): dept = editor.get_parent( object ) print '%s works in the %s department.' %\ ( object.name, dept.name ) # Tree editor tree_editor = TreeEditor( nodes = [ TreeNode( node_for = [ Company ], auto_open = True, children = '', label = 'name', view = View( Group('name', orientation='vertical', show_left=True )) ), TreeNode( node_for = [ Company ], auto_open = True, children = 'departments', label = '=Departments', view = no_view, add = [ Department ] ), TreeNode( node_for = [ Company ], auto_open = True, children = 'employees', label = '=Employees', view = no_view, add = [ Employee ] ), TreeNode( node_for = [ Department ], auto_open = True, children = 'employees', label = 'name', menu = Menu( NewAction, Separator(), DeleteAction, Separator(), RenameAction, Separator(), CopyAction, CutAction, PasteAction ), view = View( Group ('name', orientation='vertical', show_left=True )), add = [ Employee ] ), TreeNode( node_for = [ Employee ], auto_open = True, label = 'name', menu=Menu( NewAction, Separator(), def_title_action, dept_action, Separator(), CopyAction, CutAction, PasteAction, Separator(), DeleteAction, Separator(), RenameAction ), view = employee_view ) ] ) # The main view view = View( Group( Item( name = 'company', id = 'company', editor = tree_editor, resizable = True ), orientation = 'vertical', show_labels = True, show_left = True, ), title = 'Company Structure', id = \ 'traitsui.tests.tree_editor_test', dock = 'horizontal', drop_class = HasTraits, handler = TreeHandler(), buttons = [ 'Undo', 'OK', 'Cancel' ], resizable = True, width = .3, height = .3 ) if __name__ == '__main__': owner.configure_traits( view = view ) .. _defining-nodes: Defining Nodes :::::::::::::: For details on the attributes of the TreeNode class, refer to the *Traits API Reference*. You must specify the classes whose instances the node type applies to. Use the **node_for** attribute of TreeNode to specify a list of classes; often, this list contains only one class. You can have more than one node type that applies to a particular class; in this case, each object of that class is represented by multiple nodes, one for each applicable node type. In Figure 54, one Company object is represented by the nodes labeled "Acme Labs, Inc.", "Departments", and "Employees". .. _a-node-type-without-children: A Node Type without Children ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ To define a node type without children, set the **children** attribute of TreeNode to the empty string. In Example 16, the following lines define the node type for the node that displays the company name, with no children:: TreeNode( node_for = [ Company ], auto_open = True, children = '', label = 'name', view = View( Group('name', orientation='vertical', show_left=True )) ), .. _a-node-type-with-children: A Node Type with Children ~~~~~~~~~~~~~~~~~~~~~~~~~ To define a node type that has children, set the **children** attribute of TreeNode to the (extended) name of a trait on the object that it is a node for; the named trait contains a list of the node's children. In Example 16, the following lines define the node type for the node that contains the departments of a company. The node type is for instances of Company, and 'departments' is a trait attribute of Company. :: TreeNode( node_for = [ Company ], auto_open = True, children = 'departments', label = '=Departments', view = no_view, add = [ Department ] ), .. _setting-the-label-of-a-tree-node: Setting the Label of a Tree Node ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The **label** attribute of Tree Node can work in either of two ways: as a trait attribute name, or as a literal string. If the value is a simple string, it is interpreted as the extended trait name of an attribute on the object that the node is for, whose value is used as the label. This approach is used in the code snippet in :ref:`a-node-type-without-children`. If the value is a string that begins with an equals sign ('='), the rest of the string is used as the literal label. This approach is used in the code snippet in :ref:`a-node-type-with-children`. You can also specify a callable to format the label of the node, using the **formatter** attribute of TreeNode. .. _defining-operations-on-nodes: Defining Operations on Nodes :::::::::::::::::::::::::::: You can use various attributes of TreeNode to define operations or behavior of nodes. .. _shortcut-menus-on-nodes: Shortcut Menus on Nodes ~~~~~~~~~~~~~~~~~~~~~~~ Use the **menu** attribute of TreeNode to define a shortcut menu that opens when the user right-clicks on a node. The value is a TraitsUI or PyFace menu containing Action objects for the menu commands. In Example 16, the following lines define the node type for employees, including a shortcut menu for employee nodes:: TreeNode( node_for = [ Department ], auto_open = True, children = 'employees', label = 'name', menu = Menu( NewAction, Separator(), DeleteAction, Separator(), RenameAction, Separator(), CopyAction, CutAction, PasteAction ), view = View( Group ('name', orientation='vertical', show_left=True )), add = [ Employee ] ), .. _allowing-the-hierarchy-to-be-modified: Allowing the Hierarchy to Be Modified ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If a node contains children, you can allow objects to be added to its set of children, through operations such as dragging and dropping, copying and pasting, or creating new objects. Two attributes control these operations: **add** and **move**. Both are lists of classes. The **add** attribute contains classes that can be added by any means, including creation. The code snippet in the preceding section includes an example of the **add** attribute. The **move** attribute contains classes that can be dragged and dropped, but not created. The **move** attribute need not be specified if all classes that can be moved can also be created (and therefore are specified in the **add** value). .. NOTE:: The **add** attribute alone is not enough to create objects. Specifying the **add** attribute makes it possible for objects of the specified classes to be created, but by itself, it does not provide a way for the user to do so. In the code snippet in the preceding section (:ref:`shortcut-menus-on-nodes`), 'NewAction' in the Menu constructor call defines a :menuselection:`New > Employee` menu item that creates Employee objects. In the example tree editor, users can create new employees using the :menuselection:`New > Employee` shortcut menu item, and they can drag an employee node and drop it on a department node. The corresponding object becomes a member of the appropriate list. You can specify the label that appears on the :menuselection:`New` submenu when adding a particular type of object, using the **name** attribute of TreeNode. Note that you set this attribute on the tree node type that will be *added* by the menu item, not the node type that *contains* the menu item. For example, to change :menuselection:`New > Employee` to :menuselection:`New > Worker`, set ``name = 'Worker'`` on the tree node whose **node_for** value contains Employee. If this attribute is not set, the class name is used. You can determine whether a node or its children can be copied, renamed, or deleted, by setting the following attributes on TreeNode: ============= ================= ============ Attribute If True, the ... can be\ ... ============= ================= ============ **copy** object's children copied. **delete** object's children deleted. **delete_me** object deleted. **rename** object's children renamed. **rename_me** object renamed. ============= ================= ============ All of these attributes default to True. As with **add**, you must also define actions to perform these operations. .. _behavior-on-nodes: Behavior on Nodes ~~~~~~~~~~~~~~~~~ As the user clicks in the tree, you may wish to enable certain program behavior. You can use the *selected* parameter to specify the name of a trait attribute on the current context object to synchronize with the user's current selection. For example, you can enable or disable menu items or toolbar icons depending on which node is selected. The synchronization is two-way; you can set the attribute referenced by *selected* to force the tree to select a particular node. The *on_select* and *on_dclick* parameters are callables to invoke when the user selects or double-clicks a node, respectively. .. _expanding-and-collapsing-nodes: Expanding and Collapsing Nodes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ You can control some aspects of expanding and collapsing of nodes in the tree. The integer *auto_open* parameter of TreeEditor() determines how many levels are expanded below the root node, when the tree is first displayed. For example, if *auto_open* is 2, then two levels below the root node are displayed (whether or not the root node itself is displayed, which is determined by *hide_root*). The Boolean **auto_open** attribute of TreeNode determines whether nodes of that type are expanded when they are displayed (at any time, not just on initial display of the tree). For example, suppose that a tree editor has *auto_open* setting of 2, and contains a tree node at level 3 whose **auto_open** attribute is True. The nodes at level 3 are not displayed initially, but when the user expands a level 2 node, displaying the level 3 node, that's nodes children are automatically displayed also. Similarly, the number of levels of nodes initially displayed can be greater than specified by the tree editor's *auto_open* setting, if some of the nodes have **auto_open** set to True. If the **auto_close** attribute of TreeNode is set to True, then when a node is expanded, any siblings of that node are automatically closed. In other words, only one node of this type can be expanded at a time. .. _editing-objects: Editing Objects ~~~~~~~~~~~~~~~ One pane of the tree editor displays a user interface for editing the object that is selected in the tree. You can specify a View to use for each node type using the **view** attribute of TreeNode. If you do not specify a view, then the default view for the object is displayed. To suppress the editor pane, set the *editable* parameter of TreeEditor() to False; in this case, the objects represented by the nodes can still be modified by other means, such as shortcut menu commands. You can define multiple tree editors that share a single editor pane. Each tree editor has its own tree pane. Each time the user selects a different node in any of the sharing tree controls, the editor pane updates to display the user interface for the selected object. To establish this relationship, do the following: #. Call TreeEditor() with the *shared_editor* parameter set to True, without defining any tree nodes. The object this call returns defines the shared editor pane. For example:: my_shared_editor_pane = TreeEditor(shared_editor=True) #. For each editor that uses the shared editor pane: - Set the *shared_editor* parameter of TreeEditor() to True. - Set the editor parameter of TreeEditor() to the object returned in Step 1. For example:: shared_tree_1 = TreeEditor(shared_editor = True, editor = my_shared_editor_pane, nodes = [ TreeNode( # ... ) ] ) shared_tree_2 = TreeEditor(shared_editor = True, editor = my_shared_editor_pane, nodes = [ TreeNode( # ... ) ] ) .. _tree-defining-the-format: Defining the Format ::::::::::::::::::: Several parameters to TreeEditor() affect the formatting of the tree control: - *show_icons*: If True (the default), icons are displayed for the nodes in the tree. - *icon_size*: A two-integer tuple indicating the size of the icons for the nodes. - *lines_mode*: Determines whether lines are displayed between related nodes. The valid values are 'on', 'off', and 'appearance' (the default). When set to 'appearance', lines are displayed except on Posix-based platforms. - *hide_root*: If True, the root node in the hierarchy is not displayed. If this parameter were specified as True in Example 16, the node in Figure 54 that is labeled "Acme Labs, Inc." would not appear. Additionally, several attributes of TreeNode also affect the display of the tree: - **icon_path**: A directory path to search for icon files. This path can be relative to the module it is used in. - **icon_item**: The icon for a leaf node. - **icon_open**: The icon for a node with children whose children are displayed. - **icon_group**: The icon for a node with children whose children are not displayed. The wxWidgets implementation automatically detects the bitmap format of the icon. .. _extra-trait-editor-factories: "Extra" Trait Editor Factories ------------------------------ The traitsui.wx package defines a few editor factories that are specific to the wxWidgets toolkit, some of which are also specific to the Microsoft Windows platform. These editor factories are not necessarily implemented for other GUI toolkits or other operating system platforms. AnimatedGIFEditor() ``````````````````` :Suitable for: File :Default for: (none) :Optional parameters: *playing* AnimatedGIFEditor() generates a display of the contents of an animated GIF image file. The Boolean *playing* parameter determines whether the image is animated or static. ArrayViewEditor() ````````````````` :Suitable for: 2-D Array, 2-D CArray :Default for: (none) :Optional parameters: *format, show_index, titles, transpose* ArrayViewEditor() generates a tabular display for an array. It is suitable for use with large arrays, which do not work well with the editors generated by ArrayEditor(). All styles of the editor have the same appearance. .. figure:: images/array_view_editor.jpg :alt: Tabular display of numeric data, with columns Index, x, y, and z Figure 55: Array view editor FlashEditor() ````````````` :Suitable for: string traits, Enum(string values) :Default for: (none) FlashEditor() generates a display of an Adobe Flash Video file, using an ActiveX control (if one is installed on the system). This factory is available only on Microsoft Windows platforms. The attribute being edited must have a value whose text representation is the name or URL of a Flash video file. If the value is a Unicode string, it must contain only characters that are valid for filenames or URLs. HistoryEditor() ``````````````` :Suitable for: string traits :Default for: (none) :Optional parameters: *entries* HistoryEditor() generates a combo box, which allows the user to either enter a text string or select a value from a list of previously-entered values. The same control is used for all editor styles. The *entries* parameter determines how many entries are preserved in the history list. This type of control is used as part of the simple style of file editor; see :ref:`fileeditor`. IEHTMLEditor() `````````````` :Suitable for: string traits, Enum(string values) :Default for: (none) :Optional parameters: *back, forward, home, html, page_loaded, refresh, search, status, stop,* *title* IEHTMLEditor() generates a display of a web page, using Microsoft Internet Explorer (IE) via ActiveX to render the page. This factory is available only on Microsoft Windows platforms. The attribute being edited must have value whose text representation is a URL. If the value is a Unicode string, it must contain only characters that are valid for URLs. The *back*, *forward*, *home*, *refresh*, *search* and *stop* parameters are extended names of event attributes that represent the user clicking on the corresponding buttons in the standard IE interface. The IE buttons are not displayed by the editor; you must create buttons separately in the View, if you want the user to be able to actually click buttons. The *html*, *page_loaded*, *status*, and *title* parameters are the extended names of string attributes, which the editor updates with values based on its own state. You can display these attributes elsewhere in the View. - *html*: The current page content as HTML (as would be displayed by the :menuselection:`View > Source` command in IE). - *page_loaded*: The URL of the currently displayed page; this may be different from the URL represented by the attribute being edited. - *status*: The text that would appear in the IE status bar. - *title*: The title of the currently displayed page. ImageEditor() ````````````` :Suitable for: (any) :Default for: (none) :Optional parameters: *image* ImageEditor() generates a read-only display of an image. The image to be displayed is determined by the *image* parameter, or by the value of the trait attribute being edited, if *image* is not specified. In either case, the value must be a PyFace ImageResource (pyface.api.ImageResource), or a string that can be converted to one. If *image* is specified, then the type and value of the trait attribute being edited are irrelevant and are ignored. LEDEditor() ``````````` :Suitable for: numeric traits :Default for: (none) :Optional parameters: *alignment, format_str* LEDEditor() generates a display that resembles a "digital" display using light-emitting diodes. All styles of this editor are the same, and are read-only. The *alignment* parameter can be 'left', 'center', or 'right' to indicate how the value should be aligned within the display. The default is right-alignment. .. figure:: images/led_editor.png :alt: LED-like display of 90452 Figure 56: LED Editor with right alignment ThemedButtonEditor() ```````````````````` :Suitable for: Event :Default for: (none) :Optional parameters: *label*, *theme, down_theme, hover_theme, disabled_theme, image, position,* *spacing, view* The ThemedButtonEditor() factory generates a button that is formatted according to specified or default themes. All editor styles have the same appearance. .. figure:: images/themed_button_editor.png :alt: Themed buttons for normal, hover, down, and disabled states Figure 57: Themed buttons in various states The theme-related parameters determine the appearance of the button in various states. Figure 57 shows the default theme. ThemedCheckboxEditor() `````````````````````` :Suitable for: Boolean :Default for: (none) :Optional parameters: *label*, *theme, hover_off_image, hover_off_theme, hover_on_image,* *hover_on_theme, image, on_image, on_theme, position, spacing* The ThemedCheckboxEditor() factory generates a checkbox that is formatted according to specified or default themes. All editor styles have the same appearance. .. figure:: images/themed_checkbox_editor.png :alt: Themed checkbox for On, Off, Hover Off, and Hover On states Figure 58: Themed checkbox in various states The theme-related parameters determine the appearance of the checkbox in the various states. shows the default theme. If *label* is not specified for the editor factory, the value is inherited from the *label* value of the enclosing Item. Both labels may be displayed, if the Item's label is not hidden. ThemedSliderEditor() ```````````````````` :Suitable for: Range :Default for: (none) :Optional parameters: *alignment, bg_color, high, increment, low, show_value, slider_color,* *text_color, tip_color* The ThemedSliderEditor() factory generates a slider control that is formatted according to specified or default themes. All editor styles have the same appearance. The value is edited by modifying its textual representation. The background of the control updates to reflect the value relative to the total range represented by a slider. For example, if the range is from -2 to 2, a value of 0 is represented by a bar covering the left half of the control area, as shown in Figure 59. .. image:: images/themed_slider_no_focus.png :alt: Themed box with shading in the left half and a vertical orange bar in the middle .. figure:: images/themed_slide_with_focus.png :alt: Themed box with the value 0 selected in the center Figure 59: Themed slider without focus, and with focus ThemedTextEditor() `````````````````` :Suitable for: Str, String, Unicode, CStr, CUnicode, and any trait whose value is a string :Default for: (none) :Optional parameters: *auto_set*, *enter_set*, *evaluate*, *evaluate_name*, *mapping*, *multi_line*, *password, theme* The ThemedTextEditor() factory generates a text editor that is formatted according to a specified theme. If no theme is specified, the editor uses the theme, if any, specified by the surrounding Group or View. Thus, there is no default theme. All editor styles have the same appearance, except the read-only style, which is not editable. .. image:: images/themed_text_editor_no_focus.png :alt: Themed text editor, displaying text ``a*x*x-b*x`` .. figure:: images/themed_text_editor_with_focus.png :alt: Themed text editor, with text ``a*x*x-b*x`` selected Figure 60: Themed text editor, without focus and with focus ThemedVerticalNotebookEditor() `````````````````````````````` :Suitable for: Lists of Instances :Default for: (none) :Optional parameters: *closed_theme, double_click, open_theme, page_name, multiple_open,* *scrollable, view* The ThemedVerticalNotebookEditor() factory generates a "notebook" editor, containing tabs that can be vertically expanded or collapsed. It can be used for lists of instances, similarly to the ListEditor() factory, with the *use_notebook* parameter. You can specify themes to use for the open and closed states of the tabs. .. figure:: images/themed_notebook_closed.png :alt: Stacked boxes displaying names as labels Figure 61: Themed vertical notebook, with tabs for Person instances closed .. figure:: images/themed_notebook_open.png :alt: Stacked boxes, with one expanded to show themed text editors Figure 62: Themed vertical notebook, with one tab open traitsui-4.1.0/docs/source/traitsui_user_manual/index.rst0000644000175100001440000000102511674463545024706 0ustar ischnellusers00000000000000.. TraitsUI documentation master file, created by sphinx-quickstart on Mon Aug 18 11:27:34 2008. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. TraitsUI 4 User Manual ====================== .. toctree:: :maxdepth: 3 front.rst intro.rst view.rst custom_view.rst advanced_view.rst handler.rst themes.rst factory_intro.rst factories_basic.rst factories_advanced_extra.rst tips.rst glossary.rst predefined_traits.rst traitsui-4.1.0/docs/source/traitsui_user_manual/handler.rst0000644000175100001440000005212311674463545025221 0ustar ischnellusers00000000000000.. _controlling-the-interface-the-handler: ====================================== Controlling the Interface: the Handler ====================================== Most of the material in the preceding chapters is concerned with the relationship between the model and view aspects of the :term:`MVC` design pattern as supported by TraitsUI. This chapter examines the third aspect: the :term:`controller`, implemented in TraitsUI as an :term:`instance` of the :term:`Handler` class. [11]_ A controller for an MVC-based application is essentially an event handler for GUI events, i.e., for events that are generated through or by the program interface. Such events can require changes to one or more model objects (e.g., because a data value has been updated) or manipulation of the interface itself (e.g., window closure, dynamic interface behavior). In TraitsUI, such actions are performed by a Handler object. In the preceding examples in this guide, the Handler object has been implicit: TraitsUI provides a default Handler that takes care of a common set of GUI events including window initialization and closure, data value updates, and button press events for the standard TraitsUI window buttons (see :ref:`command-buttons-the-buttons-attribute`). This chapter explains the features of the TraitsUI Handler, and shows how to implement custom GUI behaviors by building and instantiating custom subclasses of the Handler class. The final section of the chapter describes several techniques for linking a custom Handler to the window or windows it is designed to control. .. _backstage-introducing-the-uiinfo-object: Backstage: Introducing the UIInfo Object ---------------------------------------- TraitsUI supports the MVC design pattern by maintaining the model, view, and controller as separate entities. A single View object can be used to construct windows for multiple model objects; likewise a single Handler can handle GUI events for windows created using different Views. Thus there is no static link between a Handler and any particular window or model object. However, in order to be useful, a Handler must be able to observe and manipulate both its corresponding window and model objects. In TraitsUI, this is accomplished by means of the UIInfo object. Whenever TraitsUI creates a window or panel from a View, a UIInfo object is created to act as the Handler's reference to that window and to the objects whose :term:`trait attribute`\ s are displayed in it. Each entry in the View's context (see :ref:`the-view-context`) becomes an attribute of the UIInfo object. [12]_ For example, the UIInfo object created in :ref:`Example 7 ` has attributes **h1** and **h2** whose values are the objects **house1** and **house2** respectively. In :ref:`Example 1 ` through :ref:`Example 6 `, the created UIInfo object has an attribute **object** whose value is the object **sam**. Whenever a window event causes a Handler method to be called, TraitsUI passes the corresponding UIInfo object as one of the method arguments. This gives the Handler the information necessary to perform its tasks. .. _assigning-handlers-to-views: Assigning Handlers to Views --------------------------- In accordance with the MVC design pattern, Handlers and Views are separate entities belonging to distinct classes. In order for a custom Handler to provide the control logic for a window, it must be explicitly associated with the View for that window. The TraitsUI package provides three ways to accomplish this: - Make the Handler an attribute of the View. - Provide the Handler as an argument to a display method such as edit_traits(). - Define the View as part of the Handler. .. _binding-a-singleton-handler-to-a-view: Binding a Singleton Handler to a View ````````````````````````````````````` To associate a given custom Handler with all windows produced from a given View, assign an instance of the custom Handler class to the View's **handler** attribute. The result of this technique, as shown in :ref:`Example 9 `, is that the window created by the View object is automatically controlled by the specified handler instance. .. _linking-handler-and-view-at-edit-time: Linking Handler and View at Edit Time ````````````````````````````````````` It is also possible to associate a custom Handler with a specific window without assigning it permanently to the View. Each of the three TraitsUI window-building methods (the configure_traits() and edit_traits() methods of the HasTraits class and the ui() method of the View class) has a *handler* keyword argument. Assigning an instance of Handler to this argument gives that handler instance control *only of the specific window being created by the method call*. This assignment overrides the View's **handler** attribute. .. _creating-a-default-view-within-a-handler: Creating a Default View Within a Handler ```````````````````````````````````````` You seldom need to associate a single custom Handler with several different Views or vice versa, although you can in theory and there are cases where it is useful to be able to do so. In most real-life scenarios, a custom Handler is tailored to a particular View with which it is always used. One way to reflect this usage in the program design is to define the View as part of the Handler. The same rules apply as for defining Views within HasTraits objects; for example, a view named 'trait_view' is used as the default view. The Handler class, which is a subclass of HasTraits, overrides the standard configure_traits() and edit_traits() methods; the subclass versions are identical to the originals except that the Handler object on which they are called becomes the default Handler for the resulting windows. Note that for these versions of the display methods, the *context* keyword parameter is not optional. .. _handler-subclasses: Handler Subclasses ------------------ TraitsUI provides two Handler subclasses: ModelView and Controller. Both of these classes are designed to simplify the process of creating an MVC-based application. Both ModelView and Controller extend the Hander class by adding the following trait attributes: - **model**: The model object for which this handler defines a view and controller. - **info**: The UIInfo object associated with the actual user interface window or panel for the model object. The **model** attribute provides convenient access to the model object associated with either subclass. Normally, the **model** attribute is set in the constructor when an instance of ModelView or Controller is created. The **info** attribute provides convenient access to the UIInfo object associated with the active user interface view for the handler object. The **info** attribute is automatically set when the handler object's view is created. Both classes' constructors accept an optional *model* parameter, which is the model object. They also can accept metadata as keyword parameters. .. class:: ModelView( [model = None, **metadata] ) .. class:: Controller( [model = None, **metadata] ) The difference between the ModelView and Controller classes lies in the context dictionary that each one passes to its associated user interface, as described in the following sections. .. _controller-class: Controller Class ```````````````` The Controller class is normally used when implementing a standard MVC-based design, and plays the "controller" role in the MVC design pattern. The "model" role is played by the object referenced by the Controller's **model** attribute; and the "view" role is played by the View object associated with the model object. The context dictionary that a Controller object passes to the View's ui() method contains the following entries: - ``object``: The Controller's model object. - ``controller``: The Controller object itself. Using a Controller as the handler class assumes that the model object contains most, if not all, of the data to be viewed. Therefore, the model object is used for the object key in the context dictionary, so that its attributes can be easily referenced with unqualified names (such as Item('name')). .. _modelview-class: ModelView Class ``````````````` The ModelView class is useful when creating a variant of the standard MVC design pattern. In this variant, the ModelView subclass reformulates a number of trait attributes on its model object as properties on the ModelView, usually to convert the model's data into a format that is more suited to a user interface. The context dictionary that a ModelView object passes to the View's ui() method contains the following entries: - ``object``: The ModelView object itself. - ``model``: The ModelView's model object. In effect, the ModelView object substitutes itself for the model object in relation to the View object, serving both the "controller" role and the "model" role (as a set of properties wrapped around the original model). Because the ModelView object is passed as the context's object, its attributes can be referenced by unqualified names in the View definition. .. _writing-handler-methods: Writing Handler Methods ----------------------- If you create a custom Handler subclass, depending on the behavior you want to implement, you might override the standard methods of Handler, or you might create methods that respond to changes to specific trait attributes. .. _overriding-standard-methods: Overriding Standard Methods ``````````````````````````` The Handler class provides methods that are automatically executed at certain points in the lifespan of the window controlled by a given Handler. By overriding these methods, you can implement a variety of custom window behaviors. The following sequence shows the points at which the Handler methods are called. 1. A UIInfo object is created 2. The Handler's init_info() method is called. Override this method if the handler needs access to viewable traits on the UIInfo object whose values are properties that depend on items in the context being edited. 3. The UI object is created, and generates the actual window. 4. The init() method is called. Override this method if you need to initialize or customize the window. .. TODO: Add a non-trivial example here. 5. The position() method is called. Override this method to modify the position of the window (if setting the x and y attributes of the View is insufficient). 6. The window is displayed. .. _when-handler-methods-are-called-and-when-to-override-them-table: .. rubric:: When Handler methods are called, and when to override them +---------------------------+--------------------------+-----------------------+ |Method |Called When |Override When? | +===========================+==========================+=======================+ |apply(info) |The user clicks the |To perform additional | | |:guilabel:`Apply` button, |processing at this | | |and after the changes have|point. | | |been applied to the | | | |context objects. | | +---------------------------+--------------------------+-----------------------+ |close(info, is_ok) |The user requests to close|To perform additional | | |the window, clicking |checks before | | |:guilabel:`OK`, |destroying the window. | | |:guilabel:`Cancel`, or the| | | |window close button, menu,| | | |or icon. | | +---------------------------+--------------------------+-----------------------+ |closed(info, is_ok) |The window has been |To perform additional | | |destroyed. |clean-up tasks. | +---------------------------+--------------------------+-----------------------+ |revert(info) |The user clicks the |To perform additional | | |:guilabel:`Revert` button,|processing. | | |or clicks | | | |:guilabel:`Cancel` in a | | | |live window. | | +---------------------------+--------------------------+-----------------------+ |setattr(info, object, name,|The user changes a trait |To perform additional | |value) |attribute value through |processing, such as | | |the user interface. |keeping a change | | | |history. Make sure that| | | |the overriding method | | | |actually sets the | | | |attribute. | +---------------------------+--------------------------+-----------------------+ |show_help(info, |The user clicks the |To call a custom help | |control=None) |:guilabel:`Help` button. |handler in addition to | | | |or instead of the | | | |global help handler, | | | |for this window. | +---------------------------+--------------------------+-----------------------+ .. _reacting-to-trait-changes: Reacting to Trait Changes ````````````````````````` The setattr() method described above is called whenever any trait value is changed in the UI. However, TraitsUI also provides a mechanism for calling methods that are automatically executed whenever the user edits a *particular* trait. While you can use static notification handler methods on the HasTraits object, you might want to implement behavior that concerns only the user interface. In that case, following the MVC pattern dictates that such behavior should not be implemented in the "model" part of the code. In keeping with this pattern, TraitsUI supports "user interface notification" methods, which must have a signature with the following format: .. method:: extended_traitname_changed(info) This method is called whenever a change is made to the attribute specified by *extended_traitname* in the **context** of the View used to create the window (see :ref:`multi-object-views`), where the dots in the extended trait reference have been replaced by underscores. For example, for a method to handle changes on the **salary** attribute of the object whose context key is 'object' (the default object), the method name should be object_salary_changed(). By contrast, a subclass of Handler for :ref:`Example 7 ` might include a method called h2_price_changed() to be called whenever the price of the second house is edited. .. note:: These methods are called on window creation. User interface notification methods are called when the window is first created. To differentiate between code that should be executed when the window is first initialized and code that should be executed when the trait actually changes, use the **initialized** attribute of the UIInfo object (i.e., of the *info* argument):: def object_foo_changed(self, info): if not info.initialized: #code to be executed only when the window is #created else: #code to be executed only when 'foo' changes after #window initialization} #code to be executed in either case The following script, which annotates its window's title with an asterisk ('*') the first time a data element is updated, demonstrates a simple use of both an overridden setattr() method and user interface notification method. .. _example-9-using-a-handler-that-reacts-to-trait-changes: .. rubric:: Example 9: Using a Handler that reacts to trait changes :: # handler_override.py -- Example of a Handler that overrides # setattr(), and that has a user interface # notification method from traits.api import HasTraits, Bool from traitsui.api import View, Handler class TC_Handler(Handler): def setattr(self, info, object, name, value): Handler.setattr(self, info, object, name, value) info.object._updated = True def object__updated_changed(self, info): if info.initialized: info.ui.title += "*" class TestClass(HasTraits): b1 = Bool b2 = Bool b3 = Bool _updated = Bool(False) view1 = View('b1', 'b2', 'b3', title="Alter Title", handler=TC_Handler(), buttons = ['OK', 'Cancel']) tc = TestClass() tc.configure_traits(view=view1) .. image:: images/alter_title_before.png :alt: Dialog box with empty checkboxes and a title of "Alter Title" .. figure:: images/alter_title_after.png :alt: Dialog box with one filled checkbox and a title of "Alter Title*" Figure 7: Before and after views of Example 9 .. _implementing-custom-window-commands: Implementing Custom Window Commands ``````````````````````````````````` Another use of a Handler is to define custom window actions, which can be presented as buttons, menu items, or toolbar buttons. .. _actions: Actions ::::::: In TraitsUI, window commands are implemented as instances of the Action class. Actions can be used in :term:`command button`\ s, menus, and toolbars. Suppose you want to build a window with a custom **Recalculate** action. Suppose further that you have defined a subclass of Handler called MyHandler to provide the logic for the window. To create the action: #. Add a method to MyHandler that implements the command logic. This method can have any name (e.g., do_recalc()), but must accept exactly one argument: a UIInfo object. #. Create an Action instance using the name of the new method, e.g.:: recalc = Action(name = "Recalculate", action = "do_recalc") .. _custom-command-buttons: Custom Command Buttons :::::::::::::::::::::: The simplest way to turn an Action into a window command is to add it to the **buttons** attribute for the View. It appears in the button area of the window, along with any standard buttons you specify. #. Define the handler method and action, as described in :ref:`actions`. #. Include the new Action in the **buttons** attribute for the View:: View ( #view contents, # ..., buttons = [ OKButton, CancelButton, recalc ]) .. _menus-and-menu-bars: Menus and Menu Bars ::::::::::::::::::: Another way to install an Action such as **recalc** as a window command is to make it into a menu option. #. Define the handler method and action, as described in :ref:`actions`. #. If the View does not already include a MenuBar, create one and assign it to the View's **menubar** attribute. #. If the appropriate Menu does not yet exist, create it and add it to the MenuBar. #. Add the Action to the Menu. These steps can be executed all at once when the View is created, as in the following code:: View ( #view contents, # ..., menubar = MenuBar( Menu( my_action, name = 'My Special Menu'))) .. _toolbars: Toolbars :::::::: A third way to add an action to a Traits View is to make it a button on a toolbar. Adding a toolbar to a Traits View is similar to adding a menu bar, except that toolbars do not contain menus; they directly contain actions. 1. Define the handler method and the action, as in :ref:`actions`, including a tooltip and an image to display on the toolbar. The image must be a Pyface ImageResource instance; if a path to the image file is not specified, it is assumed to be in an images subdirectory of the directory where ImageResource is used:: From pyface.api import ImageResource recalc = Action(name = "Recalculate", action = "do_recalc", toolip = "Recalculate the results", image = ImageResource("recalc.png")) 2. If the View does not already include a ToolBar, create one and assign it to the View's **toolbar** attribute. 3. Add the Action to the ToolBar. As with a MenuBar, these steps can be executed all at once when the View is created, as in the following code:: View ( #view contents, # ..., toolbar = ToolBar( my_action)) .. rubric:: Footnotes .. [11] Except those implemented via the **enabled_when**, **visible_when**, and **defined_when** attributes of Items and Groups. .. [12] Other attributes of the UIInfo object include a UI object and any *trait editors* contained in the window (see :ref:`introduction-to-trait-editor-factories` and :ref:`the-predefined-trait-editor-factories`). traitsui-4.1.0/docs/source/traitsui_user_manual/front.rst0000644000175100001440000000335611674463545024740 0ustar ischnellusers00000000000000====================== TraitsUI 4 User Manual ====================== :Authors: Lyn Pierce, Janet Swisher :Version: Document Version 4 :Copyright: 2005, 2008 Enthought, Inc. All Rights Reserved. Redistribution and use of this document in source and derived forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source or derived format (for example, Portable Document Format or Hypertext Markup Language) must retain the above copyright notice, this list of conditions and the following disclaimer. * Neither the name of Enthought, Inc., nor the names of contributors may be used to endorse or promote products derived from this document without specific prior written permission. THIS DOCUMENT IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS DOCUMENT, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. All trademarks and registered trademarks are the property of their respective owners. | Enthought, Inc. | 515 Congress Avenue | Suite 2100 | Austin TX 78701 | 1.512.536.1057 (voice) | 1.512.536.1059 (fax) | http://www.enthought.com | info@enthought.com traitsui-4.1.0/docs/source/traitsui_user_manual/predefined_traits.rst0000644000175100001440000001562011674463545027300 0ustar ischnellusers00000000000000.. _editor-factories-for-predefined-traits: =================================================== Appendix II: Editor Factories for Predefined Traits =================================================== Predefined traits that are not listed in this table use TextEditor() by default, and have no other appropriate editor factories. +-------------+----------------------------+-----------------------------------+ |Trait |Default Editor Factory |Other Possible Editor Factories | +=============+============================+===================================+ |Any |TextEditor |EnumEditor, ImageEnumEditor, | | | |ValueEditor | +-------------+----------------------------+-----------------------------------+ |Array |ArrayEditor (for 2-D arrays)| | +-------------+----------------------------+-----------------------------------+ |Bool |BooleanEditor |ThemedCheckboxEditor | +-------------+----------------------------+-----------------------------------+ |Button |ButtonEditor | | +-------------+----------------------------+-----------------------------------+ |CArray |ArrayEditor (for 2-D arrays)| | +-------------+----------------------------+-----------------------------------+ |CBool |BooleanEditor | | +-------------+----------------------------+-----------------------------------+ |CComplex |TextEditor | | +-------------+----------------------------+-----------------------------------+ |CFloat, CInt,|TextEditor |LEDEditor | |CLong | | | +-------------+----------------------------+-----------------------------------+ |Code |CodeEditor | | +-------------+----------------------------+-----------------------------------+ |Color |ColorEditor | | +-------------+----------------------------+-----------------------------------+ |Complex |TextEditor | | +-------------+----------------------------+-----------------------------------+ |CStr, |TextEditor (multi_line=True)|CodeEditor, HTMLEditor | |CUnicode | | | +-------------+----------------------------+-----------------------------------+ |Dict |TextEditor |ValueEditor | +-------------+----------------------------+-----------------------------------+ |Directory |DirectoryEditor | | +-------------+----------------------------+-----------------------------------+ |Enum |EnumEditor |ImageEnumEditor | +-------------+----------------------------+-----------------------------------+ |Event |(none) |ButtonEditor, ToolbarButtonEditor | +-------------+----------------------------+-----------------------------------+ |File |FileEditor |AnimatedGIFEditor | +-------------+----------------------------+-----------------------------------+ |Float |TextEditor |LEDEditor | +-------------+----------------------------+-----------------------------------+ |Font |FontEditor | | +-------------+----------------------------+-----------------------------------+ |HTML |HTMLEditor | | +-------------+----------------------------+-----------------------------------+ |Instance |InstanceEditor |TreeEditor, DropEditor, DNDEditor, | | | |ValueEditor | +-------------+----------------------------+-----------------------------------+ |List |TableEditor for lists of |CSVListEditor, CheckListEditor, | | |HasTraits objects; |SetEditor, ValueEditor, | | |ListEditor for all other |ThemedVerticalNotebookEditor | | |lists. | | +-------------+----------------------------+-----------------------------------+ |Long |TextEditor |LEDEditor | +-------------+----------------------------+-----------------------------------+ |Password |TextEditor(password=True) | | +-------------+----------------------------+-----------------------------------+ |PythonValue |ShellEditor | | +-------------+----------------------------+-----------------------------------+ |Range |RangeEditor |ThemedSliderEditor | +-------------+----------------------------+-----------------------------------+ |Regex |TextEditor |CodeEditor | +-------------+----------------------------+-----------------------------------+ |RGBColor |RGBColorEditor | | +-------------+----------------------------+-----------------------------------+ |Str |TextEditor(multi_line=True) |CodeEditor, HTMLEditor | +-------------+----------------------------+-----------------------------------+ |String |TextEditor |CodeEditor, ThemedTextEditor | +-------------+----------------------------+-----------------------------------+ |This |InstanceEditor | | +-------------+----------------------------+-----------------------------------+ |ToolbarButton|ButtonEditor | | +-------------+----------------------------+-----------------------------------+ |Tuple |TupleEditor | | +-------------+----------------------------+-----------------------------------+ |UIDebugger |ButtonEditor (button calls | | | |the UIDebugEditor factory) | | +-------------+----------------------------+-----------------------------------+ |Unicode |TextEditor(multi_line=True) |HTMLEditor | +-------------+----------------------------+-----------------------------------+ |WeakRef |InstanceEditor | | +-------------+----------------------------+-----------------------------------+ traitsui-4.1.0/docs/source/traitsui_user_manual/custom_view.rst0000644000175100001440000003466511674463545026163 0ustar ischnellusers00000000000000.. index:: View; customizing .. _customizing-a-view: ================== Customizing a View ================== As shown in the preceding two chapters, it is possible to specify a window in TraitsUI simply by creating a View object with the appropriate contents. In designing real-life applications, however, you usually need to be able to control the appearance and behavior of the windows themselves, not merely their content. This chapter covers a variety of options for tailoring the appearance of a window that is created using a View, including the type of window that a View appears in, the :term:`command button`\ s that appear in the window, and the physical properties of the window. .. index:: kind attribute .. _specifying-window-type-the-kind-attribute: Specifying Window Type: the **kind** Attribute ---------------------------------------------- Many types of windows can be used to display the same data content. A form can appear in a window, a wizard, or an embedded panel; windows can be *modal* (i.e., stop all other program processing until the box is dismissed) or not, and can interact with live data or with a buffered copy. In TraitsUI, a single View can be used to implement any of these options simply by modifying its **kind** attribute. There are seven possible values of **kind**: .. index:: modal; window kind, live; window kind, livemodal window kind .. index:: nonmodal window kind, wizard; window kind, panel; window kind .. index:: subpanel; window kind * 'modal' * 'live' * 'livemodal' * 'nonmodal' * 'wizard' * 'panel' * 'subpanel' These alternatives are described below. If the **kind** attribute of a View object is not specified, the default value is 'modal'. .. index:: windows; stand-alone, modal; definition, live; definition .. _stand-alone-windows: Stand-alone Windows ``````````````````` The behavior of a stand-alone TraitsUI window can vary over two significant degrees of freedom. First, it can be :term:`modal`, meaning that when the window appears, all other GUI interaction is suspended until the window is closed; if it is not modal, then both the window and the rest of the GUI remain active and responsive. Second, it can be :term:`live`, meaning that any changes that the user makes to data in the window is applied directly and immediately to the underlying model object or objects; otherwise the changes are made to a copy of the model data, and are only copied to the model when the user commits them (usually by clicking an :guilabel:`OK` or :guilabel:`Apply` button; see :ref:`command-buttons-the-buttons-attribute`). The four possible combinations of these behaviors correspond to four of the possible values of the 'kind ' attribute of the View object, as shown in the following table. .. _matrix-of-traits-ui-windows-table: .. rubric:: Matrix of TraitsUI windows +-------------+----------------+-----------------+ | |not modal |modal | +=============+================+=================+ |**not live** |:term:`nonmodal`|:term:`modal` | +-------------+----------------+-----------------+ |**live** |:term:`live` |:term:`livemodal`| +-------------+----------------+-----------------+ All of these window types are identical in appearance. Also, all types support the **buttons** attribute, which is described in :ref:`command-buttons-the-buttons-attribute`. Usually, a window with command buttons is called a :term:`dialog box`. .. TODO: Add diagrams and/or examples to clarify. .. index:: wizard, windows; wizard .. _wizards: Wizards ``````` Unlike a window, whose contents generally appear as a single page or a tabbed display, a :term:`wizard` is presented as a series of pages that a user must navigate sequentially. .. TODO: Add a reference to the section on the organization of Views via Groups, once it's been added. .. TODO: add code and screenshot for a simple tabbed display and of the same View presented as a Wizard. TraitsUI Wizards are always modal and live. They always display a standard wizard button set; i.e., they ignore the **buttons** View attribute. In short, wizards are considerably less flexible than windows, and are primarily suitable for highly controlled user interactions such as software installation. .. index:: panel, subpanel, windows; panel, windows; subpanel .. _panels-and-subpanels: Panels and Subpanels ```````````````````` Both dialog boxes and wizards are secondary windows that appear separately from the main program display, if any. Often, however, you might need to create a window element that is embedded in a larger display. For such cases, the **kind** of the corresponding View object should be 'panel' or 'subpanel '. A :term:`panel` is very similar to a window, except that it is embedded in a larger window, which need not be a TraitsUI window. Like windows, panels support the **buttons** View attribute, as well as any menus and toolbars that are specified for the View (see :ref:`menus-and-menu-bars`). Panels are always live and nonmodal. A :term:`subpanel` is almost identical to a panel. The only difference is that subpanels do not display :term:`command button`\ s even if the View specifies them. .. Do subpanels support menus and toolbars? If not, add this to the documentation. (If so, why do they?) .. index:: buttons; attribute .. _command-buttons-the-buttons-attribute: Command Buttons: the **buttons** Attribute ------------------------------------------ A common feature of many windows is a row of command buttons along the bottom of the frame. These buttons have a fixed position outside any scrolled panels in the window, and are thus always visible while the window is displayed. They are usually used for window-level commands such as committing or cancelling the changes made to the form data, or displaying a help window. In TraitsUI, these command buttons are specified by means of the View object's **buttons** attribute, whose value is a list of buttons to display. [6]_ Consider the following variation on Example 3: .. index:: pair: examples; buttons .. _example-4-using-a-view-object-with-buttons: .. rubric:: Example 4: Using a View object with buttons :: # configure_traits_view_buttons.py -- Sample code to demonstrate # configure_traits() from traits.api import HasTraits, Str, Int from traitsui.api import View, Item from traitsui.menu import OKButton, CancelButton class SimpleEmployee(HasTraits): first_name = Str last_name = Str department = Str employee_number = Str salary = Int view1 = View(Item(name = 'first_name'), Item(name = 'last_name'), Item(name = 'department'), buttons = [OKButton, CancelButton]) sam = SimpleEmployee() sam.configure_traits(view=view1) The resulting window has the same content as before, but now two buttons are displayed at the bottom: :guilabel:`OK` and :guilabel:`Cancel`: .. figure:: images/ui_for_ex4.jpg :alt: Dialog box with three fields and OK and Cancel buttons. Figure 4: User interface for Example 4 There are six standard buttons defined by TraitsUI. Each of the standard buttons has matching a string alias. You can either import and use the button names, or simply use their aliases: .. index:: buttons; standard, UndoButton, ApplyButton, RevertButton, OKButton .. index:: CancelButton .. _command-button-aliases-table: .. rubric:: Command button aliases +--------------+---------------------------+ |Button Name |Button Alias | +==============+===========================+ |UndoButton |'Undo' | +--------------+---------------------------+ |ApplyButton |'Apply' | +--------------+---------------------------+ |RevertButton |'Revert' | +--------------+---------------------------+ |OKButton |'OK' (case sensitive!) | +--------------+---------------------------+ |CancelButton |'Cancel' | +--------------+---------------------------+ Alternatively, there are several pre-defined button lists that can be imported from traitsui.menu and assigned to the buttons attribute: .. index:: OKCancelsButtons, ModalButtons, LiveButtons * OKCancelButtons = ``[OKButton, CancelButton ]`` * ModalButtons = ``[ ApplyButton, RevertButton, OKButton, CancelButton, HelpButton ]`` * LiveButtons = ``[ UndoButton, RevertButton, OKButton, CancelButton, HelpButton ]`` Thus, one could rewrite the lines in Example 4 as follows, and the effect would be exactly the same:: from traitsui.menu import OKCancelButtons buttons = OKCancelButtons .. index:: NoButtons The special constant NoButtons can be used to create a window or panel without command buttons. While this is the default behavior, NoButtons can be useful for overriding an explicit value for **buttons**. You can also specify ``buttons = []`` to achieve the same effect. Setting the **buttons** attribute to an empty list has the same effect as not defining it at all. It is also possible to define custom buttons and add them to the **buttons** list; see :ref:`custom-command-buttons` for details. .. index:: View; attributes, attributes; View .. _other-view-attributes: Other View Attributes --------------------- .. index:: dock attribute; View, height attribute; View, icon attribute .. index:: image attribute; View, item_theme attribute; View .. index:: label_theme attribute; View, resizable attribute; View .. index:: scrollable attribute, statusbar attribute, style attribute; View .. index:: title attribute, width attribute; View, x attribute, y attribute .. _attributes-of-view-by-category-table: .. rubric:: Attributes of View, by category +----------+---------------------+---------------------------------------------+ |Category |Attributes |Description | +==========+=====================+=============================================+ |Window |* **dock** |These attributes control the visual | |display |* **height** |properties of the window itself, regardless | | |* **icon** |of its content. | | |* **image** | | | |* **item_theme** |.. index:: close_result attribute | | |* **label_theme** |.. index:: handler attribute | | |* **resizable** |.. index:: key_bindings attribute | | |* **scrollable** |.. index:: menubar attribute | | |* **statusbar** |.. index:: model_view attribute | | |* **style** |.. index:: on_apply attribute | | |* **title** |.. index:: toolbar attribute | | |* **width** |.. index:: updated attribute | | |* **x** |.. index:: content attribute; View | | |* **y** |.. index:: drop_class attribute | +----------+---------------------+---------------------------------------------+ |Command |* **close_result** |TraitsUI menus and toolbars are generally | | |* **handler** |implemented in conjunction with custom | | |* **key_bindings** |:term:`Handler`\ s; see | | |* **menubar** |:ref:`menus-and-menu-bars` for details. The | | |* **model_view** |**key_bindings** attribute references the set| | |* **on_apply** |of global key bindings for the view. | | |* **toolbar** | | | |* **updated** |.. index:: export attribute; View | | | |.. index:: imports attribute | | | |.. index:: object attribute; View | +----------+---------------------+---------------------------------------------+ |Content |* **content** |The **content** attribute is the top-level | | |* **drop_class** |Group object for the view. The **object** | | |* **export** |attribute is the object being edited. The | | |* **imports** |**imports** and **drop_class** attributes | | |* **object** |control what objects can be dragged and | | | |dropped on the view. | | | | | | | |.. index:: help attribute; View | | | |.. index:: help_id attribute; View | +----------+---------------------+---------------------------------------------+ |User help |* **help** |The **help** attribute is a deprecated way to| | |* **help_id** |specify that the View has a Help button. Use | | | |the buttons attribute instead (see | | | |:ref:`command-buttons-the-buttons-attribute` | | | |for details). The **help_id** attribute is | | | |not used by Traits, but can be used by a | | | |custom help handler. | | | | | | | |.. index:: id attribute; View | +----------+---------------------+---------------------------------------------+ |Unique |* **id** |The **id** attribute is used as a key to save| |identifier| |user preferences about a view, such as | | | |customized size and position, so that they | | | |are restored the next time the view is | | | |opened. The value of **id** must be unique | | | |across all Traits-based applications on a | | | |system. If no value is specified, no user | | | |preferences are saved for the view. | +----------+---------------------+---------------------------------------------+ .. rubric:: Footnotes .. [6] Actually, the value of the **buttons** attribute is really a list of Action objects, from which GUI buttons are generated by TraitsUI. The Action class is described in :ref:`actions`. traitsui-4.1.0/docs/source/tutorials/0000755000175100001440000000000011674463545020636 5ustar ischnellusers00000000000000traitsui-4.1.0/docs/source/tutorials/images/0000755000175100001440000000000011674463545022103 5ustar ischnellusers00000000000000traitsui-4.1.0/docs/source/tutorials/images/interactive.png0000644000175100001440000002523711674463545025137 0ustar ischnellusers00000000000000PNG  IHDR0. bKGD pHYs  tIME IDATxw|%i6IR "eQ2dld *'[䇨,{+{J'mWf(3Ru=wsswORmj=N؎Q#""G¨BY*1%2L+7 l`(b􈈈$Rݐś1H&/ }AiJق;?zi^mhUipM34 zrSوv]D/UX*(|GD>^mh2 1$ۅ?zehsӠI3['`udS4m=ɗ/A \k%̺ ӦMCnn.E;IL[y?K>l-A"CyiX-;xwdGiޓWW>~̶LpՐ{7?2~rICy0Qm6M!Qf2QgEsì9P:^€5}>yGѝ WnQ쿚oEncp5!r_f˝Δܡu62 ߇iN=`1/ }s X܆@tG~ò%1b\ ](RUry,gX=x_aA"LǞ?axy\;zMY6;ϦhFcwkvm당/cK$.0p<1uS[%0Frnd!; F :`g ϯAF2p<7eIDο4@޲?`wU&8ȖOЮSeַTKv* [޺5AD`N]D./ٛ1i֭T{ O } ;ǚټ`ɪޠm hy;[ƣ@^,63_ #tZ-.݌C#ocic"xHqCL o?K^3s1]2+NanQ$Q WCwz jhlV4x <<؉~zIdzfY?OعxI_R*Fφ m\؆oV!G;% zΐ )>8u$haa͜[76_:8Bs?IQ>ggAn÷8|f d%\ÿ~SDTr\"v\9Z**WAU?RJW:MF`6$\&|2= {tGvR@o5p^yu|S30УeR:]6Bpt_fmxtje $b4ػzSXF BjjFd'C #=NqY2}G_}S oqlo4ムo4 W~u #v" UQʿDPIt1$ C!شj 2}/,E 8y* ^`߹ Wd @3PQZj)\W1Y^;;Ϙ'/S" nkvFaJD}D򮰝™{ O6Sb>h P^?+nm$|cNCWxy"00:l]iщS[p6QOA絻P#rL<- 7&[_y܋W箇_hrӰRF8 I:tGB~X߬GE֭DT6<z5ȉ~VvXϖzaqF$F]e :.puuő#G0x2$Uw,_/@tu+n@3B.#8|3̺O}+I ٱ G|y=DqD{%%0FY_L-4:#dR"Cbq"A=X=}+a'n =Ni!*c;Ҷ6 DZp6.yzHP٧~뗽P$w(F~2S;}[e4̢v "#0B9#0>>~JW-.̇/@ y iiiHMM5˒j-ܑ.>| wiꌛ)aP)h]H@P<(FM}[F؋4 XnWb{vwAtZ#FN, D!A/IC2HG ! R! 2  ?ٹHױl7AP\2c;NhBK:KA(%G1AKE[O#>HQV|\$P+cC,BR; ''~~~ܹjjnd-a@J)Egou<@VqGwJoGY\!w3\jU STyw6]竫@(:S-Ŭ7FANNl0dzaqX6M@xUZŨܡ,|"'>%zdʺ%S 7[0>ݽ==ݸ)zZ3tr=wZZ G` fTF;2DDDTs7|{ IY5e|4~0"""q"""fRB&"")ID;;ڝ!.>'9T """+#P}֨lycOk׮SD"-#""6oƁÇaoo:;9r$u֭[wY1x{{c]4вSadWHNNxyM`zobRϫ ODDD5N%0! 0DDDT"""jM`u FSjYvvzyYYV;vO<r < DDDo?se=Zl77W?ӦMRDtt4/b3˯a0?hw9fb0fhڢ Bˣ 55J{<^>@!4%&MJUa?ѿ3f3g l1 o_ہ-^H0ƌ{_}O~XڨO֭ǥK/?ԉ#JXު*qJ5k֠GDDD5;~X,o<4/4_*bx'k6s~oOenݸr;-Ga/ ""cD";~:vC᎖-Ξ=+V7K*KLF#JM:hDNN֬YQF DDD5HzkcnϿ Eƿ1#ʼn#˸xҳ&f^^ ?|n\1M^\;iӦɓDDDx;JlݶiixkSZT {q2 k(ɘ3oY1Nõ1i4e!ÇtHLLĜ9sЩS'"""[N`A;9ڬlX=h#GceֳE?ѬU;<˾66۶"ykL:z=;bȐ!pttD˖-͛70BCfjMaܸqLDDT,XS&V2hDNʟ "" 1!"""bsbQ> """![l RADDTۛ c^g ""BzQQQضm$:xK'B$"""k#PkFbgkADDT贚ڝT&DDDTϨ """"&0DDDIly_AL^/#""6b>>~xw4 c} م!~C%"""+p+m #XB0x84n䅈J%4h/ Jh='%# .F#{ xB&U͎uzbRϫ/DDD6ɦ#1y 1i 3?0 q]NDL`l-!"[9^y<QmI`8Ch])Xٳf`kxLD& lذ gqD~x&"l8qi+/;8`VV3аqjk}jvVT^|R՘9{6B6ChfxwV`ƍع B4Br\ahѺ-4߀JG21)<8qo7`0xyp|ͷf>XԴ4;rډcǏ[ IIJڿX`>K^=1clSG /b׎8{oHRt9KNX;_@\\i[aἹP(X0oYX0o. 9X`>nf̲% GGG.ʾ-?__d25k&v730|aj -- 7)1Tx+ Iaoo\ۨ[7hvVT^\i|\|䞞Ŗaqĩ: 7a :6~@I.z"@kx4}dxzz{t~xs"˔y"Ǡ]6jgWϧrHJ\vh>CDDDL`1!"""&0DDDDլJ~ 8|p1||hViɉu, F,]$@↠F{?[Ifgƙ**M`bo=0` oDwBzn`ۖ͐:8npHfe!E4 k 7OD"Y`0 +=/nrGܟgƙqƹćm|{hи ߴJg4h/ J*so\Fhx[x(TzF7Bˍ3sgƙqfqxօ[+ .㑛 LV2 {2Xr\=qfgl<8 螩`H$rD"g؟?3Ό3Ls'0fՂafgbgQ38\;ow88G`q|09|uOR836{NqI׿ }<>HMbqfmsUuU?̒c-19l;K/"//V}b}}04 7I_{c5wW]/ahaȗqڵruui֯獇ͨ|m<6oѷ?~79zk{UY0'gك];z o:y3 bd0[8u8:u숉oL~t}#>oEcАaի'N}>^zbАa]jN>ACboc\dd8oTq11xxS'ڿW.E s.\UDkuP``ƍع B4Br\.ga&hն֮l}Zg#i36m~juռsFZS \`0'Nѣv*t:i]oѣ8y$̶ߠ8~8;77}Is..xmܸyz˖@mѠq(^T\dffy64+33-۴CVVf=&9uz[5uCf0cnjƈaC, # 15%޻Ccq1~5_mC7/wHhݪ%֯i:z 5iB1lHX|j5Xx1jf-Meyf0X ׮E6аqL1T-jXR[~gt1s|cG];qq[ IIJڿX`]X^CB\d2%$~SbNgptrۉNǻ=z!/Xh4ty|zIIb!l]aaM`4ǟŋصc;ΞR.]777D<Y]m܄յu{y+boD\tTGڟ+i-k:|{{Y:|l_vڍ3f/@:?mq>|[2Ęѣp?8 4_.\q5ڱGG|B̒>okbeb'NwȡP*x5VןXd1|}q"qeS֭۰p\r(r,7lmlǂysPuZo~#Gp $%)ѼE+t:(JLyC'+ %wj IDAT%M!up@* AAfIpppD*AH}NN6 f-ọXȯ/d2ޚ5~|a#ot0f̨ ׽kޜwɟ(.== yT4I?o7qȄѹSG8HpqqY3pQ[l PnnnX8̒>_=~X8űZ8p^׾r=Ng` OsgNA +-Ǐ.T ]ZnLO^ȊN{T.h4jKnq~X+a4s3{ ID=͖|}Q/.~W؅V-Cuursq*OЧ6vB|+f}YoEvmԨ ]U I(scp/;W'[^[Eߪ6o^9_M%IDzYG/OZ%0Q ml6[}S刏u frYy\|Oj۱ຸx ڴm ;;{JU-$AxӰ0{<;Ο[scL˕-E KWDFf3ұd{f}#+4,^E<>8w$DA8zp)ّ+t, 0B"6&֬.OOO\:FZ1qPx)`tߢ}}ѮMc' y ]ظ8:\qS0-x7C&iX{F떶?n}8ʛ&O/6JJM_}ƗS=ӵa;s_?8O8~6mYYh58&NyӴZR{'$ ̶sǢ%ˠLV"77Wz>okU&Vd{߻V`@Vןk̸1脷.@ttiT`K/bİ!gS&MĜХ[O`#wS1tQx%7ޜ<֎}R 6Zn8\zju G|B"Μ: H???df{ 0 qFr@U S Rbk!_b+cz!!0~iyAXx zE)w9+5NNθ~4\`?KVz*n^=:A ^fٟ?3Ό3̩qK_wyoW/}P*yŴ4{Vm: ~Cxx|Zr"bo]*' H$rz(*3sgƙqfq}o$0Rwod3883&0UđL&qbgbgƙ1!"""*-1DDDTsCG }<'gWFV2oLCGoVUҪ ^^x9iW0JDDDd5Ҕ L7g⏽HǍ|;C*u`Ԉzc,0%/%v'"""p02%IENDB`traitsui-4.1.0/docs/source/tutorials/images/mpl_figure_editor.png0000644000175100001440000007243711674463545026325 0ustar ischnellusers00000000000000PNG  IHDRIsBIT|dtEXtCREATORgnome-panel-screenshot7w IDATxw\S?7a)֪TW-ւZ֍Xw-Tv(Z V;jRl+jj P@A Ȕ@ޛ_(InynnyyP j/:0 Ô'gY|2ݿ0Keþ-t1 0f,jjs*Oʠ١*tӠLq,3 0`e *Nxp T %"dSm&+a\7I~r%kMO VNa+alahߢQ={ ~܄ :Ofǡ/#a2ӓ }˟V럾\3 ȍNC&FmMQV~ Ľ, DjڱcqɇAujrبhr qUOUltZ<~hN@ˊFq4C{miP" jRmh;@i\bNFl#̶ t:]8YR?_Ǡ6GmZ~.^KƅkŶ+Ck/7r+t@l X#57$ ;BTB)MF>Ҽ#^mazr)I nR(zGn{%SAt:-h'm*h59X{]~~w'w#{g+^m_j?ړMn%^AÇ_C޸lsÇq8;;ch۶-hͳ͜zmѥ\ k`e|많u­'^?_<ӿy:S-h2#ܷHs8 n^+Z;uV~wQ2IwX>`X;T&>߇3!bUO6V[jU=[8غ{A["ܷxt1=4&&I~hoX2=`ɗg cH?@S4%nYt£t2Rlw iT.9hsb֬YY(O/[F^p!"gjwP[O.@R%EW";o-Bǝy[^B[x+C8vCxWpA0#Px\:–^&[ipNF㗓J<S>!\ +O߹wڥ4nOy%~it}OXЪضyjbQ@+" &5]E#jЕ`w/ii50rV{:i\GXQ+ lll>WR r~0[o\ ,06,$=vVvt+GA sbd>TUţm7 V`GԚpE卓%hw.<4 k_oƲz\[:MEzw6=eZ^{+>xUzpJj}>\aHs]TEMNǀ&j%rpѬQ6N^{5u''CƎpB]RRѬa5 5p.!mj[}|BլYgo޲YUMǮ<M_X D\wP>'>]kx߹0޶3) ~<}W0spΥh?E ?[JԡGd#,Stuuff7 5?b\E.lmz-];Sg/6ozmiAmkZutcחZb,vִbHZ=ͨ%=;akB Yi}$5Ӹ /?9OߐrzΆe 7df>ƶbF_$ @PBA 7YA~3tVla%3k0E}W0kp# n)HՓ!}qk`ױ;2n;CUay: Vo[mSu&#?hN=5֠h7p34]bnsyJxuQjծza/дFT*f7u'pG1b8'ᗯ"Qhf -+i?"m6/qcL/WCِ>.D' } 5xm'cDSp%~V-OIJ͘0B=V>~*=3?堞Cvp NjqhU舣GbԨQzd>BMn,3%=FF;ڍ#_uo_w2מ>b3p? ZYЬFvA7M:،76ƭ9ֈ\lQ>T vcjn\KBF*֨f9PC9'wi}tN~Lt&Vr~JނR4x#BkVh\ݪL}q 2EhuJThn]oH] :huV@6|?D%+Ji^%Ӭ=i EhPԮVb i5jUHOOGZУG' LmZ(u]lPiNImsE=ײxz7/>yhT_I}@mgvw_ZnT^Ø[}v8iiBMI3:X@]2G%yDvv6accjժ8>bWyM[Q z:݋Wn{-P`ҰΘg2>f\_/;RefsB oWO[aEж+yG䖉a@`>0 0X;{`x?aaJb5]l'0  V4 0IaE0 ØRKW0 TN \ 0мIҏ3AF30  haŠa1)haŠa1)haŠa1)haŠa1)haŠa1)haŠa1)habpfx"oߎcǎ%ka1+0ѣϊaFY(tuV-0 SNhju 0m4řH*aPo:++={Ē%Kw^!** +N>-h 0bРA[rcQfȐ!>}~\b1fd?yMWhdD4iŠF)`ٲeر#ߏ z?>>2IgBCC&Fm|` 77#Fys]ytjkX0 rK\6%55Փ[ xES0d9X̘1ᅎ Axx8B;::1s%#X Xpv"c z\,]j+AObnפ$,\DQ[xE/\???Z$odJE R8}̝kzF(>aҥ@FRؽtr19aJρzg)gMΞ5\ c.13#FE௿_Liy™s&bIb13,J9˦Mo|LiaeL|3pM ŒaE0z*VNӀ1L`E0zW3G=1X0L1tl,2^{ c.abؿ5nvv pqeÊ#@z:ޙ|-owx`fkhGrK W`L(o ?˥" {J6ԡh1c$$99hP~8xw+KM #cY*.]?&#f@͚1@)|CUL%qm>(IfP`*@6S+V;v#GJ+'cZXTB/vZ\Zѣ7/t''䕚ׁ L~._[IHk|- o9w.:b2X6G'4;=}~eeQy3"DLYq~}RfȡC_񥗀";uo_6F>XTB5졻@+N(`*ׁM#$'Ü 0˗ЩfM[g:O6F~XTB:tΜXCnޤZ^jFՊ͙SΝMߏ)577eJȔ@joE`Ԩ(V4֭]Ӗ'r%p<0s&ecjLl~:u"f'edLf\vm㵝 ۙ)3`gG1ij&L0nRqa~:w&fnhfCP1Vk+JJÆɓoظSЖxxR3'~8VQQ@V#* >2Š2}:h4o[^}1w)AQܼiٹBxDo~nߦ FPx".\g}t:֭[{Cڵk*zN%;.|?4]_y];^]ڏ'4&-ҥ{a,+0t b)yܹ7nm۰uV\zPunn0m?۷SRT\<<$+ Qkd2J/&!M#W4[n5hL4 puuŔ)S#͂ljȄ֡ \f>JJsh J}*cǨД)0s>3μiaCj W^s///ǛJ,سb޽id в% .J2&;&ժ֦4hc|aLȑ޽/A~Di-t$rI /Id.]"Ӽ41xzzhp\\ԩSPzO>,A kJ7 J~E< /HoIH9VŠF/%%mT52R>Ξ={pСYYY2Jc<,Fbƍ NCTT|T !%d+!^^+oE?R[|90{6n̽ȭhn|V2={Jwv6]߯< M|SSS!DA3<3 ubر7n LnEDc r>: N)T <|(OǎѤbJ镌(yn_zxxxjB,epʭ*8 Mשb߾/5r97l3dRl)}ߌ<(~EHkQy9qp Sɓ*%}RdeQLWWZȡdl!3SI`E{QիRQ6zT13Sz,[*Ȱ?E+O|aE&o2jMZy61`b`jUDG|aR*mj5g<24iB&eˀٰ !vvGRr|IV4LxxPA3/~~~cqs<%91p~VBL S*ޔl Eϧ}tfϦ< xޥ0 MqYx8mT^X0Ѽ9%ii1x0%IW2ǜrWZOȶk`+`6 ӧ˛޲% & C:E~2şRD= S&>Ž,Y.dBCiWΏ?~?kR\>M qi&V4LBNʅ3͚WNO`[s(BJZG~JEj2V4LpuE ;;N>9ʃNWp_Q$!! Tv2aEÔܰ0௿C&ظQ>9wk\Zl9{!*)Y0jUZ٬^ 9#@UPFsȵIJW/23) c '۷9+ڒjv2ɘ1@.?YiRݣxBZvϙC)HnÊ1 VVd:IH>Hŀ4۟9R:2+Zɼ摋,n۷P) v(+p͔sPxP-zlQN/CFb">=7(ǵktג{Q$-й33@ڒ`ESii4`VJr= eFSqqK4LxT)?"2<)Sh`+y}{6mv_R: (Rqa+x`ru5\te~XvE 9"s'ԪR5k}ش)K[։ǔDu+m`cC]eM ܹC[OZvT*%{zz=FC&8Jx۵(R!-hl°hݚ̡5ѢlJTwwk ɥ++Wڵfiz TyY.s- gj0~Ĝmߜ`ESegSٳ_;6ڵR ֨AӼyuo~ѨQ~U T*ڒsN.]eɛ <|Hߝͽw}r\~i"MϏ~r_Tj!U4:(4hs|666B2)ߏhۖt?{TzݝV>I $v4I9%̙X89rs, ɷh PU1(g9PCzfM*$={cy' rXEsNܸq۶mNҥKk.LEKQ:uɔQ$*h6,-ݻt}DzPXjO $۱X#Ox4+3vlРNNUڵe߿O+Ѡ }%12)@44H;ϟ TN%(X`p~-)S|)Ӈ&@JÃ+(TjbJ=wIĤI‘CqΙ9[gcH'Kq+ݻi5#PY IDATr|+)D=,&*R"#dMɡv={6J5(Ҫ-2SIHH@z{yy! !!!8}44i_ NYˉ;֮A{-V-sI2$%m[rX6jdcG?Nn89 АMh;ŋ@T4VK)GWkhyZVvhCϞ=dݻaaa2Zۂ@gɔ6t(/ߟػ7?*Q#۵3͍K>ewkkʯYf?ɴR|IٴQYִ1іGW&g/`)X=>үb'_ƍPN 2O "#I>}o\3&Bf[&磽M( ++ZetHEB|mN'o5,LzJE믁\ysJ~LKߐ;̫t ߩݻڕ&kJy۷ꑒJG{CgIYɄ(Vbƍ NCTT|}}e˖cǎؿ?6l1aaap4B&JENAhF2;e`!?`8R$$HNN7BCC%];2$$#=0ٜZMa!tv͚ɜ+yHLn I5믿BJ(Xj[eES͔l7b-9A+#$77J֭Q$M&%K@F)˷@z:?s0E2֬I-{ӳ, ?|MpvvƼy0D=!AVusaRlhwF#FϪU T'%@Cށz`,|P%V*=G܈#[o^SD ܸTKnsMFƒYUY}ljXј++d  75jPئVuw *֫W>K` %N?%FD(Tr9B+VJC8~U23 V[2RT@;,e߼@+6myZ ^4xlIŝz; %3l[Hj5e"%jFGё&o,eA))G`"^Q V4Sю ݬ)h2&T\sp/]"kA};VTh0ANQX?ܩ\n&4oӆv(h9q2WT}{ k[ Kxy/AwzwHPtV4-[ 2Ӽ>|W])_i2r@#ƚ5@ޤd>wgd`(vɄGfىyc2SS~^ʦE r"oHlKBPVT{((`|z.w.P!ǀZّ^t%IQ`4bRFa%Dv@ϓ 4vB,{͛#իS#_[J>y֭̑)2r*E]L ǧrD)V4 ݝcPSzUk8ʸ[rÔFVL ҖP?`EcFڕ'&jf֍LOd*ׯӪ?)\wo H1ƌQꑍGe'O3x=zT.{ZNUaEc!XYP={(kR2%89QpϞx|ŒE~>}wIsL!ҹ"*G|æF ܽK'NPB)cb$ULϹфV 2XE aʔ)X|yʣ,2œC[xGvvmXY&wrszl͛..(V2 @\23' ))q2(J+܆(nΎ]\ ?F&!!{x=kXKGOL:ܡiQpP$VVOJ2R h<=yQ:e'/wj*r RwL55jpsB)Lf&) VMٶ-ݨNN}җiWWf}vv7N͚y͚<8zTjsd- V?ZMa P Mg:t(yVV*___lܸ!!!to<6,, 2UΦrɵk}..?^Ha GWJ[?N>RQoo 0L> ξBwٺoրп嫸KQ(Lr`Xv3 Sv<o3 H V :x?Ogl*h?߼3ui(h"[7`(2pI(e|V2 ( `*Z̜jT63EnI*7o?)d`ߜ ("Ř!CM^kkvmʊ/?V#KC,c0w*S~rrԭ[Kyƙ[iS Qjm=2U*`NN[6)W!99*^!RCjJ? TFVN%YTN×Φ/o.@ GX[SZҦ =/K~@\nPN02w.p<J AAckK钜ҢHȟ?L#Epu-{URX!哓C嫎XMgf#mm[{ E"Ͳ{:wz(RrR)k,Vuu!!40Ѧ ,x=,) ASɕE*g) 9B5VB N.K MJ'HX[S 瞣 K9O*fQm#;w/[F~3-''0YYyGzzݬ@@Pfܤt@L mM1Sq7BBlz8cNJ+K-,llhPGlRۖ}<|orx ˯6R)MqԬ Ntt\9C߿OLjbf ?_)xs8;uYO?qk*[^~cG֭f\*UȇZV?jv6\tRN]k']eRR4[5`_~L1yaoO>ؿ>V=&(3ƆJÊ1+c9{g̨u,VRe f䕍1X0F9~ݛJnIfTY}`&J.9۷򚅘aEÔtl  S6C+I/yI0eM ONKƏf͒["F.i+1c_~!_\dVB&V4\@+GG`gVy* Hќ(Rt:DFF"::(bРA JO SƚZJ(LuNggΐ2|e˭iWtAA,'ߦ nnޤ4Zn-d\(Rܹ7nm۠tRڵ z?ÊŸh48@zΨ11ke]t_`^`r%&R9=y'ߗf 0z40 EVI WWWL2111rU)h>#Ә;ELN I۷,O lժdZ6?rW2Rpp ?ޚ5ĉ@l2eeL"MBBի %~&$$ igj-N hV,/$Ҽ9& _uN2W^ Az: *xz&fd$(9ieYX>T4gϞѯ_?-٠PSȆ d*SEh0uq!Y{*|TM~Үb VU(ez 6y2T"VVTC-2V'? ǒ RБgѸqc@\\ԩ!C 22BCCaSĞҧO[~s%'LdGRx/-Q:D+AV":|YRA q2{6ҥ_{X7n UHѣI#={СCyϳdxȮhsbƍ NCTT|}}e˖cǎؿ?6lXqaaap2Ct̩Sd֍f%lAJid&%y3L֬ƍiv,@Ύ"S3VSΨQ}NH ~~O"""BF슦8c1c‹p$''ˬtIf؎4u/L/-YY4 '${2鉁):uHQRe4+хicC ))$sժ a)[WXXT#5H?wVVmye]|z;q]VV@ӦK@JUYhЀo~}ZۛF֊Jݿoo3/QY4^\J&> mLWk(ؐ}荅(< (MJƎzt卆??`|ZWFcM4OO["4Xј9ǎC8\T?dظ1?V4(JɡC;he$\@bbeDTŋɜyQD4:쯿iӀ+W䖈̔^ݲ%)%"(c& ,^ 8;ݟ~:w6^{cJc$oߞU }WiyS*SQD5VVT'5E6dsr[2 }tqNRdkْVFBv6 6MC/iRQ#33K ,xGHȇӴq7NNp*)^F̌f4%#TeD*gd1ȴ3mN(=+P9)qs#U*&FF YSb- :%$N><5+ٳp2P2 \\!G/lij6oYԬXA草JEϩE-^,mP. Y&@]P)SUBh+e5+LfD)YG76ml -fLfHߟ|@X *)*}+I"E`Qb0d3[[2/N |i(V\x۷oDZcpt:DFF"::(bРA J!Rث)x;*lBɓ5mh.5Vg*i1o(3h[[&]Phs~_^Ɔ]|غu_@aǍ/L[:DJ>"7J9m~t3kk=ݻT.MR!ɭb!(wfNfEsA'2ׯ_G'Tqqqg* "F>}߿j(R,f\ᆪ‡RTE xyMJS͘1T^hlAct:srRƽg*k]m )r)/6n܈t:DEEWO°08[NL|6'ߧYR&h V4a2dP36o\I3~% rR)+Q߿7552Jd㓷)"5AQn];ƍ$1_~Ie"- ⋲mll,])wBF d_CJ'<;nqrFF%Ө}/'OfnwS}tTw(V\x .ij>[>>>O=,={-(z.[ڵS@rrMCBN#kboO@P:ppUxU .RXҹ; C@@lll%Rb%8˗hrvki5iPL–ҮJ J?zJԬ 4higv.Qٺu+j5V^-(TTW/% ڶ #'5h 0m4řH*a(vESVz%K`޽ CTTT{'N̙3666rh=iӦ-Qs\Fvv"MA}y,?7dDFFzUVHLLĦM'8" K9K9EQs ȮheбcG߿ 6, 0{ 0 #UͼpFW:bƌ/tlHHÑ oooXp!;@ۗO.J`x"oߞwtDtt4DQĠAB6)|J&e9b)(EFߗVT3"B ޹s'nܸm۶Aaҥصk%d#ҮIY΁X}b)PFf֭?oy`ҤIpvv+LSm2_.!~JX}b)VqXhC#!!{xSUf#ҮIY΁X}b)VqX)+={~!,,Lnq5Q|=9]h Ah)yxzzhܸ1 ..NpΥ),砤Qp=ʃүKY0kb+ؼGyǑ]lhT<|}}qFz=ٽ&~WhKaTjnD 0)xyaÊa1)haŠa1)haŠa1)haŠa1)habp ++V0 ÔCڣ{a|ܹv|Aa1lذR?ojyn4<u殃Mև8y88-X&Q4߾+#vb|hq2r;6ėAӐo?7&W){cQoǏ?ŊWFwF4W*jgG/c'YB6pb}XU'6H*GVp1ÇHOOGjj*v؁^zaځ4 ~k0sL$%%=._˗/cҥlä2]@F]("#1M233QEmi"M1pe>} yc`w Ǵ=ш9Q"hg4"!h>~ `1]ayB:Mc1ǃyD ?`!=iMCA@[ѐwN1zEiw_ 6?'šy؍qBm^z ԙ.ӌGI~FkiyD fO| /dB7A:Zp / "t:RRR.<p[[yUV U㑓SѣGݻ㷫3MkBu\4h9ѐjEhu:R8Z'abf> aI6 =u w ,A`kkbYhVU*Om:u+wLgB> c_XD8 D !xۗbtln"!hg4FKa¶of8 y'6WxES1s=SwC!X3eS!y L 4:w*vpu `F#8fj~3x׳}Ae܄1bR4T<I&{.(B"''l^oX[hf OVJ ZW{k[wQT{l6ɦJ" (E *WNM(w"(*(6\BBi ElWޫ"* IH2;dI&&g?93̳9g΄r%~mߋ7b2_0PTEbUAF\V\h.=o۸;r>7Lƍ1 x4oJԢEdfSv\Zib'<6w؂ͺE0qN۷ohmg} K-%}z2mǗL߇m;bTny|v ;,3בi-,~^4 ^Ntx fr>#kafs W|ު 3YlM±9ˏ[n"mzb='MVG#3+,f]GljmkN*]U--QQQ,^҇b]$?IɊ7<0֞,݇IKWqpu\3ū0`{`DOfYRe)v]_$]^|L_Sm=~MU@9DF6MmJJHj5@lXU jfo"V+b(KG[8T}~wŋt҅];#7"׵ eTw09~8F;d#ccmҒA=<~*؃͠yغ}z9 2'"5w)wg\BK gO8q;O"qш>}KbI]0u8HH*h\~9Xe(u(* T j*&Uh`}aZ1) fYbR,dU{{ P:ned6DٳgW9sd.(P4]jUEl]%IQ֋lQ0Y,-VkPv@G\TJ@@VΊf;G~]s쮑(VKdaLXB{d̦d_bрnNCs\vΞY?EQ< lj>zͣCs,e3a6F1/=Ǣ]AfՎ]mO&vhO&|{XOIjr#fMLIdjP`Rl8GTX1^'$iQM4i;w$ȲLxk9x re2@u$''T&ůfɥN̆Ef=ѵTY21k5S$7lzYiJ"Sh*E"‘3/r05OS%M}} 9]_U1 qhY';Iz۫ d"ҵkZQd2c40,&d]q{Dn~EEFF&gz% C͊f)DShB4 l,5&TmP|,?X67?݄9nVEs/!#z+C{2$ŸčOwk<2@56=kY:,5ďdGX<7q)Or96;s7N@%g%KY{`棘mm z7lYu*M|}tsMP<_)F%dY]]xat,Kt&wU_Dф͚ KwIDAT&l:SJw68MҡY @ҡPM`5ڪӜ@bD뷳tX1붕x|pƮ+U=5~U q"j{Ͷm.YVͱJ6UI1mgtxEGD:TЫ =Wgŝ9eP@O E r1kH-ۃ.횃&Ff\~!:YBɤt$ۇYqC[ѐPKC\:]E_m+\@hjdw7\ځH h,%$ MIՒ)Z_A (9Z&0p,bⱕ[X>cW%?">5,ֻld=LOgΗ_~Yjh\g<&?"^EA\MBqEg٢ "}TmuX5%i߄zWsmPvHXm/ 䦐hقcE?w?!sXz?rrjӝxq%2*,4g`j;k.@ (sմo74BTK`6rMɓ'ߤ30i87dHW'?2q Ičd\VGG*e{D۷'uV3)g]PFon0LpUE'$~іZs5NϟHbKOS%RߟZq^#OXh롨 t{~aC$F 9 Q_UIӧ#;m۶vj'z`dKjG ..hP-yH"f4tpQ--SÔW&~Tod'k' fD{ڰ1yoY>-kєڻD찞p++ˬ Y5a0 ?U=^`*6uՊ`gϧӴEky@[B{ֳw޹HΝR p=N 4$lOpr5ٲh^(^lVgG'D>x9֬ȊSxjA,k‹ndݤݘ},z,kodL_B6LT=*k3 ꮍȻYu>qy!h##44.ww־ٳVkE+^\f!ϙy7gd_dO\1ݠZurOʵ^ o8:~j? ᧠>q'?U@##Kn?h@TDSF NE@ 8JGsAgAu{Ǐ(KMeW&AYDՙ@ 4@ p*"8l9!W߀[:vb@.F /aP@ #h@TDSF NE@ 8h@T:泭,Kxsm js<y9sw>q0?22ұ*V({sѸq8 7m!|v U$=׊*9Y*lNv&߆`0,RSO];7`-[]έR p؟$mވ-Z[V\}Ϯ*>^eY& 87u?SPPPnٿ;ke)' U\TUC%ZkC2>[!:7k5T8t#v g |v9" &F |v gS/*OC6k>Qu&* 5|nҬiN| ]?sCM=>gnk}/֙V;#G?ms}(G~T&׶(?;bi||+;'rc[hzE!e۶:g>esW5*"8 @" kHBîctuo" 8N[ n_'`Ȱt֕{{nݺ2dN?ql ?#C Y?.|N=C_ۯ_ګIN^~ǪhqiV+G~=UU4%fO'(UUI=q`޽~`1[n,KuY;`^޲eM3*mIg:,dB8F7>>ތ1 㘿%ڴ~{7bx]+ˬmΛ11<:z$p[o!~b{ԓ n m1j4ϟoڼ%k>wK7УW$>b13p#˖Y o=uuLW|_ xմyKrwp}v< L&cW)7I=y̽?]cU5ΦIF*VE!)ѹvv7lC|8s&`r ˖fd%$$MHKKsTObwӫO~,\uqQk=DEbzTT_-vgɇ+Wp=w׹pڽg}DVXfDO?w֭ZʜWK޽{[6oC?ҽ[W}{ rܞotiE,_~ad~_<<t{x.I󴻱4gS44%}={8pgfС(BFFm߄/y %Y#_{z"l-[l*"r-M1xy}YK}MpЕ}ԴIS/rM7J^%;"Ar:ၯ/3g>={Ky `03_~=lys"͙53畗6lī_!<, ooo9Owݝl4k$6nb+/Wګ9Lpp!!ye5aÃb`XoŬsX$a6p0{1:X,NYoq6QXO?~d&'"$I*YE>wy?K֌ΝٶSƌUn)Ӟp{񦰰:HmZHp0NѲE+JƏ@pmV>Vūӧмmm(,00_D4,ԓ 'B硓e}|ϧqP~##-cGكFMF.dfɄ4<T#tnd?+B5mDV$bMPPPXi'k}]s/Ėu͚-n oDNnfC?̔'˘L& xxs:-Y/.őG7"\<K9yVɓO?[WSyU !+;L^k.Dֻ$f4M5%L:?#D:b陳 r>uߎd2aٵ &7`j;tDTp2+\,aaϗ(wjYu-cur{7N:a9-[,SڦogCfVƍS>hтu߼;!"#_Rfhܷ^獷6m:aa7;?-ő.۴'3MxbDHJF=͹縮eK&OĺYUNѳw كS&]e;u@#I:6ƛ:aTTHa~.RuBpu7jԈaxyD-Fӡ( y=iܸ1-Z?$U6i҄۴I8~Rԃm6$,̱b}~DU|nժ_zzԴÇ/iizw=/Ug Pt6p$t g |v=q@ 8M5MMTMC+VdYBUUdTsӡDbUtn!|9gPQε"dۨƒ/lUCG%\܋* :ʶ-tyaBC U)ȽHʎ]3_mpag!^>~5CPѺ͜<;rPUͅJ6Uyt_}FFF:V5]Mй .~MS᳓>\Mε&0xz}ղAxz.|ATڶIj |v gPK04nܸVDoo*ﴠ]5],"@ 4@ p*2XX:@7Ev~)2'^>~uE 23x|w.5 oC">i]̤ N ᓙFLM_}#AǴu}> 9/wó.t 3Ayh;\@PeݻU'IENDB`traitsui-4.1.0/docs/source/tutorials/images/traits_thread.png0000644000175100001440000004702011674463545025451 0ustar ischnellusers00000000000000PNG  IHDR0y٩sBIT|dtEXtCREATORgnome-panel-screenshot7w IDATxy\Tϰ8 K"g.Y 4"K4nfY^ʲŮͬ%f.h҂" °"̜ "8}:yy0_suxJ]B!ZG;joV~vG5*[֋N!E_IIY9⬶mcwWbF å"e0\& !BԨut|v*}8cUkKft-2I\BkiǮI'ک,)7τP>qDePZa`У+ΗE! c'ӿgP{Tr+QwpTBB-Feq Lv:jߧ5k!Fd͏┄Ot7d;zɽ+*WL z]6 a-fFZ\!c#ŀ^WIeE1?ovԶPz9PRRq6 FX-fNEu|'Q}z]]sFf0tTZ`0?k',sʨj痌2 ꬫ:7TJ*N5Ԙ1™h΁.}ֵFezT*666&4T[B\azOSLMM_?UU6csLfm`WXTlU^:0ߎ^WɲUbv_K9z2ΪGoᡑUlIH5Y&MT<Sp}{r@q1$w-'S8`ɡCҷoߪ Azպ?f1/: c{ӸSq,]m'>'ũCx~~ogЧlD;Wt;~r6>`"R>`naӸ+)ߑSPF*: ǭx]:+-7$PƁ7Ʊ0 9 ϡSQ{BE_)8%G!'r*Q 5ӎ^WiQ}mJ;qSGL[d'Mq"J.(+?ǥ$oUQ{Qi̛7U K#n zzCx Iݼ2.X d/p =5`:zOEk'ge 5"ܵ5.;g=̎#g9_f_/s1{>Ń?b\O}J >n^`i<:+g萹U]>|F/6:]#o,}O6c&ǩqzP}HKB_>gD_ܔکN,MU[w_K۹foMc_ĥCXT cpO^xh0(w ǡJZwӮ];~)1kp/Byz{94|.毋ٝm {LOwE-5$~yݦw֣<ϐ@g*tc,6*?mېpfqLWJ;C9ڃ`V4@7qT5bMo {Gtz =h_r]jB\5Su?ϮmΌX;=Xq=Ѓdvt5K?wЉS ;jBxJ󷁽-\}oܯ:΁yގػxfp.*z5;gpi\ՆMQBO/[O-;IE{N;W@H3xxzq4>76z;{gM9]B;qsmxz7m`0p!8iqrRsKqj!唔8W\ޢjuTVNIXƶSۧv;*j$0*&ȵU=CmAgOP١dqi`I  C`~)5])z]Тv /oC'Fo{Ť Ϫ6rsR^yɶj;[҆mǔ;g`}b,ǏEp'͵<}e=̗/oԫ֯&gӗ\q9A/ eSNx >OW?%d͜gﵴoO5X[]"+uޖ::Wp$}ϭGfwu|m+j{jQPڃ[if}N7¿_ǥʫyUai-iۃ w&s)g.<= 7J +Woa_ӼAfUTWCT?4,kn;1M^捯RuʼAuSUg.ʦ?-SGz>t}8w]n'~wׁS:ҥKu aM:˷{3f2n 6Ra{[z޻1&>gKEqm[Ew/G;#rt~x&ELb>dPc߆=?1p̟a+x&qUxî>[F~:1RSXˠRHqGwu)DRU}8וj[Yᆰ+;Kک/YjvbqD%f|_nvF_CUR]<ˎLjH K)dƹӁx8Ҿ}{KDD:γ1[Dol?gIz%*t [B>=']WOX=3ۯq:;2 )`oC#7#6?@YzΞBQh.nvaԷdSZFEJlauPTٹ=SR=*і=W5`fvC'OUL1sπ+, 430zf`xy Wr o*R ::wvgӧ䯡c' ϯjXf` ہr3t+cB칻3'(P0`b|oW.]FeRF ~\X_}|\ݎK`P٪iU|z3>̅s:.U*( ۪#]u^RQZ7 ;a_g_s-icn;.UN~^!~TP ԋgNMBH%1njPR K͚q<y%zbGv"{~gk\FkT5g`;T.nL5ӡA=zQQQŋi׮&g 4wձx_FB+lT*~M"l-Z/Y&7Z;6XxoCڵkW(9$DK1wHBT:ʟww~޴m~R g\L4+BrJ<ԪKeuLB!MB[!Ba1;MO#_B!z:/|'Bq]F!VG!BXI`Bau$B!ՑF!VG!BXv}q[ B\/lN 66*4.tӧIIc3uB!uiop!(;z`SMa s(vpuCHB!h}-l<:՛@ LNt Ԟ$0↡RBq899ڱQ8vɡII#BfSlyFJմTDF:~8> j ֭[:kJf6B4]ee+ L#2j(nvN8AQQo&[liЄB` ߸PXH-Z$0… 6 /_<2228vf&eQxd]63-Rjİ!J9o?]_|󰷷 ;;/SZZJ׮]fqww7k4ֹRyx?;w$$$VK߾}3**gcb@Ϗ r}gRRLΝ;On݀sFMffq8qG̙37g___н{Bqm Ԏ {zg888]K/Ykh33pww7Tۿ?#GJF4NT\錯 5&77פɋ%qgk.۶mZ@렠 Z6灁Wª>_BCqq9W-KsHcƌiɓ'MVVf i<(PQK1h Kxwy'ˋt봴4LY dzBqcbccYf Ν)++ә5kV۝3gg&55NGRRR46H?NEEd͍dz!ϟO^^<3L2dcy󈌌>GFF2|˫!7I`[n||wѾ}{̙ɓlڴ ̘1c5jT]d Çg899ĉݧqL0{Fŋ?i,[h 2K/DN "88___VZeR# # OOOVXaqyC}^r%ѻwoFYoBX$^ T+,W׉)Ba=Om+wB!D=z^z`|yRk}_׼ШBB!ՑF\ GB!C!BXI`Bau$^qÓo< !DHIE1 PJU/' 5$B!H1 s=`|^.rkn6pww'"",KrE͋ !% L#,XVKFF={4 B!Z$0Gxx8pB9bv* 6Z&,,6oL=Pߟ$>iii₃ƍ3csYYSNEڵkM,]OOOŋf㭬dt 777֭[gq,*5kFaƌCscn:t邍E}*//g&c"# L~zFm>qqq޽BL„ ؾ};qqq2qDۇCnn.ZP.["N:űcHHH0io>|DZ-,^l|+V ))D8uű$$$DZZW]9irȑ#;Q7ԧ˗GFFǎ#>>Q !r/$ ԾR,'{%88jīRR4U\]]RvJ^^$$$ɓ'֭MvIHHZ}̜ԥKѣGcR;JEJJq,N8ѣ9sUcQgc,oOHII{r>B\C[?xߏ0 'R0? rI8C)\O 6.O/Zfq[B&P"Νˌ3,ޯ:QprrsN3޿?#GJFXC׮]M"44xۛ\eggTgYCMf )''$υBy޿E\\\X`fmLy{{Q{LBsV^/\YΞ&73]-" L#<#ot:y:t5k HOOg֬Y&,X|?I9s={6t:0޴iӘ;w.\pg}Xbbb#77yi,sss#99d~ꫯRZZJVVsipLSdd$7ItB'3hVu!Y:z<}?;. L#w}L2GGGGAA[lfmڴ ̘1c5jIUh4ѻwo|ɒ% >ѣGDdd$'N4^ll,ۗ|}}-`Ĉ'+V0-ZA|hƍl۶ WWWZg5ԧ+Wn#G6XBw!I}*99Ǜ= t-U⏫x-Caa!Z 2iҤI!CH~LL!mZB9t %=Mttt[!B(.:A_- z=P-j30B[)!Bk}30ՉIr̜;Y!⏣갑b|^=S?`@ZbҾE!U''eeeg3۹sK4!D7Y!$GGGzd?yƲv'ҽgͿ>d Ǡ! ݟEKLyEE>sY?I ՗i3f<1>;;[ŋrH- !V-?Mf,bbKC|I$o\:̜>8AA|e76_|ťI};v,xxx0uTcT Ij΅ ,S;ͥ n^0)]t vٟ/obj\\\Xl U%Mɉ@ƩS'$0}ڣ@y׈!??:0eʔF#B^HyyYͿÞ}{$vפKKu%?=3= [(Sx^~|ILugxinN/G3Y 0塇߱F1..ݻwSXXȔ)S0a۷o'..B&NHTTqpbbbEjrse˖QTTĩS8v &^ÇVёŋoŊ$%%HZZɝ !V IDAT!$&66r(эq!9b<P/_N^^;vF'e\CH6DQE)nҡC3U==W V~NEuZ֏&>prJJ/+K/S:x@y)&y>P:t蠼+9rD R?~UY5y~~uIIIWRRxxx_wYIMM5NII1ik׮n|xyyWINN6[^_,b|}qפٳgMSΝM8qD!h9rJiqR|P)*WhsJ~N{s&M>uRJ?9rDrᓍ;6DiQt ERHW??FoNun?ۈzIdfϺbR>5>7~z־U/“sQ3~j3[޽{O?ݻ[$'':t:h")))LеkWk 5U}'fggTgYC\ 49T>>>&SNNI5 !q4;dؚۅ{cv9g1g}팾vȇ#L^/y)L mٲ _0p&aɓ'ꫯr]wѾ}{i߾ˋSN@FF>>>tZ<>>>ՙ5 @zz:gggGii1+(\$c"p`0?3LwԹn:-ZĮ]yU':88@zz:f&u,X|?I9s={6t:0Mj6ms%33 .Z T;//\͛Gdd͍dǫJii)YYY̙31iO̟?8&BqcaF־ Z`OgϞoԨT*[6mĂ pvvf̘15ʤ|ժUUow :{{{c%K>|8GɉH&NhXBCC۷/6XC1043E4hឍ7m6\]]:thuPV\qLF`B!jİ!J9nT3u JNNf񤥥zr~!~<ɏBQ _ͨzn~VW--mfQ1-s/$vbbbX|9,\I&uHB!B1.'(c(RkrӴ+߰( !88:B!nT2c墣n0BV%30B!:!!$qÓoH !DXֻ$0א|p !#3f vxoդR#ռ]C$y’B!,% L#]B!ڊ$0PYJņ  DVFBB7oGjORRq4qqqqƙṬShfڵ&mz.]'NNNDDDpEVVV2|:uꄛ֭8JŚ5kB0c MơU]2׭[G.]hOL>dLBx$iEqqq޽BL„ ؾ};qqq2qDۇCnn.ZP.["N:űcHHH0io>|DZ-,^l|+V ))D8uű$$$DZZW5eСC9r`Q/_N^^;vF':Ƚ,P׽,9A6*|(--E\Օ:+--k׮KBB>GJJ ݻw~Bq U '>hW If`ZQuT:Ng|~F3* FCAA<'']_EhhЍ7f&((βb0> 4(5FSNNI5 !qHsyyy̟?ߤ|Μ9̞=Tt:IIIDDDmoڴi̝;L.\>kq,Pug켼EFF2|>OG!čAFMKT6mb8;;3fFeRj*4 ~~~ݛCbooo,_d Çg899ĉͶKhh(}% ___c1baaairgE1h ڸq#۶mՕCYgm iʕdȑ )I$Qrr2Ǐ7{Z !+-&&BZ- .dҤImBqɽ\pp0!!!rB!ZS\\\% &::ÐGB!X ŀb0(rprƿk:!$!BXI`Bau$VZ~u]!uF!VGF:~8> j ֭[:kf>Bqppp0rp{-ZndooOYYvv_]T@n,h4WsuuvIHHZ}gc׮] 8???m~֗PYڷk>Bq}u oTor[4˜1c>>dff(b y;Cz6I`,t*#]I [;:!:)ll jG49dG*ɋBDvvG>[JJJT$0ķKWEAQ:MQQQۥ+9ٙ7sY5b%aiˋKyq:16 H!r/KԓxmfQ1rL( ?d|.BM}lzh3I UIf8!! Lc\͛>^!iII`:cLmBa}2.7} 30B!DL>sں7(--%GfGdw5;kP1>6}& .^ȫw";'gggiS6l(~dNov[ͭh+Gosi""2t`n'ǎbj(UG~`|.,ִ<\*++H={X+B5k_YW^7 Q3yqs뀺];o7nsf=$$W_͘E~~<[(yՇC/=nzÄ8~q^ϚWq[ \/[(CG"{OޯF3iqYdieߏ?sK⋭ gx>o@k%}\~^ߩӧ>sC{=Gg,gt4[OqX3dpGyy9,!WoBzfsIom@# ^*++Xj}gl|F\[k,jGPu!<\JJgIY|5^7 ̾} g|zIfNF}ܿ V6{c˿χp߽0}|xM|w?/7n;8^j5/U:%_~Nډ,)EAQ6},Xr1?|8Urr= /NuoOصVk7kArqv|%~'3+Q}6זkk]qT6IŽშj^\J,"KSi3f7Wڛߓ`׈]t[GY?XڻUzDI 5O``_4yLԩq4ŋKY5G亄h+EEE=>T]{?)t!FsA>ВzΜg3v:tIY]|Pn7#iq߿+iiD<ﭳ[ʿ>V]7qzH#cyy?ă?5׻-WuЁzGfoRL빜888ԹN] Tq3?%q4EyYաw|\k9<=EQHMK61{|j|]ǯn򞪹U5>ysk]XWj5˟_0~A^:{{_P`W盍#7/oO:-sCmUoCjcV˨wl_;!IOކ7] ̰aCxlm -YĨ#pvv~77+N<|<-ZQ* j-T*Xy2˥&>,zF YCii)}oR>]ѧwo6]^?qrjک՜ds˚#G8u4:'NcIM9WZMsYd%rtٹ =[7mƵ}{3M+//AڡYYo>IسFI7}86k_YK/yd ysfGq:}LBƎS>"**@EԜeŚgFNϾ7PTt7׿nfvLAPHo5/5k3`0SG1ATڪF\z5k_^wgccǎ~xn;oo?I7V] v{?%if8!:͈z{  L#.'0gFI+B4ZK}~Z5jq$/B!DL"Hc![;[t(gFɣ<ʣ<ʣa8"#.Igqn2έDu8V')M(2*d[skFZsqn2̭Cƹu8?!{~#: X8[X[m;w'LFkVcRdp0?ð1X8[G賵ƍJ`=M*Mw_(--m밬4{FK>~GN[HO䑩H>~d~&8[ƍm[ԓDy^}ܝm>cr-꼞~kLZZc՜*7&{'Ssz=풑CS";ND;NIFzƕmkĚx<=QQmއSxO:t(?c +~e޽Ohӷ?:VKH0](xO998i2iʘxs*=v@/m`*3/N.gj6?s p7YSOyzj[qX6k'ÆAŅŋg>m^~i>8::QoƲ>U+Wp]n,x'"oo4 K/b߶l'@:> +c[,߹|y|:7kYeAjvuA gۛyVLQg`~eR'$9kYe  ص5\|n?>2-^@nakZ扠Nguׯ\ >@-V+,{2hz{C^{zw$T( nGOAo^rd_O(..gΡ E_ JeFe(Ԡh9:;/cvYqk%5$cU8v^}>x #ӫ xu,]̴։Il {cwsˋL5\.VV%\]<f JC? <í-}F^de6BQѴ#{z_z=Οo\@kk+&|>!rqy 4=hzNN.]<Q14$<]e2331p`vVKnɏ)ĒiV ׃^ yp9>/y9v;팄j\#p:p:8t7@cú|wk]Vo[ G9ll2r{qcph?_"Cte ~ܴ=pul[鎝vYp8kg 5mG{G|>W]K~qRyzKVc׫ݱf+;wk+JH83uTd."eFL&#f́j=0[nB&d2޹Xnƹs "rss!4Vthي/̫WZZzL@BhuC LQ˟aC;&zmw".;dA mo8X 4d:6w̯PRR2jn+*oau]=zm6y\\\?l_{^#_Vt:bWOr%d3tQNP2x\pzFqp_d LN KJ~[w㸈ˆ7??3g?UǡvG·7*).+}8ύ^ YSĪlr.--f5Kf钠gϣ3ݦHSiV4m2籶knL033𙠜٠٣ !"9>#qNoaQL9?y(g6ə>x<)牣و&&Z {h܋)ڈ~y(g6h*܆iEVv1`4SΓrf#G ^S ϗJB4enJaQD[.`diP(K9Ǐrf#srrqdqDzE Zws@7PΔd_|s_-ZX-'錸@$]zN{?Ÿ825@Cv6s|(g6bje||#Xš^C7U()I9OʙXs&~r&(8yr92Jq祜G9KγF~aʙ ʙXr)aW;'٠٠٠٠٢ۨ !"94!BB!#A+uB!DMvˡ$B!1Z-ذi N>sdD!2!' >$7V Ӟ!BZ0׋ƍ'9OJb"6iHOW&NB! @` W,ZXMO'BHJ8uLxx %OIENDB`traitsui-4.1.0/docs/source/tutorials/images/container.png0000644000175100001440000002656311674463545024607 0ustar ischnellusers00000000000000PNG  IHDR/&/bKGD pHYs  tIME8! IDATxwxSd4mӝRR( Ȟ"C@Oe Y2( (*PY.:INдM/r|ss9' <~W'3OJߗܨfΈe/> TΊQ0 |dvSH$d8xTca.LE A s9ɞガ$yy"Eea,dh!""j 6V}6 n>6eP7d2Bd259!#DmxVL+IR!Aـn7_y MYV+=MucshBV͡xvh ?M0-(` v&#ג`2.=NO~h\vbf Fȡ:&qVYVCE32Prf.}]mL|6NP~IӘi1D0 " Qd+,Z|fQV} 1*)2xdHƖĿ>wX: /4 ަ>֮>x3s'{n(Ͽk]{p#0GD /Fpm~N\Jü,+.fV[+$[J:Om!R4/psЛ1sLh4 Gǎ G^)hrӶsHt2 dVnlg%zbgZ,[s;)?h8yA,;K;CٷΣ32 6 9BoZ}|n !wXp ۍc0s;,)~1VهkH {M7F։&JT;sfSFc /,x`Wǭn~J%Tv';hM'6߄B]6Og Qx0`_-C;DM٨.AG@߉|w,Y4"f]`m?QF̴]Fu6kQiۚg۹Lx~syPZX )bڗk<kX?>x ve4>3?`Erc?YOɃWjvrLy\l޷!3!S/bѪu;<$?;rg^_bq:~y`SB {0 pݲg vF*9œ<<]d2.rh|xprrxڈ[3m$൅Km v;Nm? FuȎ6{oJjt Woh|feYCaAnЋs!׾OADґѪHzmw>,]N&o&=G홟.66sLz>$rN_JD3<H12‹G^&q~Wkeߝ}1[S-/~83s#W>h|2@.D^H[֫M5/NKEW hQ>V:+Ɍh>qm(5+3}Zz@*Ao?@vv[A%DR:>ڻ'm -:ln\܎><݈SǛa2|W~~G .pǥF`A9]NӏV'V8uEE`5 \>f  /`4zxaY6}}-W w0,C^~AnߞחU}@g0"!dB&TA'Z2LH3݇>/ ײ< 1ls;}Vй6G.=0u|?1 -wܨ[}"ݮoI~rフi#+l?ËPBz})!9'09&@4b1>WѫsJ%jʆv*?7h>d*6 Z'4\muZHJȳUQ|)r) +8,/:A}Gٟ>BX߱]۷B!POSϿ߂L0Y1|z: facV,H׉s(JxԪUat)*5*Mis]A,}:L^mフ#1O4_҂AR'7UcB|s8 yπjN wSP_g=T?cP|jMƮk^Y~Gm8*G=(C~=j95R^e؏'mDPp35Y*l%\"`dk6'8&b=f e˻ӍP\jݪHg\C; wF=O_#Z&>f{<!)1f^>e˗'SE RpǥF9"zתCʌX{=HhNg݀a}rO#)E?YnGvB 3f6cߦٜ@wX!.z R-%ͶڂUo~iٲwv$ It(, :NPay͚M#޴)9E3 Nh@>${p5Kr/9p4+&' S`E`WH%_Qyl wGVuR١~~Ft12ezTҮ~_FG^B{00EZE7+i鉨) g qw+B師.e8Po f8 o"ÍO$E+G"`^eDDD:̟*n~ص?U2ځ:=7euHS?b=HHLºoZl̘]ZwO^IDDT[5/romXUkxkZ?4ޫU;-v| }|Bpp/]Tlx{[o ̛(JzV)2F777}wwws$""D]Ru,Af,n YYYYhj<YYٖᄉo.6 ,7C{4tմQq4777h4xxxνU.˯776!!1j~bRտ}}oJe5?!1 *~_|"ym4&rڵ;Œ/<;.JN)զv?z(ڵkǽVBLa֮^Æbxn K]txFfV-Yiwwaɲ /Ž̟K|%z& R?/ܶM46~Vcn`cˣc9QqL>jڸ`w„ ;w.RSS9s^IDDT[5/,GǢg; Ľ#7Mֵ  _ ӧ>gPCPai܁Sv;cxcJ˼eK}?}n-P]`܄'жCgL !./eeʔ)۷/ڶmv;ĉWUvlwO?v:hզF̆1y\q"""âYbyZGt"""bx 5IRLFFTRNIf!~5 Ë7}hY"" "._8[>C~kԆet08?j|}\]]w^4k~I q|Q-|W˯,vK~V/IWCLX ^#CDD 8Wܹ1cմ3fKNnh?RKѦ}'tu;`"ZOHLĤ)C]ݮ#{r233-K/Ѫ j30qyJ/o;oVn_[ClMѭ+mIYd2a+sO?,|m.ްzk׿Kuk*l//6}_۶8|妖'""ӑ㷍jf7`ޜ, ^>loɢ<5IEFq 5𒙙`f!!VOV©gPXXf{%!৏uZ].t0Lu~jER!9%CCIVy~^}ynnn(((@m]kw* GY.*8~pw2`...y.j#G +|bf,YjNB'IIXzMg^DDDu],Gǯ(^ Naz2DGE9|;lx9c^3owwu ,L#i}y͘ΟǣChNx ΟZ&y.Kxo:˗0gЮmh#F~im>>lRQԸ\Mf?v toHǏCΝ!J+}>"<<))6~ w>MvzuxjD72mcú7XL6[i@o3S Zut6,XhDݱvj;AQQX* ,{}}(bш-[j0d`Z5F*UVZg?Vȑ`ْEP(rnt^XCn=0d ո8Her@b|< jz?  Ɍ4Xo5("91J%2g>#GTONƤO?G22 -v8flf:;w{vჿ!)92ͷSgN87 ,{ݪP窶Ǟyթ9ZƚhK:\| ' ##m@Bm.7Z73#mu ymԔ5op86GAZ:v(PՈnW7whsuZ\q-4((qWlyQz]!ii>6#\\Ƚi)*}ξ_U?Rڵi{n*6cڡv-*/~D^=PgCYt1)S&3y۶}  8(X85˼7o!(0J̞mrChxdҪ[_ ~~X85|zrH4ju#Al.׏l|,̴$L&22O/d(V*n̗ z.ɮ'\Z'? Nܬ zyrⵆ_ڬsMj*ˡP8!''r ^L320u?UDW<txyyZm0k+pW[. :{yy"-%~~69~_XϜEaa}:;YKh@U۞VcC#J/[֭*޲M˶TVޖ~>̬i&ˑWnzaa!M/ .ڑQ+Q4"erH_?Ԥ$pҵ+r'x']X[T\| 1; - ZGGàh\0a5Ta=c.<5I;vB=O?; +/Š^:?OLos秿g;n 77% бk2"V?__$&%#"<~fBg[B=OQRyJA6ljcHg97j ]|U8 P<`5; AD|B"||#HtsCF{$_:9_-e5BYYJ% F&zt ?He!U۴?W@B[O1g,˕l띃ws;|L6כ ANs_,⬀ IxumhJOXt9jh4je޸Gœy Qą1}K\3:Dldgga5rD۟Kpp0\rrM>]\j5v,$Iɩ8~$ svfHNIa6R6#٭狄qs$%&spAhPxx"Z&k\ 5-}9wwP͡ de_tݲq_ "wdG^ZDg`يn];㳏?DDDDڭKߧS&>F^gcXv= ЪU#X}XK@=?=2gո{hf<3yS&O |OBzF:ZDDgvynv팻Zw5 S_yqHxn7E|Ҭ],a4(*РP ѣG)=MJv:@ لȖQRaC.._@wKc}sٚ@ \U!,<ήJHRFQڪ 7OofgX PV #5^Xttk|J|tu8[IɵPH AXM7v͚&wcޜW0o+OHxzd<=e]Wcܟ+{UVS&O”ɓnݠ~uPr7f3shf#?7MYEu늠@M^Ǝ)hPXP_ٺ[U_M$4 32ꭒ%`Yg> /-JŬ3ܘ,aXgֹxAm/ : U֙u: /+DDDDF:y9Y,  / 3+FDDDuZ:単IENDB`traitsui-4.1.0/docs/source/tutorials/images/code_block1.png0000644000175100001440000002543111674463545024763 0ustar ischnellusers00000000000000PNG  IHDR0/2CbKGD pHYs  tIME  8 IDATxwxSeIҦm]J[F)P@L!8py|P( dqQQ@q eљҖte(Rh՜uI79I!Bmإ\{jռoG!㑛ۧ>= _/lXdIzB!FqCCf1^oGo|DZdQn/BQ,[o,[^v̹x0fpkGv)< ͊Ř&ŋBQOa/MVMt㝵+qsUkǔN"d@ӧslLǔ^bȇ?O}=B!D YmmUܶͻՆbX-ݚ3مv ft6RYdIя +(?+!DvVsaA.bn9W3\6sʃJ#f#;:ɲmK?lgS,o/JqQG͆bTŅbf9d:{NṯwLqr6Qzl|mk*V{̃Gq()߄ [TnY,k_ycֳlq[džsh Uܵ)(`NTmBrw/[prwwv(sދ)- Պ=gd̽c7k,M7^㎗~B$DuǠ4}&f&؝mޤs]ĕѻzG:;Ka19Joޢg4y=:%h͙tmn-ʢ7Q,$]Z?o{ ,V0|ͺ?ណ~lsELxm\ܱ;OL޹tx2P䥑WԿZ=0V8vnmȋw`ׇJ 9.n(VWE݉ $,: =hM\P`ŷ蘯e Qw ̜[q LhBZt/<;߆XϢ6Bd.՜5= =yP@FF:M<+E)ANȣmvN3}}u c\چj]b.N2BzcJ<a_r,5/Jv\QͅZ0VruB3ZV<P`*V( %/f < 3t;'`]:jj ú8hB"k`~8b,Z0CBqs&6Ho`hDAEm$Qhr:VbZFyF`6DLDQjl#!tT 'g3/ϲn3mD>Bƴ؅!Ω}wD}o4ߝ^T/<'o|[K+5|cش6.nF#+F )9%"mrmqp:N:k,S!!k^g6>ooW{˲ z~ƗEM~gx\z8l$ǃc"{+Ѻ(FRmZIygٱu4F|X rmvwfߧ ^_FF#@'W/rfqEEqc6-w^EQɊYd2v`ѧηd1lAlhB~g̗Sokkma7tj'u(Пr)D}W50Ϲwb*v'[z}tkgIp>$W7e5dLg{Y3bqהq9#X C>9'V>^Fb^ԿWDZl:pV9{$->宇Li{6IƍCI>sbgO1ZqEQU}3)w^sv lʠsʸMYtqb*;3f{C6$M^k/8݄`/wٶmC-wBW;_ó_;~!~ʹi,v:5+fQcJs_{)ͱl\;'l!y&+n.*b s%Z)Ն9kL| IfL;:BWi8݆JQvj#䙭}]hweGU9Q6ޗj;}̳j%+D)L]kCq;߭jX[\v(Z55Ar!B!jB+O~z ?\c"B:ArfIB!u1LK4BQNqBQH#B)`B!|%e2X, B!DE BVR XV E!$ZM@P0I;I?ů?}O~ DRK(B!D%lVOyZ7#"N6oй!B\F3Q摋x/әd%! 4LJKsV6B!ZR!ΑF!R!BԚ&y2o$EQv&N v M!J}đ%/H*`-[Ɩ-[ؿ?v!C3|p N!*94ytV|İ+d@Q[K=i٦=Dd2¤hӾ3mwfKJu Vmٻ}1^â>ui (ҩKba斻3sLBCC c֬Y|G !5QL"_}o׭oLc? ְ0dq ^]L?~Ǧ6p:>K^sى4{v͊={Vjݳuk2Ϸkbj̙޷o:urر#퓽P!k`\\\x}"/\+%tQd:Ez:e_Yu4rkݴNXX(sfͨFNyq"~~W~ɴ) F1gKSˌF#^^^^(BTR]sא;xuRG1R\DFG4"--q?==#HOp[,}MnZM̀^ T8İYjFKB!cԇ/ky9_b||BB.8z ڶwdǟۙ3s^vh(((p?{6Ӊ&߷ʉ#󧗪S֭wA֭e/B!jg3X`oӧq]WH -=3pmnffΞ?Yv 1<DZ'0l6lžjUX L.Vܔ):}¡Ç=v|i"އzɓ'LRR&MGP!k`LO.pC6VLpJNi`}z=cG?qzPƏ߯_Zy xu<Ǹ3g?Ҧ}g^:T?ONУjہ1c$s9={ҪU+Zn_?.{BQuݻ7o̴jk$yz2K̈q H!3&b)NcH8ɈQBQH#B)`"?A B:WGj*A!UjVn!%! $:I`2՗?|ñZ-BqV `͊Oѫi$IqWZtBQYj`zGxD0MJiն!BTلl,B%!B !B)`B!B!0B!W| >`HjB!*KQJ^}m%Lu;u?lC%isR!,‰cGXj9Z7w"ON!]M?n䮡ЬEK)^Bˤhh֢%w }M?n$77ש{Rhn0B4Hp+MF$'`4tRTŊZB0%%%be5J]O*!r0R!uJ79}$BybXxxKSY[rȁ~B^Tx<;^0U 4j| OȎ..g;:05]I8ul"!2obܸ%7⊛3_dWXX3Me\:y}t?uĶnÏ '--1[ٻ12;9xPO_~MnrVnZĶHNVfHIEl Uz`.Zј˶͛lL|arG/M捥0L,Z:g \޶ͻ/NaUsE !)v+>?2y6cqj8z[fΘ/O (yaQu\3#BV(<ݻaݷ|E)wy777,5ȅ:BQ l5r|3^'1)$$&cx uwM] *^!8:|nѩΏ"y)`Ȭ9s3ev;3g-17W/XtE91 +H*;BQѭ-6&sg3j8ǰsgS%mיf1 lul^ }z,!!8߮pu* 4m߱q;Oz!Q?lW2޻z=Ur)`Xp>P'|J~}Яo )e\<̙x9#t+B!dysc9Uz%E"gaS0Mze749!!W08{Vyuπ;]J%Bq&uyykOݩR+R(J巐聓SHB!`,9Js5F"B0PX_%˲Z,526"!$HB!J?IHHR\7ȚU+xDF5T(B"VS'p3:)`SdT4n_6}bPBJRkބ5] ۊHF!B\v N_s$FMpp(={!&,97:α{iT*qf#+#wqqO/9K "S'O >^6Gߕubı#^;Qђ r.J?~d?q JcUDl\'Onn,977>@-žX54kђ>7JΒsɹ{`r/'7,FN'9K>EDb)("Yrn09WycQ@\Z YrO9[-VyZ\/u,9קꐜ%g ZHΒF!*z/\,jj=E,1 Yrr m[Уuua%gy*$犄GDRrYժ~MK_2R,ܰrGm[^8qyoۻ< dZ[3ZC<4mEV<ʹ/moXVvů.$00FM3{&oTZİl63j5`Z7!_XIn3!C_r\ejل}@2{ Zmݳwұst a6??fL IDATЬiSNQbnWV]8?Mx1~9sкE%M;sNAn6#HNJó.߮۶bmX, "7' ))x%j444S'x1n Sa> VqpБu6t7&#,?8slfa}j4S_L4tgf6~;w늛V'>mKL3g˄ȑ#ػocܪU_i/9}|3M%4$N 'ƍ qjZ歸/`ԗjԗ/׫kuUr b6WJ*n/ՎnwZ"08㘦w7-Z7WyqʴRzv1kTFW/pv=L2X9U캘Ǚq `+8AFF:3j\z`pĉsnG~ѩ4 '!1];vR %3¹FHLJf׮]vz=QPЮN<5:ρ),,MND>&WC{aKmXE( %=l^,$4bkm=0Mɇ1wBf]@N.s];w}IzFOd%u14o\OVQ[sd֜$yАF<(6|tQxen<ӣt9b8>234fԓ#Xv끩lV:u[$77[nOVTI\OިnΰZ-5( ]t)>Ň)j5nvbj5#h{G 3f_m 9_y"0@OdT4n:j5zqu|%O?28+ReN-FQ$\L m-pc-ԝJrnڴ)o_>% h^<Յ)^`ʤJ6Pg?WU6#3r:kשo&5^v;9pѼܜ2ʠ!++GSa¢E3f9d\+{h޲ڽT[ ~i$gɹn|^.%YrmF*Uǒ\rVI\K8rέ0r`sP*9K΢ 9zՎ\b|YrWR4JB!kFRlׄݎJHΒsYQc1Pksj֨%gɹ\ۏx#pr΢p痜%sHh#N8vN.9K &RcdDi>>WwYi=a㋋,9KAQ)]nNܬ '_q]~KΒsLY]훷FfZep&sarsJ$J}P#%ٺg dNwBt撳ܠr0$dĨqU)$}P(n:oF<~4$gɹAۊHYr%gs.ʮ8tn\HΒ,9KΒ1j!BH#B!B!DY OB!D)`l]txxzKB! <=~"[~-f$#BZ\XP M{tss$%!BD3~شYJ~SzLMRB!DzzDGR9]ӅBQ+l{zeY$G IENDB`traitsui-4.1.0/docs/source/tutorials/images/application2.png0000644000175100001440000136261311674463545025212 0ustar ischnellusers00000000000000PNG  IHDR~@usBIT|dtEXtCREATORgnome-panel-screenshot7w IDATxw$eO=yv6 gAAAT~=5qвZk_;e~ǭa2m7@}ѳ75K.zwSM}c^AA! B]?z]qB/99B݉T( p+[  ͒}o._ F#Bs:{^p6o g@r ܫA u9UۿzWЇV|iw>V / C|ˉa8.<+S5Kܽ˺yV/1tsZ>%ܮ;p.-gꁟ#&#]]e$!NA{+zм6Uξ>e]g>?pŎ5G ?QMAx àC/𽙺%ds |n=sǺ8yy;_5d1NwL߶-skY")!&ۋyGǍL>l6$p9pauwH S/> yeW=';V:Nk^ 鹜u_gpe'|BO+);&x%#OArW$?UdWj[%?(zD1@"wd9-ً߮Pn1>y|Og @{^MQoYD{Jw< žEᾹ52=p[0w'y7׶&WOz;38PN6̉. eZ)ә~/uWB6ܷogq7tS7HA[=2@1ogOMYfh:~w/}Oر7Kt+KNWy~zUzn}_}G[.8կ L4IoIq4Ǟfx`NflWۿݻ}5oK~c aT+W>{&X`w= ܶ۷z3c₝*ζ׬e]fno9ٯYgYmsGwgLnn,j+ h!/XK+_+?t]nwu Ͷuq?OЪrHgswݭ%mM'mzE)⶟]1/|)+y59z^.M`: p9ig߮׿=KM^c}ܗC[wO+>#;g;>o,G޺L#>;Ƙ6W5T="5K>r1r _p 9ᝧ;+O98 0iaK~~j89~8;n1?ҟKOX}9C׵OFv)d9N=ίE<{Cg\ ~ 6LsԑlWAط[?l-?b=?~bR)/y a18<>?w14{wZGt/|y}y=7\w &{1u5,|y.C,?*t_Xc<+^}'fwOgNlշ4 X(hH9 .q²9$iOqMo)~cwL8Tmxs 8ሇ';^ՙH?MS&VC䯹 qtL=x'>s鷎g|mo zsY j?ӷ^>=TF:19qUdշ;ֳdphnĵ߸oVLjQ6;=󢗞Mx"+wdI^n=Řǵm}gky7Br7wU:nk|y>1wˇ޽)X7>HwOx) Mjv|2n+=tMO%{3NXg/ĞwY% yO8)x,Lzdݸ}z =iq_ֲQ޼dT*7̿Y v8Ǔs.)O-vpp?{p}63cg/oͷ`j2,ɫ1{mB楌W=\?2$,dyǐ%s/?acɡhpFca^-kw=xW~-6v$b (, Rk4 eJBO8+8/?^7;58=~nzFV+Fa:-ڮpoHz[2qJbX '1.^3+nDHJpHWIC],, :DD`ZcՀNa++T絇wkV'XxQ"Geyb,jڂNۍB%H2Kz]6s'sZ*vH$ C. eOt]'rEa6׭O “ۛ^z~~q8еS:я{# aAAA'J x=~MY$   *5?AAAaQLg]ŹJAAAxں_]~      ~N$~ $x  <ũ{^ wy%'t^i;AAvocOd'1_Ax/H/G*AAxQUW,J"Ay'~A O$ £?AA"="w^D7a{˯&OAjD7/w^1'T$"?AAx*?kզW]w^n̓˛N~Hdfڕ7' OAF֫2g~>\xSt]/{A)Mo|<]P}:x=-{:. S̵K^2 o͚5uY/a~\~/9_WpAJ$} £$~>|3h\s 7oꫯ檫bÆ G?2AAx:I/;D7A]uU|_wd2r~/e t#);D& OA؟=.OTen… g_/^-[q  ou#^O9%OOhwo|}caȕW^ɱe1oE}`)B.D:zSy& IN׏/gJ֍`J܆m-+XiX8 612 k_y}<~[,=΁GMr,=Ė{lg ]1!Mli ŢffQ?$o7:!Pp0K0%Ku(K3I?3H5d=YԿE,ן$ߜ"ߘ&ל tA/8Lz)RX`DOMiI<5IuLj&Ymb<̺JVbB5Ujnjd#Jq4YXҢ!AcC jxUkaWĎ?&vDQi稴%g+ih&mäǰU0 C P=\w;]?c,8bGQ$;Mvݠ&eب/۟#.< t@  VF ⣪>|:EuKjX}-X#`:HjDΔ -?B} ͌Lݰ{~yޙGK_q1\M ˴Ei)FE*o>E&6}7RK_:U3EJmư$^H_P/Ҏ⬑bt0wKo&83U;̴CˊӶ,niii"v(O, lMJѧMϔ)v-ldm&İ4NIc%4ԱNd-Z~oD*=<WʇM/}ogw׎}z^}ɜ޹\GiW=_{7j\[0i|Wr/λ~h6}ޞS^=]~n| ^CO3gK>G.}yw\|=\Ϯ?Er%_xG둙9q&>O?ߌy 2 h 0 2;XuJ5O2mLѦ0{mɣdJFR6O!:F&[GG^a/?H] ;Ă64}4}4!_%㫸#7X[BVjZi)ђ-ZJbV-6b8Ao:=SL'FB:ip:N3c-r G$*,Qn7f IDAT2؍gPOfP!aR } F*T̀QYfD4A3vS!Z5dc hIHST_d?$nQ*$:V@&6H(MLX!鷈y%b^'S$ST$It6q7pJ&f"hc:D*FETh4'tĈ6HԫiTU=h=.j2Q K'2(HؒIJ3QǢ$]ȧZ4iwKeqM6M_v^&AeG&Znn&hEIqI.e,ɢtBva@iFJ,(Qa;Paqܽ}眽u=&&'GE} .S%馛v9_QN;4N;G @$~:a[ƫ46l0)MeI^Ki&7| QD|qqVecՊH ,-dK4´ۋ-GG<\ "D#z偩w`y&GhVt_>@22eOݵ jEѾZ6R$MH*!'A4- c4q{ er|=GPr:ٕ D]2:Ek< 4$"M!Tʹ>ZS-U3ߨtm(נR#Bl=hq>0 aU,PL^pxshzA'{&rr qu =^CU5t>IRe)tnP{JɎXn·40h)uv%A{a,қI/`Z<0B_aoH2[Veٲ)]Ca;5t~ ~ξNʕ =;%6;яzltS^CBhzvOýw||gsqDzxѢ6of%?.7'"˟~?i|sa}97vSS.ّsI>gwGdNEݪP?AkI˴EmBS4:iZaM2a\FW\ 4)}"=FԖ}H0 NBi$1hmQ[rDNfq )."$\& QRL%H.Θ88ؒI3JP  A?qw ,FiI5RHSChiZGGv+Ld-cj@Lt4cKe=DӻI{:9Bo0 XQ%P|f`ooZH*j$zBN`PL8kءA9 )j$( f;hE5$L,4ja8R,@]D-T$L^-0>>#k<%NNK'Fq;%bT &q` BlFHFHؔ#!rb(-bf4H60dKjIL9`K&H&vݤSq-ա2D6&I8 jU:<@<97P$59FTpeV'>* mRIM,$&fԡh9:u'F"U!I5qBIhK1Zr I Q]!V7l5j&aJh=/x1~ӽbxHBGƷk"a5ًCϗi8&'C"59"8Q@5#V%/һpP([ۇ*#m#'kU rn-4|Р;1WG"\qvͻ~ve5]1 8.⓼կmoy\x,Xkr/_>kcɤYv+V,+9'3yݴm`ϽH{>wn|!OeO/pTJ3J%rS[{zzhJ" 1uA>g%z(O(g)Ohe& =(VH%* [LCغNT0$*Uq-lO(M4T6.dtb21&[$.,Y"3Bgm]2J ,)2JW b1$0cfr43YL(3J8G=R/`  S3e,i&ZJ=3_j E e(D P>jb[29B._Fi@ffp"1d8l@UdfTZ4l%3R^h$룴nrNi"h?-iI(RB:IW$J$jӤ=fAiccgPgq\t{[YfuoFyMGO#1E2wd HtHt4)Yer"xI"~ j1jcj&^KCEBAFABOćʷ /.@~C;$*x?#[ E)OQOPL*L*=4d/ ۤ6QF]MJquDA~b%LGR[Bd{*NǏ. 6\<@Nau0 8TܢD՗Rl^D^``h(gD+T< $E[dA7yC4m$)hR~N652:AV!P& DF3E!Ь'`ZlAJ-qud#t gq|~hX&htc ƘNYHP7^v8$}/x?~˵qfz{wߣh<^q`1~g~o 7qG>Η/.p1/jʓNc9s3>.etkb3>쭘4^iZ{!/9w<~H&Z-FxLqMh <<?N"&2+YVJVbk ,YS]65ADruMqpzAV(ܔdLYHTQid4IN&T 0=MT(8mW(=={(z&nY>:W1-L Q!m5z567'Y2͒2Vȥw P'2!>$pڱ$u[YeqzY!I5RrB=Am4]=QJ!#a aȻ Z)0F(!;(π2N:QeyZ&A&Jr~5>wgihizx2 Eo*X-Pcur"1Gc,L,d,.twV>yB0;%}u<(-8 _QMN ;&~MV›i⬈,7q!#u"Ar2+rk9${73wcmL5Ƀ=wLɤX2*qL4,BtZhȰ[IPM(hBfdAV4>pT'o`&}%%a4ugC0^R)bbaF%4Ry$*,%T$"JYGf ZrÜWb't"q+Κ5/ea|"8S|Ex)w(=8/_y{ϻvx}NzX,|3>8]{18qv1s`iif>sG/!O&O/dA*^g{&P,&~ ExJKSQixAp@"-|ۧ5-S`R>ޛؖy>}d,٢ Igl<1ydl!@S &0"U/=}'$m*b+7pN=7]3ᐾ -$ &i)4Y^?C]W'쌈CP+ߖH)">["\|,ZS!WEUm;֢42Sa"ÎtE&fPMGy%>S/4H <AD"2RG L(>?ûܟ?xooy1?%S>#gsTQP&=[=Nx:{ɯ\)gv,:_C3s@C HF~cwvFQ[>gnTb~JԁNiԕKFɀ8+Z w%OxfB`Rgif[g[b[%#Šc΂ YgKv: lcQ&Mӕ)R"%bGtNW+e*ײ?ʖCQ)XFՈjz5bHsĢ[VGZU``ϛ :epzЋԤ,*AUQ^1L%S{Ie4n::B}|xCcJfъifq݊(bgEÈN? ͕8fNYb9Ʈor[fQFjl)t6246 #}CHzcK|2n퀛A~ ]`MQ=Z([\F͗s`"`mځ@z7FCEZl1(G2hnA[kFFw;R/ }R?@as55ь =! "?:/t>1r}vrHt2`t-k¢,l=P42dARsk[ΒB=wE4IĈsy SC}b4g=b ;[RM'140}*;bVxv!jy<ΎnjNuAc4E\!`A)P@A.` \*.kF|?0r)̅˦JAbb@e冹QQ)Ԅzr?@ZŀInjrA}Xj:C},IlYR.EC䱆Ӣ.7u(LpC03HF NѹlňOHOFOG7~&ٳg~qO8?/___UwǷZg sےl^x͋}e5)1On9]X65ds*y^e씃( d/.>ˋ& }o- 2zᷧ#Rȵ"dM5>4`;L"gK`Sܮq IDAT{GiF5qbn_g1gU"v {.+_PoS [X`Rd-SLJ#%!\Ցj*6e,7%i#b@Z$atvf@Ox"'|CCV1kK¡ѩX+j ec55hEy$?=`4,HbmbLfM܇X/tN1ڞ0zœ×VIin:GC<@0ᭁ=q=9s!9C7%١J-H4 yy*3;7!u9;4dN*8r[ؗ(!.ǜ9spiV=K,Bl+y@p(ր99!AXϲ1FX3y#5<_c5 {š2 -VS:- jllkܣ!kQ.:Ҁ.5jSn JeBk &@łc'd p\A%eS1l֋1ru NA=TzY`hʈᄬSoGz>b*DrsȢzʷ);l!rѵ́R``z' /lV4kah5&lzyab[5*c$7)~MhoXoO#n?JW‡%/hB([䳎Q>bD w], u^iF+S~B wOraQPfp/>q{|~U2-i dpohGG/8Ox|oVOx}|z~ _ߢ򽧯8%O>/sC,ы#8t $_)үA +xe A3m>) )#+LM"5BsI㈛gg8yE`8 NoqE+r<  #FƖqHm!fZY1f-D |5h0eNVx.8$MڂCuԡ0V]t)#fOݠP$xNٔakfL#֌M{/g,3kP?@Aр3`߂}tRL44zűp^oh-<"I,=nZ6x# +O?* l~Qn%jDG8?_9W|a8VfVC-:==n~^/JRZHiE_C`z*5,'>Jl1 w"<G\ g4C)F>A:G1+aEY\hGN([8X6+WSkp14ٖcvs_T?{8Fk![1$17-vT N, $x߰" _JkE!8$k}V *cz,Ph  /N9ْ>F$B{ˎecrDlu˭ǧk5JөcnxUhmk濲bx_8GL .ȅGFh)t[83P`^Ppୀ/01!޻#4 J_j2k ~ޚLl1?%7};=ݏVkOIrMc6B[tu (ZV=3 G al!jPJĽ=q{ sp3<Tʦ@ A0`DE1(PAkDǂ}bk̺;4O  275Pc ih0bqNS1 MhPXdy@Zy@hRle !ɔOVy,wF-*I8gsH`a.q%IlB;[Sv5c|pOtlcJ G DxNHǬ)rHQtA33iPtT8j/"E- -x9awL L t{}nu(!$a=`aga|l :S,v A\E쒈]sD p1gY̑V4Z:j6c-4C&hi3($﷨B ܌@eQ6(E,\CB--VUs9jwuka<~:qŨr][xl, N~^oS8a94P7T tl#v!m6Ĕ5QsW$TkXDhP!}KלZ8<MR:ʦtlAlb0M>8/)5)Z1L}!Q[*7VA;\y\ aSi]#@:%`SBZ9 /-2!EI[uԝF:Wwo[[–GC֤O^{.xy󈫛񍠽1.)!ijj ()q*wX&d66h( w=W;O=:d:B(:ݸu3|ySO#~9%}w|<_gk?/T?~V"?dk qvbhL:pDbS2n- HBTȧr tgJ-$ &}%<ҧ..쐫w\g>B*4%UZHU@B+8X^ȗpꢟx'>g5建_/jt<F4T2QFSpF2]%^oe|I<$w~}ke,֦Z8#d* W>PJN]ѹ̠ݻEJ@^/mjگX%{ъ+"ޞ? b֟O_.x㌽ %%m'xtM,Vc YZ#.逝63"@rڃă5@ʦnlԤ[p%یs< B?l}6݈wd!h:Fm-s*C[tG&ݱD?Ή4 9>~qQiZGkmk1oGvt:Ϣ ](PNWrh>BXIJ))y'#yA^O[Nܿw8KGu`QYK&qyeoV(ɇFB9߯Zi(Oi=g ooTӿ1Lv{c.cv!X} d`mđ9݁m]ۯSB,C MA ||v:U% ~a3eSMޱ ؈6dՎxќ,~': a`>IRԻzQӞŨc<_"~a'@|D~l|v!'tJ7!3hK'`gdOQ㜃z'?]crpSaQd?hqd}1?(߃MvڅwSoG9{kFy^p Z3xaPo(;kÙ*Ji Id *vZE(X@4E%ƢI JC]Beg|?;^ͧ~O_/fvdЌ I x#D\O5 Y삏3S}FXh@AsZG$ƀPRѕI7j.[kL}*IrE/ +ێZ('DC='l3f 6EK)DRld֌o]pe=?&BSR=R 1Q*| 6 ߽Da<3 M&.7>-1o]nA䕸[^tw +\t;k>|99Khd'XFEŌ%Ɋrɕ$dNaa5'.y5\\\\.\mnG)ޠ x:xγs;uZeBGr.H95|_ۂYŎ"a$쫄uQ&El,N! SZ 5N4p3?d"p)]%I=^0@~@2`z\u++iUK=ꑅ\y¯ڽ=q{ |qfHXZt6N٤cĕBYlA`%NJӛSc`bd:i2|}L,pv~f=.uP\KG 4̠ JB?alDi)Z!oWLb@XGS" < M ۡ쾅Hi)WH[R5Pi6M؛-lDߊX4$ޡiԍKSTdO6:F78YjA4u*w P`)-A9)Gġ:va8v^Qִ:S6Oɢ;f9'xӚj沞z$Ka ZQAC7F Ч}.|{ukI)[ C@$UQ&-M$R%@:ԃn(}rHD@c[0fAed@iɦr谼G-ц;,Fc$$) g+grOb|8 ê1*j+RL0tZXB&#CXL7$NPTY Mi.mh,\ib6h֩kY 3#8HӀ4) IDDAњW6kܪ < xteR)3l9fx͕U0f@jFDǮY6툝8!k5>() 舌nBWCK9YOVI&tMZˢmMaQMahk`:ð,=K@:f¬"Gt)T)fbrǜnZ&m>McҴ41ۖPK_+K.m6B8¡4]2!|j->>ea8n1'ԩIr&7M{= w5:ˠ03iL.9d82n7 7w%!o'.Ɯ]qy5\ h 4{!pk &ftEZXR9fY (DNJtGP5ԁK(]~ǬYzi] 8 q݄I܄I79 ^V huSu6XǗ$itdToWhmڡM:Tɐ0+\33s<+5 d mӼ(Et$a۱W}hg0.!In[ vgXs gj8锭K;%VA8aT`Xlm՞EyT0oPscr7)usQOd:&E] AI&SMM +n0.c~wLZ8k!J8Ү7[^mj&]PtP 3|'?;t#nM/pԿd[OxkS޵ZA Pp&EVBs(K[2K5f 悓7MlG ݤr*ͦ,E@zބh^BlVKuR. 8InQsjjLvxlajO[vq,C&D^p,9DzBԭWR'&vGaRf٤C ubc;i;iq&-"M]9T=Q=q{|k~ok8K&rdcggxx ٳnPRclvoSOVXdEQjpu3PG l#V5\j,IYc֌v}E1pNszZz `BA҄ l!ȀN"8 H%̣OKMMzӠ\I4AYQu\2mO4t,"w!eMn7hAG=Hn' -}Pߒ~1`:bEDi=a$ÓkK/1_&?!O+$ߕab St5 YDt j퐷>7>;;=bOܰ&"$ǥ+Zޜyo~0f4'퉎6V^ŞpsoP>S] ,iDD/ׄĠ+,&}2j6ө)% {A~{ NԽSgEXLb6>VTf\o_#6ܬi A[MN%;f6?^ Is1у̜'dY.7ؤ5T.PF,fs≔nmҾ0>7Q_%}_W|\p4 iE01vo98u2kf[vnջ#.rrdxdţ\C!p;$$e>M{'~ĢpӜۄIx|rC^FPak+2p휶 |R}/ԟ%_VE_ep֞ u)*թ4rÉy NcӒ*I:"&ӹ ۻ=q{ y^8Mv[e6'pque A@--P߼i DJٺ42j,vPeTբ9-'1-#FMLwU{/i&8zE'9%RK1v.JNrd94fXm[ "҃TFN- ꢦZK8]eaTOTOhcam=@)@#rb 6r![*A ;<=]Guf94}ӠE8 Bk;lkBQB_uԉA+Ne4x]G`JؑIEl9oSkheH404zۢgmI]jĥ yGmjΞb!ۍq(e8 QIl3*4TXnšVht(%RV4uNF4++p׮pnq m7q *)j*X#ڜ7&C tJRǹ0+v-;I)iIi-@DBHLH$x2jN+H=$xX=̉xssS.֩+}"BWxQ ɎO,""Y%f0P[s?e^O$ٙCWԙ{Apw_.@UjZ9nVu.8 3hZ~f",2{ڍq}u>OjWjE☘E5HW.}gikiɨ:F"ӎi!K ׏ib\m":ܖ\񂷸8jѡKKTxn`KZixu:\dIlmW#Y(a"BU"SՈǚ0(YNUK-&NQ,(ԲG4Ȥs$r򍉰cfcIw8#;0HMxG VH#VزDJ䦉+"<LZtlazYz\IoH`A ADC}TRa%UR%yU|l?۵'< ?lpg7ox1r}L=mѓK:bIW%sP-m@q'(2sZ uEufܫc)֌asJ[r3wmn6dYZR78j~3SMa3M &KeۚØÄV9xHd8HO޵0&W'I9$ϻm!A8©NMY)u9m }~x b Z6[zњ5% 2F,l9]}e}Į2 IFB&N(rE:uI&.؂fA͜)Xz]x`u ] oG%moZ MB(8TSg ML"\"p-6"{[;4!wv 푺 6Hu -Wx% r^A7XQ UDlըF D5r ʣ:ZQ!Y 52Pmy"9x(iR|a!;:?#V.쒡5+Hdc|gԉ.鳚do3jq1OiTHPP5iN47Mo'3#zU5_ Ox~eo8k_qҾy[G.G_J&zلdƉ+d[=X>SIAXK ˨iN')i b/wW;V5[|MԷHGd$~//S!I $fUChuRL/'NC~C&MkֆM=ksКp=G߳[c B5C<5CJPŠzsDu@L~0[E~^61/ ^z-'fveH>/OXga&J<|; ʕI4(&z (XITY:tH]ʫ^3 ib 0Krd;[mGEP&!jM/[ҍV Vcd7`q{gͺeead5Jh(K#j`L{/ 8) >\= Ymֻ6]hgy}^]`) 2#$*i$r40̡]<-! szm3]O &aP%UP/ʯ5/:mV_]` [{gj~CN7s|k.v.P&]v23F|}I>4IF6ňkYZSTPv> ?Ơ4 NY * WHOO|?2*J.AS;Eu#_i z3+P=K|8,{,ﻔw&‚W* {w.GunR_ۋ9 /?š˻|9_0^6HOd[RhD_mEU #(ΎvcMYӖ|3"fƨD83THTFnb UFedA%%QGWö.ho. xy~ɆelPFF|0Ov^MlstijiCHǂk(n 1=7O=_pw8n}I= Ox~ 0b?[zjBWi.C8٤lmLa4̘Cc4+bI亴K~&M &\] 2-_r9 I@9-)W?<a"@;~GKH,(kWG,'\Y5i2;~NjKdN=oshk7`kc=d/=E7RdU v,JĤ@jY#W5r,I|%)gɕ_?o7r79K$B$!2 C.uRP΀-+LjTqE#.Z'Zknv@+]Vc4^cAPJR$;}/1T _"rN RB|ִRƌsz.qn[&곸ip )KDP!KD^+FQ  9s\|; RҠNҐ>q6c-A log;w `뷙8Ԭ벅^f{#C(3&5i yePh6)I+ԈKSۂRڤIM QP٘>;6̠nj 4 ϶%*+NP,x0 Rl.W$ PF\p }w3R_QݼyR6@\[DǪ0h)hx13Di[k~U[ )TRbd52 r"AIHd HU3GA #rć L'㸨i MkB*)Y$2m.C6)!OW~EcP eHt( sf.0),53/{'< ~/2\snf,fM:3ɛ&7& >\buq L(B&I]wS۞2oFE0RZĥGY2C5Qax[j6_JϺ=xʈiE.qG.qt}wECuAXr]z$e |m=.ϹlX8]S &դVTɐFb9B!,,qMfZHR8qIRu*<&VU "nSp5Ӏ/m7KXQЪ7S\ҽ}P  HigCrl|cKC4 81iijD&edWߖ$%aJ{)}0)PT;Eu'\Alڨm>FeEeJ41/C-9l--⋀X<(d=g99oh`Rz"tO'< Osa5{7g,Lwcfy[ࠤ<0t I6^=Yw>2 V}=xĥMYI}`S  G76)BƋ:`_{L13{GX$9\3p'4 G%UJh1f=GesD 2GY:"\ѓ)C2RFW\{ߞ6Xg> v4B|789@ᰥR0rjU{G-?MT,Wu\"pr[c_)ym\E|iS&f# R*C6*7z건,Ehxkނ5eNW`5 {K. .s;beR%u c΄acМU ^xYB5qXr&D")MЖ 2ۡ jYgdYE&okʎ~.Yz;xAt5V>A:v8uovoGb5kŚ˺ZY]vYt=>i4Rǡ<4E\PT1P iB!P,2 A#pp]bn4ٮZ6E*^?dW쪀PhᱩG|-vɐi`YHD e#,AHh"a1Wb,>n[B(4ɮ[}nZ'( ?G8h%KMXdMmK NA޴ټhS[),/vS,R9͑O,=k)1scaVY3+ΒnAk-_h'< ]!7X`)|G(Z'%ќ`A@oiyI"|hQ1Y'=JejҧE3) ~m44^m}oIMq15S 4Q_P_GX' 5ጁ9u&kb,cOA#1u?)W 1ⷡ' Ɔ\!wHh]P圠9|Ival2%D`= σ75Uǃ ~zvNM_Io8ļwI~M *g/0Ś{<6ܒ`SsP޾]$Yt7w3fF&[FL1a^ *k!:_Mz~6WMiYk W^SE9{9=s}8 GHY!EM(|Lwtslq-=Lulev%Vs.93/Ip8i!xI|O2}UbcRjo_hR-kIJD_g`6ܴ/)2bnw(;';^5Qt3C!rp`s}sdqubR($RI!EJT`Ԃ LjG4"+*\YMz&@?H{[.lE_0@ԥA]`S{!i 5ԁD j_B)P?|3IDh^qqA9߰Ý<﫿!7JϢGbgwV5qa9ӀXШCZ buM8lU@_=&tMio#=I 'QFEC%eb<2q|H$7;֨)uP;Z9L>e^PTA}_ o[VX2é#*D"=tHz Nұά _n?C6(3&s9לs+#laKdHjL?ρ ?^t?v~|7_ďu-5/>/}|맳w!B X7y/}קysӼu_Um~RTE¨L12E2*c2XaLx}9=p!⊐E1.[6QBR}*`:yl !"D!Q; jDAM\)[9SyPN0uA(|3Ja S !1I63U IDAT5֙l]w:ώ(:00咿{'k ~yˈ)eT)?J-ƍ# 08dMڔ3Y4 .WbV_.yCdk<6cg1n'ua5]}&Ijd;Ws`ώEcCfm&+2 EPҼU=[^os"% C1WP*;b3k3F7Bt4N'3fN(j6ɵIV;&Qj9>E'B<m8.IA4PVlavZ8Ncz5Aa{|}P-@c%vnw]§FP}^ o̬~`d=ʜdgSed}IMaXC* ;!,O? ~~zOʹѵ=1zKG[>яG>2*@?lՏP<'"H"4Z ^H}{c 觷#k}ѯOm?]?^>zy;-~twq~<^cy}קy= ,"8灗[c[[MVsܻюiI#"JxO(8f$ Mmi` WCv+0Ï9I0(?8o3sYBXrRJO)j6?qC$; Itj2q[|Pt = jBYi\q>[" MMv\C̺MjաWΩET+`bayaKubZ 9yuK,7խMas ŢC4(#UnD+<)5FUi q3ԑ@_X>dRulŃ U u_k 0paQw cVY\=[WF*bӏFڡ7o% Y ;6(:ԁ7em3an0{d`e"BHPXG~)UaRJEՃ p,KdLv+g/eEQE1a0sɤIHdUa6FS =RWTD)Eӌ76 n"3-r"3,2,ZޖhE^iZ;K n#*[.rK(}A7)Yc΁;A5i`6m҆E>lMn*ꪦ\,9Sf#T ,; vd8bD#yJFG'{S$])kL ̼DkA.ObT.qX$GL|NbƸRhuӼ>돺w1 LGw/Q19?1/=._s^}vuc4HqDJ[S3GbЄI;M?4 /+_8)8 [6&GV5ۈ.gzi{w\)DXcAҭX4Y ?}VܯϙFX(lt m&mR 9uoy}/o IB25\/xo.WGF-BEv`SlM&Va41G{nSUI xsw|/b5|!w8`r(6vsjnR>T&D:=]@v;!fSNN);î)vǬƚ9ZNp$ "|둼U0 ?eH3氱⼹椽e+}xysjrһ夸P8b+l>;FooQr cbڬ6kZR;krE]%H旤ϭiSr\zͻ97َhMlE'_Q̲vaZKb ˼(o,ƛyYo7͗xƙD36" ߕ[3]ʑu=1eEN%:/ #FU%9Wەa  dfb5o3(ڴY2y+-kOp'Wo;ض~~fYɐCc꣦m_޳ОwVRx)?cOZ?Y?:dٿ-}|k~|SC#?&_"?ݏ}}޿K#۷?OK/y |AGXӋG*~ 1!c`O?E<=9C]Aw'ys'8?Ӽ>Ӽ{?~k wQLA])4CIM.б QUe3Qk s%]<]b40[ d%Av9H wS#1-D^"4[!FHK4;) U(QRxVB%q㖺obLCB7 }'<',|vuV7 ,,$ڵ<) ,&ʕԩA|oA j#lUX!USZ62mQ;*szւ.sł!5rHmaQy rFvjT@C*0҄rS.%")5}3L?3Q#ƪ"6h l0Tdʦ2$yf ]fanjRmRY̱'p-I|EkdP4RZF EE+MQJaC~_[fT ;t钄6|·(}E ZRjIEmY kLYb %4g9b9R֏s, 2,*|f 2jSS&IРlTm Ib q l*7%~;̈|PunU74a6HA0H ,Ȥ 4) ^'4&ku3sdCnu5?&!vi<_kVBd7P I:&Du(l:z,NL{+Ԣ¨&ƨ u"K'tJK'eU!a-#0 LE.x";yhQ?XQiC"'KuYX:%6KVtŒXRVX+|Cj9Kg cqXr6&)^Li 7Kd6wE*).Zkm݆u FcWVfkނǷ)aoyO# nAoO⁵\[swܱ{Yܵ{n= ;*`)Kx8A{ph׾ُ[voGO][&eso].6c=$݉Fm܊\Hݗ_[:)ېy\SremCD;2}R̃>!!QJþ״ׯћ [#߯ l;BZЭV "œp Ź;jkD6QEjzkM]_]9o&P V߬80X&}fY9`6`wbl/8 (04sa5]αuR'[( vCU,鱨IRqa!"`; iG1R!5b3ί܄^gTA Q R:D0">(-A7[!hl)GܤhL|h ='x eBUvWvΊ^l2Gmެy=:vȟ0L|eMwb uziyie.mĉrL9,bߠVGax,03 W֗1K Lf%;LhS*RtK=璽%{%{c(ZШ PFRAflN[1KPm'&>RH/ h85=5g/huJeL4X=bv9OpW_)u7mSI`;4]ڷh&^,tcX>RP$n4DZscfMTHz\>fz6&>wija=̃9c^! u.pGM6q)5%%=wP$ mt (4m5D1kR!i;#n:0ơv2kAlL4ET/}7#Nǜ̏Y4DHZF+֨I|tbx|ê?@ ZL]^fw/8\9gY-b$< SY*IMi+̜>xp KetYJiQJr#W~{I"J۬A䳊;$C[%{svkFkC/0ehw1,RT?iqOn>Y-d--ʼMԶR܏Aȇ~ ]w7otXvJٮv+}f}|t 7c>ӍEuv<|kf|ko延\Bɕ*ʯ7oR.[mj|eeLhL1/Oh<~k@ (5n2D J11'Rvs$Wxs#.%ħ0 3_jT]Ꮧ{0(:#>+l,%wVgN|9/Y, v*xS4Qas>\Q:nb7؋sEdP;qbΌcQ̾[KU:(Y8o';#yl_"˚%, >rC-MWsJ [ԖDK,k$+b%UUUEgyFdl4⧡)%=`יsV(uBIkd.sʜa4?7|~{ ݀/H3MXLuh3FJJHsӿW  f 1sv|6g__id_9Xj { ?x VGi=>˾7{s; pF-yכ f6h*Y™J6R Ua㰤+xq)Me=`/hyƪ\P ˼ [gaq>?BƤ Ơj4M]M!K:%xE8iD>O01[ss X)%,Q5+^}5W#qy^N(c>y0{\)ciɢ@$ABW{.wC0Bg| Xn>3[ "moCqDxĸf]֦~4;CйYٹG۹=@w^tms;"v^;@+nesu6hCNNE*~BhT%( A*$`S;s r#_ ߛ쪴 9Ў2882E n^5V(j`eV27ĂˆzR#%j> K`)|I+8JL qG1 5*BKEke"IymR#yB8e4>Uin%ZEdfQS/** `B\cdMҩ] 3ZOAR(eeG긤pu֊$Y1Ⴃo@7/V פBKʖN @†݈[F, :`Agu![B40(Q2Y7M Fd)w?v$qL+N# ԉNجSn#St5=mF4&Ԇ,.z\ eALwBt*H$v7 ,>c\+mؕWLqUBd ƌsU*CCix^@?cXM7WW sY(yQU@678z노 ^u`mΤCCH4JQ$C&ԕN*W,[RTb)Œ&R).U#AԡI:%V%i8-'b!S"(JĘDKnX,fDTzH@L!/MƥhtֱKHB40zKIp9D* D*%N 6P3Sn`~3{g@{\o]USٿa3z{+zKz{KZdK%u^J 7\<&24L4K:# B敇TUNC}JW˜z)#NFC b2>擾Ǣy_R$*s~Dfu:rX=V"TJ}`Pq$^s$߀ eKBPQ ᑆE_DeL:_TZh 3zszYL,g-.JXܣ^; xz1OQAF;n:[Iћ8v1A%fc) qnZﳜ8s;wگ6YנjPv*VXH^eds\ LLt'dEVd "m&cZ+s sѡ7)hn6*BUJƔ1ehLp5Kc!,d +v+vԾFFmkԦJ+TmXkq#FZZQiɘHw6a9>W“j4 $fp0L?' X#iD'*u-`?|_Z߶omM;ڒ2A[vr˭E]_n̰w妧D[>]lŮ[@vمl 4w-AAϽ{p]}X{wfM6H[:-b,fGwx;/mUލw+Wq'wr}'wr\W;1. `{dܟbbo|m1̿P}1G>Qhф$r#&b%+/R"k.ЦD/[D6Ņ ib]۬}V*$_P A A +iWV$hKi3dZCf0YO:|x%qhQrʇWhM2Pe:l̍>+C`Me *% J测%#nw96g߸hG:{abKFt7t O?1͹Q=rQt}}C74]6+ :jroPՊ2(5YY7~qIEk+k+:jDgYm+;]h4N]j4Xf׹`_?gW`( zQ M"jPխgeؽ3i^D:ыĢ]Ʀu@mk=ǣWSP)}_a%[:szޜn{VT'-<Կ f{gEۚwpq璣G-=^]XRRQRw>r6fKPRc NY)@=:Vt:+G}'/Ik ( jd]rd B+R A5QCӒnOheu!mm&GO5 k{Id 2eI*̒A{S_3v9Gp*; ]*jKsKkKuLTF[2#V6J_8bd]T4Vw_ p,^̾6'&u"׳;pXo@POݿϟ|}?_8=4 x`|7߸U}`>A>|'rvゼo[ͷ_¥oO;}Q};ZqwOߺߺ~%N 믢*~ťNqe(uߚsG"#T]Bex .'?y>RA؛EV,J12@-ZM6^) y"95uUqcRC{Bߘ}BuC}4#}ip=}uۤ_䅉Y F t핌{WXvBS$uʢгő(S#p#QLPp\|oɟbh9SЙuq؀W]4|+:Uc13{ԕNF(=ns. 8sI28uAhzK>>W.1+.QRZ"PtT4jnd/$ٍNN@mD_G>(tWٗ7O1&H cnc~ʏ)LWcf$'%R1(R1+) +eC=g+":at5n!5 JS"JIo貢%rD+Zq"-&uUD&c1鑿ޠ3CXG4E0n 4K;/,F|c^c:9sKHZRmf2ehto^?ϞQhF1f?r ?9m%#Vt _PVHѾ.+]T8ra5l}4q~vȗ?dY#0Ca8:v`dӴ4&PV5A\Khf->dg>1$j~H/'Zf5nJ{oMow^ĨsD UQ?ܞǖ&wnjnQgw~ן#Wxgom4 Ʉht:Ene*|o9 /q3-!owl=l }Eۘ&n=&w Qa6߽=ηCm~{wr}'wr.*~pLVܜ|E']yF L#.:жD#*.iI†fZ@_`st@!|o!76:G5I-J+J2b OKЬTY BD1]TbnEX^}Dv܈t]i,4mBUl#ft9kFnNP&%iA.yu2;L%:QrDⶱ2|>e!Y m0Zݰo\=neeU e=f{ VU5j RD V5:%:6N@jN> %GsL/ʐ;ݜhOC6ɽ-ѽeX^bY93% XAfm$}eÅ[) 3i;8c4/ VO\/l֚7I" {dy*(0Q(>UIbIT49:~L؜Z>!S,6NYVTl(XH%VWb*0N)?vבA|%f6ŁA(HARdP:C8{ͦk^N<{G\{\L1bQI8V#=42L322u||Yޡ!ł]ȝcE4(R$!C#&]gxuXuk $?t=B?9odBo ozH$ݿ?psvw?g][%v,G޲@>C%`bK۞+-}9Ll-6Bۉ=YXqok6d]%RNq^~N)Gno-p7-M<ѻ8wr}'wr\X񫀘<+p(W:W{ :#Mݱ`G1r?QlGP(h^n]>`Q*0S`ւ`r)(*JsQS4')F%$%Y 2اt%ז? (BA\ ^ӍqND5)8,  OB?aS"5c_Y)6 18"c8H{3"ey1 Ħ77 NMkhkZIͅzNҪ7}%\ Fc.z,F MKKFFS|e*+|k-%]cT0h[K@SQ6+e np]aT5ei.T2SA7cv8~zo8, [KԔS,IK:FѩwC:Oc85i[缽K։WmK0v CЉ i1  ܠW=._f`%G{>3T="%p:,xEŗG:B.2ꁂ(trJ63?a Zg췯x:3VVmk/vr.KTY "Z|[j]#Ppx'*%G <';X3pq9怋.a( nM3KL5mD;)({ Q@AqVwYסO2b>8gTt꒾X':kã-Bf4Cb, \(BAx#("(TGPo'!_\MvOZM Ǣ#XAFWhjH:k:ƜΜvFuhȞBYɢc:0iҶM~S k.43*Ê~Փ4"3 FmZm;d-fcNΟ%ZT"M![CSD8,6}nJx' LL2J2T"l<&ǫ"ńQ94yFOϻ_my[3~ܵ5L޺~pppdVE)]yWޕw]_(~ 76ޭqCk]}h>k's||zOl6?psa8^G+~O΋MJ9öSTTYuii<nn@~"`-RIu'ʙ/tlU\"6$3li\I`wt<ȑ[_FC@Q=+CK^",`GKHOu)P7 >oKSw7o8~֋mju{>G $/ߦLݱ%{ o'y}ۙ< H dkVU0 w]h%Ll#2a̩(TBFC6d4Rѻ`t+n1N0'X!50e}Ůrnq^v+9h}Pe7&8o(ʂឤ9 >W_{ĢMamZi4BXd AYp]dnIb-f^bdFVg>BSjꂎU&~n\WtK/+bux#0`Abc! IDAT 6gҖM5ȻE@**íc*Tk`!]d& ꒁ@|>B&` # i#G!G7_St1pHqni.+Wk*UuAg@"?) (}r M"V Ј1/&5'*C.}žG\&CNƇؽ$9-9aZ9b2CQ\,=C\5 ʪF]֨Ūc  Sj_pg=>z3y$Z$pdˀ04H7#yf,/g.L.i\ِ (ZV)eJĎE\QZdžCcKHlBS!h$4BBCIsT$ ,V~z M"M2KcW TOEěTl%" Ff%J"!RzAV)AisEhFnFܴ7Ұ64@JDD&v! ʆ\ Ba#Ӏ":+7n%heJ:,* {LSt#wojϹn\rFy+M*ԻԤγwXYH9oqMq' sB>C?O~r//Dj_G5ݍOlk[~6PKoɻuW)\oެ-wfA)G|Oz pPɗwzowY͚[o`|[{p]ޮ;~&K"9FOw{^mDF:봆欜`s6gG[<x\yZ1x]5  28-Ϊ[,:MoF;7.[.˺|Tk:QDPj jZ-i:ڄN2F)$PdeL/V:m;Lh?]EH./G˨'g%5sՍP9P3AzTE&2߫.Ag{#9dqS'@KDKB*:P7 PgB~^g2Ce**vT=}N9 jZ-Eis:3(JQydTt+:#lC9SɆPHmhi%bbP%Ljqǎq*1)F"Ʒ|V j˳ii"*\6 P̈R2 o?gn;,6CEi)_T䜖9+"fT3ɪ kPJAc; 1yS'ojdM  K(34!1HK0=QX)'! j.:aLdWn3T{3{'X 05|d>o,,Je7G+W啶9k)tPPjM :Z%U.)gLih0ya0*sQ4xU<+mFa#LHݤ3o}Ǯo72>vܮ?_O0 ?CO/??vɟ 7sӟ?70 9<<|l'l |m^=ķ$_{~ߚl݈g]Pfݾ_gwoU꿷+ޮ o'9G93ϑ{)ۜ:8:{ KE©lJɣCϩP?*Jΰ8cZz%cÕawF)4a"T*S?it =mLO.gԓ%k) ͡^RhP%_t:_8̿h$y]G]/rx:c:j# A(BTڬ:$0. FV05 qY%D!-;YESZ֧Vߒ #ɗ&&jT2I3~W}._ X]6N-tco1;aeTY5mVF[DׅQ|*URѷR$5 ّ3PuXe96m1>}eDNXQV5ug?A cz,MlWg'=^1=ot@'u)+`.p3Ŵr.İOjX | H&3 x<|oX2 Ca.N Ri\c8W \ @n d,1:M)1SfXJmDy>P  ,Y/2˜iQuWs(eȠ"CԢ$*VX.e(( KT7NZRXD4 @2v].Qj%, _EhaZ6'x5F(q&<7Dkx[ 0nէRΨ,e=2i`Yn}MOIIqI(7AfF9WIhEY\ʛשH I.L| -X3m\ݰt7"ޱ ހQD n4Cy ˛q+|S&͋ t/q ݝ :D+X}={n*7fH{']wo㷻s?5Xz4cx>k9cz.еC}'y=dDoW^:qlrxqI=.]]M4A,:g XVoVG (#:.I.7 Š#ÄmNmMXcsʚ4n2͚L&Nyl VIӓi3y2{>s# y{-B. L&fR)X+UMFc%8IJrEUn(pY PO<\e6"Xj07SXZ#6N]<$W9?UFcJnD0}&eY'!'ƐAR S(”:Mi;KFFqf-3iܢNi9R9`]bչ:0C0@EB0oaEĽa X$6˴(MIJ*)"KA~e5 V#3#49EYidY/,Ia%w٫] ]I E`9 JЍ HReрeԷ |5wы # NxTpos].ZKc9qa(bxt m{B5*R"XU6 V%Tq p1 5,Ѣ5,)a ,$ \#xuOf>Dۗh{FUJRŘ1n$b$1Lbaϧ#FNST=bI,K"LTӥ;۸`MUF;*u~ TX.DeR<2HpɮzĮ8.dz] Q NSZ!,N=^dⵘM#Ni3Z w9rjq\"5j:dyH{F}wE}oIB/3ҹh}3|vBYP~YǗ.(""T~WQ^|b~8 x u׻׀;p'䮣!{f7^7UvwߙUK]΄2oQ3x~o{~}7~D`8^Qef>00yK1J#۫f\]Y{&S/lo!~l?ԏ-İX5.ESWW9EPR+T0aS.˴Tr|mp %Pm@ݔ+ %ۈDy:w}oA.㤇ƈUbNY0!!(vOK~9=?O89>y9yAe8"F% %,9 |1]^|ȴl#)Q*%e7r`/UF '-j΂KE/yK1nLJmox7T2E2g{ 7|2]yRnT$$<狋8foP5xEYQ]6PVbJW(*E^?櫓'zy ;ϰf 6iiin/x`4PBQ)TRKϧk]SCjFD tP* *kv+<(XjvFmLcCBC2/LTKy$H<Ȥ*V K>0_嗸b/OAlEu`G`DH#f҈Z;6eK%$Us#^z >j~:Kʸ UϾCp7ąM63YmpyF: f>4@&YH4JSA}$AJ&$T!g|l|?k]s^^<';<~ţag'<ႜs )9G2Dh6H%91߁v$m_ n{D/?]Tt\u|Bo@.>:A{|[_G_uͮ [{?buܦ'ǬJ"W3墆 KHD$D5$'XusAZP7wciZ{@@@#FK%22}hiEyZz妸__ Dz)RAYB$]KJ46҅DG(r}(0HWQR`4l YA8Y3P1:Qm(\T5HK407;)DK4jsV'[#}[M6`W|%>씧l3)3TrU'6s$LbՐ@ T;Ǯ89\E]T5guXyURKf&if&ib+z eb&e,AˠϙYCXҨ/(4s kqF5^klj"BWSHUQƂ$5nqE%[sc)KW-$Pzzb!:B_gJ_CQ zj65*Q* "3]!8D3FduʠwΠuNӚR \WMZ " T5]yɃ쐏/ђ8nE P"C"6e2D2 e SJ1.ɞβZu1JV^ $*qXeu܅Bӳ/ٱNxhvZEKb?7RMQVVPP'LҠP ["Q%,Q%ڸ!¬%XS;\(#YjꃀZȔe`4X.u!rLB'SU,5BEFj(jixl$) t DU EUHdm@".вHdH-G*96 s+, q# * 0JcU= 0G!+ IDAT$FY?C1+DGQB!/6iϩtH $5I"T1W䥆TlQHQM^ɱj)ND&QlE&iyQX$0aFS43G24+C5_E*JR "7YP[s%]k[8,5}bp6 $7}0.1m ,Enw۵ݴ wwԹ}ns-y_^#7]|Ȗ׬z{7}i}?I\%cSiZ GBJB> rS\\o,]][(u^Y'G_24pCmgo1B^yaMڠ6X B:1E : HGAGE j2f=PMjcjyNPTHXDAYM@marQ4͐,F'#Uj c!TVCĶML/ZN۬'8>y@0 .5K`T_ݿ;\W.YKj؍a5B);ەcv#2$u4֭WCWPz,+!F/ BdK?2r\T>s9jJ#N۷4phVN-m)plUIp.˰h*j䅎E.+gxEK'Wt\)iJ>9xI9ۜ-ԑM$B/AV O#L=WlsRKbL }Lg0ݝftNfT%5mEM[RV(K+&S䅊V$yBұX$-i-8hq2~H. Pt6(&soC(Xu[ͷ8i UjuFaJ.rtg3}}*4.H4."`SRa D* Q.m-oAVUi H5 i 2GgYh5NqhQ SS/ .zb`9yd^PgŦ 'K͹;w!@漋[boje]W);gt;F yIqހB!Qq;\_1A+P5Dw@7wt=tMp|;}J7#oRn66-7?~+q*rޮOخ[͕/gs.'_q.óll5Oyq_])^PpP":1"Eyc}^e XB[1y2<٣3jfQe˥aJMJZƞΈH H-. VofuAg';{͑TJO!=&G N+؏COf44L66(OLj΂+ qWSx o`,.#ckoUUs@ 2"§iKZGԴ) +G|UyXG(U{Nǹk_[!#UY?5bAfqjnI6k K$ ذ fx}Am{\9;f|y=!{a@sU[- ]ѭ\R~y*6ukɶ}ƎuĶyLGNS L0L1/SKY((E7R i [&QicAce qq4t4 X\ysO?ᳳOK:K}CJ$JS3S>3>7\zSOpu>.6h!g5+P+,bѐ_49{{x̞wLÚ)Qj*sSns(%ܚݝ^R{K9+xij"6#d7Y̚,FM:ڄO(j uH]qT \/mNW(kH/- أ*+ƹM:b MQqYQeIUZgaAH|CØ1\̶ Zx`o8JB뤱tX#5 BD~RrEmrQeZǯW}S4QPbиMG$o67BT9 di7j6YrVV+bP(ïn+*,U@i ? ~d F-F/Mbա(k+ʅ5ZoiE$mJ[e:ou./{vCC:d׸bSCw%AcR0-ؓue$sqݩoƸRw 7 v7)w[J.9Zky=+;yq،q] V.tCmzm|7;z5ֻF1PvBܟޭ{{Ӵo:~˲3r;Ź΃PG<ѓ/?sq*[ĚCe']L}:,rjA@Bb_A { mFcBQ)"I`7F>yH9,^8&&[v?:*EKNj Q`Eݚi}<$hPzTn[>Q0 JmW]W9EEDxVuL}s8ecL%ܡM<a(@ KԨD7HRVT+KdZ4tK9jsoqz>-&mH4PThu\8ʈks\6oD AAPٔ?ID LOO1k6c6Jt-x&6}hJj榨jh b1SjNU)tFr`-c,V_1xR{%ͫŭ4Gnxp4HP@(%P"d(J K!kjd]T՘)MCC&8:iD %BS@ h·_=F>O~տ3函+duJe#*DKJK,mRTUe',yyaZcEc{Ns^-&]Ɵ]շŌV}9bW7UBQAJ =؍nqIkZ⯪d8ZcE*qnspGhiF-NĴ-bQ7+ ~11O"su.t UͱOȥʺX5ed9k5X5qs}-ugrDyZ='Tk`Ms$l&4@ Dg,>VhBjľ&CJPQHœTH>k9*oo??'^Zmjtˤ._NQ|qxePy=ZSmhS3P? \00+a& *'[EAWL&h2 j_R-{;-(#kb,:G>XW%YUAUX%{ZP*mAU8:8j8jp0.~QԈ C%;)m9Ә uQ .%xٺ 𭃯ԹT8PU&1dB+&*tBS"(5X "i1Zɰ Pa@A#jkT:+o*kX50| AUn)U|bhq걮Xlo ukj- %E;GE 0ˉ1"sH8wP;'Kz=&ۜ;NKMPQk9ZV&j%{Z]+ WTr %)Nɦ)!#MC0j1/0W-([y yEFYJJ)(@ /{Yi>~"uVbW7̟݋duLh:h&/ӽe*x'^S )8^gį2;^_gc)o'l:lu/t0X+-mEl 3Q<4We\ X.,WΈu8v.r3|F!}^dϽc]OPa3 ƃe BQ56%vhZ ]I(g nkx~mWdXn,}VUtQ}ZHBJ 9% W4ʦqjc(E0CvLT90+Dy#-dG>ظ]gm_aKDöscCZe/.e&fP-K|ȮN٘8t:zHusp7p7o}FLx~@$XG\ۇԇ\Rgũ(} b ,Q xb}tN=>8m7nY>dsϢ7>>$DqF{T3j YA~esʍϥ:9Rqoؚ 1y~`glD]iߴbpd &zڑe8ljy1Wc+0=3s8 0XL&5Mal:\O~ 3ax\W$deAܰ_|L_pz)q+q_ -q س:WN ZEІ^&, &=Okb+EX޽KGG>;95i̇is̹QPgϭ>`v6;SA ?U~?U4^c.$}@,q`] Ta-߬yўag4'CJ`2Nِ98bpo13N-8bk;E P+T,T, |׼gzŜو[2dqKJmsw/;ۋ/=MV1Y-e3)?pUW))`g&)gX8 aQ=T,ja#Wm?)k2g }]ܕ ΄;kB-@kL]CS?i%4 oѮd-}_Hw8/z޽݄mcZv?ŵ4 Bxu-8[=_Ͽ_+K~+]9+pV<ŲZ){{O(M&fLLyH-:y%.u4_׽/YeZY·({-vwc ZS*`rjOr.n ' *`Y-ՠzIWSljZ\Rb..eL.h7 ֓OOݜ4HIf'P,,^F*:2[^B jP)ba26w;lY##RFT\S6ʥZz+bCMFR ɚMx6@4]Em+*BS[{kg\-w5jB`hIEW8~Moe0RR*Я7l)˜|qCw](B2|*Z鰶ԎMHJHK]y̻my0_Q {WXqM{|rǘ ѵ@hpMŞ7UGCϔL+4ǂO|7 c ^mYg6YuhWFp6}ƽڧ O幄^Fn%Am`D`y5ٛAI\'7 gS>$s)\TX B.c& +]}}e7dzĻT~>G@ r/1V-dˌ% IDAT/ًkHF]kvqKޖN!6qE6IE[3KZK1CT2RQ.$P̡A] }:5pC<D ݐuD|y=r(T!k-Y50<#/pY r EGCHIrroG| وvM3nX70`AOp *z~KKݔVԲ}w0=wiO:>˻N`Yuh=6alEhff=a5XA͑s)ސz|3DvZ~}lG$eLZ!FF7۲<<}N7Y6 *j–g_|uWx(.ч<[QQ+q"6NU=a^7!mf(#O 掃I{ǰYpc ?eӵh:!3|n1.8wL:?ÏrdO#5nUY[B%R KN:X{,>K#dLjY X#SAuP9X3=(p'a{#n^L!II7MsH0ys?fQO%QaD)0^t^L_r6)̧]bOh,sܦPT4mMCW1 V>gp_ys=G%OS..cn%E5>˦O4E)ʢm䐮"u\UlP]W|ǫ_ٗx#ICقh@uK]aŠHy8>qL.Xϻ!' dƸs'^{NW _"U6`Gy+uo D߀kvv*FCc"!o׼?ẗ́| 9$瘲 YCj>ɯOyrpӣS^%EsW9XaO-[e3~w+~_fQ]Jǡ9;ᷱ[Eu[MBIt w)!q0h66Vedzkԁ-FTw>Z[k г` 7MUv^a7E !/%Nd3Ih7efZ D_i\~|_a5XXC}nCL+ >AbfA8/ 9շpѣ֧j꼥5MVZW\}W11rAAI,ڟ_WUϦ}!l=yipA{́}Ag; JMrէvizb0`&կXS&RgSűU4muM}$L|Љ7pv'C/3#C _piw? >iG-[>k5Kbw =jۅ@难0xឱ1 1wbLc,%? O| Xk{>3 g n{LNe.[CCrXP쾤GyG~NP ;A34}mPNVh_@Q tYt̺{o{h ʅĜx MS6!yAjAr+ ۋbg `+ aukM4pmZu YK.ah0-kGSjp ]("d.$nD:\TrM8ԎC݀n$Db7Xؐ<,( -qӮJ4Mk)uSWXu[הv3xUe11sNJYN{̶z.ɼe)V)}?8tfSeFkj";g bgK$h-ؔ1FdYQ/1vc: '7>>E%mU|EPH7ۧՒLȰ_/nHDF$yL5wv3- }A^f+bƮŪm \'rd[\QmC*$(ڧ<Uݑv&-i#Hz:hM]4%kj)XV Pc6]HL*ؤC~Rݝa1K'%6.kaD+Q]U[akЂ ȚZ`N-t ʠ-q"IP:uKhN&Wo ՒRuъ IB[5jq iZT!4f=*iPiZJǣ.J݄Hms#k43M٬zlV=Uc EKI{hO%gnm6xQ0^*h%u$ U]kԎ֎I]Lm]jNK+nסZ'dvMp:Y{4:E!u "U[Έ3HD[ː0o\'ސs wKg[w2bR;B$6 rsОU*ݡM--m))DO/r=#<?[)KjmdOZ} ;q:5CVzd]ۘ|o=˜"r "<#=@-]ڥ]*&D4CF)۹`;o(3X. :Z6~3\{(C<~rk <_0~doI?آ7v>,yN>p).EE9P7E!B6VviEcYX#hҠ; *4&!V6:8k:N#6tԖ%nV>Ř1NL'>N{W#K* '`j&oC$b|P/-Q0J<ϘS4cꏱ*xRs=}<|ii=Sa? :a$M#eQznskQVCGG}͐y=j\#eȟx/M 3˧mBO< O{i' }. m0k AXTʦ*e^AwB-!7#G'ch4]]q͓G ǣ ʡKu@ivnؤCHqaҳWDfK]ydiStOV˓/LW!U8(oÔX$x Kꐛ!lD?Isaɗ"Q.[e\NNNYLń< ȟԶEuZnl)eDzQ\+AX̆w&>]:ngIlm8n/9/9^"qw,ؤ=̍]٘ Ik[}]kijUb.Kok'OL- |Bh #xО=trq>)i|ux<(z$NĺQ@}TxxCۻG9AE55Dn&|=S{q՜u|:{^n Uc3Ā)66(XSN;N;{֌5'WMfS}MfD@/A/͵wF,g{d>#._~IiZIKڡU@1)\ڍ$|j& "Vfȴ: ܪ$)_y 30s;#=ΈiϽϕ8fZ7 ʩh#,zYnjEob '7P*h ^4guڣ>u)Jڣ2os9>f9ם:ownկ+ӘGs^ooo y u&l;Ρ,-.?Fk;i9m>_lX ?ꄨI|JsȆ!YBjSaSQ-<!& 80JkfEVŬ>A$=i1rBD #}r'} ]gM2c8Mثfϐ0FkNQ.E|{~u{6Q,1 >wɑ{OMPnKc,:`UVLȢ}fLby(SzSKҦv¯Nmx8{`ľ;>fgђccL*kVPk̲UYeh Ja5_]=3ǮEc(!簘_#4˳>7w]/(t6;fA*?L _n-|5ʟ*Qj)\p|q-k~GLjg\Jqj%VTf-WLԔRjHMY}si0WsiҠS%:WG#<Ϛ)&fNȭlݧ$jdpNj'~1䷒r갽kvK|p%A>4q$$u@9`TM DjCb1&aWw/۳p$rC5P-Uql墽k>8kj$4@(^)q|4UH0A5̰+4@f! B4W ld6&Br17;ΊN#WˢDz*O\q0kld"EQL);!xR.*0$+֣NTa[ANoDR9uiU Hm 26$"EZdAsK:dhjQF[LBu2 < + }54։IQk6&ksi͖K;&uЙVt Q6ÝgӬMSGT* jJ !SlJ n )dEI+jܦm `u}HwU%ԸbǕ%NS ֢,€wmqH&%hE_.DCE#,He6gSw]&iBvZT(qEġ@7͖#sR!Ep)}"f^YУ90 %BBj*!}ɹy4nGW߳X ,.Kӣ k}-%y.[2,i[-,WBT)Za6c~5QxVޯpjlU%?1+]+`p-޶lo>t `4 -fŧ@W8/ A++4OYg!S+јWUL.XVOU85޵o;C2'/pK%aC|yI] [+Q2p#n7Or@n\vOl3/+?AíoկiW͆NaS.RC>l_q<&[1ML[,>zN\OHeD-lwqh7+֋w[c. ]M=I:V~b-tЍ@e7Xve(BV9*U4 =wfꜰ=Z.j!R[FQ4c){YP;QП1w )tؖwG; hG>'J:vgG\UKBTlsFvYjRY}ʍt63Jr({%{?m6f杻;{4Ʉrp=)4]^2OM )rlSbyڒO#0Ih 9p0c9p=b6ghGy(՛{Y sg4]-u4BXy+M4V({S~1}j/ubC@Ɩ QԹC;)[wyw䬞>ꄪ"UAӖ~b<\ltʳ`4;'lݝvyExy g_6xM¥9+x'_KHlڶ jglziT/j䐭"u^)eMCe[;߻֪ygw7&-;X8!` y¶,d"ɘи/ct&֬;sϰkWծyÛuttJRTUEw׳_{fu`][7uzI=dsͽs6.%11w6``ב3t Zop|6qrCsogFM3/1/0(Pа3Ó+(YU|mm:&FRX rIZ8"ĩDFt!6r&։ n.qwVX#'b,4 IDAT<Glo3ڌ6:,> ŹCiB{!v7U$E!o ?HI4 Q3lN0cFi|9G.i[yLj {̊Lƃ.6aPNզԪS4;t_ew]}爻#g\fFdNhidIg$΢SaZǀX<_[V}zb!l-l/)*err;̽CFVSm=L6̯W$K.:'`\&jROgt6TQz }LWHLdB'|4f7;UdJ*kzQ1)jjQÜ=}Ts*9ʪ@](˒5a󐽍Q**a5e1wO8:Km!\ArBןY_RT\VKJp)uΖhIdN\.rk=8a;mF7.oQF1R5$e|{xUԢjexM:9 (Ω##3S*PTŒ(4dIs--;G*mpxt#aW"v!7uf5׶USuR b!wCZi1Z3&&sY7E@L[Ӗԫ&ܠT)(H+ TǴƴ1֘Ecbjp)UcAUYPE'J }^=}bbQ~.(^I{sH{!ˮ˲j9,UsIiR(BD!TfZ3HE.؞шu*<%a"lbo ?* r!-Z9h&tCpEi6l't،Ψ7Ԛ3j)H6gSVW~H==6YMYgfh`࣊U)DBE,?3gΊ0Uo\zYE'wȏuqtg3qh!4I'WYS&* N ѻ~ም옝;ۂUg hFhFDT^Nh)xފZeFC*6^PIѺ/ (DwrdK9:̰MK(`#_m /ZW\-gw<+&c푖m}.G8YDuk~ixy`6Y8uVOK"bG=ixzc}^gq*+6Ydpl9bU%  2)[dʨ$n$iXMͻ+$՜R^OpR2ZO<(f1ɶӤBpك{5^npEEJrKhr**tȄATcN`z *ɿmOQ7wp ߶m¯!@o ~|Z?A>;(fQy!̻N%F=\c!G>u/Vae/Q(*UeF]QcƦ &''PX Z}f4Zspq$@ t#v.ϸxeT\ M1 ]?@$.aZ)MyʼXf.IMTX ҿk(\R"4 UȀC)`H/ GuSwwScƺI)uǏ)-ovb,ast3G2tL6IGެ0t))6§Th4k|mAk"4tӯ2Jүu-.X>7eSR]ϳ)zŘV0?B'Zi״ʧ4)x.IN"4M'8:*~9*Whe,$^+LjR\kTe)c9&m8{p.g._~ m9b]d2O꜄{uE\/r~KWؕ'$AJVPRG ټ<'\bۢhjS=1c)w1|I:n3YL r%@(%3FiL6j86 r7YEA(rBp>O^w lj5`۵9;3\2g/bY:~G9ӐzN1/!C^v?onoR>ڠ|I>1npv(QJ@.Y dM ux< τDojcu1.ԘRgMg($VG.W}ąIoiGnᆿ}6}/"w8gggڽ=NOOr|ok̽LY) y鲜(M{S*.6ie2|g-4%㨅FHS2w ;(QbUzVR4YSt.*Gp,iR$=m3>BǸ‘!FId4'ҠZjD ќi3WlM$@-T*^}I^kabjQBsA2Lh(Sb-3 yTl=8I7 bKJiF]%3U Fy? iV @&U Mtyq}=*9SUJ9W)fCosUm3[uv 4hBp2þNGgqqXI:5Ig&DMRͩfAY,*㰋PJL'~V t f LUjYKq!xZ%ZZ%9NgR*=Uw TT{c9c,* {ifeXVĹ]vxr:DrMo]---NPrAX%KJp2 6CCT%n` zfPbm<hSJ04@)%+(D %.k3*zdk(mspHC-Yȯ%DO~ -2\jk;\h}A%ĮjD" Z5UkA[PSMf=pbQ,Tuw:wg1 u7M2tTBHkZFudD޺QQ$ɭ>E@Y 5 5&IuS!Ҡa_el20mE# 3FIwh;h%jGPUȷT~"JTXd]Q)B;X!fq0m *9b)f+AI%o0ws7p 7yۄ'?IO||3|~/ KKˤrT_>uBßPQ E!FCJ86W>sEY|W-Q,VE>ZvQ8E(}◠Ku{ɹ,3^Kq٨s-}툶6(RHsHCHg qq* v$ȫW+E#:DO*xwTnYVWjR2 =cu988NE5mI]_bvyX%B&m6m&$}a 0R"VT{ ^rVlqospmH6m95y3 ʦBiZ<޺EZ׸0dIzndG&Neª[au@:F Ud%J^d%`q峼Y^yp-8^/\ML9sDnkE"=4l_߿wpAr4npvxD70Z f;Rsh34I.m(CI" '% ;-||@1`97797607 XJ%B,"ٜr:hJе/:W4[`Tsj)L=e5 WQ"T)B2ZWlO8A5M& 40S4%C+S$# .ZK\is19=j+ڌD]~C,]Τ %%jX,EԲpLrMN6]{ڢ0)UfYL &:э +4$sFkZ꘶9*37YDX2Xg- Aς6#8C$O9Y^'&dmT$i3WUӈCK:Lt &zFIw=O^S® ,fQtC'I]н /5 -nl6ENLŶCl'^a׎Tx%/X9?Fs#n}yۄ~g~0a~~M}6lmm!|_6(0:/?K6 Cy!c22>ѹE|>A~/uzΩQYso62^J4ij0`h(w\X\j: 4nltιHg4z)D: K{ pNVBF)5$4X@ l5fC$tRr\Ӯ9LгH:EO%O4ƍi]5CCUbG] B Kz-A$@"!9O4*.!.-8E2t?AHЃM6cK6ɗl^zk4 ʌۯsos}fusx|c$ Wsh<1Vj^9bkwlxW |G y) VNjoT_{0Ԅ-qʖ8a[F״'T t'p2t'f7`)Qjsyǣ=B 9)[SF;S9!^64mk IDATʳ|ɴ:nL3Wj})/y4JS4H]P AYC }N>I4G}~@%e[lmfmetkƸh˿->_7Qic"ʒ $n3R<5xCEY8"%PM&ZlkKM@@+y0F]Wxn7Wx6_G߸˗n&yYUCZ@;0tHDZX&3ȮhDĪPi3'b6\a](=yqd+`:JgRτD`|S%pܧ8X lAٗsB~>/kH)!~7no6?گ;G>>& ?#?}-ǟo}f&-V |.>"8kk乁ΨoMi)qb+re^!LL'$Wz>VJ$Rcl`_ȥ[aB T,ҎI[u?ZyK% B/Ʌ "!&ӥTLj^1UjEֽ:V.HeaVLc/ӰRMGX%&1CgG^=g|)Liop1KҨ* &G=. :Mڝnq΢1z\%}g66l`v|Wl) zK@0Th AJ~AhvЭR}f%x钽+X<^žGP8dAZ?jDg#vzζ}V䜲* m}->@Rf2Udv6$e:Wfscy||| ,6Ьi3JdtK\KFCZ'[;'(EIӘ44 0+N*g*3FFÚҳ!Mkưl3*; =ֆٯ_?$q  TGh;dAPfQ9>%}.O%c 6& )*sT)@UXX6Pq 4Q(w$r;Ya:JM3żH0)2\$2 dzIdzRTv%z\(B&g%+gXKcӾ`þ`S9g#`60jWg?y/̛+_*eYoed?{75.^~4G?_7p m__>*ЇЇ>{\<}ڽ nml#}MVjioZ%KRT|fiawAC vAÓKo}._"I-"NMȠ={|y>j9NbU=8=Fqo fXl+_5贮WlGq1+UIRYZH*ԇ49 'xA>І}2ۯqRHf/WMgoWPsb$1,b$r"Z'(Nfd/EAfj P#gP΁#/W)L!=:c}2j[ IlKF(eXl{k@(!qr:)S/5*MZ/g+z\W48.T\̥]NhcN4Ou/,*woS_ ٿd:hOuw|;?~77CοY&)['RJ玟Uj=~S?ïg ~|wc=|#z-rfOJBWILKp jI):y/5RKLcBff蚉ZHAfPg%L?]AXJkl .8"ՂM×l+\eM):#Aolf\6厏 dסdEE~IËIP+-.(+R#HML(uA) J9ȑYU֢JL*̮*c!Z!$N;,5iTc5ȄN&t Q0 .vЩ9icz5tpbC5D rD idG:yGzRkj mQk sчٍb\'@)n#ޘ2XoQ,V+UUSi+x% {̖>)^CSBeI -(JAbV\%b#C&Xy|c1)Lȷ(/1hyhyN=RͦiVrArL5]byk((Jb(vNBu45':,2ǬXFiT[ V25d1R-.mǮvԴ9R#HS0 17:mF7: JD%' zc lN7f;]pPk|gĚ!Ü.#,4PSƸbMU,h(%GHtYVc!W45,F4kvܳ#tM,:芽1'\E]VR qu\!,HAs,k53=*J=I9Z&尶<fH(a%xYbMMxʦ`㴫g)zc(!@[Ke!+JDMKN>ȇ:٥Ynjؕ%2* )!dJ8qA  atʜ}q<2Kjq2.p_Ω9 9X#˓}&IkY:{-{?zZ|r-|=~[W|M"lJafM`DΈ:,M; Oڄqٔz$+o]b$3( 2+1,)7C%N6)DhhQTKWnj7t!#Do%eIrY_JFq FsIJcBkM]0N>^~D{G5QaթL!NTdE!2f)RÄb 꺄]㠈;9vuZcoV%V}"J* ^p xk5BFH%mEY` Be]n O!TbbL*yjQ!"gIBY YIk II\È"c%t Ku:vh'RP} ;L cF\P%%*А(Eb&κ5I bV1fKf˿f˸)eXiXA1luml//V*5J]ԒMgP("g¡TbdLwkduUcnVY |Vԙf^dD eq|,\'r ;ߘ\Acc"*&*l: [%{9 Eq#K 'E&2VcJ -UQ#ք]}yJL&lI֠%'ՎX>b1\E pHfXX)[uf^SX~EFDT9ʬ~l>|y&\dv~uzrDk0L&sBKǴ CK0EBCLѰkm&VKoIѦ-F*3u 7ڛWRM]zCTb]gnĂbԊI{䞎&%_\?jwxˤwU{1{JO@¨w2X)2RJG?a?a&_yy_;\\^=?|ӟ~qW_?믿ΫUk[nu0ݏ IDAT-]5V:w+'&v ]&Gu:{")UA,TPl{K"!6(eUb'+iF 54)m,T)VB!۔gl7<(R gdyL#pńoEU e%N# d%ZSH($9{z 6Wo \ JDG!]HV R j–=GD3Pe6Y#7kf bPWhVQMHP JJ`i1 }lfqm=hB$b B r!ZsG p٦Va JSUXA[r8&AÆVR, sQ mF"_=)bKeR6<~Z. \h 욭"!-uB͞S! W)<(}Jq?H 0q9Ovyܣlav,dy"0095ŊzoN:Ct%e[05jL:SԨMi IJB%,Ҡ ,1JsI`svחtVC)~0-kԑ@-rr(q/HU uB 7 ѵK!?p6C|n3K:\S ԣvB(Hs0wXUyŲJP2|kIw;1qwj Q-xDh:JȞ-U묤EX$xAĚZfv0,J|'fs%I鱤ci ND9wA&4a7 )+z+#שsJ#)]¬ͤ: d92,`#gRjHUݸJó?} iS4Mk@. qSz;g~3?|Ǿ'_>)%?rZptt\e]~O}SYNC}0,jU.{7*S"HSRhBۘ\L'M/.dZcV+ފ$>l¦"f׸jv8mrszIqOhJ*5Zg j c2t6Hp2GW3*%>(s,Ca ,4X.+骅nfh~^h:ZYADz+͇qcvZQfڂ@ =&IhEؠ AsXv+LM4#g7-IR\}sF4 я1Ι &&$l/ϸ#O)-g7$LIId48-yV,=2"j 挪VBr]e7N-VJaeU9 ` 8b;H EVN(,.>M9F-JԲD)J=eZ,w*(Ju'ڏw#투46NVԵM{J6՛2v:Df~8+.Rc˱qM6YЪOKiE\aVYdε]ε=δ]Z#Ԡ l3)RTY` Q%܃rSv=yƵcɺX>+*}u5@Q B.j߀Տ)36ym<<ʨ$ . c=iw5δc [DX"RbVJHwH-Q&"TX1굱O[14Htt5k/ XUc0Z'&նnQL0+L4pɥ-":Ɛ7Sۺ]{)V+*jccgIO9f֑BFR6Ce~3ķ|7y_?Y;#?|q~We: :m.}\>i`kJRYqM{LQ 8mZ` m\R+GniE!aa7a^{> DjIP`. ]E9R[WT0ی-mV4C:k49xV(?d\XRa%],`1uoJ͟Q38""34&J^R<ֺZeT%:Sx]`qnZ+)9BX\[D*!7;m.*‘X)Pr<J-w3qCM`tx>cv`hh6ÉvH2c9w/رi6\}>W>W> x^ftn:Y#KSi"ǔmn IbQ.;nAXMf{D֒Dj2ǒ59Tjdq|H1WQsi8Q'^? ٽ{̃\z\{\zL6&)a+1PwL0جx^yWcZ`8jR!Q 4?`UYK6&X'IA=bߠ^+g>z͗}r-|~mo2@f Y2"" qϑw~oxG)PgQs6hvG|o]Yī\P7t>e-|Vx\gǂ* QaA5^eɫ>XK1e`]~+op31 ꄮMq(7IT/M_ # i؈ʹFvr&6 .M`*+Јg|o9I:W2VXQcyZEQ›g |kOĦXwkE5k4'C-rFp,"fVqw"==n"6,x5"1knr:I%t154ńR4T+*+, Fk 6aXWY=k]c=V{ Y~]1;%Hy֠4LjUn.^"妊CHsY6L z`2"D8LhU!m5gtt=0~ܥ|Iŵ7ZO]>/aBMHX"R3bMH`u B@%+tQY>חۼ{Nyi!DNPzD=\)7?)騔MPk%vHu{JwpzƂ*Pk\Jߴ|oZa`=[ SUA Zs/x{;=Ygf^~^, @^`%˦ H-Hci3oָv{eAgۄJ|mIW (1A%іChvG{.4Go<{{duaɰpDDElC^tt6}m;RV9ajG9@vLmbi04)M4ń&Jhlc^ ޛ|{fu;<L?>Xim$UHH|Y]JRk\"ϯ[nVeN,rt &2$ ob0JԒY3FfL;0yỏ4tmJDDm.PQQ I)Ap hp GYL6g!ZQSקXnDnX48}FGdyD\RZ341*oܫV6mx#l^gh07HRD 1vڜ4jsԡNP1Ӽ43+L:ucF65~8#,ֶڔnfbg5neu`w,7 Su֊"( մ*Y4k V TJ'tTA0ȶ`9 +&yV9 p]*E/0ԔHЧ(U(\mJ J;L&'cF%Lz CI(JԴ(bCZk"CJD Lg4uyam*3t;C LeJJh䡆\i +9~F cp3(#um1}#תBK~y*ޠ5:)sŷ1CC,L"C TUmAE[,5AQe7-P",MlO<)uބ{'{ݗ2j\[ҷpk}+,;"9I:3*81P)Je"&[W6iv JI">mC6(/3rBa48ŰbAԬ9U}DM@Cbl0i4 &AH@b"Zd"\\;^`#79i$M -$yYq+ukTk Z+\kgHs8S$5(3z򘇃DC2qNۘtjb $c7d;+./Y.+\.mjuTiPO=A؛<>)rlfipy`GEBKBaja'{f:׃>ˣ:I{ 7rQ+9x -A.T$QTH3F$IUMQ6OAS`7Kvz%}u@_T՞tLI\1S1wqDB$NR1Hcɨak3 Ԋw8e??epJ&uN;w]qdfmN|+6cMt .ҡ\(z!1 U) Zħ'5ē̱v3%1f3pc~&4{Sic"f7"1D3UL;j@1JhJ|eŮ$J E2#yR^sPThIfwTTk8.+QAEYR}B=`6" ]))0YS$$!-9b<VHb,4n-r-_޿o%jj[ݻboNs RdfX-RB'-o0dݔj\W6H JJ0K( D 9+MAjhDMǚ Kz\<6L9"XVYFu(m&3jsFXD"CFW $I᫰ P1X|u ,#&\P3 \N ?|XV ngvn)~3q1|4P-4D%LR:Ԙm6^31Fsz=}HȅEF8-:NNi4[ PK u/B6Y"spz{KZfR5Elr]9S3]Y&RdD'j|im֌xtƫ ؙZl}PF;l7E$[W7byƯ/I+%c[^DoWĒH4IJ)KjmrO~{ 45FB-H:.p@+">:TČkp@j~P,E݇FCiPԙF9EXЪfk]KFV"bwpWbȰRgGzڂ cW+t9D\XHÅ8>ŭOi<_DV ՈFĞG٬.P%\^H\"Ux aM4 m3?ߚs=$R2iR m ՜*KqGy™:FSl}*F➧G^\_7_W>Q4tw:N"hBkt/u"z{K=zg$8fk8z"p)w x{F-4Rj sJt" 0)͜u΋54h|~?4M~<IBO4OV : NO~Mi;QwD:uWR E:'wY3LRDS2j'ZF]4$Y񨄎U8WH2a4w(*:YgͶjanA$ e`P:ulWc IDATSo%\G`LqڵmęK*$rtG5jH;> yS@r`O-ImHMF2g nW{myjIHUXߊ+z(j} ݢMZ->*W_#7W%h,ZǬK2# >tȤg2+HuD7! ⋐;c̝=_w|h]aQzoz'qlxMLd* <)t26(^[(!e@ !fQT.o! }~3U$]j s΁wAUair( HWu!"d*X3[6eS5"/ 3lIQ$ݳ >+=CSnh:vAʚ\X]ie&byt=a$V`c"1(c21cIQ !- kT;sU"R aAQIQyDBba>>ChADXԅFTx!my m۵nԅڑԮTOb7Z{Ϟ! #Gh R4Ԛ$. @XkzFiԕζ鰩z(B 7p7ޭKKXZE\cj=cE.-rӦÊ#풮Xa7:Ơܘ+f&Q[;!3C:ڊ\Vt5ZԠ"AȆHsPeʞ19`Σ9G{&jmhR-c͟2d]wCTYW:an]ʍE1bP%QlӜ q E',BWwSF 6g-i69<4?"f6fwKgoCg!-Y,MIyxS]Pъ?z.7ΝPjO^3Yܒ>˲ϕ<&salj^گG &=MM[m>YNt$ʄDXi]Ąd<>:U#f} z&Ê2: 3ΟaW%2ۛ i8Qw$!9GZQ43Iv^uX/z^yT5qe>Ub)9.8~tCF M4Ԗ$Mu_C4H݉_jqQsY.;u]YĸIk:TSy4 `'%өAhaf%6h*XuYq;=`47c3 &wc>L1秤T<ձ e r' [|sDrOve(8 ($r\"C5\!&u#fXY.l@} KJvKd3i{\Kn0D)s4 S9fc}#?hPCvT20nX"1).Y@x,"E_`;z{B ]H R|h.aZVGɈwc؝颢ǂ-_?vgH<?+޿Ͽ1d? n7cVU\ beB=Xጾ{OxK 9G=ͦOykq6s"za(ENil؄y@q)gIrS\l~ݯ1Nj̀h6*xqn7wlesSs7>˪zh)gאm(56Wy8qoy}┛tk_q|ts"#+jC930Isw 8; .c^ ~xq nc\74 t걙N{>j=vĆRv LJ7#>;ѢT(Ki=Β>ҐD7 j?:llъCNX~Ft93os~Y#f &MFkaBphJw)*ʍAX(3&(6ڢfk3 fv-G W:ƠYlT~ZՖ{wi1A50ˠy?/%^6W!DtRcuF]y Ͱ˖Iv7d{|8d[_쵈#M_7_b<+hk{v)zQ^X$~X fjj04'mnc1q[(tБ`tk,+GV mGzhq:ej}fNO[ѮCNk&K˂SmM=_8Z koy"R }g î:\ߵ=n~g"sy V9&|GLp&\6 x IhhkĞbPb>  m.G'ſo_2M뇶xh̟c ?]Wخf -Uj- dr<#1uAՒpܺ"!S*pɰ Ni!f=(hy7BtL2!r&ZDQ8 H`Z9ΆdY8aJt-G%csF' T̺p]"I+j6w8 ` ]dF[l{k6i6\4w:ȻAj(b1>E:5f`n a9y[&[wU BF *L?=]t8Bq# CYZU^p,h>q. Rd-鶖dmmu,'-j55fQ`FV%FZT!u%ћ6kG^ yiq!2]Gv^M4DVY1hC]C\/H4ef~t%棜Arϰ'&rn3cHx 5^23D'-"-؉=Si8]deCAUig:B4Jr ڣ-Px*d(% mWcζO0(0))?L@Q dP/)zM^ӫW1.򸪏8N[_8pw+Vw+ߊpK+ЋIVdzeٹj]oG0I*kȴk<4QG{e#-H `RU;qP I"CRc"f~"ɫ/Ϋ/~(<I*~l]y|JPT&ht-: >MuAi5cZMFIݜaw!Ҡ;dx\b%=aw}m@` Hh=l6odxعeRݡ7 m'ȓ|; }\"NR-1CoB ؊'tvIm(OSgg46>JO^R!/mM6sȯl'|X>vG j]P;-ikKj *Լ`q%wɄlȁ}́u͡sŁ}k:ǩczCmh*쑽w(shn|C׬Jҡ.kr'{e#qu)!--ظBXaݹCRr8fZMdS7o.6uĉqNe 1W!W!˦锆v@ n0TVeA3w' kcM2qƠO7^3ΐeL;+kjCmhk|67Dh81b% \OaƪrN "횦Ҩ?FM7XqWt2B*;.GCdתX3X)9~ԉ+M!`fH. Il#]{zĞLOE<xb}dz.3cwf@w QVԈT!BV7IeDYqΤsý [$i LBvgk-9L{C.`C )mgC[t j1ލލX]C# bW[0{98 n'FS4tɷ6V5 `k%Xe,jǏ/+zzNwM7ߝim6nu&nK=}įcl24P4&mG ǦPh&Ҫq UBX|0&+w4>P>%(fd`ZP 8`^ꦢQHc DbhqP$I x"bMy$>`)5rw;6T<~W'okmfSt\PRڂ@$۩EgSiXJb~곩Fl!eix)hʳ-X׼#bu#mW[!XEN t%6#V 9GDp{ul|tZ+Z>p\rsSsSQWГ F=Ք6:^ !oLe|l'&l B3k<;{5if٘4ui.5KRn`M : Δ5O[摃워\7M` gW:gPBh _ mg|<?Q~n9a_Kv%BJҤPE )ti#u]:4GmzԖ2V)]frڜQ:gc6.oa]UBujKR9:x:K*2R/ñrnV+DnӛYVfoRM,$"Vk\LqTPI+FGF5ZFػ|ZEdyQTY`pwiI\#AᾌEr'✢&iͦAV 1D4U3qmܧ6sLiTB4*TPWBm(Nsx~d~Rby;A}M QP4BLzhh1V1bY#I1R*wSflkc#{؞2rfDL1b4j'E.1j}2>~w˗ޯ8,-6EM&7,{`9hXogĺϙ~=""nk]!;7ͩ;Az Q;9a+[!X dE),' %4=nAQژMIwf [޷X{滙f*43i2:9:9$[XqM~.~*낄(-1}+[Rf:<2>2><&s1qwh2cha'ɩK|R$^e ntcn#whB;qгV<5R낶fx}þ}eDTE#&\s@ )JwYĻ (IH*OR;cuF5\Hlt:Śznc(CccY [ 7 ߢ2AZY&t93Zm/XK,}b!ǦzU[xug׼M0( IeH4}6h 9-;$ѓsN$ID+ )c5yͩ2xC6 IDAT>gX>Ϣ7 rBveG\عaZ^9S}LM2!>Ҫqz rJ-W.Kr D+ v:=E4o5Hda~9۴jA1%hG{ɔnA.;'4e: /[Œ~gN(<ʰLi$Tm̦@4v5#ޫ'4#fQ@s%dXүY^ܦ܇#K#@DBVѼM1A=MUQ~_ { ba~sGZ1VSJR7uޡ&x+KܿhP(XЄ )v%VV҈ 0<}v7xu\{Ĺ9 m{B:Eu,nm΁~K5Z3x%efz,*բNj'Tf *O6 {nr]pUp]mVʱ]Rt53ygz`.,iHZZ$, ħvٝ t%OxqО30XzƲs1ǯ>yŽ=@tDf؝rh3L dAؐ,2wkrn@i"07rq}d߽!hs;){cu tx)gEYs̸3)M+8܏̇.Ejzܦ{ ObiJ71H Hq%j~IO.pULħ9Vմ QDw`Rmps'ڜI8eo9"T<.k.*H>΂w_ϹJ;1fϿa/@\21of%z՞zʤ%M*Q$o1\8u׼8ߞ 7iY@bR#*q+<>Wk"%%:w%yko~d81#{⛀0~{W'k[加(m A=<',*ܿn@8*֨." K+iDE%?:{?g ߊ > D\OجGimC[7-9iʷT]25Vzul CF(bw[,_ydsɗGBostaP">Zh4,DP2 ?0~sL1/*/m{wvϘ* R,7n$"%Ay%TZZ’OgI-_#D!2nC",f on^WSX+ĆR%~[]R2سq~WnG."N3~^=^5-ceϕek8 o8ʮ9pMr1eКݜZ8xOHN1u)<9`t889?s+=a9.. JpUL f^ݼG+@m OXC֭H&m$Oe߸t⏭_[q[ͭ?nǍcq 1ɘLLH.c~3dO9ߞG-B^=9O<->? oGOx7zk&<#xx-cCސ o/x{9g NY  erܭ')lp0a\w{}`\8Ln'K$G|`i ?BQp1V?]E CgG%pK~Kz(^AgЙc/٬X,zO㏟-kÒKP/lו4={Fg.r{ȝ;+ʪ,}#tm%hjð7В-TsN{\ęy}]Y]vԪJc= .k1#}]!mvd]R yP+z9k>N̿UG-VjmOK&COK>ϙ~a2h6ͽȷF5Lk>֟]7>g nd ԣ Izo?ᷫ;1^;"O}>g] 4ޝ&Ri-^BTyO <'f\1.wt؝֞G4xu_~Vh`ʸ}aXjXZ*vz  pd}CYXΑ ޕNB#/ D(D* ʊ wX]/5b /feƭp+T,.o/ y^4 9Aq{r_R4:W քĶG#,KIt8a/ռ SD˭ǭǍ;&">H -wq-G̜^2LdMSEK/x)2ȰDM`73//82. E'QBhK@U ֕U5TTʶF3l<^c*6g"£U²KD ' 2cZ]T-e%EB[p`_256W¯D'!639lЛ(wلgAtG4(w@PkG|9{Akz9C{VJ90l`6q`:J *4jT$6]yu>~׼wWt+*4Jt2LZfț3srLZehg(XfpkӠ bľKבBtƻ.F#o[9=|23h j͹/F#zXfݨXܢ a/Ղ27)2W{|taNmE29Al# L[CCb__2i];,6 Chhv_^.>B:&T܉'!dcsE-h;nt-qh0Qu')-R M*?J>G3~lg__ҵV;:դ\}O2yk>||(mi+;/kgOQFș$}6ǹ8BjJà oV59 y~a3ˆ,>zQmaP,JPnpB1X*]Mq2fL 4m J ^|'v4}U6(jj5].w̧П2攚 ՝qu8 ~P~Ua6ی'yf?#~( Sd;G%2pAZ 3x;#7L:c/ $z྿%TR|5֗ WghXZƒKeE&:TWg_"g7Gp b!|tŒ}嚁rOqH)K O쪬 F4IVSufhUWև|9{里Ʒorp^5ىe{p]=$a瓹 +'Ǣ2݌#˿gϑ[7.bh9ėf{nmcl/8~LK Ԉ kM9Iea 'cOcxچ6&Rn Wq&xZ ,*)P)p6KsV>"K-/yn|c-jL-ǴwpCU ɄmQ@iFi@_rL{3%^~UZqZ=e/g\}HtҼ4kA_p){}ysp3$'2,f*w0 b)f+Ҳawx}gO{ȷw~oxW?`8? ? XeTG:H-(h[.K\:Ć eۤh[D`*l' ݫ ZF48fGl:H 9{~w`°$GxGyF]۰ r(M+ntXNTB(j nӉqFNUsȄ#3&Ů3ʐ]3I(U,NKxVҒ!F H\%34B8RNy gY!{g}}Y]1f#׻4v*Jyi!ڸ,_Ft%Pau"?g<00B<3ĖUy*!^y5F1 [g嵹'eIAi,dJxyqt(rX_ҭXMT gb}ea a) UQaorkڥTL#k-9/HG+\6jt%]kIG]-Yd7NPcI:ĮM:4E45jՠ<7 3ms pԄG)=}[w*Jt LQ"D/rL2LD{}k]Йn4v[K-֔Ν7XœWRj=k{EjXޒvkd`ASAS ZP*mP&aR&Kf&LӪGTNU锥_mqv-q[)tqJ]10֘{nt\VcЂT5 W-6 :`vJxNRA4SzSв6^(FM#Тqh }Yh}Z@:UA]ciΒؽab]3nkKl5\P*enP殛&2l2C!.[ܗcǨjf)Z1 ]Ұʥu]|IkoyX;zF(4B*hjj캡2(u %oads.+|ִI5[z#;[%K[4D3stc7Rb:WF]ny$$GѐSX}Ee#)\3N3_#,<7j(#B/굎;W82oi[+s['(5}~[;FVWmoqy#) M~Ǚ+DwHuDwPEE9N,AjM?$:$:Qx{ ɜZVF+nJDK!L'}ԧ T^U̡rɑqA[wJ^蔥A95Z4B3bnR,Gp(:M#Ք) 5jl=~5!]m zKzIzbaqe9 4DjJB8yYrB:XuEG+.+Wb/&E$e7sE -͆H o mDB9׎WsN3N3NgEHsL?H;5@߉qA+pj.Q۬C{CKԑ 4:)숎Btg8BSq-sÈc` cCS$lX6[dR(V&bAZM8ZXNEFG]QꚀ-b_ \mQeۦ h@y /y[8N/P !k&Nlۀh4e4 ޷*? _>%"nPwɔ1`rE\FT': W*mcIy~qˤc35 3wײMaJN^ zy*/,_,{(R:'˺Α`-5k/0]-wjnSnTtYy{x_[cMb:钄-ꭆg9'63z}DS!Q)T@Ă*SVQT9(Y 2TFVHPJ )ѨHph>)ѳ7HBAq**h5VC ,fF1T,vo=,5C1%QaQ F(j]Э[I אmL6Y@\*H't]1cd4DU4@ nCB9gSyd jSc6 j]b =uؽ{l: XlkQ * -1%F7$El2yz[%_x"^V ( em!:Va/S:kL`q;v͆E`Y9_t%\u$-RA+&C+(lE Sw2Ʉ*jFQv.P+q޶·\_S:`5fA.Qѫh1!(lFɆA8gcؚ+Oߢʆ4uG=^iXY qÄa28; jTM",-7<_sѩt߭ H5\\5} ˤ"VHJSG[h*TPE.=GHV.EEƲ3\'&Q&EBW&hFͯx<|mߌ!?#T3H6ܥQ+: FŔ;F{0 \a1BYInjqbPSKPzj$|qF?ChZ\cޖY=ʭc! *4"\4 wKF9 h(%n Z;} ܆%a}WaS*F>E. K Քd}/t ;|T ڠX~٭;rirsep+.}6yxͮPV }vwd߾䠼`q%Uɕ~4cx[<*? -lѠwKn-ݜuzʦÊ铙g$\ݝN9WrڙfzIuɶ z[5 Fd͢p/2b*G̫n<^hZBP;UDU$ Vb9꘥ҥ,ٟ_1ٿ! L 8#s4G MhFE5y# FV)wTqמPLn o\BMh\CF!xT_Dkjż3Bo7M˂>ސt{Kl#"gpzP.e5Bhya[ Yf֯FUD ԒsSܵ$m[ )+٦ߍV~fc_9s9jsj%=Rϥ~O0 :55_n9=sAZ2SMVdMԚNMLO6G8T)0i J&[w\wiwT}cWP>C73 -c) >[ߧΖshxG2gG3CbOd ƭ ]$cO8ָ 0,c4j-Gł[<^5SX:aL%yba}_l鱠P;,!`b{xOK]rbt;$f'Tw* E¥QuMCRpF)G|t)|JXx?ӳ=3|/iudf&h. oZ^-gw PRRL!yM?&D99IPsTHqph) Zs-ߜ:Q&+z_8I\%Qe ~7G\L+&k;f{gyxYbaȜ1\Cd#ib1/8 R+ ."btY2?[4k/oEAŎ3 H$BrˈlA%񒈪R땡 MH]Az g!^ }lOlu47Ε'Z$K)|kSDWQk2 )''^Nd- SzaZ]š z͜,wژiǴ-:,eJXl4fn `_DPk4 ՅAh=p|k/ ʌc ٗ7jıqnskG*ɩ>bfJ 7Fs-&7}ujHx<9/?&~ˢ˧o KDE:*ڰc4fl|—-⟸$?q Ʈo<[O:{ŋ3^hsbZĢETԥ4BDŶЩzS/t' Bv )s$HS =AJKݙi)Tk PYizM+H7zbԨ.r@**bKM-4[!]ֲZ4[N`Vs])v>(чfU-&:(3^DYr4sҒ!OW| VNX)&  \GJnc$ٜ'7 nj{"PlP2H=1W>6ߨ Za2%z̩J<lf?ۏiz{vu==MbdDY%nlNZQU*O#.JKZy|lTMnfuYx^MfaUD57N!5y/l5ʂzXEۊQܚ4Ig\;TCloL1EO,YrJUi̊7zYύchF tdC}k~o_0- Kt"MBcx$CRnU&iV*%ҡ GM8LfM hV}cRX&Ԉ#."%Zؘ2㢿Mүii+R&6`KTHSz+j!-mbM5MV(IL0X_;<~_4?w#^>}'ܿɯگ1_uo}_#[na lEntpt gssɘ7yyg.{Ȟ 3Azh췹4cuskK*р2cPl%*Ǣ~!i_`4pF-؜l,g&3V?wxhoIL},rs|G Coj#S3ԢQn#lUyMb4Y-+%>u(44%&464K,/FE Q׈8p9]yo-34D^BJ6jfnE{Y%t4/^roft9]n.]`'vV4 MgMJTuEK%}mʎΛ6x%Zd]Ht `k kM_4"'#5֋ y P> 5$1kۧ˜\`TU* mA+bXBJL'lg옆 =OΒg}Wwc =RaQ9*o EeN#NCN;Mm>׼&,m>7~ݳ95c}DShmJrp*8YwR݀ kX03ޚˍefu6\Ի y0mȫ-Qw l"tY\DKu!y36sFPHjRS!TZ Ii6qb%)Oح. R7*)S{zk\"g;G]^Ǽԏt-Qn*+FB#_#J (Xȹ 5|mt7FC&}yw7Uo](TuEalġE)LqO<׏q q͐YFш>ӚuB ^6?<}o]bu>bS6L()2-M8ZMRϼ)J k8r8?!zjst䯙魶sPI)RR2V l^Z\hSgi)*is||oG_:!wDv ;wKK*|o6~[n凁/;U/4Nvq?]_r̻3bJg!gGGKwO lcsAdy߿7a[$j`ؿ`%p@vƘ,#J$n*PjN @?e_/sÂ6KaA3vK/1+3Lf\̲!_w?BvR H!\t$8pY='C>7=yoy*[a#Dφ1WۊGk#;52Dlt x?EU˳–Hl7nS>n'UF/gN1wor(d.FExr[h2@Ks 1h BR@DGBD[R!P%l TB%5M&N]أ^\XѣB?(M~yb?y?kV>Y9SyKdR-mŏbRXIJ3w;_F:(:T'Izft[7]ۈ$XP&ΦjP;cLTMϧx|SʄS ufv1*Qypܡp4;/tpY)-&rij<0-Ƈ~g?F #A,%j] K tSJT_yb>c!րԲ Zƴ+|Vt@iH途F嬨5V-|-Qmp1͠?DHSrXD y6CJQJ2p_6T(qbPBNSz:n[tY(]g]Qca1qю("_K /H))W_ bVU7|ѣG?ÐF@}[na |+ILMA@#nPQ; >s?C:i j[ mA$EZ$MN5~T @4kP%87ZӾbKt 4 tJ4 Ft!G%o=Vژr=FLZCCŰ1l`tv%2$z'&rT.Lz@2SnD8$O/ 6Np UǬS q_b^]~&5ZS#Δ=}Δ=2 U pTD{9ڏ*FLXc\q+gr5cx 6G)"Vc锚NYdMfvU{Dس96&<X|ā8a ^ǼT91yiEcQX=rl ?j~ mNIpT.| A𵐃wy 2L4\XsSJP eC4J\b,S\,EN3k0'%-}rg7tg.(? AclEp8GȦ<(&Owا9Mua^$"BP'} 7:*L?Lp|@2(t7w0O8V^`O3O2ws9QL} 6QVmˉٷO8OP,#fBs8푴Lb3ѫ䂃/89yU3}"b7Y%Z6*޾)c)#}c#R$h"V݅>vQW7NN-i6rʃ)g<̞~O ^M\j;>hQEEBѺWB,5E3 )@SA3A@@Z([FD]KƛX/SJ,nh%$N'!R4!c"3T<4>Iw"f-[g|и2d¢1 ?ˇr~ĻSgc~9t_[y{Iib۔B|nAbmO4MO8u?xㄻ<7x8==W~Wٟ_EoۿH)7//k!>?2ϲ[n凍/T, b 2baCޟ5{3;)XcmS~H!p\ ,?dظ3{fTLHU^@i; -TufB]VjM=fSuI+4s2<5R27r*שbԖTJK#Me|S$ąǫ숗^edGisOֶ({tAuKֆs ,jL(zM}NNۉqǍ0rYU]¤-2bL`E.:h[p=nN,JGGmhFHW`9^ .i>qʘ2L4,(iyK\ő1CT,6Zg [93*S Hd, dutyHlPΨ]0+&9k~Sg%^5+mXL 2i.K`6PlZB+s҅EnInEԴJN0$Tl$蛒bJ{>]0BE.Al~l 0|gc5-  L5Uⷷa$Ւ/-n(]XUmd5c&ƈl!ڑm2UFLE 6u^kBai[,dX:h3aDBt/6ԥ ]#J\X tQ`4z²}RQ( "HP0YjmRH:D+b#ui6yy_ e'Cε]Vz0P.ˌiłQ1a8'+lҢm?cѬV4%rI%2t&Du.3~HC] 'ęuh^Ah4dc^,cD2~0|+-gl_18_H")-u>Cj{w#aDNDw٠" +BeZ@ۿS+FB!f(<9zƮvueF7s nj7 iF 4:OoS?ɟo3?3/}ᐟ{sŋDt-r_\gi7l榆"٘F+5{wOh !+ARINTDxGQ‘ z7>2LtC29Vq7yhyElY$js)s"2(""6dMYud56JPvՠ(FgxjH[,(uy:%EE|%m& ȡ8ԉ]u{SgtzL!!b@!uBeqq0>eotpÐ ǥϥHd\2fN\0I\#D8Y_hCmBXZS5~2ZL}MMüae:FƠ1ΐ3q\;1~pN3v줗t Օ˪bi>u|O !H}mpV@BjOP; QF\o\^]]syA/X`jTog.Hjt}. ԪJȍ`o}^pNx7~YGj; =uκ{IC1A4Z&W4fK4">mDVeW/;JwIAm*5yҼm[+*?QըP10 03Z;KL-HTt:sr]cYry> =Adu1"P˂RH']ra |q쑖CFV5ȚZ 治5 RFw"jlgnbOƇn\x> 5Q0D#f7cVYZ'g>2.f7e3mhysQ#՘ih PcɒA= U-;lpRMJEG4%?=^qxuq.G4ƼdsYaXݔ㽧$4ņXP6hqAՏQšIIdL1|L%~#n0zk {f\'~alte\Q%e)2Jc\_ӭVTRCF K!4鶗qroX t'D#E"[??NWUկ~Dž|Og-n7jf1YE %KzbFlĖÉy@Fk宅h޽h6hNڜUŬDNuj.+`u3.8JB?"!]:+<)b}kcjZ#'B^U[w x[yR SXȈ(k0݌V>#;3:7MR\+HZ-:bEWs vO{|CqO]V->wPʊ{*Xr}-^>>+/_wKj$MffŴ=1e]68V攨yN$),^RV*+EܶiM5xVor:˫w80O[&8FLĆr6c jR)kZhVnUH]Ųs:VJi䕎]*iϏ:sa v}n—Dt툈ϊ+U.ω5DpY5~oƸ{Ŧ듙UHLf+ WJz 5}ZV.oN6p;蛂Q045δ=8CZ悖,V\P}fxtgFP7Xy Qs^SW|Yrȋ.p@ؤMR[B!RtI01EUPHhz$8)#fisrNnM rb@&ǚyzѦ<ټh/Lu_rnOG[Dyț{K?aMYzM&Sqde4=&4gQW#̊VsT@*"exҜVNߚs~Aj[EV%jR%NRk'<=1*;ᅪH%ˋx C#g͔%;fvY8#5)dsjr- kf{?A6H!oڤKtT$,v٬T#|P06S<6l3M2,j,RR*YeCQۍuRmWjI!uT5"5wg8zra)dl+m85", r"sm;xƮyPNkFrY˩K98Ɏ !Qlehe =F*ʹ mz&fZ%NPlAXSJP$7'UJ6)v#%RVIT 2JnuQJUw-r-hŝQ&Y$HSP.Z*!xmJZ(䵊*%-RڄYA&'%Ţuj]b)䐚:7fWApݤ1o  y#GѨ1)A٪4#MSȶQ&])A yBilNz+Zs%cZS(TǓ,Q#oȎ ϣptT9RBTJ\kC^w)q@jQU%̰H:s{HmeEGYVW4k_\:FUKV ȱ.Q%J\~ބ>cͶ*HUetYa&u.:jE)5Ja&)f;aԞ]|gP*Fg+FL\>!zꐋ${Y<;6S*$!A7ENDwU]Y6fZxT)r`*vnf s_ق`xa>NԲb+7s.DFA[K4id|t4 O5JOc$\NURd|54.;.;&5FYbs-R&(AAfC‹!ŀ,1UwsFV!V5B{1Vkg }uOO:7 '8'H^({<' "$܉K%i\=!"*5Jk옢fYN$LsxhQ0/IT1c_. B#@tږ*AdAh9Y&?iw9kmj]|LPz-;wuVÒeok6>b ֔KǾ?}- ++K;,^?r]%1AB8 cU(~<*MlO*f39OX+||HPҎ0(ZdX3lR*c퐕c[ }T{'"L ͤUUT熜us)Vow+h[AU褝CcM^'؛}¾GiaE:IK / ?]~ﳿJQHLrM5hdC֟ƴ BT)kPs _QhH_tzgDl.7t6'>F}`!1 cW NFA*u &)2((kDc &&%XfoyOOza~?+>~zͧOYOƔ_jnjS ܠQHZiiTXqYcnk2s]+A[FkK. ^oyXyEEEHOЌU*ѢMHTm=d[c&?q&ϙ)O9;NN???pT zQP-tʅN0N{{.cK&RAS|?yK5XV\,HZ+pA3:Gp)N@ǘIZXFzE-LWO--`ͩD[4)N;е%ol^wip7ʆ,cvR n+wƝ{͝sŝ{Mh;D[3k V"5a %-H1cK ^rl=l92\P.+ԋE)Qz%B@+!S~-%jQs,{THJ!B$<3CdԙB#jOQ{o/x/IZ8lUh%+I4~m6Vj80:?q8e,xUtC z*z7"[jߚ]heɉ_sk;J85d}4IeXqHdX(K0=?]xE/<kc}]Bfx|R6 Ƣ4&l CBPQFy2<@կedYm2^x4M,8?$d5L"rp#rmЏ61ijAHtݱpj|b.=aNѴL1(NHr(ۭTJI!\ qc(&l!':ȇ)hQ -/IyjG0[Ki!}mOh; d:uR4IӴ D (F$wȓiԢ~^1nx3|ϟ)Yhq >!m-6<2؝Θw36݈pqSFRp0KM%WHgYk;FRѨNQYwS >uy߾9}@OK{W Л4JS4KR \9@?NzېÎ8N9Vr@Ew |~A F+Mě̒9b!ǐƔK<հ+Ȱ9>?ʀ: ]I?Ip(d'%r@';$zkGHtnvGaj$%mUdXiNsS 45Ck& YoY ^@8w!2U*GϫGDבJkCĚ͎)IpI4]oLn#RtY Q`af6)R`? I鄠T*I'|2ݡY}!$E$2ޞ½eo wcny6HERZd+KF F N::TƱcviR 2AsCPA҇'w-r"u "Od12FV_&~?NN,f? /'YguOAL:a+*tRըc|Z,o'vMVg;Q; vxJDq6Q(Q)1 =.P5}xW qeH[$Mc _#-UҞ>}! f YIQ%{QI`.\8g,N(Wg*?.9*a?Q8amYK4Qgn*영'm<CʑJSHuTԍoo(uC\XyaOhvtvΈOj!Q2rlwN9T`3YYQdEַȾ0Q3oyM- %P5ʆ~G!.pI8$uDYa)1l\KI6(|coy8](ٙέ}AfZDGԹD{7LKƇ{6m&lRa!harO3Q'2ɔpϳ\TFe(TBl8Oڳ0)mW}"!m"aǐ2qRl/C5Q#5Dش#'oMv g10Nsi@Gx$eQVUTv`O錎HKzkBFacTl⊸tITw3H_ 4BUn=$DlԄTt}>)WTգ2dtBu88K$ E'=v4E[,%JCJKĈLsLX*AK$Y. >1sAi EeюKOe]!ݵg3-9=39[ G,tSEq^I1#wNS&SϷ>盛/H 1CHF_1;pv֏A +ou{27;+FՔ#ѣF % 5+}m8x-}@ tQz?c<07-i0o3) O 1Yi$Huت}Zp .e %("m>lgc>!}yK_6-{ (_U-~"dtz˃1Ic9F]&G1":w|}6dlH:IiQGV?wE?NjY!$ ["tA:w{4bN<8\䴷*EaV ҡ{%a$}mFL:5΃eJ<'btºl^0;[0p['nV\sQjgorSd(TB |$ôOZW!-(ao鏼(P)Ș=<0'~5IGLih}!r<)ĐRш,9њRe*>fra#:6jH1Lo-8[1Pow27e,/,Sb?Ĕ{8[.,XrvX0 XQA9m1Qz/*:[bl.W*IA*DVdi˷|X-oWpp}WS>/=9;O:zITg0ì̀1xĆÃqN#<,;6b,5Ceڴ''+Ma @ p2]rr| hX{ـ~, >'S}D[0 yxl: Adb",b"\Ͻu[~_W&JFl0ԜZUv}L t"R;|`A:蠍% z-)@ƒVQ1I1102dlS,)hj=epJO aZ8cR&딦J M͉N|_ÿ9^̎f>7 ~s' a# {y*юu^0ўtop{!+1fQ!#g~mx*ux˫W2ڑP8:ѽA,lV@1fpFtGQx#o.߳XNiV2}4×W_ŏ})/ Yꪤ5~Ƀ__P4AU$2$2R#xuD$|K'ZA4rW.r6pMױ{p8gQ<~dtd%X/< ޱޝ~υzOqL?%R c}weL%tW+w\߲;᱕5FPEV}dX8w1&xќ ,+a(dB5(ѩ:J4w "=ŐG123D YcnɿfmH6S*Hyn{ Y uԶA)A"L$qLA?1q:rr$pzpj]*5UKӓG*UzEhc $;Ŗ@<6If&g҂ꞋꁋKǿhICQ\DKL?L+E |T3 IDATC*:AmF#l{,)!֢h)ur( rH[*$Z P;tĪC}>Tʾwψ]av$X2m7RFd:G[J&}u]=`_8|Bz'⫖Xk#?e#s*2t6hNZ}O{)ڌ|J. VcN,eH:HCq3#{}";@xBQS_fb,1ʰf {b'T²bDEKamOOơX$*vm4$Y42]( /~{? /{KTj jRo2/]/D\ "g>"8>%ExDCd;~(*K&غ[tEVO=>e$mi.gwfjG"dAx2ZW"zE:^y{59@>]T5kl;0rgg`^+BE 찌y:U4F,X*g|߱=mw1=pq1Ne݆Q`H2ycv.nHx~@\BFN3<~dۍش#و;mxba\198Lf&+'o]DZ?v׌Xs>[ȢCAR:2$MNGN9lHyC;ܕ|_~m&ygMf3n~^H@I*=dI"EF>BkfLPtCkƴX VԶt_Xj6t*ũIdl!TYw^0OYcɢ4*WFy, 픃h(O%rڢl;>J|Үd_2-d컌ݚw19ѵz%VR,; =r2!7 xɻ=N?(NXc1 }y'^7X]z -h "ꌻO3*FbY3 z;6mc,H"tǺ>urSd!,#}GQK\7q"%.S}2[De}sm`(ХU)QK2!V>Qf>a6YninR4:P&*M;g3jS Fg+FJV&l>S8jЎAY C*3ftx`:<Ǡ@J!L( OƱa ++QM)t(d*f=^(K\ftpyu=c{͝zm{]vIp"]և%C'.=vdmKpx6/ /'k{uE6UI[E[ߙ"#Yg|}?-3#`/TkܹS2E^51IQT$OoGd(54uGS7t]H6z=6\w t2aSս㖩ǰ//䀞W4J6hva]lFv㠟tl4K`l6/Czi Pae& yc0.֌ =ƲUU"R=E 47-M"3 !ZDe$jL5vDMvc4)R[w ^[F|; -~;~99[rѪ )UD:m,IAThۿRƈrNS{'e8eNYShgubH))m+ɠ{^3]ms?.WUz|;c~s[&'&'?t3dFyVŖtDʧ]a4 x;ףϵ(_C0#uvyw= mM /m/ /ƒi:  $ qIrUaV<2)W"rJU%L8̐z%832aPDGIXJ8AJ֨7=}00 3ȴ]u!ܠX6 }uǩ1'sLVo/XrO'75:E M*QVVȽ 9QwHIt(iIS VjIl26êRNF&ԅ{! -q]4+NVtTAKIjUSsnkF+;r̵42.Tߪ|[>rrZhv|!6U 1H[iHVRPGJQ;KV4>cX['drԶ$SxFU5!nÙW0d^R*A DA%hJfM2nH B/ d8W*&LuE#dtVbzڞv@&LVɘ0N<%7Ř]>N-9lR~+vHKCBM4B[W F2V2V8eJyDKW4E2^I[qmO9N$H~jRSFRAEj0EF{G{D݌) &Iv(C0 YoT ji2P?O+kVZ EՂQѵ 9l / ?;%8a*hg7C>LR: +F;m$5)tB -"' zlQ }P`)РR!Q0A5A7A34@hP* dW yϱC|Cuɢ2vxFY'b!2I\k'|7$}y}Ҁbd5A+*ԤDKxDv8-)T\I% LTuػ=vrl8񷌆DPį;N'ʜS Y1YP ʖW"g 7=MQ702|fDzrέGbDžr|BsKBiϠ  V&% OhJ#b.;Ĥctao'PykPun%-2雴+.;$gZQ =pg|j[m9F3+jKgi|.g<ṙqq6"Ui3LX :[b'-z!&}b`O\i5FzӢ%a&# ,epCc|ڡZ-z]c&#T CE݄Ohѭ v΀F$|?{ּyky;g2Mm;!{nA&RBH@DB/ ZhN[35 99)bz-!r qűO^SfcG[<-.!ΔV9MXSٔ3,E.s2Gr^vvWXƖ~-=^&x>4y@X|[Gt\f/(!khjN ĤBN_ {Қ/rI.rASU6OSi6M`+PEFkݧS%tMBIdN, "auF!C9vc6^'_ ޼7>s޼z W!:D9Y*F ^[G8l9(+~Edؠ˨RTHIH*Ralt]ά,џlLiSLYuQ|Aqʗo)}=Lystat' Lnic$cDHj'ԃ $+ټevfdgjW<rP\Q#>Y\%TuT*Oڋu䠛)~ ^zK[Ww|۬{^o̻yzƷF_B?O؝;_#Gabb Xq^A؏=.ъs"-ZbK2u>|B%TȮUiEN1)ԃ9LV]ŜsF+aXuv4k ;,n9`N #(se^~w =|ywɲB+-&yQgmֲGdY䞌o.[ڈ5㏙\wHИl<=ntd;| dJ⚈ZU.vrǖAtKk66٢R XrRNbl\if,C}LGfsJe6У49Q saF[@wo_YaX!RfMpؖ.LRы?\K ,K ~OU%RUQP֠ ʶdRW!uQURU %(ycL#iµjN!drE&7r[!wDQR %DI$ujDUDӚQ8e $BJ^N%$I\HaH˽^rf(iS" 3곿Jy\I+jLhUk"GJs,"$J8FI)=t9C 7Fo$A$[Dv[#Hhoң9V;PT ߒ)P5˱ې fT$LL~ 9Qo.nK+ oFw*7wwI?|\5OI=6p 28+@}`1`c"j,w 6:&G^H)fq=ŬTDP,/J.p-5}X ̧mf6iٴMR:U"e=BšP5QUiuD8/zVeeXV**Bg|Gq ʆdsdcP *McAӘ4fs,h3 ̂R $6c[\E\Ň\EG,:fS1#IˑQ1="4:a<-],7)Phon0Qj3h@[8Ŗ S/OUzEaId5ܗ[23(1N;!1UU!Td2pCگAvYC9z ip),c~'7 fW +jt εh-jF v.ͶIEIlh ᰕm(ކ8s o $:!1]zYEn("Ɛ cC|`bC449oL~MvK~Pb6A+L*JY!2-fe(vFVhVʑw=H,&P.x8x턜Oadan3ٴdThoi.&̝67ڐX .CjΊ>&uŘ/cD"i]Q/n1{+qS5@s-CfJ 5A9d ]Hvq ;y$rU I-2Sf8e'MrNRKi7/\G5),\CPH#θp *kxG Q>853ע:daB"id' VkEag9ɶ`dz BΙ-Zf:3 p7xޘlBw6fbvr\9\9xm6kjι<4L)ů-8Ԯxqxn3b [, b`:qb;\vlTHL9ɯ $;ʲ??A׍ϥ{d=#,&.6HF\ňuRƘvۋbhiMmb#n MNq䌓W;yE+ T_HRu"BA^WHk:QdUTbEOԦҒPn=>{>SV|p{D7&7Br+I5NS8se*+QՔllC. {oqG:<>rG9;ڇfBh&ap[r}o3V:hn6;-/x5hWZEadB\HZjO7$Fo6) G8ق7sjpq9,9!e G|rGc$JMr%Dns.s&3JTso<-vbRԸ lLoҎf{`LSVRP6%2.^9(:58bKMp^>^%!XCK^kjO_+BmW+Jk]z `*.4Sгoixb?tp3g,&8X RWgQsQ"Q-7I<HH*)}$J~\ I^o,Nsm#FfU2_fS+LîtT=îU;!76ëŦ#ňf/dm3ڼ0(ڔ^5 b/|6~wHk^__q_==;}P2yc󈗛GK5Д 0݈YEl<=ucӫQv%DzMT!6MN~RVs,iB(j kƵ5q `G- 0 pkς'm\9847t:|Oy{y*S2]B ttB .!/|{$clp NŎM0H&:H``v'I$TI$I2I0PÈjtI% E(5P),*}fEIe^5)$M4 hK$D s@&0Ik@,wu.(ۜ (QU4ӽL([Y& ai9ձJ8pyM\MIo=ĹAiDihJJ'*[lg:"3djJsAhXlu]䰻LҨK[('MNv+V̀6G,"&}z_,O 5в YPg2AMBJ@@'A9 %.61&Qek] wk'ФG#dz9QQzW8Lе]E^Ťy~(`EzD1;IK'v5W'5Lmǁv;- ;T?bT^hd6p &՘X5ڢ0ӴCIoЊ99(J&45F3jz.h)[88?8$\1wYC7bK#ZĒETf4 T}mc.ة&].C>鹺l,(uAYHLID剽ث; Wv# C\$IDuBP*ĕBiko4O5^j} Z`I5l2E3؜+Cn.OxmR\KHv2P j)cx1F'¦I0 , !W U dR]&RY%A'T  Y %(wq?Ȳn&˯ʯptt__|+__:eY}??g~g>;M}3S;Y>ffsD|_d;E2)@33'Ofcpkq.$+9h\1cB15ֈ*<6Ih$T |oEdf}:W6.y:k|fzm oԞ>ԣ`P$YWc^OF5vn岻qѭ6t[|V4hAcB$@:*LW#\N]:6xK}(zfmF7ͱ]&z*PUohԘ Tcx&5 ?&8 NGޢB?v=W> ;k*h2ӛHJI%* $ʯE텟'SVnzZ !y9Bwqw y_ _* ?3s;өZhvCJ * g"1w8f]5-)+р/qӳGR>&'W%&2OѺC0*o`T |1d:݇~᷷ G d $QkP!hf4sZ̨䴺)  fԢf!?=CpS\ޜ9tL>KFc,GO3,CFcD1U( ( 1U2=fً|YTMT9! o'" BlT|ΛG|;|ɻl.}g[a't{7<~AvMw<@`֭36M>>{ONz1OhcZ6coȟ7gȵUTlAks у5 Ϯ t6TmH[zYg^lZ%bIŒ'+^~s'ܬ Y yTQ#ўxi=fd "Ԁy1-#6"eED| e@kWį3~)~)&1&161ʧfEDlA>Z&#Oٌ>S~$z ?kBXH>ՀQ1<&Q`碯S[CrOeײ?XTS1q@Lk"L"LvXLiaCpow^#%۷x>%sK&?%y@U3LRScxwzQ C8r0-L^u zPt&f6`$ W}Fـ{~S~&[7 m>`4 b *[P֤}OHDi j +X@-rd\N)?ybJKu\{!|ߘnjn.tѻo7r#) ܈.Ox~@$ywfJU)ЋCvEVT W,*aZŨ"C;㇝M={o|گIKKpuug{rr=`rx6r% An!4B3ʷCmeNd8bNB2, %٨Q%-^cy!cڌ:˹n6rV(UDDIZD7Ұ4sC!BKIA$$W $dDWt1)%;nl9*BUXZosiX6\ G%,xb)JQR^k}tT]L>iyErOǐc%~hc6_[KuyaC:\Yʸ)&CnC 2]2{,s*CwQĒcNi&t[:՜ c^OɊ86XuǏJ[W9nASӈ4ohňQӨƪp2>0>h h:IiS+ް>g`X[r_^m%# ?$|ʀ?E- ks˰E]S_-?_И5\Vd2ljb/СDBWPW yQ>6HYn a,y$8&e.KɲjgePDJ)HҹζXYL+{IU'Z?ӷ(P7 Pޏ1HqRVF餑3Wo `XUB᰾Z4Y[-m&uEą6/(SU @ lD @J,%ӜlRTK?}ĨR.F<Ԩ eO&%VE S64ʦFИz]655͘Ɠޜ>&675'"Uhg[wc]ylcU=zI>ǒ !CynwqwMqL^??k_[O:z4Oe:c*=軈TS\b@gӬ!D:W!PIW6.W\?K5S6+,5mls}cVEqKZvXr)XJ%6 &udkۧ<%#ܞչ>sPǁ)h֔1g3Y}6#r^ko[<{_ې:[Zx,j1{mS6q:-Osm\}\ߦCDUs*d?L6||ѲNJ:z􁆣8\`xan.jD^qzɃ 5Nݠ1-<+6IE:6m h.Xcz31%*=њ fa+;^Ivt[-]1"4fU[GnjrɽqId\CGKۈp!N]Ox{ƣsiJ+ HEHY}Ooz ?XН`ޏT3^}ŨMI[#LP]Q˜1zޘ6]ޏ|qyzsي%-îi3ul @OaGRL.4|lGO5LС,y8Ϲ0x=aXMߵַ|4)BJ+4H\6XeRPB$B "nekdJ KȢD#D@!GN˽+B^TۘfZb!y:!^-+fAa0oU*QfS2qb,IlP2! )/[9Sv+H.\\-\^0 +5C횡wEKhm43N;蠹 ɂ8P mq-!-K+]$Pc_:5AiB rCP))2]j1M\||x@h*TVhJTT% q`wq;, o+dнaй_|(YQPf;=b lAxX"?(izsT%@f%|l$ϲwos}~?? WhVU}/2;~o?z;As~NF4~gp~~Çxr;=c]_!~DjQKM@%R%V.WoḀy5Jp0mv/Xog8&Ol؏ҋ$4Xx)?-kko^|\F=7Mxӂ‘3RO -m!n76W7 c嘶5]0T88R/9{XٲLӟ}{wdd# s@yPpHK@z( IDAT h, &8شCi$BMj`(/G+ ,UD,cǍ8?ky'[|C~7*{&gPxl_]`Or 42KQnފBPegc̋%S$;xkxvȷ[~IcQt44g&؛XXkBvѴv ާ0 |;b=~)P@ryJ3Gtaࡄ؞iKdT`%FY*A xN|-6u=q|R+qf՜`) $%2- M(;cHp;Ý szN|F'F HmvHl|(b0A(5 /,ڦݨl[.mG$lX:۞4,]t9 WrI$G긤dRtyV SImD:uI4~^n0˂0; B(CIA}\w(M )aTESg9r2O\Õ5d2ۜc>!Z]J$$#1DN;S:nR:C-DʂLZE&-\_N .Z6FV"+܊g7enrFz*5*' AJ49%ћmÝк%jP#Mr;KMZ cUQNL3덉+/0ԨNA^۲f\.sM譂^!cS038BT(Pbawѥ@5gbig]4HR{kciFr̷(Ih^Pc(QVsIq^bh%^I!O,m_NTۻWz$R>F#43Bo,s6[Ӕ1"F%PP&QMZ@t9m}N_L2&B'RŲn[誢V]U"Aqa 3AdAJo<ۺgO bQِ(CG?O?g?7^~}g7zoo3oo}O!nAL}ww9ʲ#_җg>|>i>O `ٙ1ؽb{ۋSϤ,tA%Ч#ݮ P jhdl^+AZ'bc9.=K:ȥ 'N9pjj-w,SgUգlXwb,/ڍ#p>rrB.X>OHc%p)ń|n!JeXVmehvEAJRe:ڬw޹Ƭ}+˱αimVY쯎ٿ:aBDW:c<&/ bF9+{<>g kl~ߊqO&r#`;^eI,|cF%DK䨤J!'! 68lO"]:ƊFcISL>>vl6_%~7~]ߎ}xw?j>1yn3g&_o=:>7p~Ngwsn?]4 &oPF&եv/#5w_K#57h8vQ6eORbO1]wmof.1(I'I76EdPuByz~wrz{#[%td*m.t!r%"³6xfkn\.G\c;o#^wޥ]-^> P:cw:WN9u9YRkFZbjC#4I (6DTԀ.k qSZf@`؝қL ^żrXfnG^N9s:Gj{w`y`l]0/[%u%62`h3{ e!0ݜK,0f`N5 ͩiGNA߽.rsg3GX<5\GPm?U#i:Zi\{wtۼwل;ᑮ -.>yץ-i.hKX1Xߦ0tJCpt #cH8MXɇ8t_p;xʝ -9i}af%[y6[@(Nihhg:gojDhYMQ{5+ǫRTi5Y;v[~9+^-~$'g&dqI,1JgZǭ"V-x_|oO){&iec%Da?i< 6Scƛ|Q*KLэfb+4X 1+ ʒN5!VČ6ة/ٿfiAfBrycV=EX$C츨 Ϭb8m-iQK6.N]GdM}"BR+r(¢ATDec[]g X&"+F9#y;'TVeE"Amix (DGmcA\ڠ@W%\&Y%1oW LUrU>*C A(s}}ζt4 C|>6] 7 ^((y J*Pԙ%TW)*Wu)񊄶\1 X$MX3<+Bj !)6ڤ:f# b UЬ 9~Oyl؄'.cG u^ D\,ʔF%c[)cʰ Dn S_mK唴(-[;egmhsB\,ZMVNj^Rߚ`DG$Rr(+D-~!; 3KbؤCGQc\ԺF. D.KE|^5 -SxNDj2$vl]d&ٵ)m* V=031Ch$جi0QXe_FȲ (`!Z$XZB0( ($ tH%ilQMnTdɆb&Ԕn=S-)VQشmщט6L=*!qmrLj$(g̠XxAl6bc6<&eBϘPC/fҘmhyIіJnW)"`]SgcE"|^oc. L 6 TIiTz-2nP:SB)*$-TAjv6͞\Sި909H7'J ]V +e1yxJ )0ehWNl;HۖJU#oC+ju(Dj{de,<ֳ&+"!MJMP I4 jC37gnjTt J[RH4XME/ZzPAA& 2@:HnǪzmj\Pd"W/Gc/2L'C)]+UJ%#uN}AgfPh&ASk;1/G,I*2X-.fUM$,BHkY݃Ra1ve+ 1Κ+>YHZH#]9IYmu~-'>ɿ~??_%|' C͆ >n~xP:Ky!a+]}Qܖ<A@ #.qf-;/3"rMPmu[hZMeuL-͂f^fDg.>0ló.ө͡eCǂ   BrbY*4v~4eMS.Â&*iVwgP4]|F)ŲxQa|t2-I3Ig219*sȹd\Б mN,g6ar0d__R7 3cޘ80Y& L>^lʀVaLB mh,CK伤5[Q[ 5al{jO6F'טP EtBlBlNtZS Zh*l?&\}B2H& ^M1âSUc9*Gu\ԥ <†Kp) X]2R`\_64vhzIԱ^y~wFfƔO".R銃~rνs_a+~/r\{}>Wԗ߮R/I+TB TAٔlD-qDc8NEFDJ*}I)@PhxiBb񮢑NJ[N(uIK[i:k$,S44vcN7зpŤWI0zDd9"X,/"ePN(f| uVߊطyzW{{_u9A#,W6EeQu Lp6)z ̠$ ,fAv & )rSrvgy̩5&{P3zDovI-rF]k|wMeR+ (*n ֈQ1|Aq+s9`e6X2g`]/Ne-pYm.1>2q׊eE,by"7-k`Y!hult6`2sZs0mtUaѨ^|n`Miu]CO|??Çn~x$|NLg 2oCs;D;e+b^ 7IiϹ .\Y*Gs&jJ]b))rr|5V*Qt>t582a%3D F/kSuR5EOy-~kSzŔnYCrE.iFw\v0xrCbI Gt1m$K]'R.%nߌq/S>g}Ňp☱~IЈwxb轜u&Kp Yj/>r!a1&B2D.J5s~f.ڬ&o»!4ag \/Kg+4Xt_2|pzP y̅-NoqH20Vt+\R%%Tx5'1Kpk}_D'#nUdDku7BqpͺpyT>~ٟWK_R/~/_Cdg 7p?¯2"hjz,O[EyjPc@eRZr2V z[*eQՂ2ר |3[<Ohk,~UHU(C\ TY^M~Y32 &t`g nOs'y+S IDATwW].|M;_ Sѣ-4m_鄸\0$Q fc/_pVp6\ z0%z#}ޫ/@Wsl464 Aqf 4:)R*!C* ͔jj+B0 (q҄*ҩ)mɆԴ(L4[dt0kagO2 5eu*Œ&+"=ń,`"p~ThiMjMbxvg!r ^'#ֈb(hW/oI]ԷIMYy<+Ȇ&gl]N>rxАkrkĢHQhheM3\Н;= ';''?^!4W@qII4ڡlbe&:.S%:P%<+(ޫ 2)([`,6%U:cH~x CW&)mB+ S &+,VtYVYP&S"A6Hz.Vb^1Ծ-F#-hf+T,7\}n󤺃gl ^gC0ZfF%k|B\`, EKZ3Ndi=FT,˸ͲhLsOp3P>jTiYH TMɟЎ܉҈BhkQr:]>/ )}sf9/TAumPD+ RVLW_~.#Dk( C45[Z5X`]717K|ƉYbO?79yu`RdAj|eh-^a)]c Yg.ef)(j_LC3up ){|'kʐz3R%2~~~G1g>×W*O>7xu%7p ? HQh^Hv֔{%^FQWA92(فd1jrAW$)\"[ZdI>nyCڵ] ;S ]qt*@ق3H?G_W5+f(ɚ6fhM֢&YC%(A֭{}c*ҳm᫐U33F@Ai͡XB}m1lA'9rT|V˼CI -Ǽ35Bgq]:y+֨i5BcK|;4 $jQcN}NH HKft'3/>L0YM/c\hgT f2Ӻ\1DQaHqNo[bud0/ `Gb|Oukk4sZa9Ob̺s|JKp1l 9 q*{4k¥ǻB*n'?C KtSV^k1˔aYwX]akUGH4ҐfL7jCvȰ=!fR96' N!Kk,(ޡVho -V2э})V+L?NEt)?}wD=&yO\ԁ N1(D݊P[cuQA?^_ӟB||+s_n^7Q8G o-iY#"k܀wHI䐄z3'm̛MNY-uj#:=JizkdH dsXҒs+5gjCr By~k֕cw|(&eפLJaRHs;3LJN/Ǘ%cx9[1q;,L3IBP`cRebaR\X&&Y$C&,dPRu/=0Hv Ba~SLɥΉN&bY#.gShk F F >z+b"+"Bg~pD`oZfk`orE2"3L2i s;<\Yd6:b-JpE5>w]T5 f`0fflGz3!3mwO*Ɠ3Ws|m]1J ^ 0AhkED[[WTl> &f@tHmb"n7H 1Ҩ@J\bF%qu 0vK(.79C{ HU./:<)ĸ>)*ḵygN^IT ߡyUqi)l  )s`_ 1_XڜވSwUEI/ HDGbFH ل/}^0]U2Sͥ15{(SP7auX^妘Thxlhh !6hc2,ՐrķʏP:!-NM/1fT f5!JME[ySoIF+ [6\-Nb9ꂇ;t&7^A+ BV4%'-C+y)|CXnhBKY[u&s1Ã)wS:Ea1ɇÔ>v# V6 ZrQZlҧ.cG+Xsp);ԩbIB;\#VŻxd᲎#5@A50j9T1IBy Fp 7C[K;5^O-9!&"bM,+tH9>[9c.x}4 br!aoGޟШ^.^ڰoD@Ϝ'r+}2Go2.y}Yżd.[̽J 1 ?`+^FD4 zO,;q <7h#l =2Bⱦ͔ublRfC|6I_m{.SbqKaHhzhAX67yn Jvѝݩ){: zt{5ݻov} U ^Ub; `AV1zL{QcKN_.;;dwC[>^14__Hqhl&@8xR_1bpA;AK(6 =4c 1p ;_d4u[FWt 7??bl~SsҤL@ ~y3` nύ0ꊠHqpN+ 8g|K&⎽>{(Hq'1TbFvffL2f80喩aSh4i?O;B6t Dā>xK5QB R|[~ 5._~am%+ޗKN?U, apt ZpQrMSd m SHmե]S?T[!fT+杤AKˣkW<9_,&oI>x3z#:Aޘ8Q[ՌrƠZ cFo^)9o24u0A TSQZnkhpp9`o}>ϐDiUc}ZX~[,66SwU=Iʤc,>Et>ۢ\z=VĵQ8FP,q/J?ٛ>+v{82!{2p,r^" 7p2cSwD6.[`Y9VX eUy%3lXU&ߗUhu:QN1( 4-x.&6!;W+5T A/Yr\q\1Hq7i<7oV+`[HgڷQAi\UWQ DPA'Oi\>g>%1]D.bGrQ77OH:(řf)$Vm%R,Cf5 D~b3|~v۰uB֜uȚh{^Fx b3e_ⅎ,c3{NMcI7xޛ0wZ!J([Qq|ó#6y|䌾f`//=vc΍46z}Sx2 e0JTBR"A!?A 9{Nɬ3OsMZdE4 s̠тӗh?Z=]VkKfpY΋7 '+L;* ؃ش MUN &#3b@-9ߝ"w ~kbtC/O.9}xAc,ƱE0<|Fq,y?65͖y}DZ+)Vehpʣ $MOi=)+l+G 5DB"Yj kOV\Jl,s:pO+4@ ;3<%l#<<> Rih,zջK f'cGيlEz,'=>KGHOiSbСt(`Dq@xxaۉ׊hIs(+1UD^ӵWt5r``_`JLzSM wlÀ}ԣChT6mƙFduLPyb_m7VHDGNt^xvmq %אnK:T!W U6oF;(]oMo~ `Pǒ'y=/y3~NnkN5jE$G++R$؝G$Fu(hu̗5'Mgts;<=A:-OfT#YHD+fѝ8n;1^L s/Ɯe5-mՊq<3BfS\mɨ^" H0 w~FWkZөNIz枎TDsJn1K4ҍCz\tƁ~K2ѩ6<䜮km[֋>X܏(M $e;yAZbU ?4F8(fQ(>;:* ^țl1=@HBwYxw- G4FCe[(ϤpN=Anx/y~Fm3FDZHzRoK+D?7N#<_+t];QP#dtKL/q I ? g9Ϣ<Ή}H:DLk$94L֭#h/^,{_ ^ɇx? bl혫= {BRy0 OK,0E ]@+(pq>dΈ`HC5aw;-$۹dK:W6xC5!Tb? : ٻIykN+ʕ*-HʉEZDXփ6'Nzٮ ?fa5㰘1MM]({!h-lg @dmZJa^8RjKzgGؠH aOjӹ^s~oϷ_oN36L-Sea4w족"[3Iv`ٍNIBQ hjw]YS63^{ Spo/F|E?ïѪz/+ܛS8enkbu󫏜_hsӿ|>AOԾ! G '.h jGgѽr{̫G{<GGhIDTPhѐ "?k~Ccn Fyq|}7n֚q B:TMY<:nYHe7=Ið.2Cl?:zLPyGW?0:YWJx~E2줇eX}U9d_؋ } jiP.lKnI*9ઈ̱:6 Sz+[[v[Ŋ> e4kD-]5$`9b[) wL됲1 #wX~B*J%Q,lȠJtFR|ICmHCEX Zk&rX̘4wMF5{l۠CxľK커B骝H5^7;H){Yc)cw2NNHv욐]vhH -cK }fUICR$lkFg.b~/%mh)l@j„ʑߦ)[&;&I doG}oAqK1d.PEflI3pC8$OdmO+Wj #FqHQ#$jS$UESӞT#6BAȹ 1Ba 4!@ЁN=a#;!ؚ>+;&EĩRV3PIyΓ䆃hY3r(g_{UqIQ*xo@h;*҉kq(1MjA22IM %CJ"3\Z{9e߄D7R5 IDATM.9oԞP] DNMX|dԖF-4*]Kl;~,|jMR=,ɐrSsM8_\)&F^{z dɒI摤.I쑮Т .k* 2;|̼q"cY)l80W$(SLHIl}noyCyʵu}L1 M5ҨLIjM첫Bhrr0akXU6[=dҏsv#ʙH& .q)ZzNFhVLޱή㨠pM @O )'KUEQYAXaDԵ,4R,4TC?yo?N''w# gݿ,mxu'!}^}a37"F,}7WWkA>5ɦI#4M|߱OCQe4` p͈-$j([1waҚ8HHQiqqyfA52n/"|sɞt`i+f2K#u="Uc'0Pmp؁e]w67L[mBZx$% ]vZɔ7OA!"3w/x\4 RKRZ@[3V IqY{N{xOJ|+w 5K1&7Z|ʝrY2 {>t9 z})ΚiԾhr0` Yv,!Q}Y}γ9gs* 3m2&wmtIJ2LbiU$r JkYݦg[Zp1eҽc4c4gh(4j, ՘l̕88n4TSI6+ǔTB4%m{3>%${ ٛ!fiXi'OΙnPYy`ezbzb*WL; /-ƇHbxb\\q9W<帧Yw4+ʠ2S ʒe/c1w!52c3hRf;vXAF/_q_1 98x\s_sI%uPgvn?DfqCP&Uj5w<W,11~$IrœͶ/ꯩ l̲< Jaf~˶ 5R(r+NN|o-pChlL̴MLZLe >w tA74KQ _YNpȍ}k$hAeꊗ|/W"BEө:Q:SIRZA)1HlA ɫ9Mǻ~S=i,scq[̳l"\"+dovضM~Y*S';w_㟷7*BH&] dK QrP͐v ,R͡:=}XK,+'"{OhGbln0my"..&8c˒$TU+}HhMbc#:g9>S+v ULDC:9_iD{ÏjpwMqpp{n_WFkPx&#g(8g 턛1Vܬ;$ tmlF=Sϧէhr.Zw\ KDg}gHKωy.H<sy0ߍ(o%̠{z?GoyckbdfF%MkE`-:K0 ]ґC5#t Vz]2(|QLt2f\B0OLjD6YilB[Ō'9W=;1￙p8ӟ1/1~7#} yvSҍOYW ߃-^}%{W&lfx:0?PyGTeAU;EpHP ]՘d8T*U r( $v)6fY} i$S㖾&,JDYZU-Vi!7۠9mNɀ%ZS{ܑcPW#Э 0şMV+JC#5L"" ݩѺ b uj ۠Y5zA64ݼՍNSj.Ma %>+Ja:*B'cK#$썀(V7+1ffsQ~7){^6o`wF8#g2\ ,*#uE{3L)-Ak&og݄.9ON*rvts&ǷL_޲]Eä?M'FwO/ Fږ=dCzj=`\X0RmDXݜ1 NU<> X#m<ֈS\?So8ry1ˬOp O"ƒc9JYaq73BkB,E{9fOl<   a94>)-c|-K-Lcm;Wtdmc޺9Θel}Aj<=3#jj̯Տ8`GX*^A@HvzBJ4"en pU#-l$yg[vxlԖg'؃i*ҍ˵}̕}̵}Ly:KيŒ-2W<Gн XB6M{PF,j2aF`Ђ hEw-0Vc 2A5(hlx嘹=fdDvdYdEYt=l 52ZcHGLmg66Ф+i,(@?qQYy9JRKIJ j̦j*̺䨹Ls`59nQ:2ȕEnsYV軚rOޑ:vqIц2&M rȹ0jJ ukX*sߦ?E0G0Tda؇l;٬5Xn'OH_lo I:j<:6;bpǍqMhU7[x_W>`2^ϩ\ BFa3۔:汰\\Ň,>IrAg|:ZIֵpkc>m;Ype {-Ⱦej_oQ&"ƟP$2r]pO =77kr"OQ`- D ܄Ǽq=Yu΋NW*Hw|HxuJ =A#՛2\P]:ˌIKR^-Q Z!~}Q5:rؼhR.Q⬁!m!~mR&mR&}c`dY28Y5FWtf ]c(4'.iPZe o0WG%mvNBTJDuDXń͎ѷXZu-)VE cI; FŚvKՑTl׎KV=$;&=Sq#Hbm:[=}w :6t5o,!N@12䖛юqgvlnO'tO1zj2H 4wH cF-ξh\LP&4J'}9;s}.lIF>ᣢ`@})wt HB$֨ ʔTD *1 Oa Gm~1A3v'K@0G+o1{'پd]p׍x׌(L\n&378S"lm=Z< GyG~`=T_W #jK?Y5Q`[)u}VcSIAȺ,KL*UZv11Ř1GI :[Rh$lE-2z1F6m,LGX*'S6ic )Ma)M>+ѭuo 4IEQPev 2Ztcnֻ.ޣt%׈k]S(sroQ-M[ڑRtjѸZ'@!ЪUQ8u"9tՈ1v0/_6 \E103P v8l {s;2ΦRv7vIJTC΢@g[vX=ɀy4^H;x#[ږDɀt-v3NȬCXrx$<+1N|h7q~b-eKU⢢"ۚmG ,:4N)%vsc4.rSIgˎ=GCD4FFhƘF7jI]IZ߬;ot*R#a^JAB39dayATAKʕAdCZI6)9 '}Es||RT|(eQ3 y} `7٥c|:jO_m4kQ+JaPV؈.R6"!2=0G$8 n[unFU-))7K &#/o$=^D؋ )rjJZ<#KK;>uGjKKHR:U,I1#yʹ尾᰾t%I'hL4UVTA,!a+,bC^:yͅ.%iϦ${?uT" Q 4ݬͪ1E%S,r U j4HmC&Pz%c7t]2G|LO;7w EʂJ HjPN'зX]znDt|GyV=/W_b4%^)~ޛeiz߶yg:}<~8]J*Aݯgt ʪ2c<񙣑F *趻ºqNۯH]sH\Dr[9E?ϒ Xs\L2 K/ Ҷ4}cIv]ah`w-1tS3k]g#sIz >?|M]딕N̙@l++E S.2I~!-F=ѩk L9gttHi͒AR0L9m(MdsP6ΖcF9FV5s;N/Y |eINJMM4M̴ ܤMTE[. W*t|Qc7Ui 2wIk-kZMEaqPKt.Je;-9Ni&>u}DD)W9:lnÌ ԍ-3ڟQ}wΕ81(q͒Ni̶DHɶfc+|*`ѡ #kMq eީx=^=l!0206t(PjKA [~ {23&TJTJX8N=Hu5U2 LաN:tظ 1)RxG( (Ds[4A dXCZECkbC t-zS1|ּCo&͜ogMmԲ CvȺ6hSv-HOx).)N6)N!M)}oAh~ᗐkDyDmEi%QpI+$[UtiDKfB $ĎI8좟]v'SQ)>yP?Q~N|,GyGg+N+C.))ﶟ*TCS键nv.,H, /.xBb\MP2(^QR&kx@JAX 1ĩGݴr U1=ѥ IDATS<yHm#Vrϡ|P>:\|(ι.NQۖ2V׼T_ccEi&(U81}vˤc),,/'%bK-/;xX~F"*SŬj:"CxvZX...99Svt;k^nP;#>؝{ 713&ӑYn2W\\\5%%<ƭS:E6 }"D:S~/qW2fltwWO< t{WF\puzbjc+:VH2bM8Yg#,Vhr%%/Tr׫?Ue\+K)0UmCt8*gG١5v^0̱%/ßh#ڝ̺Ĭ ̦ ;#>s1r("㈾1(7acxF)W3n#"խysvmVU>9g_}%g1t-fBz# U6֌wjFU~G_Z)ZR0횎w6Z0$Ⱕ:Vж%ӛ[报rMQ܊);ŧ }'$\O̞Ҧ OIz[dŎd^(KmآjMet]D'-' f]1֌%FV3ʖ|Ve Bgk YS&Gh+VSQA/X6c-'!$d^%u& ʴE ]q"S4BPR6*T@6yfg>4LP%4ۖt˒ޫJ+6ngbwٝ5*ZcܳggoѪ\(yG~g5s~mrZ5_K8P~r%l%^O v%1nhjm(+b@Y0 1TMꏹ'i&P3)ϿWhJ3',>Yn#) :5f,1:Ƹ-ϰ98.Ks@'&н R>d)r0 ͐Bh*0¡#vsF̀%S:kP OIxtRV.m&cm?qKJu9a=d t,2"CKZ$;0|}?-=g ^DS.^[+NQ r(oK2[VOYZU<)0w.GUXЎXP*j&y`t57?Yt=O2l~E񽁳`W&%W6N`*,j4A+n;HqG)zR&cC %C/KfheۜBI.( >Rv hZ6SK<5RR4Gl ?@}UugU XU=ܚ'z~<^J>S&|p':o{G[^μ7o3S6Q2=cDh*J7X*C.Z[ZgPUZ7 5I%8D ~$`:鳒nld)h.vP'*R.2n6t?ېa::CEǖ *t*NƠ[Ԡ Ce6gYNN f#n7G\lp OOC5Ѻ jP3/9^slp\38jF#ReVC~!xt}|͎{n QJ\6[;`;YUaS̓el8[R?ږ*m& FR ⦦^݋zGyG~Wg$Qf;G$(pԽ3c)/o4ꍊu{iA}jОhSl(*֧|gR7IbAGr 5Y/S$& b$lJqkQ&3fhy7|AnYLX ttp;sdHVY;rܧG{wS"IqwsbqhvD0Uʮtؕw1w11q1*grF-b cP9*WK:Ei[p$BEs <j*huŒn9Y}6Y73Bg+lxD;^Fox%HFx]ARH, tLT"z7!gWV!ccx<ÛN4vpkq9>"l1m5~K?AiuDPEC+i[c/uoi^}l0ff@$fԚ̼d$I~h [pCo,4LfL3f s`N5,>[U&MP+eH#ۺ0_28fL^5|"[sJ8x^ᏼ%o^i;X˒6ٛ5B 6n&,}Oj;Xxl①SQs"9!*9cr0tMٗRQVDxܩdI`E^_n˔pp3?s_|urK>ًD;ǴkmKFւQjs Šp "cmxhlۀs}=uڠA>*L;;^`6fYb&::zxBZ!A!؅t WQM'14;IuRQQR(OS1uvGy䑟1?[wyjh-jSupڽ!/rk4l4m޹07Wm!127YތY|;a1OKZ(4eXcK5gt5QZڒIEJѳY>iVH_P:S:셟7Z ',YbEY33ocޖn?Yu:|'/xdC,m´O/xzO+¢ \ty/8 ^k/Z`h.949wd)DU<3icB5Y*C6t9,n v;5}˸^_qM _?5K|ߢd }+]DJ9/?rj`{߭擪_ǖ.5]DqHUDqɰiPipI`v( >vN)Y%?}k8{u g_\\% ic*ƯvUL:<cnC1[| ]h@*5FP` 8e?Dxs>!&ūR,a!F|~ԮV3͜q;'CtBk4nįP&~mRnĦBl 3.RcaD_١ƿGyG~ER5v :VoJҹľ@CudO:$ MW,cHMCؘ)agRu(7MhІ*m(PjB Zc؃ МfAoJDc.k]Tܵ%lxyC4ew@}삙x).-QKԩr* >ϹLθ/C,=*tc۠˒JU0<_`ǜ[1!%@"Y3`'|n)5@5oEn_32LSC!s|jsD#ќK)p`e.rb,(c!~{2$U,-LqM6LcT/B:(i;̳ . kHANBKhTcX5iۍZKll}#&K1`e;.U! ~夺Y斱XAtYj@f4RAJzʚS#;p$;#L"LЊYsF݌SoY d@GIhK+>jUíb]A8CN'As*4Bsj:")3B)T 7-2bc]Tu|:[&!~؇ɫU' }gEژNҨ [.ylҬTY%2l=gX c Na 5. :q!O]6ajU ώ9/It#QxkPN9/Qv 6jIK= 3B-%k:&wGyGg+NzŨcz3}sTzwE=JA ݤtL 4f[ %M;A {?Z1Zթb-KCޤ`j9>MqxkQg_b?5t#|:,0v3NI\*Oh2*#hsE=R< >bH4OPhe#3l$dǏhVU(GtL$%T7HnMs&&xyph *Šk'{$CbMq#OKN渹Xc OJ>kG5V?I|v{.C ''XN+Sv˜!GugZ Y-Fbwsގ~g)8ɯ1]lh ^w=Dl$FR 1nTs4 zM[iy(I4.k pO*ST:,E2S;4E6EdRk1N ĨE [D";TbIOhޝ@` rݢr,BmةP(P(u>u mtIsFtB-kz֚bHXV6[EyHː3\r%Ok}@ 4WûzQ/4ꅎLbD\{\sENv6ya#80yY޾Ĕ H6M,v) 0)MGK زgLT T4Vi)?\|? Qxl>%~T\܉CFr͙{Cf[(t͐3׌84!CkMX & pw>T;} AL&=N<"exruƸ$oI6?_}ɕ~k%p#mW$[]Cf&]J @P P\\ex1F޸(X㈔CqGE;i5lg|=vm6t 8)6J!%f^V@h m/|%(\c'b|% 8eӉ"FT.谥OD` r4FI\7vtqGX19 IDATpLY>O¯6"(BdE9mq[ObC*4R.M&]"gwt永^417!7U4rCWneCW]]B6_l.\ޟO"%G/ kNkޮ+nc ly}GGasF30gCEZ8S9#vv3dجKYhiJD">y%kqe;|_bmyc<{KBĸ"1mPD^WP޶Ζ[/8Ti T?KDenj5fu7cD_o=w~m-~/&$E"4 `MQ8rluFy#<#k~0<-Nv F9F-tҷUO` HLehRjBG;'hlJ Ie4Tj {šyXccP#%l\0]B+ F0j[2A36Og i꒮X(E59ƨ@KԤF~n0j 6 8C&2נPk0͂Щ 0ZW Y;FA?uRheJ]I:Ң:T$VTaWv]fR72 \+t [GjvH kR߻lPPQEkUIi d`Wtu!єݪ1( bCAoC0"c3>ЕSi R i 3n I.IDrvZc*UJ=\y1ݛKZc0 يAb. IiawYFxFLk( )?BLԘ鎾XpT=XQa ]y1hYQzixFkĸzTdAyKj٬vL[)O5W0?\S&mR8T0IF"d5Z4$FXOG Q =eÁxo#J쿯JL:L{z1*DAxZWak>V3.gLj/",=#[ڴFN Mascu;bX ̛sc n 39%=!I0mHS >-2GJh%ec,ۢK982lg^џ0%J)ȥKG,9R>|%2hTCMQe$o9?@GGKG^YIQzgNW,Ąk".s]@x=`q| '؁R~#R*/Nc9y:6TR:,>F#<# nLR%=jٺH)=r-}ѦN A=i:Mސb?u"Q4Kd MSmFt-csEN5S*]nG!r:dNW\WJ%ɌpA8#ca4`gz<0uKdZǔ֒Q>Ah{)wޔТ:]ޏC/y/BBIY1qN#<2`v:c.N&|X`]PD:oH,F#d߭њӣ5B<{wS+ P5ʾF9؛!J["RiZxc; `ӭu_i![6Kw{o$Gr{~"﫲n f8Cr(=|kfa_d&HGq.`Fu_ygFYhq]1iqxDX\}U2@ŒJVF0ZB(EE4#}7 kRE . ~@?'|R;acP]ė%KU#&5-7]|aq1`l8JxV^c?~|ǰ}ǰ3bعc3#q]6^GL.cD3G;Y[̱yDo-H.q3]r5:jzjDE6#w%\Zk퀴qG%8z5^yź.i:A[ӷGL7ⲡ>EhQ QwH*hhsZՌ6304lPrdc̭6sm~ Wc6z[Uґ3B}KߚV!7.G\>02J^os z9V= mm s“a43иy1L$ X-:FsV‹_3H2m< [̽&Hxfo 9,8N92z1eXamr[/rm!/L Lܤo콙j%ǽ^q/U N% .GH#P=Agfa.̚d" !%u1iXFiKoRx5H^AV*GS`, \8e)}Y[}lK_bh6k7d:s[}Rn,KJa1ܹL: ѩT*P ef(WC5+AN@܀>,tKVK<$G[3f^#,=dе2TGTȈrMM#j5=oo\M)-~N7#ue@dyna99]gBЩlevBSᰵ}6vj0.ۧ|}ωO.ia""O R@s/ds;`#TlE R!}*v[%4Y8X8͈dO魀.u *CP.bY8'n#ַk6ь<$DAArO_/I84p| SߠP~UU0IB `}P J/]iڢmT9GIIZqU |ƐcS4ai#nM [u5ptEVI%)XS` ]ThH]Rqi .t3s5Ӏ \Yʮ`eF:'p Ofr+>+K%>K̟K LSNwloV1<7]QHuJt!i]J`hp/JLY@$F^G:kRz&e$֋7#g'U \(ɢjcGu^-\;l6ɕ)3tQPhk-da# WI^AUTA:l,lNA@ Ra2V};uJ*VoB YHe q/M?qS+ VJ *ɕŒ67iQnMI53BJP .<Ӑjn&Z&뻤]餔v뱝6ҧl!hĐ%V,;0K0AQ!kRo-GH#_wd^*Y\d%gz0$hУܝwk Cs2m1JfCFWC 0rL+]1i.!Ɣn8ט ZľqGe 4x~L;}0}2G->T@Y5p*LrARGvRԊ 4A+L1R<"vB54mX6—i#=C1 Ba&,K4_b2A!MB :\t*J_PYKT2.|U@QĥcUd$O45{5oO92ɤA&Mn!({B( 'Mٗcg\1FQ=;^_һ-Q$!S2]IIDG2Xyυw:ΊN{EZgvצ/. kyn=sPyǶ3,#^g 1jQ$?Gb{\-R4^Zi+<;&3-6z\0rlR\` -<(CҖNR2X5Efrz:W߳g(N  0w_,cf%3c\bC#[ m$HҜ,8ȺO@ @T&ˬ3-{,-~EgVS l z,v8ytvYuCƭ.p#^\DwA]t/!F%!L[I;᭷ ĔL~]US&?A }a.o'/7*R91tS3M吴YT=N;,Yѓs<#9rVxi?jvB,b!aakjsP4)%2cN`ZDkƛŌ{r|?ɻsֳ&"cQa iJc(Ff:-RasM\h(mEBuX[ƸeWy--]CsvIԑDA^n}o˪MڵXCҡK0)c߹+RJ>GH#JB.֥լw!߅C!,R׊0ؕ{14_c+0jtW_ feVEeVߏ : :Nfq:DK|MOK) Y-P=Je(\dKs^a* e}Q+A\{7 *W'qV^a qq_p_b%V?F@U#sl0̆^_nSWMiW)vXNyxC<=jòy<<|MItYp rz )ea1G>VUү昕Fd 4WdawݺNiAiFEG%+1@Nrx'o.új0yc{Z|E<?*-9)UzW?>XkTSPB X7I~׏Q}#V;6/o w&7{>\}=w/uڵd>l&*Abn{"?3ym@V|-9=V f ;w|-?9-UK#8B''<ͷ(W% ^{pCFESa%)%dKd ί_dL!LB֜ p!\n` {j+:sWIR&˼RuFZy{~ŏvC$FŐo QL UXb RZ;_I !(5L39o0zp:&<:ߊ1-Wxq5DkAqLc%i0!HuB0I ^:U$ܟ*\RnP㱨H\hjN\@Rjϙ=޵O募;˜ë1Mp FuK6_Yc=kavKڴ1c,0m\⨄6vE='^kLT>%+mf˥?E=H;7/yzo:_bMsNs{{3ĉ̱&nm9oǟ J(E9/8w)tC r'9Fhk=T8ZL^Z~M|g,D4Ē.SgO'P&B*l<7s[\K~ /|} nu~3-~k' bS֖q1-/xCTVI{2e9:sGǜaR`%*C UX)VqջU[= ]'V{OLv}DD\`۵ܽQ7 P j&w><|ڥB!P]X!v?WvMs{T=cuOAz)~PPCr7n^u;*ǧ}[;%nOKtCq_?}MJBvBx ph>d.9f IDAT[e|l1__0:K '+1'0Fxa)Mn٥}&Yl R,񂔆Ѵ67]f&.M\] Y^6:ia.eB%uFrȨ2CXsYR-uQP- [3匎tpytr$w,fNp” 33l-{RuJb,˦lmmI[6 Ϛ#ĆnNOLw]ɺͺˌDb'h81A93D#tuW;;^m̌l1.IVZ3kt]f]"i撗/IYJsԼOjL.N зh͊AKmld!3gMJ5ўb̖ĎbҠ E+EAΈ[&цD\ߏsJ*R:PRCJnTV07;4^5hb hjZ \Ho0WjH;z͑FHu]:7 1/گٴ|:͔Ҡm1*58[]luC@3LteVu 5jFg5G43!JFAYܚG0 z j/hu ]5V&c Q xVgxvT?n#r22"]EykngF 9}}bb6Y:Mfz3#+k{+5τ~<ГJiQ: Bj b^kܳ-qdE6qdút 2Kek7)Ry#ƭրQkQZv38j\׮9rUd'0+d,Vl۪A^Pt%\ch9 Z΂$K-eVCޮ;Sqn]f)t}lG tm&^>է\C Ɇ% 74 `ؠ|Cހ!CyK1$6@A A7 _)iGs7|^9_NS nq {X%!ESQ@oV `1J{4gpC,"|>1= ގi轝ns\F2Gvskz/G޲j7lV&xJ?+QJXn8nePݣ**˙a ay-j[lѷ ⧣79bϰ|;V힡6Mjp`g'HkI5_xNDFE) xKwY8N/i&T..ԧ ޿+D_kFPa bsk0s||N[[p>[~Xy YY˝x1=kL/o5*['l%[ؔ7 ^{\GkI鐔q+Ud41P5Zx7)xJ3*ȰwͽXBN\^I{&oL߆|Պ_NO>MD^y__asW ܕLeŲMtQ J$lbK-{@Z%Eox Dw2)B>r<}q}w jhPRKt(efQ&[˧~׏q_) y? 48B!i)Ƅ2olgQV=(~$O?ǍtϠ7bcZl vfiy>2 mN߹ E4W e|YX ?%(U#wJз`NAY+1/O}dA56('T FmY|Yj<j ׳K7Hk#z%p&liȵ:i/Y0X'3B*ޛJ~//7&ӫwH5g4-s˟kmsU+ꨬnZ9$|ԴYj-Rkd;߃CrD.j!Ԩ>Ө^ȁ^[>k~˧73zdF~QVHD}oShўK/ԟcVnWp-ie|@*}o@BX]q'I6h=Tjj`fPxYB౼k1񄟛_ IڵH<ijI=MĨ ?'wg;K؇Rw#S @z8}ēr^ݙG/*`뙔zKCѕ`R[@)}V/>as7G$f :64 dvcGVDZy$[d\nL" 5-kJ+ǘnX ʥA[l;'Va<AfD˺`nX;lMxaLY&䩅h5U0x^CznA`iKZ6guRcG94-w*[U3:ՌА,6[~z^Vfw||UeR2*OշhsL+PVU`fY*|~M|1otN2pCqazų욁vGZ4xfa9'%b%SQ $J1'Bl{lVa ke߳HU -ȤEĂXs4B C%kjY̪rHXmm$:))6ʮȣx[aDF$QiDO8.[+v)Zы]~ .,I[Q% ,# ]J+R\i{+Z-g U24̄@sCƶJ՗xбB P*ѓ 'JiL;GvP ʶIܥL)L $/, dN+_c`Ɋeǫ~89jiX-XLW52Uk cga)vlb(% zm4} ׊IpIpHqA: vbTɤC)uJi67y(+s*:8ח4ٰn5Y-\,6[buT_Q~k֝\d&q,ZxBh B}bzH>r) ڊ\:+\$Cd%뙸VBi&gk7)s,M*d7sgL.']6N!!L9Ҩ8;?Ȉ:>cFˢIR8(aқ.c%6Ͱ 1)HQd &+ g{İbnTu*@B ժbam?8I@=\ZA`m=#1j5jw5)|0#b}2ڔR{| kh^tMk#zPꃩ>u7d(.hq'q_?}נwyyjp<:y kW&u@>upIhk:1cuY,;p}j-99眵!JX-4Vs 0s (L2f ڌE&6QG!6dfmqJ?(D?'웜um]s {#Ga|e62v( ]V()3l7on +bF?|`FfMɡPr(o㘁>JtɚO7H]Gڮ 傦\ਔMbTa9bix8S4KFcvew$w짷)v#nXAJ Fȥualƨ2;t]bE[,i+V62r{>$|jB?1ϡ YOg||F"wnK~kowݻ~Ι̌ c%_AȀblHi02_G!ȉ X8f\o߫^}|f9KZ{nOu,F&'ϻu9y%^YLͥ]Sw/w@?뿯, ">o @RY\c .Wf/J^_ qiut,Y\!]k@^5y6}#[kxW H]4V\梡r"hu\&\?rk!75"! lV~)_: ~T8̞H)|g|B~Y=xGfܸ17^]y&C<, I1+~n`٨nUaZ {Be]K~2{O۔B)q;smmT+cVLPeV&=,$~;c>|^g5-NMmxw)D)S '쮞 tDI$ "i2JYhY&˂! 7=F41?+Q+s#so8cJeV-H}i#h˦E [pː ^YZf ݃a_/®m:fZ \g*%n7ҌVRMͨ=Q]APt Zcujl&#٠sx=' _zw +-ԑՔO|yxKFڂY]ܥاl&/ [ `Kt/öB-1HH1gaP* 9iE(XHnY)+wrv'ū}ᐏ&o>"]P$*UbNc,76#"E(JURh%J\,/z,Kjb]! cUM;)H:|^|BQՏyM{OjMO< vxVar^a̻,f>e! xoϒO20[B0sV3e0$g,f|ǜ5MFO*M7&t`[,MCshmGCUNj'l}R/ ى]Qޭ#np֛x6;&` % ?%R\u#gtM+/D~U*.Ž\\K_\ȅB!K"LAIs9^` =-ϖ<`+Gs|"ux9ґH j2]mRwTJ,͗1JEwҶƸVe@SC[HEQ9~u\b{` [YjK* 4g4ow";nM2X!]ym`v=Dx0y +t¨H`$̨)6R( 0kAR̀T}yBY*9fT0)Esr,g2EQ L3tLM:ʄz{DcBe=VCdhʘ:#d."asmMbŝztkwG.˺9p_\+L@eqE\8>׃]98.* `M(/M \s}—Yœ1'sGKBS^h Wy{ՓڗK^>PP_uuwkJ,N NfuNfu ]QXQ5BrȖrD/;W"WCIL'O{dxbi<MM^1ڭ6CBrbςmɆuJ+Pݜ :%J Se擘:BJc~h8 %q ޱ1ˌVmBAu$,RX}>.eUc\ؿS6O[EMʩ¤RRejcgJP%.f+VZF<ػM+B B%+ 2y,!94_PG41 D՘SmJ 8E"J abJO Q(jA+) BjQB=F}MolL%:EOt n;O͟XA3} qKgc*FϗLJ,VO$:'n-¶sj'sj3*gsUB-^Um69d|C8[989A de.9L GN#˱%eB>P|L͌oԻ nØ:'c\ZZ lGlF}dH-?ƄV(`I31Bt" [FRfcfZ^0K ]gLhI<':b d1VQsn&ؚbf2l -fՀİMĴ4-gHP1%ȨD6CVs!D3VڦSƮm<"«@s]_c{XKֶة,ݻy??OYEg>~~rwwKKx$>?S?œ'Ot:؏?= i4FK$)Zh4/˒F@V`4}p?c$K5U1e]`_ÒܑWͼ+4ENJ#;:J?u^xYEJY\PrZ[ůsocw߹,vf5 阞>'c Jgyxq%d%+8 OU)[14KN(M)g\,iPqgwX.;lW>S$Pߑ(O$+9J89fFQ~!bll*sd#X Ia Ψ3(:%eSuF&GV^2Ɨ1ÄNGPP Ay17Q};~gGh=}D1b@~A~NK/P,cO}iXCM{H:#8 =&xgς7fxƑɻK۸ǤVEh%^+s b.7F8rXUV1<'X_#?`vVv@ATsZY1=f, ˲RzHC!6 km-t@*H:OG%D}dYDj&AXiaI5#YK8JS4+aרGSMq#5}j?aJ] /&On[46Yd>4` ssHT(yO> k*CP[L͛ @Bõo#H&j\ݡiqnrxS R'tlB!P%//|? ?|G~Gx_7\>׻KlT%Vp0qʫ?7 |}{L.^Lƕ .gZ ]6*{^xCrm\W6^w}]/^W"(~nJcǞL '&($Zڀ-kMwH')tـz6R0AByaeu+ YC!Rf,Wa<2WfDмTTY*!BQURcUTDssjI2WXd>`rZg_%|TH=EC t7& K04,=&üE?ڠX(H]?qW1eۀ@biO0SAiL`pƘ$TYʜa f :`P6xVm H-PG9j丕]"o+leU$hC!<+UtIlr 45CSr4*UoBӫbI87 {}.8c7&r媸M`[pb+Lm,5f8`K? 0d}DVe*$$dL.99P),Oi,|u@6e]#4R}mqn&Ya:Q*m҆ 0A %V`V24@-/,4T3Z!]ABiLӍ6wytmK<`)DR MY^>'4\%_h,YfzP(|j<] R)J#[Sl-H9vSM͞R[V6}LM+(zgXj+BDYFC0s"BǴSƘZ|F}{4莁Q0 X!7H'QBS) A]?6cl7/eN$RXaQ.TQJdldҙdUVsX3 Ũ~V8:v}YellO_~~˲8>>?_xE/8,K %5A\?/O.5\oПCTy5uxN\p\so+;ߕCr]B@!@^ 눅(9oGߒfR嬯L|$׫?K9bx!iy 87c&+?2^+6tΘ[ NW$ݒ%]\}>բ7V8?\Y!z/C6- (P%GBKzc,&(6k5!_,h)g1@CL&7@KofZ#vO [6^uF}4> l4φF[ d֚,| <2K'$&e;cI0 ;c ZB3!"ې+*|8b8f;#l5fh493Mb/rNPΰd|~v]$9G`Z2v m+A1_PV0E=Sʅ;ƂnY0TXN}^[Gi)gtS:)OQ( vFY' 5l%3B4UyJ՞3"ܦ?QXCkpY gV,ePˆ>> Jβ*ZcȮ1ꄾ*l [ps3ĉS9=VIᠿTۉps_.v5AqBs'=}oZ,L&J 𼐆74#GQ TpvӤ>I1&)8EO3NI:jRss) ko2wꌌ:EeXY<`yRs~'~7xn)ԧ^+|s_Dz,~g|)Zy[ubPӇaZ[xi")W`,1F1BHR`nxdpf~VlT:ֻ~ԨUU'UB#AjXg1LКeR&*2ҐN4v)e6nLr!sAc ~g4Z>sxrY.іTlwة>yga[>;EK62zzs|D ( wo2>k!g r.(g#vm?%/9yоC.wYMr]'StrE#L<"xGYg)k!;bch1 9..&.h%B+Px9yKh&$á;˼D\Xt&}:>/Ob)'7Sw{GS!cu_&5E$wJ[e\A'Jc2';^])W)u- t*G $ӍsD!Q))GU6&;cC6G՗)VS:bBʻw'T1C bsjkw"(~AԟPJ"SR+3bE1aĻ6z=!9q;G]-yF*xeȁš6 %M0Z]LM/y KK+q/Da&9dŗ'a6RNuiDgGJu_.&<|.ϣ]v6RrLj댂guMFAi[*nLh(c uX34qYc00xizuDvFswH>dV N  pc9xvvP FK[oJ!k f^sog]y;feXf%"t5ц9ʁDs,/C)6R@q7掩j:'j M hFtV{ųm4qZcz7)lA $`9P ^JO:!0')~uƦr[[xq,;,r4X,A)KQ^<..I\ؾqSw-ۿvͿWCgsÿ_ח ϿC~O;4eX6Rd<9WQ~& ?7O8,)z^x,\A\־f(un.y\>úu8ozKR+E/s^e9PvmSX6(*ׯAU&=NXADzoH)9BJ U4x!{AZ_3~zOEW-zP29l"\yYZ`sY(TTʥJuyio Ɍ?ξ=uwWyﲨV͒@RN96y'z?]} JPKVTSt>`x<2Vl"l_]P .?$t9ͩ9b$I% _]Ti@0h3,[ I "|NS3be7 ]0nymlY w;;x|Ejm""`%r`<'[|ir*]d#8l@ic:'gt>>/MQaA\baUUs\"5X CIN$$#@ _S{Ud|>$6tA F S?頃7^9Jтb g{>$kS|D 4;c,qg^[Sn*S>7Apaÿh]q[042&+c~pn. ,ThhKaK,aH@i5`͛WRQ]Y&6%‘h~Jp\NjQs'u#c IDATl4!9*Cd*nU#nug?Po7Qz#\r_ l?qG=xxěs]ҵ){`+!ڜ>78`BܤXD2>@V\c\B]&]3<7ڭ >O/}??3?Cʯ H?`6eSŹb*?w.ٌ@^+e %A}%l{{X]Z<5{ (v.*\{n%H^/F9X;M(y˚ZyxJV~ d }aFwxaz/.D^/wޱ\G9]\qO__v5*( |/\߶6+ \i!<dI`uBSV']*QZg/1>+H1[ %bD %Fze@怖? f~@ $IH&r T mO1i_DZ"¢P lG#mj͂;#h-ƄOی6{.Q>>Ŭ$%ne#yI61IIrb-Sn-+WtMFzh6C R2V(]EKeF9a%ِ┭1>xXQeL#Qth#rTLe)>Qe"(odT.P%b2FM(% 1߆a &X&4Sd*$Hi oҒk2%\]cYB!tB!Rm$5 D蒪2EE'\*cIs>1#(TA[URL4X⡈eD(ӏl'x:˪R\ҙfrȦ8kP-(U<"uC]gOC" !^<}B$gҮUK5՗7v'tNȚ@;QGڨ@;+֊ TKt70leE!4M0>̮R*3r+dPm0>Ԣ2_rkGm61mm% 7΂:3L9EtsZ1|^vELPlO5ft)c(XUYY/^+ E2|m~%͂i=`hZF#F%Z\FZY3[G) e>̦5di"cquPH!Ǵ3ϸ`6M(ڞRۘPmL1̔0w P9 gg/0BȄNT8,*㰉mnTK{Zb!Qb(hyN$LL#bXÞEG*Iش*ڕ!ʐVe@'pmҤz.'ys?!d80 5zkJL%nm M~Y$\:S3`gv~ھcf (K᳟,;_{{ܾ}]eJ/A}6.@??/2v~^0YoWjųgπe^^ Xq:ĵK1.x/K²ӵwAx{+ٽQV&CkYt}_R{z|(&ׯ~U|k0v988L} T(mDC4+ K\jFII}.+O+9Iz(iƔ1cAsJecA`Oyބyt.Lc><ؕK O { VVBT1r -Na+ rm^[/`ǸbGbG\dE)4JEg&T4y"OoikM눷3ފg$UyW.ؑcv1N&0n8VҌ*<*b|x3dDTe-|C>̎[)Q]+iۈac/CB111bj sA']$k,F裍d9"̮t3zޔ}>%p pjwuYs;?S7L!h@t^sd ed2*_CK<=s6ˈ1: x&&,1,#(R]Yo-o{]{[^~6S@Qw_̌˭]XLTBtX15)_>M(G*Pl(8`3yy4E`n;e{P¿~)RWfo kɖa?77o>:wc;wm$_җz/-|sF?|v;;wcUzW@%[&7mAܣd(vY߭힔!SCm$!<`1}/ڵۣv} ʸ["w߾f DxϮƼ&ݢp`vf_;~_oLgC&ϛJj RjFv]8"bP# 75fZG,,Iohj{/h>۠%jU%9gs;-}uѕ ʶvfCnkEH4Rf* auRq_Ь7G8X ՠA2K:n1"Gg 7Z[F-& ń>Sƛ\a=R/t?SJW!g9`IϕjHf(k&V"P3ᘽk.BG|WfjΎzC^-.>?% y W9?Q^/)4OQ운6-:x,a'85o}~K'v ߨ~QqOԏ oxGg|I~G3>R_J--%UvZ.Kͥ׽fǜ3E+6)؝RDq SIR |R(T="UXXۖ!9i%C&(vވ]ܤMD]KLkXm#CX$0A3U}[w,jMraS? _S~K.0+)kfغ%jtJ|uR2-|D딉FԩZFo3ʘ2a F ɔ̈́$sz-~|US':USm4J^ d@%YZ&=FGOSk}i`)yWg^v(9TO=~s|i} Mw:śm0"Icdv&TRGK}9cTBujFr^=z6%TFiTF7gdW|]0׻,sˊ1 6 :\qRbi¶߁l-Sޥ"=;'A⹃?<; }Nyݰr{U?Ec#3<Cyqk74/@g{;8!{pˣ[O5$y" k_:~Vc9NN99'YXՆp(@@P(+hkaԔN$<3`>i5ya/<6( azRY EU&Q)=u`5 ʩ^{쉴ٞhwZf&W = CGh%R7*jѣ\QT(jE~HW -۞]4 D'=I`ϧs6OR4?$kA@8tIP9.Qe3ڬ&SL2Wl9Ь昷1'1j"W R\̢E%tf):.o[]\紲b)j@* 3ũc^`OXk "Aj G{ bBFkԺ D3t=o1v(@]oW)B[TBVTjU6!7$&&M+fo5)LiK悶JE#7 iST:2֙JMŨKzޔfsPԩ*IJuOUB3(0QcIUF4ȶJ'SZ!s%]&Uȑ! P[)AلOQXg2ZM )Ms¢PL*E ڳfamk keoY'<=9wטVNhYG̫J jJqpCniʐf{MyHX'/S*]vB+ی4\tW4MBP6) !jА! QxeL;}tg$ǍxJLR\dG,jl0DGDW,1:{5l(,&'JҍINNQԆZM9I 4|,30JMz"\y$CYemnrjF%]5z1?dw h!d3ްwhtà?fЙ`[&2Ql&E&˨KԆԅ@" mOs>}PnN `1t=>̚Ǿ. j /E(n-"^o_@uT~V>~므]kl)LhS96l.^[\d6ʆI YK9UUd_ĆBdC6)*"ZHj\EV4pnbܽw7 l[$JI-t9Y=c.Ώ Մ`̰;A3mӽ>A(*kDsv+vkv+ꚛ\_qsK4p6 'nkHKRZ84 ȄI-T~0bqE5E7 V78ɞp=m§ĉúh`ޝ"+VEܱ+}Td5G&yf.JQH:4Y1z.3K4(+e~9,>!rJegckOJ4KzcL?/pmSf<[.gSNUi '9_#ѯqVwEP\%Cr_[I{rC{zC=]3K!AWSE}K!@wK$˒\kc[ȶ0ZF;' KQ՘jkKbt|jǣr|ꪀ"C^dTo#d[P6V5dj-j]gG3 (94FۚuBU@!eeʾN۬&G^߰{s {5{-c4UJJGxj!ۂ==;F$gzͳ EC#vGvJ ;Ucu,}֪5K^), @#hC|a Ho]D% 6Kz8$8].g{u ] OS8ܺCnڐ7aOcFR i=<>2&0kb%Rh(B #3hkb\,5Vθc9iy` ':qc"!)bFP5BV ,tp&>9&2:m=d@ 4Dӷ6Yn+C.P*Ί5;+j]ʘ^ ,=N a«:-QvjԠB jD) ^\sc(#wiO|___ p /`wW뿢:~k`Asl<;~M83r#ͭ㗥@W-mStDۢ2L2!*T.URIPUj%4!MMԪB. uN??qǴvBGSq}~{8n :[ 6II1|_c?me9gO :_Ӷgtg#M(UJU D J(H p@!)m.}.g/j3z#21_=K7nJ&cN;Evu̚c3$#sy`&WzYl Qt\3(sJdA6,0PAWqkU_ɒS4c1ҾY!@Utn[ݐfaDfƒO_]?O$rD+Yr^5ZƊCA0T~0%ߤaTz_2QQmC4$ BRT$MJ3{g"wuL6H).ah9c Θ?^#RK5!OCOToSVwXxGg=1ψkndR#75F!5Bҵ@ۃZmrXMywѽ^' ,=,=EKT-USJ-64ۦD+>.9/M&O'|<1Ϧoxc&>Sy'WX2W WJF딹{ָ')Ny|,I&I$}n|Ĝ8' est-VqdmM.C.9dVI$yư?ާfJS^5׍gH8xK9/s_>W]$R"D .j\RrNZWݒ+q$X-y"k]@ߒ EG'M,"a @+N1"6 mvY9]D&)eQJLmC >a|%z^}FZp1yh0 FpWt!ƕ1T *A[DA1Mg| o~[UEJ;c߶G¡;@y.k{S#u>͍{|YZ<>qw/Uok(;$pQi w]BHI}B? r7qqw??co&^#~  -! M1 ӹ7]k14MM+(e%(e%cy)QY*m QWYg"E+Bb IDAT'L}Hla1WC=fE1goX8$&cSHjUqR=!(4VbAg=G*p7o9/_|(isʒglT차;,P0Akll 5%/M•ba-|F EWOhT:B& XvfjmU t;G-ZfJD"l b&fjLHJe"-m$jRJ4+ffUqTUC *E%UMBei4i ik)*QETZř8:MWK UŶ-TJ*,SBh%EX ؐ[c1U@}`bԲk^%^BhmN-AD}4qh v;5S;5Ub!L$P,>b91=S/ ɮ$}*Iv~oZ$M(J*V$u"&0,U#@cct̡έ5$&v^/9J99UQ%(E F-jT(Vp BeᵸX&f}Kud8]?aBE*5`+1&:xA7Z\w<ֻ>r#SQm#ueLӺh(eG400'Wg<ސuEw[b_xEUbT6TDkc !D@G&F %~2T&znh^AYwSAd-ʼ|d}l]_(;u^w=$cH{ w<w_=c܁Vx;( "=z&nGަ=Pm=#l 0[o~BHT7`v`_a"3iB m jQ|.r=D{XNdxv5Z!\[s7G;1a1LhԅғSL5]e=mX2ŮsirYzDXxdzďrn%NO9>e1mC V*8%,ąm2Zw l= ֵҨ8[uY:,f]R%w\uw0 $Ќ.y1}WX~bNۓc!A& 2Dq+ҦMIC 5' t`gp퐶Ӟ[U˼";*l  j3 Y$"rhYud7NUk%gKEPq˘AcPa^0@2O+j/B|kf 6hm0ӎ9Kky[y wE5P%ڳ|uV,֙ &!bHX.c .Ł2}ئOkY1ꨦکHG5YccH\5$[k=AԎ@*`imwWC|I$4*<48E4='ؓ_],i R#ۊ!l}p Ԛ҄њg??cvd HCR+ʖz_jTBVSr -Rע`4qEPBי}K33^_(% n9hsppƢqRmT6ac t'TD-f!м1X>lmm4|mn6*g*N3ny򊖾D%ɄnWHE`cj)f'`;b IO;~"| Y bi07>r&6ߟBo sw:-Rtrn-րW|dAw0b!S:2u6U#jE!lz!Q#+M +üW%_04v43wLވ;,9.8\p8k4@z$\VRd=XI,5JA]U̓㧴$ 혜g6h~![8R~+t7|wnvvY(6'5]}.=]n*Џra5 yUhyKZ{N^Qt &3tj46b DMqq+vX[Gém2HbeCrFs>=bv֌n{F8ۚzUX >Spx27Wä%6d钕&23{o\A> _A~%o_wl ۿEJooGG(pOUdlZHUEi;:a L]us aQ0*cxnkn炍a)$vÎv^,muM8,.<>ڨٞ@pub!P7g!og82sBRQ(+ֶ`04ᴂ (&#l3F^%j]mSr ujmxߵf3JoR$uhJ/8 LoR X#v5@:.&lUdIEWTe*u2q] Au$3$}&qHcx6WdE&a)$7fDe$dKAMxUQ{mz+ ;,icqhQRA\opfcy zP\jA0I1YrՂcqFhyĎC &Zzc*ӰTFnN}ΗZ0n(Qe'p>5ayf֋A&HZ8Jj4%(UAuQЪXuRJU+ԵX jHTdt嵊U]/09[z7bm-٦)Wij|>#z?MDgr XJ)h g[XXDǠ9a;a;f3, rF?6am[6(*r(Je&.Jn?;M+)Ѫ rATAP6bg1IM/tn'܊.;lc(%mD߃9y |_|gW9??k.|9)3R-4% PG%bp|LhT͚[v7 ⶠ ެl,8!S|[)YT-^Wa-/7| ,JFȖXJzCK/hpqV[r/0Ok|($ؤX$ sZd .2ulͰotn/Xvѫ)zEiR:UKEwVnڡ5?-.kao3xC$aQ/k_Uӛ_> +/.ɟٟ};iZ|[OOwVO mg+^ _:暞5%ULU,XFi$XfIkŘ mTB!V׫!ɨ;阣'Zb{ՙYj<žGڷdm7<Ϙ͇\"jY Yh+ h"-iUau$>q<'oyY(?( CDpA;Xs?@O31a۴ζ}:Y╬mFl,&im n|3-TVM``>hs=x|>xIK%kutuxMtDۘ`VejEϨٳKY%h s 笌הF(Tb[[o۷LIpz1D8l3deMvc۲soA]}NnR5nvRH-=2 'pG6 C"Kej$w0XuFPG7a\ aY?``"XcmդP_ei}~sA U~T "  3 ZhyFI1cȜs,#΋+kk+"dgzp){ˬ8?gĹE- rM% ac gCv/n9~[1g.'n'nY=hm$Zͪs0/iii+D Eї^g緹ݏx㿠ʆLՔ(2B#cj,>ߨ>紥,Qy)W.ix>l(D\ȾbTpss?ß0VZ: ux"!N*NJJKu{d&,ssܕc C YP44gE|cS eCO|z'[oyEY|{.M'w7<t0&l-'Q7EiI {o^<f;?3O^ ߻_xd;b1nIsG9."z̾[(m=h$(Y ,2/=O8iRx ^xPC tUF Mw'p#z'縍=E}?VXG(JA\,}VQHjݍVcNc>`w\'?ǒs5;+#^!7NY\Y^XE|\ ^vp;l7C0ɬب-uSe3z3b,v}!! )v?3IJ%U khV>c*I jV`3E1=Qu5MZ?4G%qbŝ=90tcS@*k 7Z jUP Afi!p0ʄ41~C eLm&h4ԭ5u jvV4؈&IN/-96!mִPCVFNG^X7e6wc}<|O2>U P,b bDX"u ?`UQp8{x_?̈́Z?~>z+d!||!Ϲ2lU;*F+A=?mOv2d*]&ϰL6#ƝS/3\%UC%03ҾudG5*W="NKT;+xe,Y[eFnI҇u IDATE,(D2v}BXGS㚣CndJl;x~$JlJ[c:G+:%ݣݣ}{FYpļ#_)V;cgylng7ؙ0'$ؤq |=2Q & ?I|(*K:򊮴)oM0M4Hď5N"8fHuC;`ev?ݛnj'#fϜ#<$ǒb|-jElwX9mVZmfA|)huWwML[C& 79+XJ'iV;fEߥ_b ¯B9KǞ5m &՞|C&8Om/;6>'q +ޱo:8̯ JY l-A B %4ANjnxV@Z %x cϱtHM]D~#uӰjN d]w<7Ș)msܹ\9O؛ mKCTxb8QH# ,6C}Vf)0ag 9 ɇJN7_4xo+IpVרr{(}doD6-kCҴ6-i:is[R&~bx`ey#>yf!GCU ޞأg&w!fnq.N[0kjGW4[VrauYN{p"3i->9GG۪v`4؅-ZO?DArLV}<4-,ȼ"{QMa_iTDֈ&{lDkqV6_ZBzD7u8[8|v3b-R!L$$4D+.:Eg\F] ˷L2Q=g]p3q3,';wH$Ȭ0qxL_/#ƈㄞ=s|LfUwIJMAI ncJKfax#\zs^#% iG5tMʿctsMSQ)46XU]>|}ɘS|Hpjg;;N(2ũjNShOyS qsqu7~~`:c}1U*#n3ҡk,KlJ3blSXr%X] .: רTȬi*QH;Lhՠ.ݻLeSA) KFE1ePhsbU65A *MVrRJM,Qw4{S|c7(鲢!Xs2}<8Y#ݾW=#NٴZMf!'lMZu`X4{mMB"?8M<>0FBWX~ B,5tRUClD%X$+syg̳vq]sUs]_0N=刷 ,.uRbBuY'|+)aC#8C ҙܖR#kQ2Y& H؄!lvtazfZ ݬi~`9Fs<{rv sl,f!iZ&& ҉3Yv̛`s.~Q[2u}j[e]kȮ=W?s45&Q' %w8UȶpP{Ku¬Ǵ5: ksyۋ!b(a "k+i8@&Yn|ۗ3JY%*Iqg#G_X0E@UJ,^;w~o_폹x}ɧ?1qI`-6wNi<`0 Ḏz9W 9`I`upԞS֘uaȊY{:" p$UAM>?Z^sECsWuJHG4>4qS5|I$k}>0&InMJ`l&M`K-iGK44,P5=+BA+F(Y_cw ˢC\Ж f5|MWv[sCЋ[r{j bb.S̛ Q$F$RZP|PIH6iḩO?#l.˧V#XC.*$D**Y:& FCTw(yz첞t vVa w?A wMM+>(_[|8QWcQÒ=?Ws^Yx>uG>^"Gf-7YIMrZ'b>)Aᐠ3Cncn!I/nK%һ Mw[W||rE+ӌ4hOsm f!ʪ ,U&Y-cDJئ< )*[,7=^]6Qס<^9h_t~L8_|x%~%wݯ׿X!5-y7H]=٬HgiegU2]ccb]SnwCG *9YAJ@I)fI넅:rZiQ[llWRUcU1j]EQa@UAYCYQC)ٞL։"%Jʽ0@6*T5c,;Fx+D[ z'h^v_:FǤ2鱘1BdfyQEBZ3P !;X[Pjb/0c& +K(6y"B.+RcuCUBS٘>C?jgra%ؖOjLc>^F dkP'4L'Ku,%",sf[ܸ'lU-Ѩ4jGX3H@*A4@PU⦁olD"QfNmSKXFHr.ZlH^ Y%w;"'H hH($_[kM+p>^(H5/5(PjoH #Oh;lO#E;{c[cdRV v•: UO&idG*QL3ڢ PH am:-CB2lݧkwhcLk*SDŽd4\71v]; 16)B֐[4-`J3;w]ncPlj.k@eMh;A D =nSFᘓt\2ʅv!k8M pƖ1w(zFnPWr %Ca{9:P2)Xe=iuA26jen0Ԑ[i$V)ȏUTO!Vu%BѬ IQTVFK=VoM]O0w-}QRC~PtґN>:2ݍXmB"MB"C#sT#B5Ve%\g{_v٨-aͫjƓVbS9B5!HiqMh5Wm-8nl,;kS*fs^3Oy>1-݈L8*8yy-B|3D : ' =eNS]* c嘍Qxkz"0r#V"U[*S2Z\;gnLpz}dwrw%$:%ݳ9s՜;aniwWt9G68u>ȺY'NLqT =5&:]1䎁:c(ݱgDg?sp?*L䒊+DBxᜤAD(ۘ`S|"*HO5gqLvGwGAG><&˂o#"d~e2c]6)Lؘܰ:R'[_?4`#x戙?`0{7`yy4gAfxԟy14--eE[=nGA5D(aB;Ϻ/y%o?T3Rld;1ns~= I:ِ@¯[ K47éZuL0+Z'3D6D~R|R"H~nLFL>8m-PdX>8z><˯+bpj"\-c(1 )&IjUy}eR%bW!H5PP%T@D&C9(P! /TX#ʭTHF\h"%9mit5$~q4ew*N!Y^- e!nl*H>rI_ђ7XjJDIP;슃[~iӠQbK>%NAKDq^)JP2u"C"QV(AAר,҈u LQ%/1d0 )!nXEHGZwhAN-KkD D]S!I:e.S Z*&qۢ+HQnt'B).KS(A @Bh-T TRnXeDh[DSuNYheHI}8w\X 8T1T$rQ5G2*DUSPD5yY]!P5brBw I$j*Q!C(BhdCz8O?h0焪M9,.csD^+VCU2jPHe _m~d60~8(\ %88Muz)Uu#}O*Q+!dPÊq=-{M{l/"aXaZZ"\UdYfwT*꣔Ej!TTY6۪ITL-+D dr0ZŘUL IdD DrKDR*etIˇ{Bk.[Jr\QQ=v!m*zۡ,JGP#UA-*p*j"oꄢ62 ,FVLڑ:ª@*$ EAIr,TNB jCC76uhCj! > }A@V' vK}Ҡ.<k+&gKKM7rG,P`K!Qfčt΍txrΠ FP$\4DjLi>8;kąI)z?F|pREsɩ9f1^ Cbu$CFQkT`IQq-[ KrfYqTP{DM2ne˒ԓٖ5qj,98{@S-7f#Wl{6i-ڴ #qKlG)a5nuC`9׸e+fE[򉊽o<]agMiCڰ !µKB N;qy( TphluE'YS}f-a>xJ;D!LK>j]9ZFIhC`;(.l, Ѵ-)-eE[)+LS ҦD w3F b\. VEqT^ Y^9Q%(V⦆kf @MAE )QI1ɱ QF,N.C䲢դ+VjD V 5525i5شZMBl'rOOUw}) IDAT 30wr'S6%(%A#q<,̶@ݏ0{)Z?W%Vf+5зtY=VI,H481IbLթ{rtXK]-R*Mxe : ч1uέ5`״)5V#@5L-DS:!isgЂ P'kN9Ie#. ]"ZUݵKDu0qd~g914n9>I kv1\# =y<$|ܫq=msEZ6Wx;8чB|NJ f}ﮞUOPeOn\Q W ,WGTk}P9xҿ") iqr6i*;,rVqF7MAIlP7ҖbC` bP82LSbLmhӦR@q?G)<}/?<+#~)Џc;9) %2% 1lq|1ehqG75<=3~}Rcp4$CFVA )!릈;-xi}͇DNADA+K^e.3uerw=mkŠ_x^Z_:ygFLxi}'/-~*E4-w|Of&,KR%=yE\rZR*_/2x1͋+W|I䲷\v1˰jciT{ q'[S+hrUʙ|M'YR]ՔeW6*xlpuptn!#I 'iS 3OCY}X+UGFxZzstS钫_b@i(v{ lZp-H4I}p(maԭMT y[N7$Tey{cg$SQm2k'9E{)ZRCʸ @9ӨLXͻTvEXSģ+u DRP]vգi͔VJ2 as yF41՘ k̎kuêylnBPYxh@i V$Ha2PRؑO<莖8'/9H9Bd0a^ )MC`j UA!CWt;@V 5`SI|D:U,.. ip25ةOhcEgSI%(G%eY?fE9frL2ٝlP %⡁!EE3sU;\3 Lj"e`J6Dg= Q9Ϩ$S(@ RW rT7KrBjAp)H!eRi/9͐E En&H圬X/LIK(YT)p@;#E IaLT7闗9ؑ7=Sv{{QR/Ƌ wRԹO),""\L -RvC{Pt52iI&QTEa B 29j$٢(ȅ =.TeDWG%[ k5\#d D3tEg!R`֡?П1S&8ǛM)#YdȵxSa0 0 S3 =ȳ:b A( IGPT$FAliC DY&%3T9D9QLiYɬNbQD#qfdFIQ&2.) "aHsu56\*̩#^<{TqBL+# /P-(s X8c_{HL\h$4f񩌦a$J.RڄcOp$gUzyxQ#d-zG7W9|dٴ@ r"}^)(fJ^(s/anؖGřQkMh#1sO@^S]K}YEbD HE&^"'X9Tsf&زK-ӎM5JqM4fbƨVj%(v b9b1/;ڇof~ }1yg'O"o{_˿Fwa/^~$J]Ϗćx( ^?o E/ ;_c#O3^?[򭘆_ɷ7ϣ/s|}B?;'ďJ8!Y z'r<* .29bl{nS%;ۛ<quwX'ǔՄӨz[j#%rFN#ڙu#cZrPS8is,x a2QN2*` Mu LN-&K<Si#톈+8\$vTgɷ7q*@$/]lnߠak4m55VQNLw8U8WiD2} OaUg;g k)SJZ,6af*Y"2~aTp\s6J7S %-<1k%YI^eqĊtr,F9~nn.aoWk +|L}6ϙjUr]i LH1.]'#Jw=HM[8;Ɖl8Y8Ո%H҉LԐiV^vÑıDI$Yֺ,c 4Vf %@ǏlFQPqcZH;0NRD4b)R A~k||$3d @8]A/PKdJpy^ochO[iZ +uY~Ir4Hȑ2*(so<%hY#pѠC[:s(ӥ l1^ϫLN<ji&A(%(Em}D9ZYEPN,`Ήd:xKOUGMQT*ySlƘz4Y06kefZV!HM @"&a]El0S0Q[d[N5<44A7t x2|xK>X[ 4M|m: uyoگMãOh'??{׻yECc>hcdz!t]o޶ï|o˿Kc?zE/yB?;'L'hQ\xxX;?GyUMJ()V>[>[>7ٖ EVappKU;s%fKKyFyA$unU :Kdҩ2(Azj \ #q'Kӗ0͔IXu  X$J ѫ!i{r %BKJXI*`^]d)2o0(irH4֢HlVo$ %uBI' BIG8.ʘ5nNNר3zJ {Uv O})Nz7Y8_zUj uvN1[sh#8AiG<"e?Yc9?b#/=5*5WouYX XԔHUDH@QEͱjLu?&ˌ&X˕##g<=ZDM*#kC$'GA]YQvXM9ݦ/8J;K%<,\'IX"+FUάpda}lҸ4ORz5cDr)5R {b'bomwseޛP) Kd%I~( &#Y p̆}G׿:766i6=J9Y 2Y 2IC%čE,$%43F3bL8 C$ED!BԱK[\skvzId:,*sLRt#jEr }0K46F4JC'mz%zT#L|0-&L0:f>'֏8vsW)s?7/}>wgϜ'_j:w1~"_?~wԧ=c$ o{Dx!ojv~??c/ފT{_wMֿ-E|%~q:CR4-R=ڌ SBeFuQ o;P!0VY2w9psR#"E!! $fFbi6OsRxy<~RB%rp3_9to&UBbhE@^ * Dw՜bx[ttm)<a*ҞLiX!;@Zqb ŪZ4>:fmY_ݼWz:k]VwY]c8>:A87A! a3ژjt}24l;t---Z]c vbM:)x0UΎ{Zr<]ƏKeRM{l!{xx.7-[ E)?%,+gShgl].*wWuQeJ5AF'srJog]b׋V=H@bNCeVΓZ2GY0r$Sin:-sgػkv,Ĝv\?U ʶ˪^ ; zT&.;à^UVV#jsZߥb28H6ΑJ) |dE0yStG#=qbs`̡)ĖIL#gZg(^F3g0\1N6K7y0/-ށz&=IOi2ML*Mf6XmRڧT;.!#Ԋ1bNS(RJJ( [t_[įq%>Q׾g^p4EKeu7^oS?ޗ?)y~L?N mkK7|!'D\zw׮= EQ\z1?ۿOe;;xrKbABjjDA E|Pf>0VDW4ҡR0$M0F5 .nPihՎJҢF",뇘G(4\*'Suʜ}VZm#¨rS ܥVLhbHqdqS/V + fiJ<é$'S ɖL$D*O$D\OYˑ+rkёїlyA`63 .K][Zuq5)zlZxڀFm@HSFC;E8aEZVGnddK" "q5P&O%E#ic!MC#qUi}ԛDBa< i$Ni·cONB|@Ql]fV6l&KJ &{5t VF95yT G9:0 @( 6 2 J&%U Դ 9Ew"Tg ~dr|DxBiI!v;H". )XhG'"B' Bg+H. F1ɀ9`8(kԳ s̨2UF8B29 P8: :uh8hՐYզ0>3r)2gT3:ӰXk/C"ԧ̔(2J7pi4Đ5$euyAWd}OrJ.?<ǴQf,3mh}#a̲e8d8$sdՠ/Z81WnI?ISViMDRIeDR \5[SNA--$HjZ%ƫ۔9!NOSI|}.'5y{ޗ|'?_GoۿS@/??HVH]/{ ˿Q<_e~?>x,˸z?f0{'<|DzǶmy'gxq IDAT/{ ߼n>%'wpwӘI*BZhDA[Y-1Rfvav!=I2P@.sA" gt&816PTRY.EԵ 2ʘyʖէٞrWab4cVQ dV>DFljtMĄF(\җܔ65BhJu[!:iS!  YE" D& l5R0b̘u$g#xh$T^=ř޼Z.̭m2]¨/YexXc8zRZ?M4:};%±E2C"2XC_RrD=:c>[`FMUEaAK&(No+Xci8ʄVbYhpblBu6=sv6aKl'K$ Y(2 #uj%|jӒqkFtG)EG/75hӣM6=dEث3\c1^5*dfhVDUS'NȥsO(DL2}<ʱs^*hy:qƗ).*z#)fZ 䓄8&NIcJub"sݴC7Y xEbO[îQ*SSXA@տER-@ %J/&V~Io[v|9F!K Q3ɪiITCrs]VG,0f!{*-:ZGzEx$8L>@ E[}Y )DS<(X58g^utc:rZ:P0‘ʮ.k؄؄"6:1~G1hFԴ9%dSk\Ns#8E(LgQT)AhOB]]5p~2ziMd.>]* .]HɤB&ˋW"6o2;Q&۔:!p3>M$7-F:Q <6:jXh, 0% _XxMYV7፫0ahAÎWٟtx=ޗ_"F1O}=0 7{O}!kk?O>0HSz/ Nnm~ɩS'?){,s׹sO$|G<,}JaO?ϣR._"+_ߍ$IӘ݊ Af"҂qم w:WHr$$n m :s#'HsySXJXiӥ# )IsAh*Im4-K[MFRUk bJϩ&r_rP2Vz{:}a@Pѕ.g='/0LJ:6Mk$FąF(򇤦YbR=,a>`op4^,Mm@p 9Sxt%Ѝ1@HB)GKNgkk'wI:$]Fu'Qd{u- А)3K-Uݢ=ZR emU鐖9\ E"C6l0 mNz79uK7ܸwEbvg)) hj\E) uL1m(:2Y806 䍌dCaa3^W@-EEAZfJ9*Wr(GuhM4±+j+6ra37l<" B]'t\#U\ppFi&^P+EEQ34>( X{Ζi#JK#G40q*\Ԍ"(lLhD6j(h,1GW1倞ޡUFjJQMo!GPFjJL2HЈQI.Q$n;e;VWS6 Ob!xLq'fmI"VSK'XZj|Zt@gޣ:r) :RY)Ys٥T)eeFYQ68E:o9\ajB@PPxBȰbՍ Sގ<ɷ|7rGGЏϹ}ϟC YTJ)ww/տ\PWbyG,@2Sc0J-jdEN>UԘR-\¹,(39+kd5 y9A^JIHib(^8^fW9f#O)S*e}u֛K{N?cD(,Y4k@.`t ĢiLW,hm(!cBJdB247`C*׉4_6uAchs,U%JW2nקc,tK*ƈ z AbL|?Uz*5,O`?//^_`6=/=!wpw v2h1,Z3D!Q$P`(P%A[YԮĭ-OkϽ`[?\=Au!ÇMzE"䒄fPBA1rVq u.l?w?s69"k{N7$³:FHu \tkLUS%nG%ۯ-$.\oۤ]dz L\jC\/&]ѦKQd5 ahb4c@&/$2/1ozHue>E6J;L:$U ~Lڝrbopiz+4lv<=Y,#9F-@=Hмm' ~(j̈9R)Mifj- pAINbuf8KJ 1#'9z,% HG9QAId:fpQenVUTT>R˲%PtƒH8qoZ_f,r)NN<}َlizkW̑{׮M7eʒ!AW @u0[Ё InU{1"cּ E@Xv>̵rooAwrP \M:R@ j)bc?+t9O<|ڱzl>1Y,Cʅk{Y ("0Eyx-~g+BcMYSb1g ݐæ2}ҡuڧX`ƶKy niOr>&=z*֖iM CL"6\])?S Gw-9/ğH?h_7Fmxv:o 8˲/??ߊG??>?vLs}#?sU?yx?y䑿p_"B P|;apr?  7 9{73S>whE++dUh>IybBPѠc5S3u$G;.=&ƀ1`gF4IUKVlˈ];)=5Xppq [ Q0 xaIj }dKeCXnIoNIEA^:ŶXK!,BCTt-kMך75sMzPunC cI +b!;dy=@SVR8:4Q;hAIٚ3 rrl̈k㔹# )JH]C)AzP"d!☑8`"S ZmS.Ýf2%vdk&m30t^ n;9 o9nj zDr"aB6~q;su$3 wZEkMyl Y5 ,-;:ћCԘFeVeVCP' 6Sv[ST^aX5EbaF>uGVK$y۟]58*r3GD:(L+)2Z[X;6pB{Q6ﰋ}&U.'*(-4RSBGY`)*&]Z׮c93u͹3E =ï C5&̪ m\2Pn1ogCe \%4fF$[|K#utNIp.KG# '.P |jddq^)iFZ{,bgoě ocƦJjܦ\?C!Zrb찂h4FcԆA%L!ykCmgtY6VD4nk Y%]m4 @ntMjߠ $:Jh ݭؕ&E%; V 2 +sWgbCHmduXfAm glv&>E곽an8GyGW.qk.am j_n8$lpit͓]r%WlNJٽdgJ+.0<0dPehOM c6a&I!uMFGv`ޠS`ᲭB1o!=ȉ4ACB^.>! .hl [OK /pjkIMICFI|5bC  zWa<1B&:uiм}.osL>q~X0Vj@!l|}Gi,fBJ %ф킢K7g|c>d;0vnMmdn<0aopsP ԚP ^w ;P] }jdk̢7 k# f0׺,6]p/${"5̺4HvӸN֎K #4U>l_ }AIc!vS6y#2MӜqȈq+2F∑8bR; W lܘ[3XDMg"[Jw 4$aoǠwCkhM"bF#{gAD~R C>iA<\1 9.QaB7<=yGyo9?\ᷮیƆ46Z1I+&褜e􎖜a{?ג|0pHb+~/ӿۙFB["ؼT̿S6SxXxإzaRjc+˼(eߢꛔ}wsvۆoO(O~%^!j^ȗ . DG!$I}'__ OG gdy`3msĢLmd?sLPyǡl)[ᘏoy~fxU[e$˽}ηǼ_kB(tT:Li v0g$)t<['ɜbacv+Cu+6igih6f4KyAaz4(bm͋ηR *15 MYAY_VTHO-VM4qs|tᜮsG5'ogӞ&Rifԡo|}_?\ȷ\x<| NL>w?A: 8?pҳD3ЛI0@n9G֘*<9a>d0 {TI_81o"C~YHPm4H[6Y쐶6nĻ3o2 NP1u7YtڤFvbZ(_cܪCveΘo /a,+eloK-['v NKŘD]7><`x~2G >gQmFtbi^'*$ufs&0ءcǹGyGk+lW#4ј($^ N',VƣMhw8@A],'7WNHڧ4 #փ}ϑHG}oP_4 X(XȇUX[wo#] &d6 &f+.]kMƸk,0( J-V6wǼyQ4&R(t3ǵR0w ~;D. IyTΤl\5gb[@h@̢M{ Ѡ Ul\t eSORtjFfiVd:`wy*Ɍt\vh0]jh*@8Sk=O *H0WQ5 MmY$-0K *R]H#n-$^Ha:{L;pWCw̙M*d,E[q̭8b!cqV4Ҥ9Q&tlc^.v )ew;As4Nk2jq'v)tZeMcԊ#&搬@Pߥ-=랝QV&Ʈ ζ/I> .=zU#vP4^kTA-M,m,9 2LVZL&'ŌJ4P:KZ\|XS+8W8YFsXl.h5p)ݮ`g\')CΎN:gO9H9^8LjPA%#"2)B"2Y[2{uw6J*#<4%:bH Qz!9pitŧ7t$sǢ꠭e7 ^"m i ;`kGaJ`[g)1; WÔV1̹,)Vn6!ѺdIVh$81vv8n8Hp6zK@?uXzGy䑿` ?whL cB+\`:b;ޑ \> fus[J:`YL 墿#LֳAhA+^ҎQea);x,MY4!Ċ06]$ci >os:G 3}6"p$l0t‘[a%mV SVzAnisΘZNY>̧5~xABQ[}U8y_EWAJd92oyaDzIϙRIK1y[>9Ve]kK|=!'6+iUzJ2MkТ=h0;%wwxCFN5/4j4*4U?|7TB2R i:OSsz_#xO[D8gV6e?qLC߆6] )OCxvHpeX`Y(.a\M9ErY=% 4%LJ1[!8l? ~myGy䯑;8OCIm*Y! WS.oruCqlvv${팹Skj_qNV\7\eE's_rֺ$n>z•zBe[[~$I rJ  8$ϝsBܾ?fp,6 2i*P&ІQ&iPh$nנo$,EnFR7%=nY+"gfInccn EZk.|DfҠȑ3]ʷNaM??c@c%Ibbcl:΂_G+[«{S>?% a(< n6Ŏ{iǼ}x{ʷ\ hԮ @lp܂.KmE40>+sr? D "Q.{~d|44:nY'd7Ek^I2͏[; d w@7 ۫e׬h=R?eE{\L1G5#B |&Gٞr=f~挳抖SK>ay!9d4tRh5iI^WD nF.Y>0܇ӹXƉ S`?XS!ovD[|'S'!y.&rS h66{=Qh } oh<f$G{L0[iػ޽暳G8jcƎƤOR4OUEêI`HϜ3gt9]sNtr7ghd{k I]BsÑyGA\9'\M]swC7,9\qڻCY\e|u9f`%FP7ללԌCtXx,X"K]nEI\jiPIvɪ he_[aŰ?u!l[ݖB6v Y-VIvvY\̢~aj/[w~yL_<q|ċrp0&whl-3Cp`I-lAނG#<;l*,%Jǿss{w_W?isbtn2_v(.C.|RQ|ZșoH*ZOXuIãt,3l;}GsG=0aCNd[ Jk?&4F%v~ڃWMgjԁ ~@ŵ*n4Oy>`V̡r_/0rRcq6{A kD>0҇\܎YU1/\ >Ek(~Er}p"f<;5b_2!1cu@*'tVZҶlRYX^EX[PO'>9{T;Q +DG]?|_7&֔S|7s'Sv;Dظ;#%5m@s Eby.WG'|xv7',θ<-J>o%W ҇F`OM D ̀0*5?v6gm 0d̐{іCwBsdcTWO̜54uRblh5s'[D@3z|֓hoX]Wgo'pV3Ƥ4}t(-msZuFyT+%k;ܷS=Gqn9lf1o_}ěcF$o;# (h c1Z,{,w]W=V/tw| Vůp',Qr,/O1_-UwOXԼ 8- ã4%ihN*=g'oGLdOWK4ZP&WrΠ/S<]^}dȷDR@h)`iQ7{7)Opp7[[?--̢QN7X8iA݅e yGy䯏[XzIh M"fFVHG[` ЄƑHMo \,2ӑu"J}˗\#~zsh}n췌MC3plpǝ8s>2 }oSԖI+P4INq>VF} Z&x@""vt;w9#^4Ԥ W6ç 0 E;v;Dc ̚p]nXlQ)Fq^q I§<o錗hL+\ 7т' 5'77״%A&|+ĮfᵱͱdUWX~P!snǡ'STOK;l*BkC_TFVۘi1ErNy%?z -RhE!,&Y%Srɥˑ|?D)tu*aR6rX9-fsǼc6uxԴGq5I^sԾ! -œAgO :n(pUU3c}MyᰝcVH`'^e(_ f,\Sb}Yd젍%Ө7enRzu uԕ)#DkhD0}s.s=f@9c@e* Y1S15{` /0qv`˛.,H,Z HdӔ:MG̟F3 IDAT2/=Jak$ǜp䚿O,Ƹ1kXzVD߳9;W׸~6At%p$iOXk-zgIyiv?OSyc~e}s 7[dM[iklP5Yc5FƳZ=&mՓb N\ v١'Dl@H ː&!@H(cR”W޻ӹg}zܽ{S'4pɠVMOw^k}He9lV;C&ř­,UB$WEr V8isP0aC>+_x]f7903km.qTDUY5Bj„wIg5-©{T%UkA#q/EgؓVbCk)AEgiW'GC*hj攊)tإf pȑʂ\X5@ 3}RCJ}8T/ş̃& ( 1cXFaiVNYCOb΂fuܘ YMPSXafbB<5fר&@O9;1u^Y:", @;I maJ&@5^/mWlt;fW:‘$D3 Mg}YYϐ IO !(V 2U&MܲXnc[9rJ"jsF.H$3oiWYA[D ܤ:[r$Oq$se5mҠKjxr\ 7 ieDHAD\ :`Cdh >3jCwP 5J<ԈT=~>F1^&hRDWXr`E lZ9%{cUPVi)c>mgN~J)g/ޞlɄWt-Ω1nqQ$TH$PPi KaC_ӾwvBw:bگ3יV̫[l#sPՉ5bi6Gw7ӹ koTPqD5D*2,}E]α=#7^ș7 =ʘm^)W)c`t988i\[Ǿ`=bBʜLVH*QlJ"y]$kĆJdDTxu>ƽuSa$BY%H .JGÕ =d!(K[ C:%mC{HL:_=%\ᇮ~p@|idg;1;\ShS4 &*i&2 dgO@w#v : vJUФQ/騗d!\<-)NKQO`Вwdp]gd]kDaYrY'413ֲ͏w~47~?97:>Gx+^}q=il.=_3>ˏ?j{y/?|,//{_Zg㧎{Ͽv>b_Wn66:/#<#,sj# %RT D&; 8ÐcKu+$H)Rgu\WH*i* E)$2)"ÒŢY * RLSDOH)1C0-5/hc 9@$B2SIf:)833vT* HTg]\)Q-Rj0,o0OAR@39["o:(rܓ)‘1 U$ Q PH`j%攒) ZY|dp fTj2yU"\# ܼF)\PvԌVR%]WTܲ(8#VDi)z) Q&y)()ĔT9ARrJdי VUn7]*o`fP 8ʒJ̩&.Uɣ9q>vAw:"T ΨA2&5i/2:3/䒄,ib*hBUXQ/cahJfhFRKA-)E1m2d<*Li2-$VE/[ t1A,rV.Flg1쯎[`-VSi3,g*DBN! ĥJuj3}H5 )+#F<L9&-@P1T1 eiEPaF< FbG+jKk6<8%/%| TU Y@RLGsT-$đܨ3}"b%x^ڌV'[ K*x埳㟲ISN\xQib*FSI41!> ٺP,L'MeX&dOY@ UN+[:'g+8,QHɑѐ'K,*z5_bgK,5B֟ :! ,GIrĤe i4BDP N4ҹA 3[gv ɧ!hSN4p/EМist *aPe0UaVi TA^eHFU]>x_&ۿ_7?o?~S%owmxgS̻~ 5|/,}>8O['g#~x;o{[ ,_w|⛿WQy;?o=/^PGxG/X]e6Ecz}&b$giFlԓ9}@}kN3Gl*Ti iE%5CE'Ia8W8ѶXQkΩ4bf[udaҔ&lc }kgJ$,U&>(خvzv눝qYrY2vYT9Yi1NsIтU')eܠ­uneCӼ2LpP6v;䲄-X|*-C\ *u_f(LkMF),S4)c`u֢_UjT FwE-PY6 bTвS3S 3}_`p(MN0Հ>izxqMhĉF,ˎkrfVZCim38o3\{Lfmle'lg c̡#.ٸqyuSDͥE\[Tq .5ED!CzhY.ӌg8~="M'uD#(t"BM0C\~BWrys~7t#@' ܤ0%1iƖx@Ifa'T)mwzZ1{1i,sl20Sj̤`I wV7Fsz9X0з}3qNA䲄 [glvJGIl(eTDiZF%oKlRZ'ܰƑQsP✆>g_?v4E( lQw̖H*uyC0 #Z)uw⦄:ZGl3DAnJ,* 4rtli 00E0Eb +^ӇTW pP)P3#G\]&.ٖؖq%ɐ :i:y$SP.֖dIf|EŢ6X5֔~-] QULPHw^EHaaIq:+{s6.vN% ^a  0Վ1m¼#sfۄYISyO$o]^oQ~WMD k=/Q:<|޿4t!MUy1MS~]~_c8O|۷W @7sŷ?a /}O^NGx?%~;_.ŇP0*qXOKHiW'*Fum?]JI$RQ%15ʼryp˧n1_6Y:u<1)+s;1U{ΩT+JK:rS Xl1ZLh16Gg{K7?˺Bmur׹bb 1."3%-rRûV>Ƙ[OqS]>rɩ`1Nظ:d]Y>]lcg#x%W;\m }laTo1L6ӴIØӬiؘ#E@T6`AP1W̫5f#ñ+eP9y'aEnE$Z6$rSwa)P%RTRRk¦lvcu(aa *@ҬpwhF 5r4Qɑ]ՏGx>\̊:G&:7!"v%6>S]2 .F$ $ "a!\D@"L'jaVL6y RF\IHM!ٕ-Qe)RõE,*cw3kՊQjƴ1y)")F#Q;)! SS-,\]ݣXuGdL), aWMʖPݞ[V/WXQA19F)c$&/%R]#idjFe!nxb'[.x)(C^@Cl$TKz>,5d8Ӎ:K*G%Pӌ3qUtc)r"0+iSs(}9 H)j)v0#Q9" X'I LS("%) ai"QRRId˴ha9Ih1"YE#daR,ԟnϹT"_Zb,b"iQTXҴflt.ٮrվ|Ae;5E EcZb*K=m:J#2O-/ؓ7sj6WW?g/Xw|V7>ͽYea#("sΑN1V Y,2Y"2a6SIdI&+2*Y[!&Sf"ESbjsGI~*375\6\6ڌ-ܤ2&E>%Ws jJD/)[9Yem*DLѺ) QB$g1˻9 `(&ٰNS@Jd1Ec d-CD(RĬ@@%;2aakyY)#gC }lHjAb'51-;8vb3:++ dW{Hؐ&bJT[CnvR3\keza$,hrq;Djb:> Zl`6 ^5gZIi:srP՜5JqĥfwLB1jpot1`B%X~WdZnf6e3+_) *₊R]L=@F=\ ``\ 13.2Z"%rYS' NJJCT9YO44,0uM&s,n0kda !mB,%Xq3hC̩ 39d?9r% %>UaN{53)49b!nQ7l$F[0U &b+P gzVPS]ZʘMT1 H0( P5 W8PɂS6 .C*ݏ8^21݇aKQOm s%r!n2tDӭh#F2QY\N3E)߸`}ҫ2_ՙM^GgLS̨r{ a #j搪WY+,'F*KnfyWe>B+3X+LHI[cn"PHTm$fXPRH OqrV pydQ(ndݒD-YI<'Mp+T)"]aQY^p/k*e Ja9+KEXĜ:y.Qe}g,IӔk?oz.DQk7>s}'D~&_oʕ.I7o~+W>G^|0 u}׿Wi?o?g}wW׾_xGx?[|o^D$י[̌:^[ ֪l.0"Yu;{sd+tD>Zy >X/ ,OF) ںt**J֒ɯJD+1Ýg#t=081" @qu@0 /X.=tqy iZRN#`H ->Z$YЄCxH6b,MV Oa >)&\pCu~ QĔ2v ׯPO\)ѽ9b5IbC!h31C[GG$W"KgL:ŪH8c""J)!MmJSf4)E׸_cmQ}z君C'%4psJmmD!Ie;;D;D=SE2TfTЈ)`pD@0}@#Y*XI6-tϠ%Y@f49 K>HՐ2n]YΑ,<"~wܻw~k,K7w1yYt/[?)yٟ{? |yO|ygⓅ~wO~Ͽ˲oF3?KN/꜎^UWjV!r"PN*ƅG$Ktjuʙ,1|*\P-p^@W3׉( R(LIe!S"eWXn7n" "G(2#Gh攑HKLD$j,U]2cFRwOnxt |zw<" Y@B8T)eQ2T, D@V24)B-CoGhf"9)2q'8p:(Z%zTh"$P ]%M\u. ^?z/r8(hL+ˆW!]bQct;ۧtǔ"kҁT`9q&i=T/ь!&Havxh4(du[HURe"5Sa")SwD~$b+e$m D 2y_R>SPJP0Pp}HBnqD/1 TLj-T|(!2a@y) x r$ Me J&~pHli6J0V-\%<=YMǸ`C`C[# |p XeH:.xQ^4^ϝB , `h"SEC^}W ^~`YX3=ʤ;1,Zk_d0̽7zBzrPc(1 }A6ԸG_ī_^g\ݿ_z@( jL 6ᒆ6q,Ă4;iT(/3YB%B"P'g1(mJ^.(e4Vp:P,4Z63aD6q5Nm$v#zԥUɥ’ . VQ56o|G~=\~|jۧ^ʕ7o^߳~6_eʿ:O<#v3_x?S?O?ΣGsK_?[_Eܿ|C?3?8\^_5sϟ.Y0O1C&8O_`הMydS>LJR<̼v/9~3@';s}[#]kpd?IΒ^`nBi3HWR+I󢡙IԕA\44 6.(]3bZC^4glP9N#NV WwnXBn1i!UgȮ3bљpՙsgI IKw*ԉ  &ܢ+K* ̷ 5Oly>Mmց TWCv 1%G:kcQd7.!n; yG2ppi{m֤Ns:% \r!\CwiBV1E^쭀 <{Jxrٞ3'8ӮJب.vRh~Ȳ!-8 7yyo'mn}FK4 sǣlFMBZ lQ<&z@*p]IzGTd%+B2+#}>mfa%j _0,MyHALt MW1 #hЇ+4_qwd7<~ ;+9?DCoI__},{ݥ9P1ʧ_7hs% 5CТ>7hC*ԞGT4=>%s"nc %Du_(i1ј:n \9DU9buXw'#6qD8|0G w}1;˴Rt%_.sΒkŞ`$`)۔'U Ԡ9䓐meai[].M2e㥺 2֬9_!NA{p; +H[JY< ri#Eg<[׫SEeʄu(fI)@Q%5F]o 9^g'c6uL! %Ö@K zqqD-;ڎ"8$1!>)O 9~G/s_&{oK+(~>KWǾ#?OG?˳{kGٟ?ߍ/\_Os?ubޡLmʗlo<]3 %l0_q:W`X5ư!4$5c.h)Kfb3)mUcMbT"P';[BΪxo&Πښ쳀uc](?H㔾TL9$f> G˨TNY+fcuuueSuYrc!'h 4 M"9Mx3yN\- )b`A5׌;ͮsKϭ>G}DwF!RjNoߔ& "kFHAP =͖t;Oo=8j])q +Xz]JbK-1bd z)~[cPZEϦ%!`Ƅ5ٜ쎸)JpJ%k:E`bn#Rӥ1uJ"\ ;gϹ^Q/mtA %f;h罏=xI7^ư\g\S.SiH2͊0fKzW9ήH͂yk2bNWa(DFQ.27s'3&7X=^ p)m4lx 1hHlӎ6NdDX=D ۻ]֥jiiBHñF+Q 4Vv#rrc{Fmb|Kq'(z+ւgRcgMo^i1;R(Mx*e L*w/O_7ӿWD_M<+W\KK.KgmJ (Jb5FBw+l+#bmCO[/Cљ"AC"n%@дo#~ӈR;9K|^^g4UN4m8UB_1Zq2a{L\7ئoߢ亳fE$c)̱DnԠ+c40#Lk7?rȋ'|+ȍjȍhjvH6<ן` f^ KA[k];(:!'9׼.uF\j'܈ G+L鷐6kÍ>bOqč&$uLYAukF7h,`ǫC 38lj2`_&8eQ.~AO/șёS?ʈ 5]*uH29Ů ]1&7 t='ĒXq6D0)4|"< lG=}AGys=kU :n0٨eb2$њxCUS&LL)QЖ|Gm 9cGIS#k]JbHŐŘ>BxwJ%QI/,YY:2(JX48'L.:qyE:t+8ɠp;> qh8ZПpSǾ ȶ>ƥ:k㳷ve&,6Mf&Ы7jO%yq{hsAI]3|@*#>֟}Lj+:j+,}It͑y˨^-$zHԦI9dxhA6*!Sl"dmf%a[R`Ɋ#3 ^Su-rӢm%Vb56uc ͡9ϰ^p^_R+=P8flÐӑAU١-xbu2:#7\q-v"F 6ɷ>Yj*q%\q_SbUroI:;melc Ǣ,4W G뀘@Z~_zT +`aB<ۿAa!ÿxUޟJrwޠ DuAؐiJMcLk)c+t$[bZ4JlvQNJeY0򖺰dvGs=s?|v] R*f (:n\>i듵>emWt dA?g/SmWo}K`Jgv*W ,.'SNpX2'a-\6KK5$w1l->%{B4lX{hClkFwDzN9犭YATBOK:')ylp}4&-a5Ubģ V2lO; hQqHbh[k@&*qes60VdΣ<<%A@W3^C6Q2ΘfH]6?b!#a9F4ծG|atvb0`/lWQIiWCqR=y@e8B6ݚ\̾ܽ!rsʥy8)ɍq̇Y}n;K<;!vD-Ɏs FQM+rSИ&}ZV щQ[bCbfhF&lGfMfָnл24$f.H&!`^HZ$|Y eJ]1Ewb5Jz…qux/Б1/u;& jdKe=>vj᰻͏xY: ݄³)< ̹fԽ#h<{NgϡQIȃ,by@;CtXj=vO j J^,yZt-G3rkF\L]A+1&:笐 ӥRi4&=vПTd z"\GS4AF9k ǃB;!MnM5wX2}}FyPX[pF9$?Y)NPL*lnc#jAiy[8Ct`-iۿG&>fmb-E B{S#Ƥ1Su4DuB^n#kBgl\"b6?jyto{5~~sO3nSt,O&McQK!`C_yAlo-%ַLj}oe/5{?ZsOb*\0 F<k%w3FΊ#qGt8-'߿||ÙuGlm)+o5.`o!M`eX=vM%1"u~%;p!og`+Z[lhmxo=8iFwNp)wg<>_2yv":.mU)SS̓F!I-CuȞ1fM1w)^/*zPb9֨yl}WJg+s~;נ [գ|f vPbJS!`FfN-s{,Yc-Qh!K#c5T]q;#nGCWsjjkd 93,3ѐE3d qf3o$bc%qK:%>svzMujQm2 ,C"W;+̦)vM ZkS91{.Kj&>χs|$qEڢ1i^Y [!kRh'Y|2Wy@e8a7y7&R8d"F kGZH9hV%lX^[H L#fb̭3*/]@,w7uьR&c:hG\\W,ɾ&:·r"B-d숸FHKH]7&C- G] {CbD^Cw:2̸ flxܾ7uu#]? =oN&t3<=fnƘ)p8HM_ THDKtb&N*`tW$K9fLXBAk.7VיkZ]g^^bl2E_=s=33k\''̠!BD BM(-[KИ:i.fg.>ʣ-5L4+4"+2)2 YԍEE_[&Q9qZmNVDIǔqDsg5Gw<9fp|scZ/]fTafϠLj9̛rj,QaGTMQ9TEX.C;e 90LJaa>VEl(l DZ3)-Н iНip~D S v 'w ZȊ>rBn;mh5` 4uM6:L]w٭cE  ̷feB3$-PJU Q* Y7 z]DY8&E-^Ŕ c1c$4J2eC[-&$Ö> RSy~ :#2ᰬz,.CZ{tKy;|'"cnՔIv.eYi\4hDh-BSAKxG)523rEX#ly= .%+VK,Edw m@ TF r4qHxUNTsf,>nuv+,v*B='W;NĔi;R'ik R{&(Ǡ1õ% a  R Jĭ37ZC)$V5Q9FՀA8oڊJX]gs*4?a ] f>I""b_(1 I@j:9q֔+m sHM|huVk9a+LFo),#}JᐵAo|G9wf),d{o3a]R޷@-Hй t ͷf3ԑ]j\C:*(.ksµzb4t%Ư{{ 583P&g MBw(Zu[%`%4Rcj {VchEW#'xwp&ZGa=94:vIϝCA![+bG]ae%f>"r\-"D$1sXat*LF >ci.c~aIPR&/e RmxNNSd\$IK%#buJAcmCX%!l-1UhT mkjE&}q#Ngk>ٯvkݗC{N@3vir49&9bKA=,~03:\-ϸ\q)e|Ce~mV&H̐$!yQ6)[MZBX%7{p*dWS:*7K>|EőL֎Y&}^]?C^_=.oCRR&WbkKIW'yȎ+VšBq Gynyl"Rp9Yp4<&z>ʉ5qI೿蠔5LPO%Mܛ BNjSK~P$.y"RG. ڥ`׉x=DieǯSZѷ?ĵ2&u4om9H<|kU^rιu&4$N1 a&[6(8s=sgϬ'|_Ik DmhP{W{)VjdJ Vڷڇ_<'̾o'GXaE?\Pk :wMa|RW>NQ` 7K钞R)fSc/)VqvĞ%}Gj vt̫7xCiQ&i ${E>rڂrR޸.80 îp92w1ZO;,"VfdtW|xYތ*rl&;f.ng.W)yjj8`{! >Tȥ @qC{dWE]֊ڦ4QIWzqLy=G F-S5VQ``9Do1)ra!oL/$/D6urіbh Ti{{5~VXѹآ44IcT҆Zm4dI![S%s#s _fZZڷI ~H ĝ:t[ttc=|UA @ [ -etr7p}{$z{6EH6R,*cT6zr?dYY0{5txGq EQB%a%q k0: R6w7cŨ1䖑1cd߲i;1&CfК:mRJ|a( '1EɠcX2n5B--!1*qݴî[ǔ.J!Ġ8FN` C4BgKZ #?]h4Ǟ+C 6LjISH@kCZԆlJj :9mqHD1gx>o r)V#> ϕuʪQ!u xj?#RvL̴Y.i9uAYB+jjZ.8UI|b "EhTP Π+ `UHhr =?39zcX=縚"[(ED\gJzG0z c\ZK1 c),EgiŸY`n-a:nZ4: #@clivjΎMX]HCcV'4 olFT"8 +ʱɱX0|{1:Y.%KFheM(5b`w`3(ZL)"RH`Yt-FŜ4iK4)SMoЭ 74Z㡇[z_K čI혠H D 9AIPb;! P ISx`$<0_rdް<Ǿ X]VZn:]7݃ުae$8ӨOw=s=|f9i6rm&_8X;PTK%uxÛ5 /CV$fO\5-$nD`Rt+0A[~8n)! d78D kiQ7&u}hZRi6;#Ɣ IDAT8!;r/ѷJUBp6hd 1F?%mT&BMCA]h`$2֧Ei |=%A8 5aͣkMytPrl9(vb)]U!*`\y~q#8CwcVwCD(U-o'G)>5>-iq9]0T\T\\TH*JKP 3&cd"ztf܋eS5e3s,S̏1(sw0ȇWY0R AZw}jk4sF(m3J:WCo ΐ~mzyIj$-t tlX;9f1^A^% 錞2`MS#(TFYˬ [gyQyaEVYb.,[49\l \- &zI3 nK{ԘZ>3$IQYBuƥϤl2)}Ħ5{Beڗin aʠMif}AA*'VA3LR 4sEEE\ɷ]O6sROp&?Fb\!%r O kS"- $ D^qR^`:CRb`[k.qހus An*T-V)(䓏dw493T3TDsKT7gKT-\1*LM&YI2 .#M|'l1Ò!rB4^p |5qk\޴oz_F6t䮍uUâS=XtʠTrb1cfy~Qc^>~ 1q;LD6W1S\DsZώra۸Dmi NKϥZ%d)(b0Yu.'&9&FFdJKOZ (yGA)"Հ LK`AT oTum Nopr\긇tS^N-ĴI;Iip|,/?G66\HG#AX&I+4Jqnx5NjXK& ._[#xAtd6\9bZ5* )HtBs&6>^_ro>/yu~Wϰ7/mH:6vu+6c&]gHg6!;QmruI}2 eY$6Q&lNI;r/{gO\g&G7s|JۘKH2iC\=BJu5{=Y^2Y-aj0]k7$h8Mj;csz؂A 4 CcZ9mrR`Yo$v՚@25+&c o746grxddiƪdK&1~{1\;fQX<e!ad,g.WN_Z fa} L9l5m8.ऄ"sJ 7iߘ XV.cv0ٷ;L&tјP&S4\k&P- UؔȶjLRU+W;r;C1 CA\5sO V ;OC8G:icVώ"䋄h!첼~׸5q7-޴o~2?݆c  +T ,?CR^cs画kbĪPqM^j{aʔprod$.j&j,u9w7yk~nd.׸|m>J)e(%P^ǖWu2Kfے#38xy3-Yn SB %Ѣ*KjO4r,@!$Uw3"&)TRp[= SuYqмŁvL]{_^p=.Vq4))q?̩MY ʻHGPX :K8 :w}w{CŰ]&3: y{&wG<4 W ήhn.1p1.o0E$ Y嬎(~#7yDũicjLn8HT sj6 B2z<]|({< W*$qD&.Sv}6u3v&Ij.1Hu丹+}^0L.' D CD9ݺ-?7S:ʱ$=6MDhvjJ߽ n|/sq|J*=9L}|Gm7uiJTRHdT*a|5GZ&C;{SCޱ2>3V<{^` 5c)ՉmgS yC w@lTHJ[Pj yRT*T)+R񴀭 ϵ^yZ̰LPPQpg78 Fk+Q}$ԣ_<#=O,$ԋ׸5q޴[iB"JP%3J-GWRR!QȦD#ɧ. P]@V"jbI\R ϼhDksܤzꀞ6^&T499XmTu ZΈ1!*-9%: 4QATE\i#UB[ُgFC/9 MgF1~>bX|"% =NK]Ǽh NWlGos/ͤ+^߸ǸljL eDYrL=& #|3lpyAihfb٢EZYNN>>W7t7;N;}RiRib 㥳ay1j@hLgjiȍeKcFMZҭFl3nT't1%Qa-NƭBZ~2frBIfY,:cMlظDԪzR!s%EW ")M8J͐BAQ*'M8+7I*j!8=ADzf(-Rٲ.b1-֘M[( 8)X.ڐ/QVU4JRR:U2,q9 X`URTȖ&с,iFj8msD.G1t.K,\DEĬRd c 8iFz!jL@E1̺Zγ]4Y_:EM#nMqG84<4_02RdS=R`_9=[\W:T jfN됥uNh3kC:rHb5B,z\q#P>YImk&FH8-, k\ŷxҬOiǴc1`wpS ˩Y^' qc43fJt1yL %,d!S*E*Բ.VɺcGxo h:sxn5xlEʆ)|F15uBX(CfAFHB)J(u2i"jNۉQ5L(998]WL'+@ UP Ľ\>$kb9Eu" X ~5qk\o yn[M4U$JBr[zb<2сBxA m c%&-zM 8ms kYTmQ qWq-143|sκyBkS:i 4b( FASV2G )F.5LLKѡPZHAzMdF(CAu Eιark}Ŭdva3ݳ8eI$[25fXǑJ=W5=n.h+c}5fvsNG-uŁF63X |JO#(VExii;9KoCo팴ޡѬf4V(ܮqe qUjew9n#=hmhmNh#jz@-Y/ eAxx[Mr~i`N\K8q9vkr3qʈf0?3:Adٮ30M^_bk)V 4M)(\T>gϰ\=iegm3 N߼d~F㜭9rslpXg_t ҆AꛫU1(JAgx5, ƳY ? *D +^ 7An63v}v=,g fŁ~;@srl3Bl" 6'kyMυ ΀Ԣg4)k3m9Mwy}z&M}JXdǧVhXqtLwX+^l2imLhOVkkEE$T]|w>Xriqvrl4Glh 1%zJW*x3'r"Xk\y<'oV9$ | G+PkJMKvH^gHVkvcblMHMUU%XU4%yf(!nIYл9enĽQglЕN}]}[794TKt?c/ɤ *:44;`-pŕ̄Di1M.&gMN^org8q -I* ' D.K6/YsX:.㡤!zDrHA)U. [[?k]޺Gk>{q)%o"BO|3{3fG?_rM_wg'_vl+K^oW_|7i4||7}=qk|q~6UfUH1koLwEOf/P)JxD Vbz%wGx< ]WfkulD`sW# zz6/JJicC:ΐ^2қ 1ObȴƓK=)KB}\zN~vNe$ksai4*UŭBjUD= !L)ʪT%-y4(+(+ bb`uQ)yڇwlu/ỵ&pEYn?n1WLU3S}yaaM9W)*D[ *[U򁁈$VIa'7S% ._y^Ȟ#]|2\{ɦy̖v̦8*2h%T/~D]2_&>hq,{KQ[& ecbZ nu;79Hn2900Tȥ%um}v[yC};_()ɇNIuL7c;y wyl摺T6h$ y>̑ Au_L (c[?'\8Z2KRpAso9f23|eAE-TrF_bU F^ PBAS\ӻ5ajro2R}]2٘:Oi8.HJ2HRX~H>1[RHLjSn&Ny DCmӤ'~a:u,{:MeU}J\mn]r7o3U|&Di2-Tcʱ@*翪|Qnw^?oF4<j%>xwnK|/?g_?|w__O#g|{?2?mމ(>ȟV??f66oz=qk|q~ݵ+nAXj b5bFƨ 9ILc k0)83VQ8>sjqu`1d)WyàUYu&DU-MԂ [+׹E%+95faUD~ЯR톴)Z0txem\"k /c6xi$%2<+1ch$MbX$Ae+ZPW$el0|U1PzifȨjq,bfjAͣ6V[ uADzDh;C+䮆4AWs,RLX5b%@S"*8o3w-M-\I ]fTMfU ƨZN%PUR 6K<'9q>&J<#H`dA% a,ڜmJx#>=ˁqcQI[—X3SdI'gjQiJLa%ES,5F%U-V3:(ZEÚUpmQr- Ey|  =͉tfqL[gPtΚiOP^w@ȧO"u}ɖw)o( }^ҞcLzEϸBQQ uR8g@otľMDM՘MZ K,!N:LWVyӣTFF5r݌bGco [*Y96C{*fQJAUrZΘۍ=n"E TBiID,P`XSC];9SILL&:MFVk }s 3ŕR I:0H&I"$6q&uK0X \4ẅ́9fQՂM C 4T& { TE%@AA%CaAΔor`q`qg=j &g: pe#@O`Le` mT~Bk$e8ط?0xo3+k|7~xmoo?n.c?SO>~0?gLU_pv^?O4?߷?#5q/4޴os__Զ8osZbZkb:1!v_I}IR! JZt fe$on1Txftl  K IDATXWS=Cl5"\L}M&MdPb`ĒV+]aXZ^qח1ESH. IG}H%\һwA)Tro1k\&W;>yGV"A@U_ ~%d'HNQ0f^~zEVglyG(],.eI3Y6qdDGY!Q%Y+ɸj1.[$ .{bA,B!{,4p*,ǜe(iGt+f:UGl+`Ѭ)U:'UN6dvf5g!224TPrx,ju̍[Q edMqR=J0Pv]e{5q(vtdM!vu:NN*u>MTKA\;rCmzx۳3T,;u; i`+!L..zeٙ`BlNhx3\Ͱ ` pT0 ThXHנ2u*U#fYyʡs׹=.5f]FsnX:O_k0~A=#P50M}FG>}d4}ҾXK9^5[5 f,1BGjDWϰ/om:INpb C<0 A r%T 8 a1w `𼀸X.k2QQޮ||/(g& #6vTU<~z̃/* k?ďտBQ.5q/86/)Ϣ(9`)CCG d@\%y8BCN|d.NdKD '-gDߓ7]TeHN>\RgFC`F8L?b1(D(DD7ls¦6acmB[`G!eu{W.;vz?j[pxv|ME ّJ~"E=дQwg$5ϫ/ +ށ-Eb٩7{1^ 3ϟ2bhdaMQ7<6KB%\\i( nzZKnGֆ]{isi}J{UXm+BX$c ֈC8H'O$h]R7UpIJ(zI][P `\*N$leN:s\,y,{.$,΍ 17&$J6wJzJ!WV/0Z"ZNv2ְW8Zkf,$i[mg>]Gyn)^\Oo^ 3|gWyKSxIhmj\{\}.kۜ3d#=!g&G"lR&ȶF7feŲY}#F+MLHT#{X*zeT/s[^qYOV71Ybca1f+g\uM~Q%尤H* (,+]}@kHWgx5tSAdI̦m>in!_{dܻw/yݻ |meYc~uF1{E<=v]0!o~'~ ͍moQvm/wC~~!?+O5EÛVnNm{ARiT"re-jj@*.Im, D*T@ PlQF,9YB ";#bQe&c(:7p׫<.rX1ukNݚLڊ"1`!'$ L [E9NSaxŰ\{N*˩dPcpOBxpTE.UDA%2Gsl"jߚqGe63n]ZV#L!mb0n`3EStCn7٧eO)fҠdg YfsL]#eZVheZA;IiƝG8'Mp*D6Z'aBbtzd4/%ĥD Td@&Ok*3$.cAWKrE,3FJAEיMWxBGaUejZ9dNisZh3RLx^BUmB\i%V_X wꖄ̀!`j Mmš>`C?c[22,: $j\(ՐPUʆJ+ Kh#,-%taqf ָ09[49rAj^%R27ꌭ1kT&񂀞{HnUL5)mbbtV)raH0DF*J$Î"a@ʌZ&AWs$(d@RWR e^XD @MgL=qB-}K;ciYc:1Z_UE%qKILB0e+֓%xDET@8%F#nD(ҭ݀1M,(Ƃ:cRn%NNՙMΔMN5u^| 2KR,adÙR /+ (qS)PU zQ,Qe1j\'ihA K*["k%2@+@MA@MQY4]Wd U+!e`Fpr]xSD"gs/_x?&!"< C\3B|ӿ ٷ=?ms0~gs=mi~|Wպ5ěVŤl3 ,>¡LuԆj$m{L 3Yo83Ydi cx&gc\T tT`u9YqH.RC ;T5a/$j"#A:]!MFRؤE3wWl7DŽ; uKc,QU)Ԃ A*@ 3Gq3MƓ.aЦyʩA.T(p:U9)K<%@2ʆ LNLѓa0glz6o\pvcj38[tM6WB%UL\Up{3 +^-00V89Q(R@ANNNi@DP h`-b V`G)eukՌYY eI YD "IVdlTBP > X99[%h[EXfҐ+C:C3޻ښ}~_ﺯ}93s3((! ƆjIT*B.)ZiiRbJE)( YBBU f̙s_W={گZ<!/R"ғ(GS\ښЬOѵA+]Vx)+@#HJ(14MZMUI7M`!qK#n$Mܖ0EVy3{Ses}eFBlLb0|V֊62WZ X M*Ub-N֍#6!y8z49rՌH kOh#%dVx%4]˯(I]Xa !9eE"Pz"R$OB=P4s9YChҖwf+\]Y6sBu .g.ajd6IjH[idQEW2'WU_*EJM$r"DC%e+d+ Ђdrz4<}@0Q"A* z("rܗlgo=߸`)+ɎK\r]AzMM*WHJFSpxtC$4%o.5cu,ҩq36x(;*;*ert>e̾uj{X>j+FVr$5Gs2,7@fldC~2ĊC\k[z8lVU''' [7ЦQ,JXЪfyYeTo W$"/QHErC!1 :ք=F1c']NpՃ-8þ_qǔHYErG"DrY~6~x&?wo>ď|{s> ??w1>4;˵kryDŽoo n޼?q~,K~__*>?Ki{w,/$:/QU%* j`1V7R6EE5#wLn$ &)sBŸt^~L]XߓnF_8GS)GDMZD bP* Z!o4{cz'Û, \RѝVgNWMQIL Ъ XT_+$5SebM% R%K%*2 n1q%<,*DTKd%GUSle])!ͩI+V˲t *e6aC]ޮk "(!hj.zRP![D6Xt&=0*.[ Nzz[Xci_CDd-iPvc^ H*hNFRmܖm [VD5߸T*EEPL$a4Ou:iIi:WȎ[ 0eRkl|𻿋ǴZM~1nہG ??jݏrzv_ȇ?O?UUOw}Gx1u~gKw}0wF5\ |3O$ )ͿY'+/2/eY|__Yט]6_8$E F^"V.}璾}Ih:3jE( a L&U䚂I~KѾc-uat=JddE.d'yM _䫐rêYXџYTźB,PE 3o'0,{l,䒛<#[HKݘLpgk[yu~fY5c#Ff$H<24г&Tn8rlr1tkG5Eέ)P6eěXF%Xbx5feIo- *NmZЈn gVl.dX0 f}o1g[pŽyBW+b[П6OK 襣%#:!-gZ'X䕊Y)p?a4}MMYߘ@ A+F @f~DPI\!(%CyiJKjL11zk(Ea[2 .#P&#(ZT0(O{(z;  "D*.bFtuΡIDA˞𞻿KKrHL<:Rܤ4dƊw_UѪMk0N:7'X>z3D֑)!)($R(%6+QK(k+ZM*,m׭{'#Nvm\RnFGPI&ø2.Ƃ&g]7.ζ3<Ŀp`T 4,u=ݍ1]1%J QaWc^5YT U,Qzc??nMK }A&JcDnNg+4BSNd-;vy#}ׂE눽6cB",B$*LJDޑWڳBZU'}~ Zbl^&JstѽMrYzE!90u6t,Zඖ.(l5KM\iTlZ6;E8 +'-2&3`f Kҵ,-FlBv#um-p.jX5NlKҙ{ F.I2 6xa['(lOdx$%ƥFPY2ˁ|-k+9~o=9svv9!z% ʩDaB.%bƮr`W؅DaaZQdL2a ͕iws^)Eǿ0<[O{bb Ve~I D@EAEps&U1k (RH(pt?w_s^n#T^ 4rl<\!105[\ 4U 8䘛c싒eqt*Kݘޜވ|.CVNT& Da"oC)/^~yy߷A}c}3ґ9^Z~m#bap+WJն@dJ =>1Cnu޽k!d-]g.Jrn|ʁwtpxTɑϗ&dV@p8F~0ZTbdǬhoM72$N2Y\5`%P⺧- bZBCbJKb1'L6U%<)o"NPߙ6˥b$Œ直u2Z\5^bjۄo؄_c!^c9}6>ыGw{&vٹ%E)g{|GiykSK6G%V,os5![EIYWt^!bE&c12fcHtFZ̓CRc#'NLN}I&]~"H4Im̮-E!'j$p;9}rO|S퀉")T%@&$e2)CNp%-Jg5V,iq4IDd!5#∞4/lk<roORixID* ʚ@Qh3Zdxe2h#+=;. LP7 tP7Qً̦m|Ѡ˻:@Ӟm 2n?-:2HQ]zhjBk;+'CXcf6iS-::qeb1#y 3hNcxTfF@mu@]L;..#֌ni }4. Qu\ѕ( cw\-Oz{x^ QI(j-]9$,nsVOiڳommqrrrGGGloomndLXĕEZϿ;=kB0,&_י467).FЭ`؆2dlB*B$6)7rE_8gG8cG8̈́ 7 83N S?jumR]exţ!fX5 UzzD˚Ҵ WM^R=CB-3Y,[D+e9kyQFؕOe'CK$0X)s}GYW ]Yg"jL69i2޲FHTljCϞvVMk2E5X ]5O6YSdmro2Xnqyhe1ۜhJ"K jٺ`}/8sq&Ë)){3Zu6y0Z&^| k҈t1RuW<_~ $[m޲oS: J$PerKGDr 49!5#'+l) mN˘r~DVW899 Y511ـt6_Z6Zcֈm{@q%npstKZEֹl:NZiN3^vˣS%R2`6\c3@+_@HE뢳~ZMf4`':g+ %#LWlU<'>:lAago"%)qY Ƨ=@E C$C lX1P~{F>@DDJD9 mfSɹ nҵ(2pK}HK_H ! |/~Zs6.uI'T s2ECbXuXQ&<~ IU * t#ԃ=p dt2<(lRM 0mzZÛ&6T uա^R4Dʆʰ =,Z_Fʞ}эyz+0f!X.Ka)˜ˌʑ[jW&9Kũ<íVx1i$uh#%[b!rl3?m瘌LF^B_#[)Q$^s5\s_(;==峟,q]||__SeY}|o_; Tv7L7GpC9f2\mr-ХB&m'I6KY[Bn&iT ^;c̷l|FA'g3}bt×ᅲ>yWn,~UDA%\[\y\7:dKT_d[>{Oa-pP0i83*b4ATH hVBP\D\z;\N^i}CtHBxEVy#o˾ =8y>}G'yK+ۜmnl{%rDPs!mHyA3]_`TNkEw S EAU"[9r=GstGKC4AJuޖ+GU>oR"jNyV_͗lr5`p%wG}$7y?Bnnh&gi~! Z@@PHrN{s:/n ()4)F"~BhQnX(&FnqjlQ"^.f S`úKy!ט߯-oHޯ EC<5EI~NďztvE3Lѿ Q,-V6'+o k=DϬ Ė}XPz Z1Z-"Uy@} {1;)pB7 '80;O} ymLL$YE(,$ S1 2f|>G?l6n>򑏼qs@IYby0+8qsA^0ʀt,P: c1V#F5r$D~j&bWE!, # 9˕gB$ L*Wj&,:ma6}BHVTLjAi: pYbI>PM&Aw bwXuB߄D@QVHI* m*Idep0j9*WGf H3dVN!"'^@T(C%Q!c>qqne?6W 85{EXѻmXI5|"j;2y)t CS HeR'. @*L30L3dЮXjAD˙uLl:1EW* &3b(#BS HXuq)2S9Xe-JYXSd3`etdf͒Ky'DR]Q?_Ȋb8* +o0Lz'b%I -:e)b _p\.q߃GuhhsKHaY)/qULՒD$\JK*CR2*DP&)$xso𤸁Sx4^P˖5ߠ حN`Vr^lQ-WN1Sk f?: B|&>][JdI$NIlT]pj>8-L/Zlc:d(L$H"TH$ATrIR!rZQuq8bU,6el{aqfݠ5Z:y q BBrJID&$vQzlU׮k+:UfS91I1q3[C,. +VCP\Z$='!1 gNJFJOB$dB"m*O$d8z@&*AhiOCKfNdi; IbS\+V8ekkByDŽ߯c$}}c1?ԅ2&hU:O[W8x7 2L`䂌%Is69 ѥÈk ~as'.i:Ym/npr2YAU;8VUˠ!Г+™r8M. qszl [ maQ .\,YRgI_)P MP͊Q]VKTYx. 1,#XDeВ@[hhTMV~'_H 1@7n5b;OV'\av N]`1X&qb,s1b7s@Bb%ΰŞlf6kQeDѝvGlg0 Dr:1woadN*ܗ2cIQgNPZL.Z F%Ĭ`pm8ɓӴ#pjK  6B.}M>c]ٌz`mE*&&0d#,/ V"7P 0f奸ޞ?tG7 ۘ82`{д+GngV'C@'tI xR5j_]yd޴nѭADk!]Y޵Hlbʓ+V>>n^s_NxPc ͤn4ƢecA锚AIj2$J=:ɖaIHD6{!zaX=&);<"a?vp{ʱK$MJBР;^pI=F]p ^ IDAT.u5,[p{֔abݍ16Ze4?+o}Fc˪bz Ԑ.]|C ^V^VfEk#<= @aB »]@ si4ig6e! >v%[wlq-umtS3y ɂG# f? Sԧ4uJK45bp1}>&ZDg_yUzt3t[ֽ_E$Ffڡ<'&+f+÷Oo OW 1FiA4RQk(X8lT6Ŗs**\-&;ϘGE_0Ps9 8_8xדWU㪘-svԖQtEw.yeR^?[+ㅋq %KOY2tݢ=c}7~>^ia&M-(2E uOi! KL\AW ^5m$ RG5L W%p)}rQ5-DsH)XfNx-0dɟ@jAۂ[F _xڣi%Jhdh5?q]VnN֦C2IH)~<]ZlfDY??ENIF, Vozܿ>emLqEKM8??)~ѫ Čܲ -`.>Wy8wslztfrJ׿yGyYV>aWF乆(+&"mZzt?bpFQA@GPh$FhFhNv}ciYg]vq9-XsfNi'|v 3!h(]t٩+Py1 K!kl{W(Ds t`TnI瘁j)nՍ1z)z K~Q=hE,jt;G9v6fH#!GZ,ћKKpψ_apܸi@jfFhs2lƺԥUaT9U(AjXĶM&-JHAKL=aH15jZ=v`˔'G}I#{e$3L0[1~0'tXC ݐ#%RN@v(Gl͑}OޠRFҘk#ʇӱ=k%&Veni[k暮dcv&MvY@YW1.)mIi C.u&K-ʝ:X8)BkUȞ4f&u-2$u ^-1 g.3yK;iI;10k4,>(g Kyr2!"rG1}ЈTE:kF/6""ҘgC/73L34S,3Q1.ϟaG.2:2^DG0p Ԝv=cVI8Io9Mn8p8*g|Όz0XF/6+.ZW cH)ۄ )G^";[&)2QFIKn@ߠ&moRk487979o튕ڬTM-ZPM\!I4eW 2Ըez,]W+?B}[l At&ï|t9Y<[sZ^sjtt&JPbGZ@-XWn[$IZi0ɗ$ PZ }|~.K~gwby=`wP9: J,9+t5z^g̽$&'#^$s5!J.ϗL~zLу@P#qR!Dc}F랒j=tXeDPSQ!.3z8f-bPmB^wYo\&!D?/ t ^ouC]H}MUvI?tGN=^lEI5Qr(,=T{`<)[-6>ҭ/J"gv =#=Ӡ0trSVP\#U2~`0?*Wkb{ݻ6O'}-(I Jz=DjĮfa6H]tJ_:qIZ}Cy,xr;_8n987tկ/ä@'yS:`My9|/o8i%8ۘ8s\ôm=ybw W93n bk1cW1mcK¿b_*>.P2'2MdhfEK1dF%,z_#h%;.c2̩,EZ:dM9-g=Ϗ;G+~ڂ2]{wD*N`8H+r7ߟSn.X+l;e؟N)Z6W3#wK XygܥgyQ&uI'#|=df\S8z8f^AEh?Ƃ%=f UYFo@| O*eIh6RFL8B19=8OR'{,~f%9V?p`]]rrE傣5 '='8vi;uk[&[$3ݝq?bd#ɐO1}B _J'GyG7+t-q7NkFZ&J0 UhXYȼA$"֡6Aw32UD((kJ4J#F6&H Y({m0{g O[p>nP=D%(+2HkqLI\Kq*RTCAJK:EҦ- q=Kz貤h 泱шRgD%=AoKŖ[.w7?d:sp9Ag5ۣfY}fZE1W[;Bj9[5Ҩ5*[{ojOLd $-Q[*py0>ˢ'[ZlnߎP^Mn}<  ںFkiH\~u}~n*b`,84BDEKlفl~ɗHZ 4ep%JLc)+ ,D##wL/u"uF6X!O/L *(҂}\imHv6yfPdq'_)1K\UJ<ư/3( r;zjjSú$I# iJ0I -J|Mhî1Oj7nþSpHqzGyYCZo0kO\;s oOx=asӡ(4DVSׂ<#"588ddzH^d+Anj =aScIe Fm U_rL}>{>Qb"Z ¨1 f_m[*n}HJX?쥃tO6NHNQߢ 0QN'"^\HpNtb϶l FVi2eN4o4 [^@uSi#Vk1CLb2,E5rAC"s>,؅]my N}xK|Pc~|ۡڪ_ީe[#;5[Q:Tq*cl?09Ě\psNPB#9 q$qNxZOj[.:Q0[rY]3i!-0:9vvYyD\dxR_hv*PY8!yLݐ3B:jK__8S.tHC,ՐU҂YԺ6$.jE8$C_QUɱg6w̴RZt]>#HM. w>tǼmj+fJ*vREMl:d-rLPbck7 2/t+Xm[*# ^R uRtY!ٺ̷#i (*3x9^5!K,N3d١{Z|M*l)WA it[K.O\T5zOs".`G?D{xRa V]$3h"I5R; gn|.˃Ӑ;GiL6yAW9-'qdƧxm`|' [ԡh5X'eNYk sja#tN' U%DY~UR}hNqnԖ@m)̴>#o-C1B^| HHuLYdɶ XfՀy9`C@aNaH*|vYgaFEE«w7\76^Nv2-QNIdi;-bɘ"(~9`Bs'Nx#^TBwJ*4 4(ϲ\fNyQZʼnF̲Ec *S;?`!AAB~>7sµϧ DKURj}r1W}Ԭ?{O: )uq8,!ݒ&S+jSM4=_D\Alx,w1}m@3s|"c&d2ی8&fCļOk%.!A͢ay8nv)rD9)Kż&zh%29ђx訋jֲZtX: ,[Ȳ`X7J䡲d=uvdvI%fS`s" əGu pIbQ/%b˜Tp|B!s3 Y\l kRUe?] Sd#vjSx:u["F5qBww<7SvUW( k>pqzͪχue?I0fz\3>3>~W =Z#ҵEڤ"YX4- 2t7Y\h*FlGyG?~moW?`[͆٢ (DZg|gOGL1B4HQ#D&Kl;;h!1"8qOb5Z)ׂW2h 'ބ^PTBs/F Ȅҫ7<~5RCQls)7qSpQ#"$`CYhMFm{>Ggz*##!7d'ZDi? _^L)? 6 ht@!k$5h; veo u2S6ֈTa35 cPQ4FjԢ&l wS@(~-QԕNըo5n &slab];zQjS= ~ų D9̿ IDAT GL)SM#_Z,C2A95r<`d9MMsx/Wniwd0d:p:vrO',7)q~b_DE,*Bh;*SIsg|ܣ$isĤ9"mLt Qc9C@@#mT^d<ө2/%*QS0 Ԟ`hؒ >p2F5.q&x*>`G).H 6]V3qéEа7] E`*'fOjjɋmhF-m~2?h; O+~%Xi]~F5թt؜tf 6]5UOr?u–aD6ZAL则6:QiUe rEy/I VOZ>)_%sMX6M&)g:{;GN9 wg0qK5v-V"⑇94<4n{ܴћTUE,| GG$}BUsDd\C߿d2 C:tƸɗ7|\|zuv*gR[LGL?>?@еCN _ȟDJv=#<ȿ߬~q=AleQVbQCIV =sIZ00΋kc1í\褉FdDԿ$iBG|UQ8͇ٯַy>gx1gmf3I\$Ø`{H@RCT_[s!U6ɽM4uC]5PINkR?_%8Ox& ٘jt3g3zՌ[%-#T mۿrw''5W Oē''z͊}㳷[z-B1C!4!E>QvF>plr[ETU #|`PO3SC4>GNC {sQ]ѷ}^b vHBHZzzN4IpeV5\>kv-|Ga7<ܶlH]\h(Ҟ3]J㌣rˎ;b/]Lc89Z@%B/N@-p/د=1CIڳ7 S{Gy}ᗛM2&aB_E/[oyzu#rX1XҹM~gdw)z`ufGI W!-q_n[P;'jX!G%jTb >S՜'WuB4Qc2Z*7"|b)˴2zNI1C}/xauYg]6i^J =fluz  ;K:ΆSo&?;"X6GgCTg xj~h1ͨ8~cN@Ph:-6Vh! 5mȦ0)GLn]#!*`kĞM0OR?1' Qܢ%7 ;o? >Ƞba{f{a{&MVZB5RR+A-%s|̹ĉyjav_wdE2|78xa\pfz ˤ5 ^_q0N'͎΄Gf\}d> Pjʧqsx=}kcUJpV nuY]~ٽ`鱸0{ m0a lĪ<8NӒLӹǤέ~L>MMd?=LЏV#0]͸,xR|Iqqzz1opCwѧ]U{|*./I6:%&d$g\8n92GXmV.#&GLFL&#g:3u8- HT lHWSav|Osvb*ǐs^ [%u-ad~D`3o u{Gy7oVU(r nqsn~ ]|yyϓBl0JPޫL} h2iʨv'9*J, ޭ@4}.'FQqDx 3g7 7-t5 Vuަo0/*cT3]6:ln#Ӛ@S~-t9x?YQkShŸ84أR`QR#H=Eycvo%P#(Y}dS7vuȰZ Ie4}=TjՒ+2Dr|mGfWscE RItX ز'p'IYt03/\W>^5)muP=C5ol7d4w1=gF=ͳ j;+)'>鍁\HXֈDX,^x5݂`ś j W?;GakqQث. NKΌՂA,pdk{$pFzw9R\ؚMPsacʧ7aXOcO\'g9'5aƀ)C\(]VJatG>]' ʥǖDoyҾs?+/_ôë }ϔt/r ;I5W^Ftk) mlVj?}{:?8hA3炮5'=pEs͎7/?s=R.T+']U]5DZbj%Uh5jp3 '!7r GH US&Iu[RzGkg衂*tOw|}Ww5*E>Ց@vrUSl 0+G޾OSB]Ԗr8TJ~COmoIYhW+l*h"T2n'$.GhE/ +jo-iɟ#^ټ y{#D &4BaoG+~4h;KR/%Q1GGGX;9VbP4;@K:F%n_xx$ZJꌸt&C.ujuز&vǑ1fP+ Pxi['UvK]d,iC%۠f!'[q& tCwz @CmL: >]vɳ^gF+uBe%&e=z]l%ʅBh. +cep[ĎYa%dMBӌ @Kh!^h%'+8PrZ]^^P:o!>$X2cj f4Lkk{eKh%VPh&[brC|RkDG.6ɩtH87Pݎ9>_ϩ]`P@lr\c-g[Μ;Li{|{QH)i}44Q6{frg[϶XVqZ4<|2ߍo ;8B9B=NU(d 5>71wcVaO %}{ؾ%ߚw%՝6 tVu ?1 F|ey#,<@%Hi;6a"4لmcu Mlh\MZA%t8D[`ȜoCY2VfzLq3>,s8Zolix=Cynqğ߳^`-d1r}QtPuW4=vZU(en#)c egw8u%R:ڒq͚M'`~eP5 +1}AfZUώLAdҠGQR`-3jG4iMJTR: D-5+0UOO#TLMi1>=]v't6;'+i [s۱\6K)Id91MdkAX¾} E)_A((]h]Ju=sXym,5G'G89[N|kA]*̵o'8R RS( HX8]O45!PKzD*F9eYDGk(HTD]8*S5KRX^ڨB4G]6q4v9Ͱ$3V~Qa\wxx_\[VXl' BM*Slb2;d5g:aRܛ=[EE@01g%;eըGOKF=F)7ٞeCc( ^ O6^/Bv2R׌zF5^{ Uv$ؤX$ؔh FLV ʍ:`v9 k dNΒkhHօ4/ ʻ{\4q^ybpubOidfʣ=F+GN}r%?~<#8VW4=4Ym1STSGNyZ[ͽu۬ZW ˬSZ ^J*d$-VR2%uVŊn*K4hjnpj̟B1lLnܽ:fz>]e$x0g6:>۲^8{m+yo*ڄGM>Q3/l&Itҷt[+[|,. 10d6ۍa y1l$(D)jF+)>cSz$BTU EAa+#S88I=#orؖa9߬pm8f"Cr_s|rc[ .p0 l-pxLΏ[VE=V%UCj/Ljʍ΢5 L6Aybc%d+"N+gθrNy: TA?-z)&𬐁zՐݪI!uj A-Z8ox4QQ̪YdV5TMrij a:[/湿OzwW}vZSμ)C uM&`Z2)FD Y aa a9PG}P-2EA5/ 5끇s`i8G!ը\f..饊R nt%ˢK[P(T(B>ep"l>4I1+mtP ZۨͯP~ܡlz>ZJ5Jc,n5'9uRUWxUWX2Hm2uc&3O _>nx_ ïn8z~㯮7)7Eռ:Pg5B,$V;b~ZTW^;g̣>w1Y7~EEY%D%)[r?QnPQ#T䙂<>89X2e%x ߽/x9}☴[N|~=.ox~»XmI3l0q1S~#jQ1SrSZPCDB$b3ꠍ P4A ZƚS53'cU2+S`wRvHK:tC^Hޑi oz-0-x'^N$3(((-A91Q-mh=שhQBF}|F:ja@pP J~]r8@l6~#N[$J,2IΛTKrRm4 /Ð&KAGJ'cکUʉF9ՐSKNί暎iikZ]]x5~J~N+%xVt vVvnv: 8,]S$c7x_yOKO_]3T3re(f,G5P':ҷI&YM)J4YԑBR) mIz\* AY ccPS5^"ENU$ҠDJ/rKWf3[߮rYySC5Z() XhH*D1BVJD+eMܦpΔ32u|I{l dC"m&Ŗ~I3HCbjcjBR"l&Xd{u(PJe+Ů1nBׇH/C7st!jyDH0'm{IT H!=AĪEfBuj"{lE91$}u#` cS.Gfc[Xڠ<s԰BX8AY-) D\#r%B@ r+3ՑvMrМ2 &wI體ƾ,5%P6XjJC sHMz#wG2::ê W,q%AndA{2_l+3,C d-BHR'^:l7MQIq%g5K0%ª5PCp* V`Iu+(vХt_ZTbGX*xyP|{"FOsۯ+R:Ya&YnFf㸺WDC9DshAu"{hJAp(=&j`rGKmLXN=抁`l;Nc#8Emև,ҥnN,12 :s\}Z`y{ʁOkPu-l7< IDATAkhl.KEB(Th ʒ: Y {΂vQ4í!ɂ8k_V֨ۚ>M>)BsRnJ Vc6JSP"URZTFM]VTaJ=юm-DD_sE$;xjN)u&lGB*er$>u\o6r ]0li[m,Y=)E`ܘCkzR`^!L=ޯ޹8ˀUle k$jGaG:SeIx̵>g7虇7K&4MD:)5AYvK;2X``:x[VHeBd\kfMy>b\(K=抑=c<^Xkg[B=y Fft:=sNϞc+g:j?l45jD JT*G5*Ka洜5k}Ērl 3AjxOy 3.3fO娇 R@B`˩TrL `j> ZXw|^ϙ[m- =I5l-2`-[Ԋ`w6Řڣ86D9*Q*ӏh<}߻X!a)ڦRU{`wPm&V?Y0 e&s'$;ESM:O td*Y|BT9L.˳tMuE5I)'T#:Wv8^X=:n(>^v;wMִ~Q3ȼ̔djM0-AamA|Σ<6>0r=S PR$o/971dHVL/0)ru0E 9sQї}a2 #/RMFnUFW,2*۔dKiĕ7<Wk꫔_! ^Sn^;|x=&h'KT; ! |@gjszD^NbcaU;Am)7 Oo$ "Ld ˠVr)Y&ĊBS0ϱdTOUSr[LJEQJ*QfeYdd{}nk}0~ O&ct,RaP[7hqI;6GZ+T?Cf(9 ޘgM3Eai}L+RC]QWٚ_<>)G\vq̸Ujޜ=5raI4tGقcnsz}[*P:װpH3Ϗޠ4$œ3^jFQy*b)(Eo&fθwьѣ '!{'f8j^VIéh kJhy񡒗*P*f&nAԕH,oo|YecgkdIW1C/%Z^3] H 1+̄g F)O.1{hZVĎǮB-J%JFm~n唍R6-36֥ѵ{+jBDE{xM~㰎@MΠDbbۄ]2@ v/⛇J刼",c&aſҨԔ J}0$YYi%ŵNyS^ m5u ?cp]o VFv,ʎJd -eCKlQma n[dIm({ɻ#p@񫃚:˼.n mMj +Z !ǍCR"yDK仸ayacY*_n9j9n9p *Ѓ sЍ>XozoL}iS4}'=a)c2(c ȶh68J 2a(ǪRւlo'A [K [x>)M0SQ{b,?T7յNqkf7=Z@RBMJZ@ro,Gv "G*5]I뚱S΂'%Ewsِg; 1)`jbc7pu.w1aHlM_+q11FLwD S7<-0͆XIA[eShJJ/^vDZ\LS40fbnhu*_騣-GN>A؟Lf]&=&.:+J.ia0SZF+)U]f!mxT!C5R(L HQ)iǬse[c7 El]jG!7t^EJw1bV)y4JKd'{x:b'>FT4LT,u8B;sFtVQժzզRU^qKK1j*$Wb6,/03m2FƂ^OD' (c7Ȯrv ;?m=3L6X-ccbTD`*9 Qk C4kKԃVcM`5?Ư=AZ;Μ0z]=''c~HTDՌXdXL ,>H6}Vg]OlOZ@ilS.t2A*kL%ZRδD/Ч9}1-Z//VNW|g~g~#^ZȤ4G>YQQ4SyT\~wψ/dQEdų|e Mc&1ꢎJQԦ |A3Qvi!P A%R={`w{ga2wO |RNxgox5gGxZHC!:,KQ0ʄ~1ygoYSX(}tTxx9̗}Q78}t|< h\m3>v4mo=V:Mp0E变u#&/GD{7;/vM W D?4X-ViuڢN(3(b(FRZ$Y qIlIh˩sɉsʼn}I}@:$C嘷O;bY7A@g P1׃ccu8sهMC 3)xT_` f|Τ0^"{D,ZXRKA)tT\4[Ɩϻ|v@[qq:c..cZ^ƞz[^ 9͚\1;qq!S_^?f3VT\&cʣC~r_n>F9kcxQٕT]AaH)h)}4BȅXHEP 4pT̖1V1&zŦ(y'ވ9[<;^{<<_Wn$H˚~P 8539TNtx L;`}8m%[pR_qf_dtyL13m^攨!kDSu vc{1>bJ sM))$oRlh>xQh:z]VSh覍c4Mr3gApXQ )8>:b )HiWl;fD]iw@SX4ZuY J\SH "2{PI&.Bb&&ՠb:YR~J@p)ִ' ,2Ye=V$2اOVؘ@R7|Vg{&}{Bs׽5vlt>kg4xk7S~|դŸ;|{APyƏH0' lJTRcBCcxNk8g={ܰ-q" tA*?1:!]T@8cp?򷇿CU02HjegX/hkֿlsa)\=e 4|^^6L=.%V!3Ƞ|hٖi+ew./Ϳ~7L!25CFN5F4Ϯ1슽{={+%}F߲s.V%Gɐs ,c)WmfEmf$U f;Ch5&ɰ)s= nT AUi5hZC&|U;i1ŷ)M&D3P`&3<3_P C짚l@Ȃ } i?OH6S)jdՠ b`&6Q!6K꓎X*4!4ׄ{@?oAv.~yc~գ -+m0 n UUmm:6'W&zKQLOϟqrIA-S:]oj>+f!;e>0 f m#5rh5!#zЩ~4$#u{)Vh(kkkZVDxD /Ve @ Z & 1A?*t)E/0^cQiIV0KqNpo8x v+:0-m\#: HhHJ r,Ҥ4uPu 4'ht L_2#͂tJ,<'_9XnJpvk^=c>^䴪ޭ`\%.U#ͪQ`uq7-Zn7\l^ZnޮB҆2iJCp.8Q] =0ٔL3n}~*hm4(}_ Z v mōyB 8qr& MҹEO&wL`1/+½ &@#"٢%ߘsda.pLU@4U?5$BR$1-W&|n#oS9dIVhB̠4E&d6w`f9k+k:5+^xC 5ӡey#.ik C}C>3<vd!;,fl"!(bXؘm.S>3!{,vVCZb)5ݮikk[fuaiYִN:_|n12-k]&lpXӄm Wh/R_ЋhN6#< i L+CU4FS'-S:Sz`9 IDATd32S\`;g8(Gz%Z' I3iQ}Es  ; h W 3&c>ݟqqqpY#ggTbeYh5|8{dO̔d!ٳyc%^j7W{>^23̒Ġ)VJIf{kaPIj0l{g1PA^۬6EcC;NKNKN^^av ұI61=9~yEv[tc/8 IN$DXDD&˘;0atX|Yy{gl;#M cUUEda[|jj^uϨ@_ad=#5eˮU 7]/Y>T'X^<[1oN`=0܍'6BR:c)MVȢk?rl]qb]rsE֒#g3~;1 :Y,:lbm}kp(!w?m1y#JF>U:/3.OOܽ;G]Tt{Ğ.HOُ;^38 ^?pw ѭ?= fE8J}5%%&%c )*j1g.cÐͧD! T cCSZVI.B`{BSIVZPi;:&o:x Yt2?;9fOo`=eo>%_%2 >)W3op[0\'v-L~G%PUj2Ly;?par7LC! ͩ>hN⧞>?B]Ͼ7Iov{Lp^b_\ӆar<3: Leg$DRqh]Mi4@y5&`P |{gd:L2@{O c,Ds./0X_gsƃ="+,G2`nK B@-vkR[!P[2G:bUkXA.HS$vIEe^ݘ/h nmFP}MiKz4$*쐇6Zؠ ZX+sWl+DA zOH-,Ӡ!h*bšqZ$o8(oZU#Q&BUT$]D OA56(R8M^8ԩdivdЪTJ< )fM;jp`(m4!Vuf LQj[52Bg(ߑEcR(BFMzͪr:rX5A?*Kd=l1L0kG"(bcc[գ#.#@El-M`<@;tNV'SIe%]qƑ^^A{>"3'S'e$GEm]f5Qt՚6BmMlXF`wXiqdke?GJǍ1Fw*6 7hW/ n{c}2}53uPjBҐdI9~ȩd5?yV;XP"k+dX=NbCs&SfYMi( "$&ܭEUCcmu+N +?ŦBCPc)r( "q"/\# fo[0}?ao Z3ќͦIYd¢3 6``(K}мY0fۀY$X_+eCS5މ3<3kT g?!AJD $(*j*mFXu,oV>BF nhVM)Hb7#^!`T'8ڔTNmIe25Q ;n٠ǼcnuY!,ݨX)i::qc]pc'ڭ%8\4 ېECH#+%6AiƂLRHF*O& #6 =k]kR.dh3b pdDZ3aM7Lp M19^Dg-&Vz_spW0z`嵂0^--fkU]4-}q.jHr=;bv9R:vHIj<S1iYHc`VS,yxgINHA;m8ޛ {RSQS`%$%C`k2zqQ"*~ywgH+L|drOTY$a /VݲXX=>Z/m[&oۚtR7gy_.\BOc/tq o wTe ~SKQ댦,mjQ]BuP>4ed435eTD4)I"\CЯSyW7?q~_C+JaPh&fp=mb1@W'o[RLN; q͉$VA+ղl9`icH28-_NYYmVv+w=أ~|o9]*1+-P Y寧juß_pxg~Wa^]2x%sT&j5쏸4P?lEy8N=NP[A!CO>BSx)kQ6l~6~+5Doj)j:bɉeM^# M)4-2Kh-㞙2̭Ne9 M'.>V'8$|~Wy~|?L ,.E)c%sz<^iH511ds&&?d9Ό? S g.C;;杁UI0<~`z uwQBQ" &CFk7_ 3AzӲ3Β{©`iqw{iwQ#5^kQFhS:R-qգ9S']ՐMd3 :Ka):,D%"*br"rjrlѷ6x vRwbDfEgf[$<.%[dM^YdFYR(5yd3XK"ho~3? ]IqhY0nA.L=T0bsHn- ֓BNgꑣ#_u;L=&r{Ϛ֓xYɞ¦կ^??C~W_~7ۈJV[)D+,Ƞۃ5i %|nCL;aNÜFQ uVSK6yg7^p;VFx}$sZZĨyd!f, ki.qݶ!zɰzdVY!Mi69R?e#B(4JIVU{g ]g\ܟ0#{$)kbMY40=Ae*u)) 4Rj%̢(-PBl]XvJJ_bSPaR:%Ƥ[+yգNVh%h%= !c<Ŷ$ Y^w\$<"6;̭ŧ8VX),Q(Vy;FXJ4$O[)4,l,dؤ!$ +ET[PPjҋ*6+fwq(ujD]?hD$B=5b Z5¨w1i2(3"}QBY̢l6NPY-2|7P*N;%"`:];L:<\9d*fxrATkz h%4IAEKeZ>RmwӏI;6wƘc&d|#\G'3 c0.YcY=FiӪq<}y2*Q);b$s^MsIC\lo|"rBYp^߿EJB,]LzL&C^Qi*ՠF%0# pzGVkR+":\9ɍCٲZehS, *LUa4%JIEcRKjvC9ܟx=d೶B8:r~Y2mvAW_Е z;lO|OLVQ eɧ1wcV \f(kWz+ZږV%W-֧6X^WCT{ 5aV͌#}tI.K6u)6ڡ ԛT0+Rh =qI\q)4 *#fx3`vg@_,E0P:$PVm)N65Q`lsI9{ a@M;"#`뷈" *E"|Rj2R%kqr^ -8q0:H _h^s=#O*ǭv=d}'mBT%7aM, ijF r`sg b <8vD;l9i_r^q_D4fL=hu9C0yF>3őP *;fu#jE$}z@wp6)n{ع i|1`>0޻s27 }g*v qw$ ͢Mdw &,2"umV: ){pϻ7Tw:˻.n@,#( +NK<+qP겎D-nnOnɝG2qI&.jR+IL{tg#f(:^䨾!l-n.EĒ%A5$U6sѤ`R7ޛ(TP YR3_VD+5B*wj4ZV1\Qj7r8q98(N ʖ4FKC5iQ]I: Rr @|,jB}øu냟̰|̱uc}|֙ǦYӰAXsY}cdW9NO.Tz5aJ~+#ai,lNgi`è;_~ ~z|> IDAT6ɢ9᥎<:S>s~?9k_͊jXSʚ3cɌ536.]0 ֻy$d/"JKR)r,)66EbRUcEm"$H(\S[I;M4>ŚثkQaKM6CVYKZ:ȉBWXиJש%e!(NOd < Tf^??eeHLDc@jr THA9MS/RM@DPad`ԉhf yXar,!`Ko6jȽaP.M-**EQ7TBI+l:raıYb)a%"=(w)ye/,y5idCXdK@]t'pCC/4TlKI;}A3hB WXvN`o3-QIIKJ)Sbk:h(gygkn_POyj؅57D.Q0 :t՝Ge0˞,rAa4;}nvmsP#5١X2U.0!ҡנBC;t UY=d;rbT?${cu:1iDxћF$L[k,3[9#g_bAr Lx`B)LP 7Ok+1CeMCk8o=1BF,wcNm*,%pGMLEɀ.?^ 2(6e"<ɘ,:)UjP'UjP]ȳ4EvR=5z(%(RNMsy<'KlDPF&oxM?~MBb"c*ED=0V՜lZCg X~ס$ 9VE`謐BZu Tmmct5ccN[}CIC_W6W 7-M>d\nT)[:ގoˌxv*0NkiDt4A3iṄSSSi񓜓awS뚗hK;k~6{ߥL%d:՟4W)I(41~\g1YrH:" SXp̞RASW=uGY\r{a΄9bbZˣ55ZS4 0K 9rAK#]d.A>)4=ykn4OxG4D$"jlusAf-zlۢw\pt?]Ob NĴF:tU)-?='3k0#)[wݧ>])sLƬ!Ao \2+ݩQ}A})l-AC{0@i4sY[}V>QCːx"_Fgß'TV@r@'wß}p\U e+Xy-K_OvoOؤ=ԹqSía摿IiHF uŚvW'Kh<8 uTE坃= Hi=<(>)Ys` qU Jh +܈&rO6[Z^QIq)n)Zzl)Zu=亼gD.՝M;zA{>heSݝEm~싒Pn8l>JDz[yN>T,.:TQL{8 QB< +dۢ[(#-2 ^ "Y^i,>?hK&i2&;k#X@{GycY#S膮jD: Srs=WH[{ hh)(H(H+27QC qq \n՗,p-_!iHqX1^qq O SlȎPhgC JH_a6u'v$PLLlxޣChXm 5Ol/>_~5;ǰ !Lֳ͏]6+ ueBb"*{pώeBִ˚FL$l>ݔq)<D˞H,>NYܜX ZH!+-PCAHT &oscsFϺoy*cJ}+K0ܠJpXv}iâ5B(zƖow,ra" VFe] zkӺ4̺Qxp%[z l=j:bqxa? ({6Fkca枱v~wBX WlЌc1=-H%v3")"ߍN;6NqKQ1Yg@UMFG4t%ߗtOLs.}cfT3CAo!X*@ 1RBN?6i.zBC-D z5!_*L;=n B M.* RtQS-LTJ$6OjqNC(Es2q_xI >x/y{Ok{DgfpQ5Ɏk LĐ2l-?ۨ vqbrL<0*\tV8ݔ@^h͵Ś~|5m:^4[O9s?'~<#K~%~KUۀxoҍGqP6TGقg!tZvYChJ5qLW_H:!h^e_*U>DepXbq_y.Ѿx.bh!Y[6}A}cF$P-ߒ+mbL4f |y(#Ls_b^`Ǟ;zDMvY.kW{NErw9< HA6ґhffhVCI#eچI\S])s^'OXuz@+FaԬ!nF' V8?F^P] j1厗:v)lS U[ ;`0+aႡQ&{rR yNd4rI6캤2XSjǛP nxdI]##<#?]~o,F+qp=EZҠj$f.!$LD) KA1w${ |q}TK.]e @/jڙNsdle{QLGiJ-&))_xlͼdXR'%SƟG _,.:gQU$w_d1~=B5(>sORy,)AIٖ=cK/0ၾ`˜AuKcǒ@i`t 7+7616)+)HqQTN,]$mMU9?}^fXk)]77:mstM֬!oz??:ol3S&uzm#Hоg agG"j>IǨB'*Cf>@l\99ٜl w|ZMlIk+F5e=#Y@xqsQ^! 8l:#g=O}݈aZmcj{=Fs=%C"$ V-,1KcJ״JrH3OAS/S>[R&; f>;cQ=3 7-d}'f{G6'i}F E EYY36LFkz ^{֐Tl>2&4?4?Ԫ%xٞJN~Q$yl sAe01#zoOy+TBZj(dar &e9bhL` 3T5͐|cq9eu1ãtdS)1)^񱮨 ]ևd }:hǚ<0.z[S {rfP%*Zԫ v.$T*UC UOVxbAY0>*K#<# ^+rP^Ap.K:I[u:B-jQkT^Ӫ1K_g6ڐ¶YC:?%6O߉D A{0~0i]lQg"ʡQF\ğ0-Bd{^i4IX44W)Oˁ˿^&#Y TMoK-uDmC~cn0N:#-Ox+q 9-j kE5?U_D,69jg{&R@)P5|j9Cf DؠY-?Wy_Hm{g½=֞r~p2O߼aYL1̴3f}Ds3PD$~a5^'tˉ7i ) )Q2+qh4~ d2bՌ_ox/D_<0E3= x)ƥpÇ)}g (X0z=X,NxMyXMt;FtG[:$6$]w<1L:k<7ƿ|ҎŲb߹~@'r󘛻'gvw]0j 3ޟa@A>vL5ٍȉ|Պ_=ngo f{h@tt;76-)oZ+^ܷWQ_J 8nia@ѐ-r6!Nm:Ee$f'{3n9}@[v J 6:ctEHOAikA#ZΞg_x+o {lߺ%1LxS z8y*Ty@U1I*U&528C&7շ&&h1>Raz ~.POC>$Ghv iN%&={`Heg`6}dh 44u A(MR{wQAWuS%* ߀I էP,Sm-jNOt<#<?Y] _>8bɆ.gyqVMjxCՒ44fdij;1/=8t6 LQKÅC4zU5&D9VXU4 \JL@)lDɆF( ܶI L8; X#l&3$M@Y㸂P5*AAwDzi.sW\@pd^BP`q l/~Čjg#鐴;$ՇBr }{!UdRnL/ZusP}>o<:N4d4,!ˍ26Ȼ&WҖ$y50Xy9v¢h&,!ˡ]T pΩ-&Omºq2<7S&q]Xe]emXSx8DtN"<@R_?>=c,ZXn4=r`SX6ejݮOJ psgtzKXa "t/UJ$J5dIxɌSwi3SEZgr@]X&f᫒Xrc IDATjV7ԹNZˡtƧ{ZpS& 7 tI+t-H?(0 9t]k:`Qm,{?8f8- q np Ok> '=q *4BV)vmRy4B>6kWzuJ2&00npKd-2hk kNlx`ƄgS8<;A7;|7-+1SHQQKe[Q^Tg.URb]IΤzSLta)v/0rnAG*i@*0q{ $"| ^y/NkHOIjqlCw¯ g='6}2SR մl0Bݩ!Qžٗ!*d!>1|Qe[cIp)~ ^aT zU#+j0F%f?#(w\w$u@ZG7p.5܉UW ĂD[R[:iPY). `~oXlmx۠um"cx4~2&vDr ,'L}?y?濢ԕA:/>=_0~6'M< A2AW8ŎcS6eYH8ks0Xd{w9,pՒ_7xGezWm, ![i棶.SngOh&4S,iዖ80f;6l+h6;t/YqZi_[r5ow6.[;dk,%]j7|uy=zVA*uLRd:#zQ~hW-ki:̴iy~k~e/9z*?9p X[Ea@opCO_pe=yÇmgF0*MĢlL[0ģLL]Ӯc <Ԙ37 |!+VYJ Y!"E-jl1$ީ kI7|}-Z$_{hA-W!1m6yzS^P_2O.0D˸z3σ5@$pVkhe-.lqs>5tBi=S>=Y/y<#rJ(>gO%2nS!iAԙ tbrٔ˦.uL`{1ӽһ\Eqc5zSW5qKJP,re)T9hZf/ sgĹtC{ݐ'z=5Y ZBPQJRT`/4m 5fa65`CL3cN&wAB,1}ݘA ^BYDZJ#vnHsiOtż*q2'O95ۢKZ8dNB1EyScr3!9ęGTt4l;c0YrdKyD h[)N8q[},''6JJDD!+Π,\"-smLG+[E!S:Z[54N-4jWN ߜ.[UsJ܌hTsءh X#QVfaZbʊlSld_4$=A韤Q1p %&r.5n?1S4&'J,ĘFh*2~}3f=eGمmRXePԠpjPy}VJTREQ)ZBYiPKJ@ODrFdaI({i)}/~C3ϜGyG 5~@109K8`4,P9kl6սKsȡͱ&|":dAd@ˆfUӮ4Y)- 7&+ 26N1zlq$S0#,,#8f['Q!mA+!ˡ,Y9J)ae\1tN"]$8HJb: GMN@\0ȰI9XXgnL(dzbH%uRKLa%fŰY3hVƁBR_hl=rHi֞{J4Z4 A>|&hvNSAn@ lM.+T8W)R3IEub0b?79K|p7Ҝ.@iǐ[MmGq˵k kcͥ}ÕR`d)eIl8Ü@ħ,ʥ.Mc䘓ɞOw ڋiva2.@MMbۣ RGLDx/D2`kzC_zdj0OBː=$msw?NJwI="b].{Hevc̎i2<"#"2_@*_K~AT!=\Gκd#k풵pmhL^"Jf-:,6OU o4Ipa9 KɠxwEɸgj8ol3]i!l_2trcHãr-J_ja斑H^>nb?mb;}G|f:`qW05Xܵ\P{qDV2өeKc#`% q!N]&Nv&w(:ݘq1UAER6ʒ[yWN|!eK>#7 '==l]vSbS%NrZቈF?CHY-TeZ44i OO dͺmg#e@5XR(TBh<nC6/FŐR:dBxa]bX%F!/EEd}1tfD^͸E%RQ9O#ZP=O'x_-^W0K0RUC,E}]P?YXhŒVdm|4)>o 4:y@1P 9jNQ[ѤGFsmejd蟅Fa hʃ`A"6!q?>.`l=&PM0UpDJE^ xDؤ3H? L5cIn>O>tknҫ[`Βms͹L^q.h)[SnSnS F'ǰ KZ'u'|#d T;Y!:BªQ EYfFa-֋-dNiS,DMvߦo3AꘇקRy{G\"uA~1dwwAG8Zg-yUWM$Q Aiٍf=W#CWm&uPW*U`|Q~D{wQ?>%uz+3MBQNYg!}2rޜmn1AjYL#(^nn9yyvf5\Y/S^=HlRj:LFZhFxnx RC5R 6KσCky{g$?\pa9:ۣ|{(pk|b;B*>R96ST|uH5woN99Dx'ǗL?F|WBج%+Ѻ%qEҢ0Lc4G<8FF7!ۢŶhA"/4L'|R,B#䶁+a0YV赁VmI#Y{g°q ӌ.aE{kRX]v…ب)DMTxNDl7ifOYW7W&CC(Y%Y5eYaۂQ7{%RZH!9 VMauBy 8@OQ35}&'לל8׌3^8Ĩ3+f5r^Pݥ^x'x߁_;\5zUzc>@[ԍL B^+-#Q{`5q'1F UL2E'W4T͠)Bfi{7{N[΍&#Ȩ bKohWM  bI)q[!{ t Ԟ#5E'q(BݎVc=SN^jD-ݓP]Є!.ɞ;\aɊZbO~E=thU[$}XMM0UJg^id OqʐRh&s1m05$C;ęLs::z`kt#FFvjEAjt;Rl;)"va8tX} ~;!#mhc]B VejI,4:}z $H mwà5's jPB)Ԫ¨2\.ʶW ڄ3U C+6 SQ5|E6KS'7]vFV`PdJtyc*kLV[JUVe.uڄY6my%ImELFwZ۵Hje'$$ "1D,Pmt>6im`6mS6i>;\ck)~/8e_.͸ 1V;1 v Q 2malDhT(YLy]\7YіT] ({hqW1&AjnhF%U!Rkb"Rzkb#DWTDX5>Vz0ceN䋒hnnhnXzM+ʤXVXV؁oZQkJK L+Gz]p.)U]氜9n 0ѠD%lkTGPtnC +st#0r!2[OlP'2))6:cIq ŭ'pZfeW 0I"W9UZR-kz=O<Ŀ^gm0ݓݓ%noOJ>^T*H-B'ds|{lz}H TYR U04gꤢJF\NIU,H;8CPAk~AGpS)Q4l9a8fm;*2x>2c@yȼ2l{ uҔ znfq;bEceYe2&&gCr00t ~`ȂZU suĵ8SAbUPKjP[ 9CCLLSbX_ܴx4'ȖJylz!sc6qp 1SK4Uz,0pϹwnL2Cfʐ]V!؄[gl; ,XUP xp4 Uלhs>utzM&RB,oWTPJ(W6f&yh&Yd{n[liVli#aDsjo1?X]jaN46b2NJ~W,WI]/P$Xw @E=⳩D C*XVcKQ6E+N(~UL?:g7]4$FEc,(]#*w%i0'Sm:GԒfѸHgjY9;6;9={i~oq G>ńUujRe RáJ_m*m;ZiߔRd]eeJBA7}7 otwLʃAPu*v?[Ǹ ^p!eh! \XĶ~azTbr$!g(-A*S\P!l@(7yh-FD %A0轂^@mmvHX EJx iEaq43Ya5ov#.<7pmGx'x߅_>^^KΊO]>u_X>y}c^DKh!*"<X4Ym4fsϖpRꓚړ|.ߩ5otCKW 5նTV<쏹==w>*Qm5@PYhӾx1Q\t?NyNAaGM|yg):n[;KvCk;@<$v-@qa8fO<O;~Saٜ݀Ӌk^zC1^ mQ+^T/jHN6aKB $zNNW1E5nAze. BK*(8ULZah ~"]Yޜ2{3[:YÚqs;j_Q4<¾:6mg\8EAvk0$3IiYyKkH$ZVb+ RJRK"M"+M2ag#cR`P]2G* T,c|e£`5$H|va+Ql CI1SIuWQi$?8Ma01c&9%b_(&锗|}GXL%ddP' unuJA $4Tw Z Hu"9bP N 8H\5J,QbI㗒aIMJEJM)_NiC.]>uc`BBiip,ٕ`^L Ts4*E"UAY-߶y6u]Qˊ;v %B;<7BH5]` n'NK%\¥C| 7zPow $kd V>Op?3<0x@80`3 ~Tqr~ˋnЪ(>!ABP$#}fM7H]4bKD oϸsǫTkݺJޖdwm 7%4á Mr3s,W=18`^d84HBh nQ+T'* G_bR<7al6*6s64VL]됺ßI-?w HA*w*N}Pmt,לbm}S饏Ci9֯x9a)|ZLmP0`L2yYT\%@(YmRF2EbVP7gcx'x~_8nDRsn~tyw^-O8EidqRd&\v݈qd-ܤ4=~oGnq̒rW%&I* E9l6 Wڥ QFa<0Qh:z*J;;^B24+V  ]7k}&5FdyղA\0jDl6G Ѯ;,!%HA^*+&#_g- u^(}+OG>n'ME琧TuگQz:@iB}Q0Ao]RƟ+hV{L5fSʲE|#g'9c-TcYuجWdRBRM7P5Pu V?X ufk}PgK6Bz==/; 0%b, %& ,hA4*;;ω/uj[MqQxEWxEcJFڜI=bbUU\.nXz/I>PY,Cm4p+@s,G+stY Q1H1Љ{k͵6rl:48V(*c!*$KEhCVʦ&p #5CHބPO!d;erw(MX^H%!f8miKvMl~*"qԚ6'Zg,[$׍6O<O,& nzĉs:{گִ_h9Tbf66K{ ӺYeT.f솣)gלr9omBVI-V#f>`633X:=HzΕ s2 :}x>#E 82y-y .noP|#2Akb=t03Jf 9@A7%ai [&,r)|Nj8; KL_=.۟w=fgGB!G'F$CAS:06S~B72\gCcCۆ<6(< T dNQY<? vO1DO =5=VQ7Imml_dc+tŞH-ePXsáқ=bCX 6asdM*T#yAVŬ d-B!0޸T}IT7 kN^g*lE4X}k#iNEY4.1iΖ1x7V]4b`yֻEE-x|a#g^ .Y"Lƃ=y9E瞼퓷d .79[M4tDu^N GCYTdW>SblNT$̶W;ٖ3A+-ǭ;׼GA4sDO'x_5bwsc黿fv7!;:#%Ƣ($ advϖ3eܻ#f Mi|țJB&=$;XNj̑TRA(FrU w  G}~~(=?cpb^ Y@BZA* PP,X&N|׍?q!M'~(PW]|RU}(qM/N+N+NP9oθsoԊB(ԊJ-yi.,(9vJoO-Qas/sFwdq,4y&ݐ⦢xMQnF#{R*h UкHPM!"!"Œ Lt)-Woߒo FG[~WǗI&r{K6630K d7 ?bqqisi}1g,92Wpaa Xs+y~6KX/iU/tDk>ϰI v 2cMN }yx&A; v-$v-VansR I EI30GIsԲ@'bLb59-{М13¾^/;%Ā8ĵ4AԚIh(M]iHQ+RdEkIFv@Bܤ'G&gS"F%,* ʊxJؔ^i=rJfgY@2GѾ̩뿷XХ{SF-u*PbzW5?4 \'ۈDQ4ؖ-Up*+gXWz*Jdj;sG@%]VX2T眷9nx6alFr)Xz(8"fНsq~7Zė֨j#W~w(K%wCe73 #" P@ث vl-C`)T)}=bLlDgMDd}rz&E Lh5CZvp٫jWeI&.QLZJv]%73zR?S+ю c%(\G$" U}uyg^YC"Ҷ|f̶&o vwyO%[ƊwVt9ߡ*EAN EdAF)F*-Dʩ&>oJՏ49h@$%IyHMBUDnNEnD #ԠT jbOaح_+H,ZK|weVZ'#ZDTX2"E!LP44MbﬨF&FR=ySGԈ^hTLv(_lQ-)*RHˠ>jR>Uc)?ڑ-LҥA9t*Oլ~)t/톸NKpפLM tJ,7GiG.uvѵ8/C3: ڈy-lLRiYunM V v&T߶P2s>As$ccrimyóRJD z`Faam }}J[UC7mD8g; c;CQ^67\u+jҰkV3C*\.y=O<[~_%k4 j2K4w F;J*6Ik E9_o SJNa0?‚TH=\5X>޶&ښsĹg<Ж&W:Wh՟FFʸ`mdfygx0_:(gE"CpۚIpk ;g:<3`".sLUfpe`1gUv΢QhqJ^̷#ZNJqNJȤníI>_qjjt[fo+~].{^k 'm5ZfZT6+q萼23f7Xkm֢ZVtsXw;$HG3!\dciJKѪ=A =I&11[ ?^|yX3Ro( QDQ$Ug5|J)tʾFkcY;,=^b@&,FΞnzĊXeŴ|e|Vqf`_L!Dc9",јR*ʢ Ԏn&JSa;p9T)>sC|:$R; _~H\n̶vQ|ܽrUAx^/\ `|Lj>6{~h>V;X7\ߠ ȓ{'xʯVt˷FdN)P{&ڗ_XߨtNĂSx$Kf$+C^ڻ]I "$lPcL0l|qi" 5b3WWuus~T3@ddFfz^]UwwABS,QaщxA=Ayvj(8B8*1%ʺ,0 d!zӠ'mN5)-sFE/8= )d4oQyV|x`IOX,%7_C)L;!k=XTYxZ" [Q'lyH1w@Zd|\9@n-{]-K3.T Fhd.l\jMMKofJE(@T6 2is׻SIJkCKC$JB5gqHHJg5?0i,y* 1gR+)bLp:&,'^f~LP3472'#,0L5,kqfmzmxXMU jlHF9RJߌ u7 -9Zva{s f)IK*%i )G#hzzlt$~C%BS$T%%g J)FbYM-GqJqJq]+R:$rstJy)sC 'CNO3+b>rk)lL JAeo n/K[ E VkS֤ ؄qœaJA+!x;SHH2^ kCbW"P:I, #)٤Z8;MsM҅*@(Z !#bzz!nt D#$DC<7w\dzfB DiA;O@x ߒJ=I+`Yv0{c1D3"#!&%NuXH.D=٢d0 fjwZ#Dyu$!FHQ8dEyt'QQ4UzEO/ ^َQRꀄ5ÚeK#QqYtC,yVFw$ %po!QB,ĒE =bzAQ"mݧ@ Вp-U0玳=t2'$#"„B:1Q GN,qfei9QDԘPSt nJMaj#Ce>¼ (3,fybE*)R(\]<Jɥi8r@1HdaWBUi+9zge}hf0PP[ 5&fj,jHZkTIC"+ 6"+$M|2duy#1`Xe`D#-uH!Fϵiv:HJGh*0iCU@Vqz&l&z衺!!1^Oe<Ȥ2K3K2J+Wh,!LixS5Jo M[˭Nf+Re%̅tU /஬ud I aP)I m$@kt7ЌB$'MuL<ϧ0fK:&Q#eͩJtiq`)Zn!ctL15F @#DIX=%GIQ:J%m(L@v% "?^ACmᇜ}X@YA $ }Vh`G" $N$tuO7\3O:ّf囘8uuHy GQ5!^hJXڨ6ꡍϜ7Njx;Iv49X>02RedtTY2̫Ck4<}tUBʙx Q5mqJ!ZԑQ+!{1$>A!B}@+4&b iM2XR 5#+8MA,B$N" b zadk`FF"-3ȓ:W( ^A[)i' JX'!MF(].fE_J҃4t G(DhT+ h-[ I@s2 #tjMrjcT1zHSzx?'@4 ]UM58&YG4blJDJZFt\kYܤn7i5ԕOvdw2fY+ol/wr|$aܞ, OodԘe6 CTPQw~iG6:3]z3P*!ZhIś5i=G\aeCCtG5DwB7il:6lɟ ²  s0dz-BIi(9Jؗi7ss+$DR`>$DAE&c i"lLF0G$W٤ @UNVX?MԖ):-S,*Z:!1fs gh<9W#/)iulFGR~п ~h,8k{%I=X.dY~E m,F? D_`>퓲|]S]ST9DQ#d=(ƀiz32Jv%KGyș%CbUÑM$‘L|Y#T$Pc4һ&%dƘf;e6mqN3fts y*KyZ52: %I!ŢOiMIT /lH&F* D*X5%xwD=RNҐC2C.iac"ڟ HH#&-9rKbK=)$V$9BW\z5 ]DOHXoge i^L,*4*i+ClL2R*KY‚Z0s2cUHH"$H" t;ZSGmxoXxXt4v^5Mo>ݟΥlH3Ӵr.B/DbRZcb>)ǔ}Lc&`.2R$CSE'4k &h#FDI8ie`P-GٸqO<YEE~1+kN`RH1y 7{d%jz%BI@z%vF"/h qɵ4-ӵ7R!AH~ꆴoǖI;u,yDL/IP 5a绨zxןZx`+婇E"j(|NhH*&zĮZ4<mu9F'@Őc) AO`{g-~Ggcb7h)\RxcN^ U HS6e?0M^`SQS7#8NH8Yf$aVeI8k,aTV&_+ɗ6!k aj li?&ģDiXWm$/7K+(0C*8fLUQvhM,<h0mk|Vo-[5,z#;|_Dk%eu69Kb:X]KzCtxuR,ml>4rJ3@OV]ݦSضOYT߁D&Gڣ)ZCiǐ9ϔ)i+fnKUo$#B3&!|Y% 'T"Wșu<@ PFB$y&3;УfU"LTt{8Ua_aiUzܟ!g@N!gE}5L'xKޜ?2U}'4XaQD!zDmY([ACr&YEBoYj,Rf%KuhO+.Y8|q8; ԃ#'GvI:5 fzwL6+/_ GYjh6ݠ (e* L,FRX2Z62,F&{HanydzU LgO2! 7!BX Nu$dStAhhttzžr5KGwDMCtXE_b=JYb1B^o00L[SA 4Qmۭ)\Ce$I$W3DIn Fbm9SN7U%nK ZUfv/zxrQuĖI Rp5}%+Y@644%.en7*؇؇yy a[Tty"DF5jJ5$#g4(kk*~_+!K[M<si"f3t^ 2&X=ŶA{Qe+ȍG&zt V;oF!mu&Z-ëU(*9a*&6 T'x+_l0|Qpk>0D+:![*ѠB4 ɨ!kJY3Iح]95*6UduVneyV[ 3 ]eX!4dTLlUd6byEwɍph#!UPehkC8XZU>ZR`Tx,YcR,>n[>e{̦M/mdlzY8BK_@Bϵ:)ɩC6#<#<#NGq T0lPq;soOk{HW ut:dSb1$Bwr5Y3LI(KyU!4yfh,%e(GD=8N8i.46Hbc9`Àf&ulB S9grtQmhT) U%s}f4h֡>+8עOx%OzHt,vN5K$f*uOZk3[bxd,c2 cRlѝ_Key-|5[ʀ0`JӡldS}7ۤѫH)!G41K2#ܡ[)F]I2medɏ׏!5PUd  j qQ&YPS>`D-ߕ۔ApZ-ZgM?sbM)f !F^O\v5:'vV& Y^53:~Vbl 38rLM&biaqMRԢ<H'y$8]-RB 2 H2yWƀL8C&RLZ֖s#Rs-= Y٤*Vp\xv`= FQfXVְ@8 I6r;rk_W+'l=J(k-d':iعg6 VC ҡJ9-g֥{d^ M-߭0sT*ey,'*A/rIQ@)o:&-7|=x>%StȬsd;  _ z IDATK^A!>AKHG AՅ|Q4L]_:'_ž voz>.2֭[O?W\ 7{^vg ugr( \VAwgvι}s ?q8gÆ ?餓x9#_(Aۈ ' N;epGsꩧzSO}ׂ    ' ?EQ ṗtƟK};ᦛnb~~krs"/7 7\:|An&nJTon~_ϖ-[X~={.GqKcqm~ 3◿W:_97 ?xns"xy\~/| |{s=W)]w]w''?I@ԧ>k^XDnA~Ww}s9y"ww+~稣Bu6l@yg"?17x#_~=r ]tk׮E4ַ==H"/M7I' XDnA>9ż3_ٺu+ԧ){Nrlܸ|O~xG%\ؘnԧ>?qo8+˗JQ_OVAw#~˷=gJ?3j>v nVp(\uUMoo|#W]u+  cǎ޶m`DE*.b ;w5`W/r{9Smt:gMCqgNIӼ=ᡇD._˟ȭ ? gk4,// ۹s'W\q^z)\y#T"{yƭJӡrs"kllnNC[oell |^," `[^%\B^~/<'{T_r7uY|33 CO}>OO/~|\veK{ȭ ?z4 /|iFuuNz牿}<@E{#vAA( \VAwgvιo   {D'  [nSn  F{ ;ƽ} AAد:{AAj'nd   U2Nr!GMǛWth|9{eq~O/#n|>?]E62]Qo[ވqY),9\<]s^C$'DrKL^z^ΞD!KOGoe-Gq8PN8ݻ6|_^'  /`*l~y䫱$^EdJ_c9 3.8 G=9X]sͅ_:t>v?k_翸Gc~sE_7}:?ΆKb"O%"kkpx_GHw~į?o4;w}t:6f/}K匷p _LZ՞z)z).rQ  /H}evyד z=) pS18p9k49G_G֎o.>v'q7 =u/ן~r׹{c{?洿{np˝gx?{Sӏ[3Oo?=KҮ~P8:wǯ_IJ+ܭD$`zӨoW#$g=Oykt\l-[,?o1W]s_+F Co5CcA^`ַǃgpaW<~Nnz9[5lIQ/$+G\y6 7v![$> I8fyyM6z\r%h9v=N y?3ϤR8:@q _r :UÚx?Oq|e]Nڃ..~ |z|+|"n7c{#my|ygq}/{9oN>~sJ?79?Ki a,Е֪)y_Dq u:W؇Kܛ%r|Fl w;XH(9}=KhAh+)hBmqذɀ<Y<=SCB浇cxCDŽaDDqf,[?YAA}f_c6=ikIK_ Lv8CCC19ɟ 4rh+G||w77է>{>1藿- w9]'rS/}_r7םy<v/W>ty;kxnk|s>s?oDn^C_Ͻhο\{q\p۽y=sj̓9(F MQQdHQ0䐖0?OWg:ɟzE>xv@~TG~j~W>ÃDM tMF=K\&JgAVPTnK٢Yojh5;[-q  }bo'?[ֽ;M /`X,b6$>b;.׻v*^ߝwɻyOr¯gE_׿λfn<߼w,nkO?sok8s\9č!_kވߩ'ї~>pjd83NWE6WVnoo㣼Wgf*bօ^me!, -!" (P  !1J(!m?&LBrz9 L>|2LLLѽ&B!h^-B߀.;?9=ɓ^:t@^PU %z hqo~-R7იSp;\r>ܝϛE7I`k>&FaqVΚĺ=E|f>ML/%mR7mnj<;KF3}>6'l~ǏdMQ)/GGbwR&~i^L+stFurv jb}RQ}몉YBU A_E3\`BZج}4*/fUPP?  \@‡9pmӭgOL߷o':ŤF{Y]%>{PD [E&GG䘨zǩx|}ypfpl{F;~e8 uvH!7ž?Hfb42s]O+ݕuJOEGx|M@7L<,s Uܺa8=yoO~إJkQ։-76weEE>aaa|q=zpqVUrGtj߉ʥSeŸ4M,j;a`S<hn ʣ{4?B!ТsսWsf۾\xs@1 }Pm1=yOggPTVGa eBF&icHLK~ܨZv;SDolfL1k6R|2exd.l-Mt6 !9yꙶ㓯5TĨ!d2E25ȯzN۪.((K]g`PZh(*(!1Out@3 \h64q:.Mík5桬5RUAY2T_[tמl2,y4S@ LӻU( xWIu{4\nM4.#B!E_9:7l7//44]b1=`mm } V;[XY7ed& \ }pڍ<3*5X\E2eh᝭SWW䄫Y&eQf6O΢lV7v& I'[\ڗw&_MĿ~EU Ё7j Щq{=qi .~ݷ9|+AYA}(z'w s-R"¯tp) _w<@@44]ąjhB!⋻߮\BbELV@zB$مd$Ek}mLzRr>."2Gj #^Ԙ(W:}sGj>mt=7Tj֦ޡSa ģWslV &޵ITCABmt}P ~uTUAUU{?UAUR(4U.rPtaݼ]uVV r:qޡZE]? !Bg*L ;z;aIz]q\ !BӪ.`jUX`x*1M OܻfynN*-"ml$eL) s|8\EzWLy;8r>컞?2!I{ٜ4"1s|4~Cf|#SbrvG|w~mtBs VyMabQ;[jfi}?3:w̠>}ҥ3tȏ~DpU;}|u=}Ͼ;¹m?{}Ρ=! B!ͦU?]?>`jZ h5<&wyz} =3HŦl/"312I.$sB4)9EdMƒ|;*9r񻲞icI]=t[a;3%N֤,~uoM>];sg1Nm}WjvRrsʋe~]ӏ?saGLB!]*UYs9;FOÊJ\sy Ε_d~BRҸxpK6ouv;sRd=׫9q'B!֟p|-p1"fUB|w/w#~-E7=ܧ3uB!DaA!wS.BVG}B!'B|HB6 !B!ķ?!B!۶d~kc7^Bsg-]Bo ~W yF&B!-Oz !B!ķ?!B!5-]B!z !ע t?5U-]B!B&Pv gЛo)Ӓ5 !B!h"cЛo)qGRy Gue&B!ePq9pͷYg/+-j 00%B!BH?W#̛TB!B&߹*r@IENDB`traitsui-4.1.0/docs/source/tutorials/images/application1.png0000644000175100001440000135071411674463545025210 0ustar ischnellusers00000000000000PNG  IHDR~@usBIT|dtEXtCREATORgnome-panel-screenshot7w IDATxw$eO=yvf.afŬȡ"b:c= F#Bs:^p.oy1h&j^_"AVG[7,w~.}o{<w=W #/ C|ωa8-~w<VJܹǺ%y,3tsZ>%ܡ;p>g!&#G]Ce$!NNA{K~Ȃ7:5;w͟|D1wu~&Aݿ_{uoOg\7?}}Ssq>u6|8e=~mXWWGRBM7ދ|l255E&3#A8^tPzeWe<ܑ';╨V:A閫vvLNs{+7 "_oW(ʷtp)OBrW$?5d׼ JT%ś(zP1@"w d;-ً߮Pgn1~O @^C߳ނѳ ]n -{A}342=p!{ނo߇ΧN> O֝YHx 'K6,siB*uV#vtfMݕ,li 7 ,?Aħ>#sN6{4li8񢗳뀝{/r(~wo| ywN~7;mwK5o['!7s~ȅ'o&"I҂c<58糟ؓʛu Mlڭ{=[K'3Fr|-+W[.9x0( o=q{g0{O\˽w{=!;ukXgX}UO׭3WvN?# љ0EA@aBz7v -+FOa,5GV l ': ZUqUc^2o}\bKkn.q,noL%yKYyk~ĉGe.vm| \og#w羄:Lt VmRibnݼ=q ʣzWiz5'>mhv;$~np=$vG6As8,=)_EU9~n) <&y8Iƒҕ 1zAn!! R*xΊAl/r%KUzm[ÇTX`=|_Զ!nAuvw̻#}å \!sMgL"jAa<ϡ~r|<ϙ-N离ۺg:w]}vqwH$]s*5>Tg=cp] 2]2V _ 86`SsPBwA׿bucLMx[N U%T\CqY5M38^ȶzn}#3k;JyߤEhE;cǼKn/8Q3x)ΪێcEs) Goۚ6?o޺x?{̿~u fgv[~6pr,y6HҞ!|scqx9OЊ{2K[.8u Aw[6}ӕA?TJgg]B1,G|CS0Ժ=j;sY|+04W雮`=7_T)`ъyq'ϝFº =Xڳ9!{9^:`._EAB$$`OI$ϻ$Is}z.nݺswݧzn?Ƌ~ӎ_G{ Tg##{7Ls埧vC䯸qtL;s>sѷcb-)zs[ |fn&}y%өOM/#7 g^g\"fy\?SУ6{mws/=[E~]Ҽþ1ۆ:Oyy%Cz'W:ٻnoBy!1w^ LJ޻)p'gsHwNh) MjB2+=pMXH%3_+f/^p Kb4g "oot]X٧$ z4_dS٧EDhꃊ(qܡ :m7"A e,xw̻nX'k!AH4$ (mWQ/;B8 Yg_Hv8y/VB+ϰO8'܄"{chh4~lMA|AHVg$={k4g0{Cb6^I{oo12:Cwvw{~_1 g%6 _Zg[hq@ڱooC=Kdi CYP\ץh:Db'Ȉ!- O\w|XN߭s=! <ɒ]Ykk7 =,.:|~ĐA'N>b moyk/[\;Y7VAAAx]ױ۴GM   \?<AAAqeZ7AAAǟm)   O "AAAx  3(A%~i/Z% O"rʥ{H$ ð} tAAxɟ OAa$w_z{ۯ& “HAI.2N<ݖ~7L\.{^~_s  <,XQ@ @ e iATQ*(sijmM&\ň\tR)%1 Q Q ;2qBNh҉LTGG^GoV̨;"$9DC$%B3>fg7 &0F'0qCR')I) r }nLǤ81$9B5\4C3\$% w#dLPZ`8z#iv*XLB&V!yw"x&XayRy^"% vxfK|vjDHF8["w_\%@\tCWEs">NQ/*/Hd@Y헌Wq'?*߮2=#>ns2953Q9|>w-L\5>xڇ/R7 &-8h'[Od{߿.+aqkW. <c&ÐK/c=vcގK!R>\nufsf $MV՝nXUXU l @[BW61&kӛ+0:Eڌ⵸>k?ŭ˟=ϚgO[^滖宥l{1H6embZ4+~GGmGvd`? CY,`/Pf?IPR lob77f5gpiuK:? ke)P?Ku2&$$QW{rcDu3KM,63Qf}q +Y_X_1@ՇfvH 5H 7H 5Pu%C]P8IҬuKF\iQߘ1AcCVMƪjm+mbGwe;CNJQn稴sTYzPӕxrʹuacتAʄB(}Vr+R`q5'ȨU&IInP2lOQBI:nXA +h(O<!u0_Uqbs%DFʅDZwSیi+la(踘v1:. QL"4%l\ʺ-Yy5o^M5Vqi8n!+e:I4q OP*r%@)S)61&tXh=Fg:VK-=xjmA"E~ >_r[\<,)K9*R))J tMpLƦ49ZCktKjF=C3H3^3^?3^0F6E6M6M/SŢxkq Z=9|q_g~̹oq8#xO[vn ?l g .4[-N:U\z% shZ˸ #H{11r\$˖-e˖\/eVVZ.2|c>هc!ț6o$Ӎs,.ʗ;asv#/7p)˼Moe/{{@IDDV&bJA`񢭤.xImkVxIOm@ jVz՘SLY)Z4x !k*ZJ1xmclZ:n;@3$6MjF#i8pgM^- lC[I0jRT}kj~G25ЖhȩI9B@(,&L8BJEdZ$ Z*9 >Tn dDAd ΀N8%:d$$d3LhS]y2R-aQj}CZ!dDJ!ęQD1$\B>i-5NShb4$M;m1KLFCF#6!7R):H IԚA..)'[: #Ѷ궋qP܀'uHUh 12 dlJ6QB}tDb(lHfD=22L1$L3^RS136L3&fi-^dS)sDDfNF֑ŠbK)Rhy÷1M4C4C4M4GH:l2m)*&H 6ՖZVe#jJdXU {6i;MNo 43~&NDm$)Nh]Jcs!qs?^78'rՏG{%W_mro "ryp_~H|sϝמ]k&r.'E\srYr8CW?n1JC^V?|_u]9s|3֥_H;In=.WSN9SN9AP2'uNؖ**): ciJYk,;,W*rP~R-$i 恭C$A$C_bpp{X^侀([QF#̸؊N2{t#ʵ Q!M$9"-1hL{h]>ك6tdC7"M8lkĨl 2b4%fyG]NҐ$(ÌOL{C6V"Hvp3$ ܄ASMѮ[+  Zےp2h)QS&lJD-J=@(Ɏ^BKj O T W +F*UI {\4<4"i(H::yJyJXQR":%;P"OQ .16TsCAeX/6 HOf8; v2fH$XDN*VcYzVDYgSe)ʫYW^hKF-IIP 6WRbOƐ7c!򆐨 k*i$PR=K:ͬǖ(IFC>, gV"N; 4Z)4BǨǒʤ :fm$5?"t"t&aU-; L}"M}[:Ra&lL[XJXdj1̐t vL2UctT.ccwSQ2̴ũ&EbEԊ#M*R*Vrx RۢmhRTs+Ɏ/-W d xFQ#D1|TFr4a<|_'%9 >bZyMgdj M_ґ,e" EuõVZ1A^7qL| =X7i^\o,!ޘdZ&|-/_fo׏kL7<79I\~|͵w^6o²Kشy {%|(8*I4M;ߺc{q':~CӴ=3s}:s'?s❒]{:w ?7Hۿ> /8on_9s~!1JC^ws6MOq;;ms î~!dz]۳#$'@|$ޑJ8wB&-ӂ^ O<5<%6ER nQsl0 ?{[DJ/:$-lx n=cR/SP&f7%DEbEE!P 4 u[s Aiq"-=4kdQ#E45Fff }t (бhD6Т{/\ (infRYniNΫ0$V@ =Cq=o0@GV7UC7Td-$IK5Q=r!'0i~O5РMK5sNnE5$LN<5ja8R,@]D-T$L^-011#k<NNK'Fq;K693DuL8H n)!4$0"\G& BPZ&qim`$N9`K&H&vݤSqա2D6&I8 jU:<@<97P$59FTpeV'>* mRIM,$&fԡh9:u'F"U!I5 BIhK1Zr I Q]!V7l3j&aJh=/x1~ ~HBGƷk"a5ًCϗi8&'C"59"8Q@5#V%/;:[)hՑ5ԁ*`` 9A7č>^hPr؝#i.%$X1bR}Q7P2%UmrK4zק6Um߽V#|}_jLW@܊v]|_w҉'3>ŗ/aS9JYʓ9mBU4RI6cSn@&4JUf ۓG)e$@M# |";C`wٛ'㴗Zie&{4cRfeY&М͔*"&x+ tJ9&)nMLHrD1BF&=^TF*Q'g̐R% zAccAuA&pѱ&[TXF2bDd8݇(2ϑ&}i R*"Er}iSS'E&b3&Lٳo#v^$]vQ-$)IT2*~FƷRfU0#> >eRRzh)6Z_@Io_m0#p2mK%c82,cK3ۏ  K! t]lLZ7y6y`$:VUwq* NY(E/!ز 44P@`dWyA ICdA7ҹC4c$ihJ~N652:AV!P& DF3E!Ь'`FbAJ-qud#t `I|~ie,c4 :qNc\'*~Da[i[Ô˖ӫ3gYlի9O|䨧>N|G _zVk Í}=|?qǽ؝+yzcppksoҋwיE/$LjYa}(@CKljFb]jJKVpovZ5, bM_|`X"{ٴvQ8BnL{hnN2UT$l;cB :NEەhD)JvrJjc [,jOzNoo,:x` 5eBxpv͢^ )Fΰt O5qU;Ubl_TxkfFMr:YVd [9BO&M"(Ci!aF'R.1\SFF<};ݢ9"eK,mff4 %@~8} dFG(eyJ<55M )ԥ)J & L1 ]']e R5cͭ:d24Y޻XVcG+ѐ'k)ZaR"ɩeRyI$;C*)m\ iQHz$})Cg K2]g(1ȘRzQ#%)2>2:< Ab (UVc`d$WHpg:v6HK'hZ Xjl5B#&i*ю P<8˘TI)04NѤ56=ea;q<%c)|E7I1:tCkӼ[qF8nSU$-ʖf`HhJ@ưY(R7Ei{-= oÖ8Lh$ 8#1E&dH& %B0Yr?݇2% &Yi0J[e<.t wV>ȤyB0;֥yq<(MxN؝v2M 7)\GYYa0 BF{E$eVqXNdHi %k2R)Aawzt #hMӫIձeThX(a!1A Q*L͂}l2|XN.L4)JJòi2:`̥Υ:R@$&K4h41ITY6K*IƂd 9B6J~GouV~{i>ϗ/)qi~N>y(qv{|psi]ag/}('>_p9E:.E|_;`m~1#P Et:al޲OAx,y&~'7td R:mM5e1iS@,3TZZ&HKS aEo>f?euoy92ryU$eà " l/lAC6) &d0 ݬfU;ߜ#c<"YdCn,3Wba#OfNo-/n@/tښp  $s&i)4Ygc^_=}ޜG6p]!d0-9z~ HZ4EY[j h\p43}M<ݚq|;ﯙEsb#h1O)Iܙ$"B<0|K{`J(Qɾu)'|C~[TԺEYTM+Ed*Rc,%bŐu5M'h(S7qbszmcGDM %\Cgs[\ f%_32c֔¡l|b _e~:`b y&y40.]t_9DW#4MYl6"n)BI8 7xȰd%+ X?xO}cGxMs);jaQpD53.x%Cr<ģ8w?SxẨ{1%qQoxF%QC4i!mb.7LX$T;hӫ ~7 7 FK<-hC9CF`L͘8a(!UI9`SW3 01^ 8^Z[:K(5"p).ue&]:АEk4Skm&l0fƠث>F,K.rRKzQR?K#`={̓1//;WXj#3@)P}@2E#?wys!X vBVB89~nhNֈ![=$sm!bØ1,"w=lϢ5[rZT君c%ZJ#C1UmQ-V p(r ??KWnk~ MtS| @;<.q/"s].lxx֧^=Bp3|}?/k~Je/?Go\]]k?s]A"k9<8WӿU~:(w󄯭`nrMӇtF?^sP;{`=O}t:R*2ٱqǓgrM\s'`hL;3Ր{=Ҩc؞b3eo|Fr37(1 NJ$j_]%N#GFOljqS+<3C!h0)pIeifě %=g[`[%#cʜ XgKv8slmQ&Mӕ)R"!bKtNMW+e*ײ?̖CQ)XFlrj9`HuĢkFGZ1p'%h8Z1Vnv"~DZg? ͕8fNYb9ƶے>qsGUFJfvu&شc.*rM6okHߒfD.ɸ{׳#X{ R>8?:GFp>`$`eʁ@z7FCEZl!(G2inAlZ+Bw;R/ }R?@~j+#{DD:uP>['|:2`t-˚Kܢ,l=P42dW7ABrOkz΂BN=wv%szag]A"`j0w97Nbh`Tv:xZG7{lՄb<̂sgK76h:ؠMڢnvT!`A1p_@@A.`\(.+|?0r}S + Fj1kFEпQ)GYg\vz u4 4 ޱz7"?Y8 "]# -\ҡ0 ĀC(dt:EŌ.܉a?ވN4ޯ*~'"şK_k߷o퇹q_w|meWKMK x!f8kTb+p0lbϲgeEF{1S{s',O: ػ4CJsi+ IDAT[@dߞJJ!WJV5cjw/#V\f5z=Nc[3 %S=?kJCĖNsƒ/PPoS cR` cJ#%!\Ցj*6e( !i#GZ$EatfDOOx"'|.}..!KK̡ѩnY+j eCs]k`kЊ] nD 'C9{"6.z#otqxG/x=a*):Ѝ#'g&6[n>~a$NR,tQNg'\}ȇ/ x_ ) Ƣ}xhuP07<_@{%Q3̭)s{Ja =kC`55:+߂^*1H<LкR.*, R-z1b5R-F2;&S C:s -B UjUABKuFYm%qjtS`++ r gP6K_b50i456;yab[5*c ̌mV){5 W WY{t^JxM(t ~ |ұ5gS 6!֡=pv+cs'B=]77| uOٟ||y%vND\ V{I/闠}HK>xe ^3n>, 2#+LM"5BsI>8{~EN ׸9 AIGBĚcȸf6Yc%,C"bvK i0aJVx.;$M҂tԁ0V]t)bO]Q$xJٔac&%V w$*Y<+f^Z fjπ3tnRnM44vC h/#}l<$u2OI&hB[KkWA  >~LeUL5V&{;FNTp]~q^z';8VfVC-:7==n=+OJRZHinh*M뱭"L(!,X܊?#grcѷߦ,g'x /fqF;l]h@vC3 XZu􌌾"Ϧ-hF=,5o/oPJ{+>/lDHD"G޴dfiz}JP%T:hmF\8i(G|.W|# rP:(@!Yl'V! CBCA?g?vo-ň$ZjcQ޸\ H=Nb슉qttxBi:>{!/ b3KfG  1\#i]IЩ gW>Ӟؙ (((x- j:8@wk4 JG2e(W̌5,eooE|~vȫ=N ƎRkOIrMc&nCtuvA.PޖJKvtL$v+&b' e1URqR܉;w5h>>}i@lډ @az nX =֌dtFt$ޖZaY7~ CAj촡?Q?i]BYiT4[,FقByHt2Um@|Q)hUq013+X0dlcM$6!ݭOICj 1[{֚0rWh>8^E'K =6!Mn$[⽛#݌DxNHG1۲OQtA31ifPtT8ruP6!iS4%Uڎȶ!mlb1Q1n/{s^z9frB -`?q}WZ(K͌LʧPJ ԉ4:נ{:i 싚z^dޒHy}vgxsvL2wOk]2F{kf3+h{Q$a}VT P9P@A@]SLJeS76Mj-umS>n#U4`YGN9brCHD3眣K^pKܢDTJy+/γBE ӕA(kmFqjQ(NmS Zĕv3."4Pt",:E! yXc1"dAHdAHԩ${-IdP\}.b62 ƘW-1#VG$:I_0s<=K_7^<}unw\tr0{5ɆxpD Y_X]W;<QJZ'ۀts&`q_+jyʰI!qңL<y7yK[O^TLkyñQ~`QENl6ww% !v3J~EvC#YHKG/Ƌ~܇p;7~J}G|˜E&۽!Au$P] gmđ9ݾm]:X@HOG&lu(w[`/٧ea=kϲwМ,z3~0ih0v+}'>e5=QK#Ό1p ?1FrdA KGCFn2A''!v]X)"wYXMJ9\18Yt@tUw\>iY:#m U]7iLENG+V}gNS޹wG:e_Ͼl) N]{[?_8zcK+zъ޽5zMXkN7VyU2O+ZPL kP)ݍU 4ڑASZTҡj,@.5^qxG>?S||ONɫځA34h&+Mxqc]=+&-s?OF)a-Q#dh=R@#KEW$mDx,)l/SID~*IDȥ-r$.o:3ȟAmA4QNX{:fL EK)DR@1 Mq&.4-!7]n+q;}7N  \t[??S~WZf5%ЋF %K$|J~~{>ƌ !̀U:D-{Oy9gFcsVdېj/]s݁GWts>2?A;@ H6sm'+[QMMIZ#+ w(ԞRZs[Z<ȗ>e@qм./ y8!(FML%2ho,Efm! QBtNi|>7KqR.I{JrխKHҪ y[ ?܌p;/&/_x\}g$V2-:tT( -IivX4N 8[ W^KTwW& 3pOk%DZV%dζ葶aB#; hBv,{WBQ+-EU 4`A:ܙ-ŮѱtiHLC%ҶfQ>Blu>n" #lq0iT#R[)oSʑC1v0îqii/tRçpmv?;WOE̴2F0T#\ [Њ -!0>SAtUnm#"|;uKaJ;ʤtD*Ğ1+^Gөu jߤƠ%8>l=/utF~n\n||,:,*,A c-꘰' =IhJB%ymS9X^MԵMXzpSx.A^dC4iNHZq^ad5٢O*fiq3*]%ΧN|>rb|V8= ê1*j٭VJ 0%bj ^c U> (a)3ej^:AQydO5W6ܦa8s𪹏JڠitZMdӳRNl8"MdGhH$"xRV߻YV%nWQPP.͘J٘apQ$h6ר0^А7=R$5" NWMcr~u^Moʿ+q6yg>dy>)R@B BQ΀H\h01G5Kj:(,q(76OC@H!F wT;] l[f;kgv0nM?6!9)9:'^ċA큠uFy"blxANGF@jy6ڨC h 5s<3dzr\@6:K$l;=d!Y"sDl7b{5pz:ΉNٺTn[dǵأ3L_p_5.h }^uu@jImiCET fc ֎Y-TPYdVQLS58v{/'=xP:uSS~A/D qy?\'Xެ?%d9\bu-pX֐; Cq]2l6,W<͕M ohUmxnAP Zshp)|FQ2 ݅?Jq`XCU§X4(IG4i'px򈫗MLC 0孃/Hmc[6=ʥG5 jTJL{px&Ю KʠѥD{Oy/8[fu^/Oh"}֠ ,f`6yM[tbɚMS!,5<.СTCpd|szkmƀL%g l!q0dX=VҶ { `Y0i%bR[( RNhQhpp)pTtI$Ȝs<{g;N=uYaE!aτyԣz#Y,٭k^XX<~c͌<`lt8'9Qs GG=}-vzW `BA„ h!Ѐ#85H%LOJuMzݠ\I4AYQuTl4Mt#7!eMn7hAG=Po^xlؼckGkֈXtE˫)>;=KslhCEUy =seaӨ>[*0CDtd+>Yfq^d:&Eߴ2a/H؟%콕N3pꌡ1m'sܮvא+S rAwYrjX׈~/%x/nJtBx£e.8p|*Ubp[/|oO^>#WƠ- pǒ;Vd/_ rH^[s&Μ2紺GC*FVWb\9DJ2it/t9w/y ,;?I:뇴 az\ KN ŊmpN|cq搋7\9dRХ IDAT38^28Z1<^+u@z\oIS>^2v5=7,/^0fPO=hf-ŴEs[ jlvϠCɧĮזݜK|ވcZKHӶDbK$blUQ)D0CH&wfs>4^9{338QG(S*͡=V#VƬpܒ["_.W.WC.E6LGׄ9h+H-kz,"r<-n,1nNi;Y~Ƈ'DN]yOw"{k;ҨRJ(:'1IL$&:)rte">]mցُ;np;VehmhK1YdS]FZ3BՇ@KS, /bU6ȪAU-bxsb<Nj$q\h]I0+:!̎)ZuQrD$̉1jHޠLG2"7tjQP5J"r.c ä|*ͧ}0@SkjYJQzc Y# RZ)J'/=SYxCٕ>Z~;0!Zۡ f[cN ZXFutZ&8\`xVhD C(LC-z&V ΡޚԥF\wIk+ZKP'}٬=t]GuV;)A`P0JfT!¢tpָBC) $Ҥi 4v2l z^A][vxvkui6IVPiOQP*0צ!bh-]gnV:Uy٠_J+I8mNSRh"BbB"VWw])LGb$D7%~N ƛ*tN]Fe/Ieyggcf\H͖lY [6l o^yKԄDQ)2+r9G/n$IPe"" }H,4zKޞ0e2PVF bA_=gli)i.,Anܪ*T!JsDZR|BT|d͈j w"ZdOIuq%511mĮXy‘y,[.[Έil"de[G u*Ѭ\WU!UHC* A (G\g>yB ͨB%[%PӑTL. hq@l9 AvU{1cQ3q ޒzkEZSLIsŰiS ECS&D/rF!ݒ˛2)1J-FMDIvR~HEX^ڧhDd6Du8VHV)\0`c m_؃٩ ]tMeK & E:DvI:^`ѥA|epuvMff,%H (bde4[cJQќRw)OaxUq0Aȥ UNI/b-uXё; C.nKt Z)V-8weT6.͐p,|N j@n@  9$f YaDXGØa 3en_?~׏Kv'lW*cf>E)$V2E`Z\&]Ѥm=Nmy^UNX44%,鷆wըj\| ^#_0Ij V虎;2AG" F=>ϰd)%F+żrQjtCxsțo<9Ǔ{D)30Y(:qjJ2w^KyKiKi6i"c]bd XdØ2&/K  Te#zp`<~#)(jg+}o\aĺq4}-[ЈfԽ9wC0Yi2 -]f6W]QD(E,Zȁ50.Ӹ|PP=d';%I4-nźj]F!ՙro5?`z-A&h]$h1͈6.^\;IV 1_msl:f-Tn\uLIزG[lSeAyaLP J5AԼ~jЊ~H,/uSN}d ,u&z4R;<UN;>b uF|S υ_DB$YJ O!O<g>eҵLv&(pw f WzH}7([0l0^S JI` B6^j;xulO%W(w.yh=!stqǷz`#)nv 3%)TbAJ4FqZZZP1T%YZ"c)" R FŴD>H8H6&!%jAPn(upm}H kI%ueJEY"+KX!Z+7ԉ^ƈU-0%@A8 _@r&H ޙBlBgoD .0̐?rW?C6 7p XDn[~G7.) yH]P;v1}cLAT5SR}zIͨiR-(wVH DB UNk~q8}ܡ.IN4G:LZd " uS=@?*@3*lpJϬ͉*9wOrpg%G"5F|4 v9U?8lDS `" RKFHi!i4tg?vj|+)pֹ*R!)pѓ5bQb;&Y XAqR 9W %?!Br2" .d`U0 (U| ե4JSTRIeDV ZP_d? 1"qNB \lTѲBt bT3jdk2=+8mqbIJNKqFLQȀ@lb%&@<^/  ]-PҊ3'xͧ(d"EvXiW9xmN9YFQfyDKLVm&MřF2ZQqf8bI^:%eeE)[5Xo۬%XhB!R`!%),}̲O P.iUl!VbeW5, B1݅!Ta6=.gB TaS!`I*Y! DVLI l-]/RiDgm RYK6c6`^oEdvBQYҾK.XCAR_!, e {lMWY&倦9~[cXf=pۜ *"%.4bԘM IP| ˧-pXbk¦-(R#C #j*D9RgyēvTv)T-uI2/ЍHYJÛO3Β : R>acD!1GY*p$(Ռhp2鱚hV5N6J캨 b˹B@KꨒOi:s9Nc"Li1-&w3$3Glzcgmz\FkD]jq䍓YJEYPUT5w.#R{>G$TXbaEñrYE-RU'(Z{=vHW̏tL9Ji()ϑ ]>=Dm$M^q+:$9*Jbry|!1wp5QV88Ցf:CfvFHr߰2B! VY?HSH)p\P s*$V"tik,aK_{)MmLWwѯp~yw}/gcϤEe8bmr{ARrsBIc!* pI3 0Ya# k')R#0EDC i!9"]JįeN?Vf+њRf9 54@c+6_\*Nj>Y*3MFl[)R.Lf,eOpZ+֘5dD,{iԗ/ٮZ1&T e1eNg$z \pyt]VQhU $9P\YcO Qp.tq=ɪgn٬M}:# "\gU9y*j)BuB,B*e]P;1Ō`ՙԭ)-mDm Z#AM 1j9f9i_SoNqs_:Ul!1]4yO4e i!V`E>hdC6/\F)6+&tH7Hu\ʈ"̉ H*9q %ɹ'뛵`<^ƚfcNǘА), j,ʄKa1[6 =dDI[vD^;~3bt=9Քɏzg*֨q4lGlsA*Z=pwJ[|#W 91WBܷM{d)?/?tu qh ԝ 㒷% ~]RwCTu+j l~|){ã,Ѿlo<2 ;*U6l ϭ3}o8[L~"|YBŒ)o|>>={E$R6_N)oWy>,aU{5/s?qAD#%i諘Fv6_?g׎w/kǯIנ,o 8$5yåg}BPKf8_XPzE |ͷ[g? |/W_<< IDAT /lK,4d%$1|1USێ)b~6v 7sLjk* [\\;~.υ_k>28q|u]׷9ȶ]&u*'vo yX}Χf#>ͷd)'bϱT* bL#쉏9 '>Fi\`An221삤w爽9֙2ی6k?_f" vyfNc'mf:Ke A2!v|$Zi^ٻE{犾3gW5YeVR-5A/OwXD5*9ZkFӲF41xurקw///1FFJ5Pjo" 9&&O{\}y~Iΐ IIAddQ ̧0 K>Q0 RfAa)yz^[o~9Z/(Yi*m&Ʉ&d6X,UVʆn)9wH `i$B0By!Jś ś*[ TdX \"+S ojM-Br+BݏQnśQlS'Hw% H~H~N 2E"7uJZF7Up5Հz@w5ymqS"^Dŋ"E\c՘5Jf@9n(=DZq!Hr$W (4p/ˬʸe%y.QH\K&u$( mʁ!+ #`b7X &vYlz\|\zR'fP*<Ջ;|>|`*7q릃t(|:++:+d5f4i26Mdci>cGzw8pЎ.FtsjͥZs֨j_q*zȲ[{st|o{?o7߾n;~~6S7 :fiDI-^$l1A"UuX$|۬2f\A5ۧj(F 2cJQ@=sxI I,0D^RhnhK&v UB 6 42HtjS{V+Tj *wTwgHQBFANA$UgmN6+ }fQЉC 5̑I2Y1֘Ԙ Lç_9g}s8a\|( XÍeX[chP V{s6r҃͛yp:x/;=YeYN2\鐥1]M@ۄ -eu={6[ .o85јc.a-fB "\$*+lL $]u)-kjUerAQ<O/1D`CG&@Gw $LdT&k@PnM.3LI*Ah SG&P""ĐLgޮF&;Rj)HuF1B ,˔UfiIɨ2"U#4"E#Bbu悲ƱWb&d {3(6ySLC0'tt²NXё%B QXdYNÚڟ1n] ^qK2Ҕ&S1lwy^Y\hR# X>yE"m)$- I9 jRX> 3S03qt| 0&#bL>VcƘcaWwqWɮdԡZ]P3~wB]b[빏Q@ j=rekb@O\eH&IB% P+Uj`6ٲF6h]J=Rg_9bʌ(3l8xv_Giu )/в3 )]sLwTʱw\[\\[D:e@?Gr[(p%+׋vuhe4/eK}g %SRcR_yKdskn/~k,d@%~Gt {>eGϚ<%O {PBJJ"Z3AB Y  8. NlB#d]Һb6F'Fr/ "ftQP 7o+/IœڦD `J).3oYR.\ q[}^C!uye$\$ D6'&`*5\J) gNѪE?DB0"|\wAȘ-SAbA`d)ր4B.)LşYͫ% ױӄ !oD_I1sy+DFHJRFŇ |S|(fD?~ ">ҜꊕlfdߺdG?gqvrN&ɸ+ۜ)}VRl3.EOXDtusJ9/X(rReA\TWl9$OiƌW~H 5sU'*Ve8~9|av"KrU՚ZgA6vkN-+2_ _  _ ,s m&I e"Ey"jS7~5grǘxc.˫*ˁw0HiV됾vAsIs&bT)F#&dk9,ᘻ.>w?:Wǩ ,G*aNwܕ?bzLषYFܵ&%l@U$&qD9ȬaiW4._DD/t&-J6a9k}"q*F삧j,Ӽdd2l3>0:1(#yTEutAa)X)0{wo|Ws 7_Vc/lȷTVu* z שVЛ)vӣ^R*̽:aа[1[oΨ) [B2ADPaZ{M%m+bE) -欹c"Eg--.Ti2ULB+0SQ͜z$ebLHD.%@7HT\HB HBH(1Z R1"j0BBW"Q:Q *LǣP`ѽ̣ P+pJ[QIa-$G+/ps 7Sq]H͈V2@C$J3 .ʦd p"K5 [Jp?/Ƚ|l C2tEd=uOC)"HMrť\rH.EbDg78KRd9%d MKMm'eTjn6g6nbVE?1l rKS052@  ٔCR#@((l=t9\T-'tY!Rd9M3LiIcl!@6uY2#3Zp @28!U!Ǥ30HMev2`(wYJUJJ u"Y'S$Ha회*uuV&5R]%44)FCÈVHO`dv$qQ C[)J?FDrLOsK%µI83 \PlHmdDZHL+ıF~R"2dQ 3zc.#I8f,O9}whP1P,Ue\ @9X8aI"EІ@*#ccDH"12`-hf4˽sw߳9oO8w4b 4~~ut?_?}ok Q<`5v :βh8m32n/P0 ,-t E1){zadԌPI>23x5"F43<AdbYfCYsbBY\6Y1MbvD{0gL4 9+vcɬ[$SuL| kUF]-r2tEt&F[a٤&{K&~o<<Wr}?knEdwm`1G={42L]1ȅ0=1=2=$T/ 1s^I+q*-%jA)Et!mdLыbA71ZnҘ N`4ٟ] ;2uV'juƒey&YSjV+!ä2ɻLf]f݈!N3!"M2 Քn>WLS CA5I5ʢZV%ZdwfVtc2~]HXT>FĎWԃG)5!; G3W%~ A b:fN{?.R*NP qP6Hi`0OM o_M#9^RZYL  >-gA;י#6wy Mۧ7G 5X1Zr6 [KbYLg_#EmfAکw }'h0ɄIlD{F[ML'\XP: #7 j4-]$՗4li(>eu`:T-ҳZ&^R+¹x]=eO^PP%͖O i! f7H019(M2\d|8 v WLRj78h6&rSl9J'䑙cMP4NsMLduuN69 CN<;}gf0vͻtn/6h -UR:ncس#FuiBO>qB=Qzf/Mb^ ~jcK$ CZDcӚ]ӹs8Oyf~AbvuWSt] ԚDH,´K$ Yc!UUEA&iB^%ΚihJNSp6 ZY%ZSg)=eJ/rs|O?e>1_ 2,k&ǫm>1~`65Hc*1+jŔΧ_¸^`}Uڄb"s%ssһk.u(aXK$В8퐳ry1`ue&QGe$QǠQ%Qp,z^0ThdN>seJ@Bh8B *:܆[<@ԢpfֈkQ!Or'_M9UML]&An& 9J4CD3 !4 ,WCeJޓJiq\EAdj %\=Ia58YeiePT˪.3*ǐ9`A\K{ZJlmSi%cʜpҕx-^rws\ޣ%kRZޣǜ}4٧HVzSe<ٟeO {o{`{&y}<|%~BhMT% A* ٨d8O`#cPSQK-&En:b9Sf( =(G%r+:1Z+0')CG +ܾCACDPV 0f) :!J rrX&s¯<\'J(GTH$լ<*nd;p圦"mNjaBSТt\1 …B.+Fr2Wg4%V@Ztf 3H!$yMJb:EV3p=43hvW439Eed"М 9v0 JI^)݄moĶ;_#^z@+H1A$2vi62qF3^&TuAeBiɒqc{ .a0O0Y bi",J6|K3ZOglS6S6)c\3j2yUpXb`)JYQ*!ĴR NgB1O* \je$9ZZ՚ ^nc <WsLuM:4TP IdI8M$kY褮9qŜ5"U%*5S*yݥhVB%td$(reRP`T4eL1fbd9zc3%5,ff#cq'ĉ@)*D!MVKV,C`U#Zľ g\ t@on(X.+j'M<&bV#,-Zϣ&UDd*j J@Nht'=_7GtĜ6Ӝt*N:4z(uDVSjf#tM\!ZF.H)Ðr΅>q&lM?S#i8(Q(.@TD X[E2!tiR'(Bi((6tJ<3 VbjۈPҒ,\ ,h!Jx!+ f-| "2I8/I-DuWr_ u& IDATZ^)/6>oy[?8>>h|aXd_<1OyERE%ϷKJηZL~YOho.hoioΩu{%+ubu"]pr8ТZ$"09 4N4b7o"{&dt˅VyiK nlr dcC]OU R{QWH ġBa&Y:aUc5_\`t u' ^=9C\gV=2g,]'04*#T2!W" 7367cJy !4P5F=4U0.B -a^@_Nx0&iJη^o2^g36tFb2V>2y6j@VJO9=Ǹ5xzUJ:\u:]'U#̎QrZeA&i}*E݉hZ` B21-F4:`ud7165Frln'~\Y?)TӭO>e>{rϚ1N3'+]0W[X$РP4b– &}Ⱐ), aPX'~MGlIL/]2m2a Me,/'?z"  ux뿃׿;a@ܹs>9 ?g`p;S<'''{7w>;|wm@~$I뿾}w̻މiyϽ7 ?gs_M?/ʯPozӛxHӔo[~^?F~Gt_Wô_t3?#?&n޼?=oxQ~'<#c<^UKELP 6egx }JuY.?Xi !(XX$, `} -PPV[Ǟ=< Ndm D(*1p𴵛gQ¢( ђQ@* a _69v9Hv8w9@։Pi=i,##U ; QҊ<1+exL^( i#)%eaeQS={DsOvNy$epmZ}Ľe^_.z,Y 9[sS,;*C2fV&IH8yG" HSF<,0\M\L=l@O \^jpf3L6eS p$ 30q0vǩ>5 30G*BR"K@%S ܔ$::ѱz7ZipUWfObU(@ ]toHvّ s:1b+:bP R@",,ЊF\"f-WŊJ׉btYP-9 2΃pƈ J-FeUfj0?3/"Y󖷾qߏ}c!ڿɲ?GEJOprrӟz)%O-v(RJ=7孼mo}q\'Z[ěx<ƍgAJW/_j { |F#~'!oxyQ??w~o~%JηZⷾqͳO ɲkoQ{5HjтZ\6. V%U .˹$U`fAZ[5*Q A]HAj dLeI-}$tHvl"4+G"K )p &}csGrݔ8>&Gp4-GKj> +UpE]ZFzJⒾQha9rPGXTUph^4]hĂpnqlbA&ia&15-/:2l|r֢ u5bzgJM.n1Hu{b,4I0HlbT4VgJ(_8iI+_-*YYW˲EؤMbPeR68t;Ŷc43':ibqV'3(RIҐXn`+`'kSfRyΌz$f>:K|uWD*?v1\0hNh4TBi &4kDZ]ǧLYj邇OQKW1+[~]L1F;!MMOkh-b(b&7lm2+ZVyA(ETZV2ԢDLSp@5vF=g}X[9|E5pMFN荜fX ҞcY) ̇s4*ԁL2gO%c@S&^&Y7ZaD1 ipLe,%{f5P\0I]6Ii#4*0RȞTBIT):gڐ%k#ޑ9$tP**Y\~,C)#9uuUb$ޘhyC@j&km+*A$hgZKNɘ>qc}c}> j/I|ɢǘFiXF´lqnqn2I%d8Ԙk$v$m[#XdDPPb. J"7^07( _)=?yX~ܸqn;fe?vٶm7syOGqD@{XG7tD`X ZЂ`rYG)0ݻ<`MZ*L0Q`R*({*Ju\RdT1Dr2s(3&A:`zESKizs KKKs46I|ȯ3(ST{cErN}I\9ouE?nOZ-V+Ud:\nlFlwGl_?GW%MN'$,m`=ag&nf,:L6;M ^A&h V\Ϟ(k,KorƔ UWPv RLTA sP;d~ʅ!." v19TH&QeUHU拉 %b :MnyIŹҹ8gvL hl/cv9oqt6yذQ7J uj9x R7a)rDveKWKA||P b,4ɛ*ƥ7[ňMY`p087 h+fTĶCdH, \Vչ JهrX0"]꜎5G{żfiv-]!MA+TBA5$ͭ%McJs8.=0a\˙ڌ{]&.K\Iwt C^dļ #t{!˿xta??ď!7]oG3'Iv^S}~|7}_>шa͍E톃>/\wvv%???o ?KRgv,?o?sm(5*+9~cE頷Jܕ5V584<޳]. p%l>m,~r.10!`Rݓ @K:`H$B9c9krʏŐe1$ 3)Ȍ4wȂIqܣllkf-b P k jG4ٙ&4GhwPT_3|j {쮰>KvSy0~*' x=Ao# ^WN$9Vqǜ`1 P󌲀87H2iaq@yS O*Xb뷸xau,ϨTAJ)RaRW#&GOPX?FIiHkNWiEZi :%,Z,=r(xTO T;hK@@P:ibm:iӍZ#X]~kBc2=F FC3\y\mp|.\|퓘Vſ>`rgႝǔ_&is&QjvHM 9O/aLr-n޾j!eTa: Ҿ0)n#-“ZDpغvJ9q65)l[!ueV(>b&\pD IyZJp V;GR$ rQ5HC5⭂PP+ѠhiM좆.r#qun߱0>sтNnZLa*v!IG _aMt#I8rxKoM*[zH V=HS 5JQQ͊Φj+~IVwN3umWy^3aRH^[ U X";c4eel3Ih5hhtŧ.Hn֘>G<#HIDuod\ r#g$!"Ȁj6:هiq(EgKqi/'4 W[K0rxAb bQ/o;ok/.?Ļ^ /7ou Ð >/wü-o~ɶ}\twz/j/>`ݻ\rO;_[G/Y48ױy%i׽/?m2sK|*&~:@HDfx!zGʨP ,wSVu Yj֢ԔS1oU7PZ]Նj ]m$XcSK P8*Q :UTUa "̭ s 3]nHxvВyFU4i(ʌަ$v/ .ω뜊MBQ' NTNZ̒.JIOrζ9˶Y]Dd?f q31#ӂ3sȁ͡řIД:$[ e*99tHwQQS"1Ș-L&%d-eGn IDAT T.2*DetML]uFWUggW8Rw}0!1Bz=w%Y_ uq@sY8MT_Q M"Iڔ3vl$X |'XFC44:R_#t{OX8ɷXdrec]nt|.b1`1cLse&9%W[(u^.JG%lWN50eMc-I_vަ:! )cQ(H$r8Ijf REJ2 $HI|BR:{OwO{=Rujʇ{}za}픭ǨDl^8A_HIdc4xuj}d1&p4m(8^縿`XĐV&馸DJnNň^n V[UyĺpB*I#9#aa<"Uŗu|X%I|(fV^.0DJfI Q(ʫRe)A :iþ:M0fFĆamXx5Ήt# F {:sL).)# P\,!Xb:!f1R!9"yBn%F4b FR"Cb;R7$Lj$DcŲNP2 B3Che|f;Ur%rdt0@]Cr 1¹8Hk!r>)hQpmrhoz5M"|CxXcg~}}/j~|soZJ%vwwrAn[L ߢ ߹ty;Xߴ>O}Ư9O~O}g}z~O糿Oql_Ї>'?i>_'Wmoݺɯ7?0锏ۗ,_dkk of~P=Gh'WT]3=LQ$QXDE?_͕X͙@3egmK.,DV6Z!YsB-qZX[Xc8cʍ1 j,6d +*`_̰w"G8X(#*悚4.4GJ9<&s5DCjWT!:~CTp TlLL?1,,%ΦOJ]"}y\,9J01KLSlF8֜5ıDF?lџHzF!3}4b9DhdA"*x"2ˤNWINK {[yN?jq7q6|͋DMCoCo6'r1F.FQgT eiBEaasU2BW%~ΠYc`X&.kۧ ]Zq[!n)k_ :Ո5cDCmWv#E$)AE! !΄| Xdc!\%*)r 5a ؂'jFi(RDend˅M`ì[d82jh<_u]:?#?o|Z~#OG>?i?gmm }~/|g}CM+i~~'~?ӟԷggߋz|L>˿ħs_|c'? >s?OտX?/M>яGߵO4G\t~뻮[U[of~A'A 3A*9MsΖy:$".2[o73(y3v=m}g_a(U1wWtr#n/Plθ+=] 2)G:iGlf :}@3bL  JQºQyג{XҐ4MyH-S g1K%$;RF*Ce^3 nLn=5TΥ+ 1R#[-^J '̥>,wW+.z*Ɵ[[loqWQ:֫`Ù\oZ6mJ9[6ۇt:]֚3ȑ\-`#c `ZD!@7GW$'0#uR8& #A)sJƂ9G! b9$po`dwpid{ qCA6ƈS:f@u+FUT$SP@v\qsװsI^X+ ,* f0]@.2 P\ H] 1T-P"AjC1#NӘy()sv޹Ϻ5a>=\,u[|}n=_O[Vժc6_! %˫JbT`~jwK,tF@Q IMJkY  R]JzHHUPU"YcbTpuЉePOV]L`]Nf"ıcNkL0rCba  XI2'L-&huS wX`/3>2\ϛ6Y_6AduU$}qn "#Ȕ$aB,I$4P%MVe:K$UDg[ PdHaE*(1S*hVkg 8roP](Bf3ZYXg*ӴY܁PMlmΌRIXliF!Uhz4s?7Y~d2`0e1X)b wi.-K,1ESZb>"9~fd*Q&R; K[ulfJ4:>e&,XFc!3<%J$dK yTԴ!NyUs%q2:0;wVV,O\!虏i{IL,)2K%&S-~`1W L2CFlrUħ X׈J _נa5q@J/o1 &K3c״QˆZ'5)Hnz$L,X袏.芏J&L"CѴEJ!j;"O IL/H$OQ%1 -Cps`@!0Jɇ R( +EjJuCQ|Ü@"qywd2E y(p(iWԐ3́əĪ2vѥ WsUVQKZbSlJ0`vFNK".3¥F< 2 Ì$q*DdDr]X`;.vdNXXO&q9҂a+*2D$U89 },?gߴpu7} ͍C#"Ga0t\E̎LMZ, l"] h^=C#T_Z$/K-JZSE&G9hrho4XT`*f>EGaRTR< YōX XB&h%FAQ\a0JxMdjyhqr\' @i1GZ%т\I` i, j4t14JY&3Z9Cfq9B6qZ9O 7-jKw&e1U¢.G/ENSX&79^ě؟쐺iIyG9f ^b5d::DZT 5\']FT1UyD:TW:ֈ JQ5cmppatPUQAetX#U-a+#*#ҢG̢2 W![gI_%.$CYslهl; iQhYaXLuܙF0M`:*mU:e+<|1Fb1bLe&qh1h1a;oqk8/N;cqPDIc f;f'$Y稶ѓTgjGTgL*hEP7T;Ԍ! 3{f2ܭrö(nX-"-3҅LmP]? dv9Vb+Gs,GJs4& j.h*`9.uG+TYU"I'>fSr, &u؍`"7"R<MH;8E6MMM969r78o$#pC=gslo1uJ CȮ`UiDES5Fxpul\)}6+]JsJ[39JMTg ζ̻ S{slL^U9B-GM t.PF:iR3DSh7+q֘WL7+6^6R`7C~wq=;^}7k>c|oTi+49OjL&j,'@иv!.1RVRδ}J)F^O%}"C7 .;+D UZ\h A#R/#DD%K!.f6<,*!]H@nIDFF$x<12"@BOv`JI+ s!DP!]Jđc/(:Sjd/!H%BD0Ѷ8ƒbˣteI>Mi}90\U5_gM@jFTQ] 1]#7+^Kus\12 WLďM ~$21r bB̈́ׯq _߱)ssLbER Y?{=c< b77} ?qy&"Xg6-L DJJHILQ+!)8e96XLjcUPk SHmHR2r!ɑ 1Ԑ2nY+c Bș+bX.ҌJcNS6. Bk/K" FqIo I )9*Q:q::Y7R  Bp3{-]o_4ЋKriLL֕NerWF b 'X`.fࡧ>!j*I1O @YFzHXnآPXl"M¥E*((]Z/|EBB%)M ˸~߷D=_+K4kI5mMތ ))}%{ra1VA%(s!rD)2'_Kye!f!DJr=H2^&R#Di:=?#9P{!z\k $E6󸄗ؐ ,&4s6c.(!R!'9j :<9d dq*[#&2Cdȃ b@ɨsvR%E  #fQWf6-3$SX%YEI$Qд9r^$*aCESΐĔr9y. bO! E#4"'&r1!ܥI&# ᒙ"#X z1ªX5?ט6" :^C0I`@V"d-Acd=FteDWBXJDIY$ʒ6{"ޢ2Nť% .vŠe$ 9$ IDAT [#~~//Y111mo߲o*\d968mrtxXtt1n-: &IuuvF=l/ DHm#i źͼKt|AOUL XF٪>T^Y,-qBLHCn'1u5 %LhG5FgU'5CXb.ֶy)x2sWٞSߘ``0iH2FyQK*!!z$2e"XHm`I< ɂrDM_e("ӕ '<~_|k7} X|EpǷ7L:{UNۿ~~uS7j+\A@D@@@iw\puKs^iЫ9/787댨2BF/sa?ρ|eXW[E:g2!ݩ@0QR6rƮw`z t0z)fǺrĖz|̭"JmMDj%]1Sb̨L!(YWOw؋vS~dYBU Ƅ٧a1]@Ã[}j"H؂O0]<)f1WN55‘A@'mz:j:`7W\4ΈERk*˹IIEwoQ6m܆C H\OItPY:=acul_t)0g2>c財QGԳdHhjEj-{#.{Mi*"Q]%T5 ? O3RHnmAR@VOJAA1@iss.mN0GC0D"I^QUmJ M 2 MW¯d|HVNҀdrv6]>ak琭Gl9G1!)1,1K*qY"&TֆHvLcܗr_\l:8`h>Q1u+L uyȓ+ErE]g%$Tl'OؐOhd}D:27prZ^Q6OiEc$\lQdO, ,ΊI^RK\RVg5UuS (P}4GKѾ7Hj"z I2Q AlZ`>-0+p')(};je7HcaRcT(o23( rt C]ҙG:HƢX-+ H0RyrI疇蝙^$.?bR;61;U 3$FDa0iprl]g[g̃"ni<4z~Ec;QMp.Sl'׼wq'ztPfAdhFLI]Дԗ} 9qCx3;+r>nqئL2nn6aeFnNעwF~.QMq-G_Nmv{Wӓq?yaADgȣ{s([*wU&_֙]&Kf>|W`dEp.6ُ/^+3+u#2UM7}'afizzL;?N0c1V$$QHe|?|\>.7LIAw'τ? eޟRb:Go/vۿ͟,< `3>1گ2ޯE6ns7_^cwU΋mvy~y'kkי0a8nNvzReV*ejQ"[D5fu!CftF^#]̎fG #zy̵'x!O\?), |Y8,&5 :٦H)mkӽ22ӽ22vsm_o7-ܾɝ;7us7ϩ_?guEqh~y~nQn)GT#J1Mq@C4!5s@RT!üƃFJ%2S 35_3b"\WVIZ-iqLUZ^qX|"I3y᳓"3Zg<^橭i{U& YѴJߤޠd8wG(Ɯ1O)SJR0O)S,C3t3@3qÛtE*Sb'S`lL bTHV,&qHQ<gޛI}<+kzf\ iȔ#W< Yd(dɑ%O,)B=`1{n(KEp1cԕ?+6n4Z7tD̚!zY3dRq<9yu;k,|l.x>.^>OSG|g}`2uN1w=y7y>$lС8p^f/3o2ʑC>v)]=xyam'-?ɟ?9cwY]FRv:gf\Y.{,W}֐=df [C U*p%% H'[w_xѷ }~ O ~5y埿?{Wg[hny鱌,MxO6hk>~K~|vn|z>=1_M>`||+W4ISZ6.~1/}f*~b ._R }!0# #0%|ޱNm&ϔjTN;lMfQ--k^5ANN #T!FJ`{=x<-'Mnp+ELXn fU}VJT*e/KxU? of_ 1z.Ο???zxݿuo/1~}=s4n%Og~O?R]W1sLmT_q[h珙Zt!.]6^׋ z: ]&rc S𶆷Yq~sH^\ގqTw4TwE^J f/f4A@PG(32rK)+']&1lL 28-H16ا8w)SVP&^"p#XCC)tBI4[n٨KXm7hy.63Ew]a<kW_3l XA^qsʍ˥~ϥ'k ''yyY7c޼gcn#ѩ9oq1 TuUGvP ICTE*i6+<2{I[dcFZtY]V>myi+hK ĻZ*JAb&vg<9_P5NC^:'cb j ^Bb`/`D ~}*ޣ,"VbHGJ- +mu@P%U8NFY^3O\/:;${PtT݁lM; SCX.ڡBٴTejkB]͆QǨ4u!8SAKDDGzԵIԷ /CRP.R6 YhꂪB9M=2i?ؑN~ӄt~Xs=i/_G OuH9X"%ZnOXhCYS|f,W 䆞\X`dpmt.o<&{hEEĎ*dZߝ3ؙ1PsrF%lJPRsx]>Fۃ4q[HݢvW 2U|\<-~x) {z#iț#Թ@VPu-ǭct6жK ЭwƏ毭1}%wuy#{oWP ڗŒ^=C5S2j\#jeo5~)0t z$88``g!3Vt 0`m#E m Rc7Ǽ|o1/#^skňռ|u2vPLUqJ@*53>? Aڮ1oEO!k>T3KhB;Y:O[4:=AePj[i(DPȅqO y|ÝE[I7wQ+t{>(wh] n-o@ f(gtc5#$J YkA]Y@{$.]+5IHwoYl_)!o?[G %?!r!˷W3˫7M{ѣ>F;; ڇvjTKH-FCrиzgTs>~@28Mj8k`Q@64!!4=cdFc~j3d~RfU]GT:B:Yi6p-FHQBYdӆF >̢!>ހȕKE{ԒL] rD҆4h"_j Ri*{Mr.n Gΰ`-Ѡ  t'SLjZM-J\X5eH cMI ƃM Mq7Hvu gP, \DZ³%'ޯѽMkՆ]uHMؕLF I)g̺;G5Ak*ӤZTKbPMG6u*@wx;]{>W\-!mEhTrWnքn(Y%6M*zmp7%n3Rw<^, >.f6ԖIiѠH#LC^ݴ/=ν9[[V5ƨkq̄I#mĠV;Ό'o)U2;k3bmthwF|RbY&΢ Qb[+MrR8NF94#^? Ϋ#΋CEHU(h`gv6dʐPTEG!%0T*<1)iS6(m{ӣrl|'#7 400ݮ71,0oΌc$Oػ6_}.C&71 #1m|y]0@ctȫs|6mfNK )PRz-W5s/g'k,Diۉ IDATf()f-$Dކ`%=oskU=DȚ1Qt#~ k|& ܄cahNȍF12ft5 +E%#.l1`;b2{ÉKTXTXĤBIDt3[B`@ǀNf)zl0W5ٮnJw/CZ=}fւWf31cڮmf`p+XΡ:w.Mch 0X>4mGzpۇ,ieG4y;^1z|ɓok4΍C,:5-&%. C]Hvҥ꘴OSp۳mf6fLcO<(Lӫ+ 8+\1뚥cb]-_F}{X[09>QIt{&7>4Gfwhf70w崮w9=msXvE-L*,je*9Z@.']pxxe\^puO iJdCBA6vU cqbQ($Z@+ &?3ɾIV j v ql0ۄ}QXH^ʢX¬cDh'˫s= ;7WJ8mᢁS  &48tX.BwHE]Dl*eQ) DF<}X#7 Ö %7L/<Ӌ1!l6'^>裪>l3ܠ97ieƅim+h::Scq6w%sϝ?*3]w}di`Øx(loy|Q| Nx{Ye}y:0ox*"O_w[QIj+ՠ ZϠW3JZ+>/Cg0m{`SҮ1E2,V/x+ٌ.>zCٔEյoc c&]JvDS[G)>?h6&F34ft5g D B2b"Ƽ5b4[/kP\V&U1>kЫmd%wI"Kd2wI`@}sA0ܚR|=GoXƀImj5BGkȷ򍆚۫h(н>ɱOr:T_:~[K:yKK{d~GQ}zdY>D^=ʂvw PnM #kzjؘpb! !1Qyjd)Pxƣ7{oy99ni갱;ĖB46/-/-?aQBU}{Y^;GL@r#Ln5hBu*ᐮB6Y]mtpO+@:&BD:MR6>yIArħ E]{ۉv+=pmiꦁk[Z*67>Jj; sp׭NZŀl BmR =j,jˢn@6lŶ1!y7TNƫ6D@t0i  ƪ+Ʈk& (6euX 2w{ܴc}>关=fT]Bd0DvQIJ * Vaf0cfت&  gbPnBhZM*{lDHwevJvC*"3$uCNHV{d%ådGGzK(JЀ X:}&.toV $<[ML^B]3$!UcbV Fb 4ȅKūr l&clQ>i@ɻpR^Lȇ.ԑFP$BnN iRW&Mfbh5!1tEAhBCMqM/40bH Mk(]C:Jl͊u*A R5YVUk-BW苖0OH]E-$'떺ݲMKJb5JOZK=u^@a [,¦DS-JjT"qX\X^ h:zҠ zRZѵ1={NߜSsZ1FL]6.Uݨ1DN7TN{Ѽq]8['kaFZ4Eu϶4{j$6C< f~'+@"LZZMav"ꁁyTIVj{m0 1Újdx&KԾ Գ0,8#>,H$ EǼpY2{N"}έL=G\GdC,T|}Ii<_~þu{U,*ѦB-uRJ|%(/4TZ݀t=s=_)%4]%]ꞁXQ.Özhې|eiT]m=8hN(0RMi:I#ec)\ aBBB 3fplCwqAwS.%aG F,y1r:1g#Mѷ)z6%a&FkZ JE4THG:&3k; t5Q" 6DbCDfL&6=fӋf#6QH%.NWCw}KQԮII4M\1A0Lg䐩4a0*1x>R;dϺ>yEyiyii=}a? ?x^s(ʡ&ڈ[cE72zq]J2oUc# !ZG3Pa<|yyt3fgN9Oi%].#JGl4ƠMjâM:b$SdwP nncTr|r`SXЀmjh6&uN!.5W*4Xȩt׫VˣmtC}1+Oqw gT RB1n Kj>lH1w:6--o5D X9\?^C- gU=1y?M#o%=jeKXīr1e@zP\+AuX& "I'ZKKKDΟjݒhW&B5 u LZڦZ˒c{kVZP +B99mrvzLvm ߻:h c X:w<!0th(Ѐ[nN;I>Zg㌺PkruE(ְY %T6\-xd3 ;cUfBt';w\-\<̣.WzWl.V!FOhff4fkRH4s>7c<2:\ұWt%;jʎ1c7Ǽ==Iz>MѸ@PeʣW6F#w\j$Vjé $)_~3>о`fܹ;L!t;c+qT7nU34JpY#~jpE/`GϭoN#]vOS^$ \V]S2M)*eQ&Cߎ0x}ͳ7<^k'4K~|ʕ+ /ݧ\GlfcL,E[HSCZ[ 9n 4#ڼo?+迈eBЋyRv-OV{ KUTT E@VR:暎ZU!봇n3L:CfKf8G9:֚xƠ?g'2ܝSPk7/.$1kvS6EhK>5M33G^r`ѱtQi*{L]M`>4h:b=lѕN-˫cKҤ4/ri:mh09q쌎`l,~ųWXlrR\Z kjZjP A^64NCi7~53?gXf)j,F%#XL|z#3dyД֪DlҢ#Bt;HllY2PJt)l|ϥ\Q^t pKX5_ZE-tj]65jSZ4l3֧# yghDIjif#XNKRK T!ss={{iYq3=Bk 4:qd)FjSVlv!p{5q4Fci4K#kAUԹ@&$&2f˱w{GZnf*Se R8(D6i1vj|𵄁$vrhjRBє H02zhi 85ݦ{&@e&*0|°y1Wъ]i+VEeeYtX\5FkE{WT-ZBzkdp@+%^P6^ ([:Ss*ZvR+LmtQ #m}* ."ƤjM [–%D[@Z'|3< +m}>4 jh< IQK6*st.K c횑1a`:+"w;Թ&]VqfeѬM9!l5Z`ΐcuǝ9J9l b%p5rJ XXM )dI-jn ĖNNuOgKD)vXM&F=Zע6-j˦l-/+zC44 :iԹElm҄&E-ay:o&}0R1jR>Efq(]̠dxN47r#T8xIN0OU&%4IQ:XITT lKw4(5O,{eg]Q&iܐƒ&VMi=h0G ,12G\+V.=<ytGK7o8Pp3vri1#}K^6EV6E[wh+ v3{3ƽEf1-,)hD85G5^DH4%1JZIsєn_Q,]VKRu)Z`^ kc%qې&>onSrx?#6BpЋ)=9&|Mƴ}h{)Sn064AeCaH#D$qH7E\ko}z9; r20݌wsQB$' btk =JvT7d (`v y *ViKk%Fb4[h[ĠAۡ<.ܲGn\vLk9NVn#[wO+fClwFr)؈r7.d 6 2]IV1 {Q6R-&; E+"vX&@GRM'M&cA>Rj50ì1ݨЪ*ЪY3`NS!curc01@sA8:,#ƣ ;cLΔDK+zCv9%[/5B^泱flԄauYU}*Qn_/(͵<:xKnW7;)g߱/&wh17sUHү;M3ML{)awsLUb8ޛXu{^kSUt3A:MF?t [K ( &QƐU#i!بH:I9TO޻׺~rƆ~nMUXf]u%(+  Ѭ\t4+jʫ_n?/ZUtVdyAKpAh-0m(orUvj7V됗RU^GmDn(J %Z+9EYd :2)h]=c>(볟m$$MFT ( 3Ӝ:duDݙȕSdIRIMU)>[Ⱦ#}SNqc BZ$E@Q$HJu,UuvKþRQ[B8PNUH{fu`][GuD|{;[q[˨ 7U$]dv/yo*wG]msrã{mQyi :ۚRSg j̨sL%F5 #'4l(Ld AHHHZcirat(u9~9/E*j#BJD{cH0jً(IX0 w+D8~yϓR IDATvLsg(j3Ujl5S52 Su2UGK $H28#qu *dYUߢ3׫d53d+Qgs|A9W\t8_!*'\~9`h86y~dYPgv]'r`(aTu9yj7T{xjB?6HD\֤du8kdBXdB':IczSenJNV2ga1j)j[1]N.'rqjP,J֘v֞S;@L׫, .gO TlVǼP}ĻHRg.{\>yzb%u1&lOi1DV(Z}''\=oPDKE%YBȑ"Ca)g .}Mjkn[T'ldjިP(JF5W4#cڝw;xaH% 9WImiy\gZ2GjNfZ\ͺ :|;hU/./)ΨcCvC3U*PTł(4fn ~1a,"k>@TAcq.3!VHKeTB X>圚2pc,l-AIzK"prUnUdkzY/]4rv!6!v"PCD!VubM'V5~P6L{>GN~!\b kA1œSZc1P X|^^S<-|eA;P9'\- XxW^r|t5vLՄRPmEʷbV]ZC 2SIr S.PbRaa`ª Tָ=T ˃ o~V9 dF"LĩG4Npo/`![iׇ+1iMX)ۍ1fb*յɷ2&Ra)VyyZb0dRS13jΘ>F9Fa)bk!Tb'Fk !u$"81~} 25l87d,L^`rKcl48v%3|NpqՀ=VeWYU`\Pᑃ-" %wo%p 7/-~˿>w| ?ʲcya%Kk/O1vd*.ȫd,I(]ll֮('ѕÓۼz2B}3KOf\\qq'}*EI upO#<_ʐ.A\!x,}O˸f;N1wgkClIؖmMI*ˇ+iPDD!R Rv8xVKзc4-FkDdfV?TI`ҙxU$*徂x*1d@:3hF[V}Mɨsʜ>.b(g+>VEyp[sAJCDE\sYt]=Pga(Z$* JPPqju&T#^|Iw~FsVLf9}3*:YO'D~d&OhxC I|>M/Č6FP>_=|/U9dkS(.sQe&|fhJf8ID% V8\yʔ:&TlbI%]G,D*ɑ-A-ObkK4-J*ʜĂq 6a&:i3 qK$#ϪtTi0iL 'i̓9n~uuIv:b2ix'(*s%[< o1 L&sNĚ-"cƔGވ>s0d̗UApPHiTT U&qK%yNjj H*ZVsjJy~9^@LS4O|!R %KwO>cs"!HyƗ/gdn2rwdM$<\=xxAぢ"Usm49TwH :d Ut*2`O3z YˠtprъXp 7𯛷Lz=mk>SɟI>gM\˨Rowqxb,HDP$~mzus^>|[q n17'w1SkUX8HQ"P*@^ȧS6(h#YUYXv1Ż9x<$!e%*y"`P,wm6{7$F=%jijw=\y]DT)umJ)w3]3kyGOʕڈ{!T81968278V7(B \Ljkϑšá)/ӝ ٺ8e,M1 ]?@$K\,+´RYQCK\t[cޮQD*D iXcđKZ hv&zn8d딨g*N'W?&鋱HoeF3I &G[>{Х RvJ B Rԯ9 pӓ-Nk]^J7(6:gߔMuJu5Ϧ% #'c+tR匦zM:|B3Ќ'D$B#tbacJS2@+Sd!9^`8BHUK%-ʔ63r#IY=vM6E 1YD˥@dH=Z G٤ pKe@, BP$%M%[L٬ڛ⒑<}1%X<OCKZOxmy]߷'MMu֐k5ˇkH*P]AYHo31HiC]L 5&ԙK>)YN*C>\B Ƹ]oះ-ne~Ї>įp]>pzz֛;mW):]U!/]3%Ե1uo4Be8RqrѤp2Ww9yE4d0ӈiJ.};P_,6 T@JʖcC#k ιW\Θ&MD\t+6JDF3p* EFT)63f^ڄNr< \ 9X0 S:gE 41ueLCsl(ɫUbıMf༰]bCR rB)P#ͨ+BrJ0Bg!-sLа dRJG/5o7xC>#1uJ1S)g*Tcmm~RWPU]uTY9Z ^&..euJ>48MSX7kJDLM҉I:5I& jjmF6% bV]Rb:JŲt TEZK:^sCK $IbQ qY~ذ4 MYQ؝dogҰvifXfe%zJ[If6YX, .Rk]@.*YFDXeFhIFJEzٖ {nݵl4fS,-VR|%%&L1Ɣ:Yj',gVP܂%T,Y>Wz+͕f8RǤ,p%vg9j&IK(V#j:fh:TXZ($5tRS#1urEC%D]XU#zFE_]M 6a44P[9/YuNp U&Dùg;h5Z-[(]SԼ95epd \EXu`jxCZe})CGUJ*ňITGF*[@#*J$U4bz$R{BMB IR o딷u4j/;U&fݶhĂ3AtF[)mWVsD JQW/PDK;*Tc+D4nԼm\4CT%0S ?l%(|7nn. O}S擟$ԧ>ůʯ_߽Y>6IŰ}ꘆ?.: EGtisugq39o09m5(j GT J<*/Qt =!]NyRkr,8vmUθ~†qʮvH[b)9!SHXJBWGl8#ɱHi̫WM ޝ9;n5V씒aaaQ-"hi _i36sGT=Mش 6q$ HؤI\B(k'&:tk3ƐSC7Ϡl*pœ[usK4IL#dѩV]i cPEV%JV W>+ŕׂrN*gΗȵU}rm>HZ&+WΙ N7v8mF+lZB*umƗM =Pz1I Åsb~|Iv\X\C*`)f3 P]H*ᒮ}A׹aO1cVSL`)ӬUezJj2c}L7YFXk`MR 3ES22EO2BqкtFoB_Өi>7]Ѯi#ڳ1Ц$-br*=%k.xaAԲHQB2V2:5:a$<wy XMmmAV/15Xm..zX5jfD TR$"Q-2ik P̍ "5#"q%J>~`2V<emFJD ^˯sG<ޠ<0)UfY :AĆAikC5-uDq͚ y@D_ Ye4VYBA`3͐ NQ"ڧ,kcLJD*4ϙ YBp4bk/C'):cxte=B$l 'v^S® ,fQtM'YI]н n5 -nl6ETŶCl'^aTxo@+rfC>/~ x_~G~䭾7noҗ//a??{^9::ǯoxfYQ!}=44k#nOXN9{2&*YW}^#^B'_朊Pa5F>gj#Ch|厨HC< irǥ ٹk3n<+4)lfo ?N!Ҧ8q1JgmP .>U|R#|>޻T%nmsk%JgVy.{<^ܥQN nԍ9 ERyIgl, rn087L&yQ*,~9Vc RMA,T.\;̴:s =STDchUM\q;t_q)TP)$D$CA?U)U$v70m-A_&h2%IX$_Ib _W|x6m$z^MRKd ԼD7rL?(W\Yu<ߔ/=񫸳ݫ6NjW/ej†8aC)NhgCڋkڃ1k9b8Rzc N0ܔ( <r.33nszoFz^TXYdZr7&ԙ)5>ބ^V`)v`MS.(uP@j IDAT@b)}.q$G}~@$e[lmfmetkƨhY|YΈF9ahT%VR6CSsG-bK\8bI!Tz`,,RP a^!L+GoO+wջ|`7Ȫ:oUu<ĭ-it'Kby:c e"-,ȗ%(%+1j0P̄DZؤ +YKI`l$.EF/R٪T3'(x,~Id3)N4'5Aj [P%L2=,J%Q_Sӯwz3HOm Rة0uNA!4VtwCtT_ j 8iƸ1NS* oKϢ4cu<&- xߥ0ee谼}#6{tjWl68߾KF2B%۽oo!|?G=* 'U n eo}}??˿KWHy{?>Q%gy{G Ͼlz"/d/2T:D>0*Me&YQ(+9z@FoVT(lA:ӈjc5$Z#C1KH HEf.0Qj tC1}5BS2rR M Dz6BQ\͒Fi%cDt]EC+ epu n5Ʈ8^e4pL4 #Ѽqҥl"IIQ N4![h3ʸ>ӢܭP ag$m 28zD[kHj1'2W!6,CnaN<\K?(*bhxNf \hݳ2S%DJ0LSrfkYg .OԈ<+11f TIYjd$y1Ϫ\}ȥO[m.:lJ9:!N"ߚKZn2 -mve+B [Tr[%m&EYbEiPT/_ }n}vc<+gHu @ǬVصvMG *%k9j)Qrk%T]8o SA=<xU'݇0bf.b.jw9msXF\u\- kj֘6\d!F0O\X.5CsI)&Iq\gԉ^SՔ &ֈjsЫ Z#Cmg(ɗX~%X~2&6fxaz;5+DZ3l;rdFW# ̩Kƌ9ZJ:¯7MP}Nb`3l[X%^)9gC5U32%)]"yYeeY[g*$LcZPF%E*+!}=tdd!NBlIa,̀ZXp3,,%ѵFdjD*85(}q, ܨpj̽*);Y6Zrlp]z>я~y{z׻?O>ggHe|}GDVݳ|3|;w|C>qxx?K/PG?C }/yo$9;;,uS/~G//Moq>>c?co&i__SA??9I~~}sx}{oe#[şp}>xOO?;gG|KycAB-sOFl3ynSFBXy X$tNrSnpK"A1. +PpzV/حbvL"[(K \b ҚOl";]J$vD]PZ,o!-{u$ 1ʄ:5j1vLJH5aDu1V.SNIgkB{sJgk[YFVaZ9;q~IӤi6uYeubUexzMY!9j ˅R0Phk/AJ~Ah, [aikHC vCvC#,b^Xx!+ B'-WQ&j?sZ36S6zgl$gUA^]lr2: 7Iz/4r$#õ!,,׹2<П#T,[\k,sb ʉ6MnDA׺jO9n4<%R_9E:i3$Z{FUH"qqn7*tK:وe ׾׸(YS4$dK'C9;!`B[ ҃^L[L_L[# -\e;8ds~\ $E28\rp4! &:Ǖ M3%Z=Ch"Zp=NKI>5X*L .g}Z b6FT˱rmdN@u{FggHp%JC$ʈVeDYsǸS>')[(EI4&410+L+=3M}eY#~G{AaMzր5ePO tpkgح@E8ks#2ߠl(+\pY>'Q1 Q9Ped G*rPPoP8W@Ǩe[bmNHҙdj01 "Xc5]"B0.CdzIdzRT%j\(B:4=c{+g,RafDmjy:7~7_IӔ~8l6?_idY;~b_2rZz16. +̕@[ @ۖ۶le0H@i@a\v%32#3;(d~ңysN'2Sx==_FO}SO$'>?y{9* ??>~75/| 4ͯ{_ɏۿ|}}c]BUz~s-ȏG /B~~~|_?08>>Fx#^3wxxȯWS( ??o1g'kcubS KB,eSC;CvLkw~℠t&X4XPnXp"’ ڈ> t|$/}-*΂jkJ$IR5S>7M46uCN$ yARH&IeZ2SA$4Q UVTYk7 /Lni,nh?:X%3x1sإ͸9tiV,eⳔ=fia[? T:FQN?1nu&4 аMY.ъ ;Wmih}bbj$/(OH}pg+fY%+(20s6uJ%m^7-妾dXk2uD"X.Ӣh6O\s|EnsיkDKp. |i^҉'H@Qn, CM[Xsu$>aq̍軭Vt]圎2ͨKPv2rM&Q5B",i{;ܺʋ+g&Ijd؞pmzo}J9JbU58]FqofmX0,3i7/lG}:8@ $aT$/)OPOf9z@ Χ[|{&0ۯr٥̮&+9a&nK&r "%مFx0;n081ZȻ%N["(eS3 Q/ٮ߻z] LU5LU9Ӻ:J9; |ɞ8eW'NY^x ^8o^2I6og=/֝xnGzFnycY6\j=N3JM)SyRevgINfb( P#fP΁2"*_RHD3X%jhf0Qm%$M _uh4x?oo=U5>,㓟$o|_%>O=}_<˲ ׼??䳟7~7x[*O?iַJ~VkC~ל#Gf_JkBSH:L p JI)IBfhJT)VwHazj,1 ꠨9r\ /AH) 1^< {Y"DT WA4%Rl'ؒq5$|֩EI&Z:WTѱ)*nRWRwc.4L#$A Tµ\etKb$?BFȵf6\RCJM"uRbj%HffYI֒JL|f>؆Ae S#l42R 6sdF&iBD<1 ;XECj֚7ƖCJU %ȑ)I#<#ґMJqzb)Zy V]VGHKF#ԭ1[ZK A&,*R K|bh EQm;ZAi RO"*bt`JZɗ1fJ9!y&k&)42QfRP"EQ8Ȕ̮zC/"VmBK6.X>y=+PP4ͽ=یm TaJ$hq&T9^vAy• i30ŒJ .0D#H YQ/2MgUG-" -p*}E"P<Q^t^xע[GOi*̬:Ӹ:#2Qd =FK2$PU-IQ9i6]FH3)e Lp%L!SL ț , ]-KѢ]:@Y ȡ@K$[k3|iVG9,QI & @Wq{\rJGPK'̳ W([,ĜSSeJ<2;^e40޿[޿FhWs< =A5?\mggg<㯺??3OO>//aY|2U<||xx=z|qq#Gs~[Y",rabMcmeD^0tk@(5 v+&+kb )u2+ɝiXRmY_gIDCEU:ꐎ:hkC-G FZ $>.R]h~c5ClsMM0v>J~ vGUf*=8QLeR-vl,؝97̱*s&6b#R+$8fBS$/ؾ|AFR$ff,3 jýLkU K'$cABY(H er8571ZQSgU(b/:"HL#tT]ۺρz(%rC2$DP%JDT2,pӫμI bf1fK`˻`KRb 1uC!a1:ZǴ],=e7 " 7YXy¾ɮ}4C-l^eVW% 9e~^yJw9,d"&hv8GY y̾tB@d\㴺Gel}ZJTK8+mϐB PIYcү393!EO!L:lb%T#֚Z)T2Q6u!hVA]_S4v Y6Vhd>FK1z=eQ+, KB3c{;St7@Xe7C<YM#MT…B9TjkBӥ0tPRsGNwR;!XvmQ '9(٨|w}{y|w7^}_[[[Zx7_­CC#$R]ؖO8lm9")7}ZR(es.5țUv"4M\Q(K2bK%E4.(r#!DC6V^bb)%FfE_rvX.d9 99V%8d`u /6=jbN;%ZR4n{6'wI#4Ic |8+Âɋb_!L#{L#W5|gN3[ӻz}09wb95Bu2Ʇ;e^u_YU,ZLS_֡K8?e99`-H7a1.qz〈_cWUVCM6AmFlL&I6Ka[%L*sRIXQcFZ-&gmz#w9oo|cr-ˏ Kh3h@q/Ho>K@2”6}L9a;e_e%<&y~$.wYi`*1VA :pHu[͔-cȺwkS,"v3v3*yVl ?6\.L3ڂVgH3WsrnyJ{9d֙Xu&nF41M]FW ).MQ-&f3wIѢ%x~ǝ5_39N:l1{Vٍ T)JTehG9(# nk"JV Z!uc^|e=̩3I͑Y)ԂTYJw>gu\au*CiG^U9?0i4(hhÂLq !E*j9F/Yi)k=ΩI3d 2yc3[]6ىNzW`ۗT<|}TdI`OkLmxJ!6L]\Qd KZD-)UHu7M^ϩ]w (˱N6įhv4c2}jW:p%e IDAT8wy'P4ź*"%L~x׻ůύ7?}sx;G>(UZ͛7~}?C?{^}Y??k>Bw{~;{އ?ӯB>xk +9MFue㸍79{>n 6|.#") Š.ң M%@^ $#*BN*+d!-JSŵB׊۔ęcL#p܍ _(+&JBJN-t"g%jS{ΑCA8w-οpG ҅`p!A**/cle(Le`*L\nQUrJaTQ|_[ ol$K2DM)ɘjL]؛õ,sK22H#4r!!2b!Qq%ϛkqOpmJ`% Ed؄%ĩ*Q9\($APY<\P #)O])Ŗ¤.yA\P-)h[9ECʄ5Ǐ! P Rz2UoF;:ap?vr6&4$İ"L%f!*g>ͩ.VԺsRGP$zVcUU)+ !>|3駟~C._eַ~:_<{mcǞy򖷰^|g~g|2^uoo穧b^___w>{?|MG<~rr2ܡ8 ,rTPX,BqA f,w8/hV'4 d,bEZaWwqOeY/\&KuJ!Q"c᠐m7EzBTw\imż[d]JXۢώg#+IBY`bJoTNM+7O|@eTOQ̂'0dWT*YUcZ0$K0SY>f:-CMsyGe˨´\uįlihJZ"*gg4j27 +9mt/ьHՔsiT'!*և!ڀNs@ǽ@sSKe1%VR }#{IK,!lF %ϥl}_smo{o{^~_e}C_3kycww㫎}Yų>˳>533_M3 g{5x#^o\7d3UgB'.ũ|+,3@LiT\;8[Z7TY0W JEž4mVp#JQo7;sA{{d}T0P-JRtWgUԺVQ 8y㛇kk'\vLZTsFFcc!6oHПɎtR -0``"7H\aNsr Y!DŢK,O|HuuT.(-Ґ) ҐF6cGz7zi"̽N1U)c0y.m.Gw.q!w\Ν˔&BV ڕG^'Kj܀0ltXH>.hJcۗOٱh9{=Η==F 4TC2%2'?菧J9ls]C }r!]uj .: cdR4Un)6RK"9 -{ *j^:gG!\A>ʑN eBG\ۺEyy˴hab*cPv 5:"館n[ X>z nT$j8_l-Ixl"ne17[\!tj WY+\eHn1j)l<߳<# "Ӡon*pїX_~Ccv̬2kB=dowx#G7m3|;!JLB8BY0? E"#<]=<⿼e? @CD9و0[MmYī6gA.wB;NXK+\NeA䳠veH_A7/d*r4r4ӟl?1v5BǢ8h;FWf&XO-ʹJvL3 4HDDvcM#zo_}0 )5e,x| _Гzl Ҧ?[&^01֊zsLMvRC:3 _AkG}ۧW?q_Cʦņ)%?`X,.4ȄAX: #I9 i\RG%bH5" ]*  "klm2~`3. 4f=e;CXB}kPT Jy X<ȅh )M:갬W7U~lheXAA-ЍfeHrT9hatf1 hm85iun<'x3!&c$ŘRHUiJUQX\sMBR(P ab6Ov_ EǷ\*7?5C3$)'(]"9]\!6a+ PQ%vHe{JgpF[?Key޲ h*JU`K 0DH4 1 !2$5V̭:J&9j6e#)]4J@ %Gsd+G* ʺ weRC'  iu@4 oJ@33LδQgԫSj[Sj3bdmMhF'q5טV't2Ec-{r"%"r8vK*ü͢YE< [iF~C ђ*-WdAU@\"k}zeMA]G}v`ұA1PDR!5LXCWrPY)Q<Ә&ufii^gXvxQz#Z]h"P!TPk,h79Ccp1w)#emm#׊L :^9@)}J_qW:d(%Hh#:N1_[PQ`2jӰn (r٤A0q&ke䵸aAf0T':iS&$S0ӫ̴*3t>q%K&LVZ(tFT:kȹZ`%ƀ䁩Ŭ2ZO]MFr}FegFLEGcrU0rwSjzAƱ1|B|2ωM(,".O<)f*e$&RU<&QI`UH# Akd؍SKХ E*@$ЙOd3ԥL'4(i'({c/6ZB'^6 + "r,@J]wVx%:e\\ˈdH!QM2UP%$؊0C ћ!ΚBS` tLc׮ߠ{x]_!9(+Ҍ&crt"aIHX"Όm粸ML1*dhr5ߓ?#Gk +Xpg  fmD6ķoLnJSp ɰVuj&\_ƷL&cEVMM#j 0J$'G* W"u4"$&@لQF2N[dSIFJei{oYtW@68#X!P|Mz *T0R٠<|^~AɸɭUn6I$o$Գ{mÖwf1񗸝]Vy[ 3FÝpu{mns}kN5^]?uiE$I[%15晏Yd&4ҶԟGёE1( US9Bf!9]F7cNT9m%G' @iCb3יu&N2I:DG ed"5 E\#:68VH2B$IKismq+ w˜+[\]j\+\sEĩI$/#$ mt˜wTM}++!.y]팕f~Zc*ՙu I)sFݦ.MM?>.rl9إ?!raL8CZBflb%{f˻5#{Sos~ Zr;{0%͠p(e,Ld۠@,WUL' L'umBg\]\E2MYڷ[A)}z&*֜mw b`N [[z[JH4H|3v*mEXp'dB㸼IqqaIf&"iBA[!\8Kr!Hh ]P!KDkDgrt@+s woIswHѝ}+Fc!ͭ Jm"rZ Qc"ט*5 S %?Y%Y1ksgfeeV;-\!}cc Seɖ@1HEIu>vU2+3Z{b/Visp~O;Zo| _ OOOVũɩTnL}+RE^ȹ*:Z;9{sv VxzDk:Y 5.) z[#j;W1[1.Д O (cblrLBj@ÊNuŞ<|d!2* ׸5{9i蝯r>6B-hFs>GWsFNAFx::yQrPBu%H4 ٰqVj6z'Ԍr´BJ"}|51^-'ӌu¬0)^3lMH+Pzʣӿ!&L]N{l-.J^{5B^zvy$Ə_U9-oąM P WFl<Gߠ%ĥJXySu'M,Z @JTRRj82+(wXݠ+FnC?o}(2a*L6HJQzE($My kTy:ͅDa(9"8@ssg̝لnwmwx;>-e±˱M'9GDMdD5UXpX %;Wo󾫷xMC)ǪBAA뒸sbIʱ+j"Ee[+l-AWs!AXćWLV_tB6f)+ эiht1fcl IDATf9'b.JUŝ hWT'= ާDyRTn&>JC>ҐjT*vRz8vHkcJW^-G ۈq[:L==xgoN7zL.R<bLFϔp]9f:Y3DWr$ ɯ5qk\=,4&}ܲ =fգjMtM⮅Sq%U9w! KI(3$2IBh(J]pU/( A[( Nm LIa,jeFUJT?WSJ\ȱ@rl#6V溴oyV'J"FqCI"NZdBW{{CJSUPҵFj*m0OGs˺Om5g%]VJ: rF+gYi2MdA`U!x~U 1[94pJQ&0_ 6P͒f#6jپJ-N!JOUO\}.xAD/j x뒹*Uak1C$EMAtaf5Y#|B!Z |~P+ZrVM2ֺX+0Ì(Vg8J,L GY1llOe F>2UW>e:osئ\&r:LkCw"5-rG_&$EZ7r\W7,npE=i F`BTi49-cBc), *B*Y8z:u49gIjX43tgBX lf!G*RC"<\ eFSPf49J(BA4tɸlT']bD2a1l#uUg"\Lz@ X:KBԙM&f!v$Fhw3:+%: Mf -oBq]Zzk\{?ɑz#5Hu9621۠JBŦwc6nli_1F\jmfzi! ^soՔBSFK|aR. XHJY=`BKTO2)OT"K!)gqXcQf"H}*VXLM'477.hl,hId=􆉾ɗ'9zRߙwL69X 5ۘpSy̳[ &RiT%qlD%wx_ vx +21ˠUG1:iF6T*VLir)&V#`{; Z h[`3L03Hx0U䤎hc/CVHP upt̵rY$6in׎Pw B>aQt17IPBTIK`^Y*W:络d;S[KB%7G|BI%We U(p7n[$G&ѷ|$ R>0>+1cjfoVpB%o +Ay =\}J+9Vw=C* (`xO%.2r;>np8h> Z+DZ(V]ڞNz* NP*d eR҉gCF˝u'#4҅N>2YXúT[ޒa6@MK2aVyŝm>?2}һyDYۈ inOhmM(UE`6 5 &KwdF78.|bFcs96<ho*oMΜMIg-&+Y?;B *a(u`jXrף`k̈́Ym4P@ofZH:G7xxz4@IDIԙd#?cK?a;aKi)3e@=_R`7` 8O6`V{(ےZcVn(a]n<8_$o@y_dްxV(A(.p@(um-H[A9(Q `pJ"fP[EN pwwWO/"[[[skm\k\{iZTXIZC+d52TI*]IqihRR*ih\\).ã>` Ŋ8(7("&Etf#'*٥Ivc¢]ڟLJP3jƂ}Ii nV>0EE>2 !H+QQ8ZAQ!5/i{o4֥lKF |VWvwÆqN~ѿyA\0p.aV(Z*a1<*nMMYcy9-u\*K8-N\^l2谼hP HAXRJRSuZp:o29˨5٧&j2bǣ3\κdSЏ.A7WATgm0\̷oa4 p*LcԜ~#v;gнo_0(.Ѥn؝uORa-ջ JM&9Z?Gur"݋wSL'GJtMj&ZIخ `UȖ8:a1tԨ\A >o z3_l3|P㤿7Kه4H&=8hztKG QN`L6'=ޞe1=;V,'Pg4l7 Q+H] T1c-V$}y. gdXuDY VDlyB6!JȁxM1oҒk_΄uVb_@*D"PJʱ/in6a 678fۼ[20 Ԇ ;1ڔmgD8hmPՊ^4\a8131z :`R%¶W8U_g!]Zy+Wt)SԬ$sv(7(7<Vhiƴc ©3o4XDuv}J߸b-xeEJ2i\$я}1˲_ Ðy?qO('?ɯ_cB /a/|4B<k򯳀⋼K!w)MS~W~˿|zMqk\{7IKeVg5RTAU-PYM>H0ƱE-Y & EiZp'`u]f 0%QQb%z^5^XnnhcZ֘1*05/ѓArɽM_mT5C3ZFNiCH<`I-X2bv8^Eq[˞~mqE=rR p\zRTzc#B+XGFTdQfdvYumS礑N2b:,y} wqPW49uoR5\~p U/DA%j&Qb D׈2$C:21taSk.K|3]%XUa樍1Sw[y %5.c[11 >v &Kn((bIÞhJ(FSѱ&Gۏ+M϶G]KX5]fI6cv~[ &&e! Zꄞvf1P$4 . 5K"(q3^QĉK\%}A(' D]Ϸ@AF`]?e:ZBްN y-! EL%zGǹ+P_U>{ӟ4: Oo,_yשS/UU.׾7 :uNTU>5qx9g-$*}V KjjP<)Q/jf6p) t f5g /ؗapbmoUZUV%5eIiJakj(VUxJ&fLQ Q~M ,#i'x wS 2VUhaߍqvWI MVGZYHJj(aJM%LBcV6HK.S9 u&jW.K|l#,>Ű%0,:AR'):eR& P)fU+-ϑ[&H"l]_<.qO(;*usF2:A\֑*yvV`gB*+#kT:ۣxrM qE@dW;e8c:k0ۄYE/s#<u,g49[u}APz>VP.UԊʯ@Bt$N"2,sl5k孨3j9ڐ#(SsD+0 6sG܍UUEVTBIA]zUZ$\(\YIEdQ,c1gR 2 E*ڍ ~72 r.Q2/q M+TAHBc)|ԉ4 ljG \BL)TjDKbN pYB$jU Lq7i0QtMP2Z ,2L'h;9V/#ʂV2EsʂSBt%g[?6wPȉ&ӣ#M5hIZ-sM:+q,0IWq*P͒;F!r0;m=lVf^D׹b=g9bzng JJhj7_a)Z%Gjbz\\PW%*bk+ݺl IDATޔ9^%E\nq܄+x O|/| O}~뷞no}m|3aoo??_SRK/O_^7ߗ%^~evvvg?}_zO^x</~OO.w׸ gcU$( /%@!P2t%#9 ) ^Ld=fZCd,oxmb1ynqQ%YZXABѷ!â(1Ldqz&0;nba9FJYIߓ \lgG,"& ktR!Dǡ=HB,h.xs^ k5͡3@u%R*ꀥ#G\Z kIz نEd V., ?7BoW5'G@xHjj6aTÌu9ydNtw[̒&P ga  DD;D{9ўj!u([*nMV8 4CluP*&-s-&kswٴ1PV}Fa!}.glwQcfJ}W)\VǛVԘSVsnR)g 62>PJWXmfzIQ%9'1 ^k<ljE7Y04z&نMEں pq:b(F VS R*} {L HT]KhcG8U %=uH߹ q ޱob6Sʮňz Zx h\՘Vm&ͤ!n9xꂉ9 XV4vZ\^If$M$cuLۛbD$ uxE44&;fDo},:U ^9?&nćl4W ԩdSdB ͜ѴF[Liwh7ƴov`1R :".mF&ʊG'1jB?.hIV\[\=)P- _B8`tQu/,UpⱃtΈnc ̃EZK^HnI{ͽs6glg4K";Dcp\'Y`hM"u_HO먝v"n]LSĪNDLk rA* ೟, k!x|eE^ɯ|+|cW^!"ۤw쌻w~ײ_ₛ7o~uXnܸtX/666.//k9k\-wn!r[ *ȠBkgS@ɑBR:[/sg378RnpFz˦ascL=F\lig5^Mofx+KLSElM4 TBPvˈ T38+8-8+uZYK1ݵT4Cu[KUf9':W)c6K6!LII:ݘ=ii1F_dgArw:\:&Yl1MZ\+&OSX0ֺN[cZ)&h' Nē))VL-Sp{! &;%7Gt1`tHkD-b_hsN=N"2'Ƅܬ˭JV:`cW1QdE,-FUYJL:#1G]=^riY)[\>9[℁qΒ:3r" d"c*V j:L:rV;xv wr8#$I"V %F[ɯ-YoVݞ}4uwΎ.~b*T{5->>lai1cq#%cl<7-,B*Ī Q+ R bjPV:SmSIJ#m>~z?`7퍻|Db>k99 9t1qBsn Com3FZ<]qoK Y<^)F c t_rpr9.< nĻ Z>Vqj5[&54"D5T}jMhW p&H? |HX̟ZK9ژsn6q6/o5/!4.4S9]s$#l0{a2)i5'\<#7\j0T«eZe$*WypX4)ItӞ-|".S1ylWx%#q̆v+|w].DG:ߕ>W)S*P( Lu '>aT?7H=MZO\] DYb+7s)⒝ ʾ"8J$Z]DGBw'G=!>9{^{b( 5!)N9 @k BL2Op-.//y?ﶿ(0 0+_{*_7AUUυX~3 OO˿Kk_ڿ/*_+Wcglz\&?QJERP%4 65 HkѦ}EYg7 YbR=zm=ݛrzoF9;䥠M>TxZxޑIe`+`=|5`l>v(g͘Ve7cz%bIXP/EDXXETZD3ē Ih'h/ym2UE d@ R]-'6Ei89c*^K.6kTL2X^G49"QT2E"Q${ٝ~ˬM.KXDXA(iu_wHLbOsw $\Bżj23̛ RIb6WK-rnr,p3Zd>C^OQ:+A~AHCcUYԙ% fqAxi;/=P%o8 ΒcS z/&/vHKEL yj]l&Zd"h__~xwiZ<ﶿo~| _W_o׾g>677q]o̟ٟ?p_ꫯ/SU_W}'>K/ʯ{a/я~_׾5!ɏ;??泟s/~=p+\_ 83jm'm 7:*e[!6TP!/*r$+hLUI v}J˞ҩMe?aRy]'LN#b d9`8']`6BzȲ^7 R]Qr{x6; ga+%x6 sTr)0! 򦊦8V0?c3he32dx?vxtxl(NaMO1]I06O/ /)Qp}6֎ya>k 1W|PYPЬJPՔL($F* |aqY7L[Fs:%dL'bN &SS^r8wiISDO1!i:),9M3ϙ\UYf{2\0OF' Sj3cz3B ߰9N1T)gJB b-Jz1Ls 8 \Z} C2&7yXXycxU";` z'lb1ZR͐撢y..GL %z#bx.hrB$챍G “P T9Q5mDZñ"!/X749&s◡bT&UGUZ«3/]Q,7YWJ4rYa49bwyM?[#%9 *1:5=u1 :S4hrxIijr =F*DY &TB,&6:ڳsrE,PITYT&rY'$@$ 0Jb3 AQ *.=L9nt K^3+OQ E(jlOk;wȮ:gRЗ i3Rw7rL*uS^P;%:ilȻ;M X)qh=qQQjk2g:Eʜ QlHߠhs U* O}O}Ssh}䓟{}lY7$I|+_ٹUU׿׿۶X/}K?//=>og>?c2 o~||W_p-rh-]6qHC`gMM8`9/5j<#\d=RdAt)h8 ^pڷՎMFlFN)ιT+6."N/`ÅZ\B09\5Ti-%G;ZNxJ+ E"2oC<:>zqw2f+"VFc}cnc>P!ULҔLiEY5Zg,pIs,T("P,5þD2 2M#kE[VllU8U,"˸ǔ6Krlt E%SXqȆwH*iL*&9qn].EKeQ6S<= sۘA 7]D dDnsf xz2&STL%'5})q#̂&>sA?  މ_C"^?b  !QuV{$Q $D%;!%IW&D(|ɶLi2-f49a,(<q$)1܌6Xj8+/$: b˒&ӕΩKs,BT2`E"L<_"5RW滄\AR!0XEfgMܿ˽S:3S6ֽU#;Na58wz=,V:PQ+9b;G/4o^" %^&/|~iʫ//t+\ KoBEHP٨Y%HJUK4PlMYMUd arD׻u4c!\V#rҦv9WĪb2,b.P(Jz?BjDlĥARĥA^ԄS,%C+*GH `1#LّJn k]scx #55L-΃!zPW4Vr86x0a IDAT-MpiSr!s€y \c.5GhiahG: asm2M8z(NVODSSRSe48,FYFFfhL6y$>[V>(c*Irf5'-.b1ae!GʊE "a3>&,l EFZƔM24;(IN(&Cfe>eLiS\$ B"-$-J[,J9/$becRc!ה]jީPIEBxF~#yJbA(䎲j *gʀKLiT)1a>" ΔFma`@C B2::SpQMJiKADFԗ39}ZT#)X(7 McRψdoVc1q̦-VLȔNPVeUYTX.)5cvB" Ox:SeIa tSD2( 7 %ݜ2r'cF e)G AT&K4L_eDI 8Ylhy<.iMðc&<ȫ<)c}e:߲B΂)]v]{D)ijVBsdm Y wKDP %% $X*H` 9 "w&DATMP [i)PU[hפ\]w eC/+WÍ7sa)p+%~*~Ms% z c6t15ǭ![# S0e K0e&ٹŐҔX ]Lop*Ɠ!b@ZpJR3wͣ_NBK}:{m/`(XBBS"Bd@3ѥMJE]#l9HtJRB+2`jݭQy$s;Ӥ4m3MۄVvV\D.a4R>TB!_%݋tflw2tOi3|5Oh,X!igSV)LkMn4TN>[ע}}(!M5A=c#}PTPEN+]): AdU;/qAHw4S3u|&:^%.^y\А|v!U:(&*Y n)(;)!*A:I/ C<Ȗ*e)0刡8^9\z\λF^V^И./Oi/L[LGM0[hJbdN pӶ-nxFa.BM YEبdجWWxIku> sB$蘄=P MΥb̶v|3 KgܱEwC6]2W!+2.j 5|O]Iyd5\ϰ$/IWVBcX4g%5Mki5Vof'ljrP9E2I/K(bI"4=J4Y%04&4uma:ўNH.U'fT%!Zu}Z툛cnY \cc.Ada]^=SS]C (/d.68FJ$GՃLÖ1n1 z/z{*RPtt ת}6c՘@ _1 $DSQk Mi†Gf(y#G~!G"d6VY*CYP&vvaAkԜ%.-kbdWo5\*/W'}s)I9p+=2d3ƒ7x4"U)&T2Y%rY%x`ajՒZoI{/vC+ƴ:cj,[.'d6l\yt$JGI^?Bj#K0SH$Q='~IyUѪ%&=L9K'CM&CBE*KB*KT9EoEG_ 4#!uΌ.3 69,->Nhv+g$XǙ:ı}fԇr)S-$B&tg~G)J-E)>](N[;*'>o6z0HceU!!S !S-hfl>⃭f8ţϷ;$SgszEt%Z-10W̭&3m2Qˠ)b^(ﭢV XZ?%B>I+u;2 ]lKJraD6&yQ1 se&']OFX>va[5=8;H0 JjHNhm^/_* VpWzY|P5Őh ) yx,r1:3μrA3eā)#uH3SnĠymp8V8VG\ҡRW3lixhpm%r!e&SNeL50zz3ҋ2Q} # 2t2dT0(/(SyUI 81:GitWE2 f3iS4U1/dJa4 MyJ]SgI42{r'wIy"ku 1ece(4k1Vt截@R aߥZg>n_sǺmGgٽIg:"AV8K:\.XK*~Jy)f2 w)[씵Qv sAϫJ Msu3CKR$#:33wY;Ii"UWLz#ZMK-sVr3)^,i قf@2~+\ W?}K|jŴlq-BFT0N2fcrIj QRB(AːAYHET HqA%$Dg qQUYPU*P 𩱬\",l5m.\ ɡV"j%CT=C%:fJI# &8u0IP]K՘\ȔBzjRH!$ejBg y<+iS0ՐrIK\bJ܂CP uNu {j*4uXG3I#Z ,%Ci#1929qvFd$1͑Z$D&KTT'N LB)r2MIIMBn~C;Ez9b|BĹAE+g;3#Wb8 lFTf|ʎc=Ŝֳ9H#e`1RC04|Z x]*2]E(2J%!RU V9B85rrKn.hs 3ƶ|L犺&5Bj8URU] W޷߮>'9[zD#,X]X&Ԉ&&&PH*P3s pl!B.,=Z0CZDAQxCɸh#|{/ub^NAlI&[2F䩂_9H%D#v->Δ~w̨q&'U5)#W5fTisXu]c- ,L01KTxAANW#Li63d$ \"e]13XPZXX]#lMehr1#F1# @L)`^r7e])!˲ҩh~u Ulr^ EgwIUE-zRVT!ˠ*p*J-Z唵#c,b#P |^ET?E]V#M!r+g +*YcD9MG.Z R Tm2]c&Z+T@ Zژ^휙\Rd.tY]299֋!!FkA/?yL$P*H+:bf P~7 M&,/\vϯvz7`R<)YY !)C6񄗳-mm-zERg4 ,Q)FU֪1:љ&஭9u-ҥdXP^ CM۵tjSn֞b!8:IK )B1BM$xQrpmir6<—-|$&8RHM +K>x&E( g 1ⳭRT ҲuqX3rNXsՎg\}έk]iEZ' *9\]UYQ p _`R,*UpdŔ.>z9Mqq>_/1/V?xHȄDjqJiՠ%u'k23k.Q2*Q9gQ!si=6k$:zDS9ֈaj&6//$: Ol\(d##NG PUЍ;cCrL۝ЬOWʐtEg6fmRC'LaP\FyAԯSm*0*}@"?w]mAW+"=֪\gK;`i68}Npmz`|̷x>}a!Q2=ꤲJYPw渵vX1X*6qarx;[#Fr_)qaR90Q;ڍHq2~MArRj(68// %А)pX $Bg),'PXHW_p\ W[7M[={*TT˱E)T01YDuG.lYT *ft쌞Grcn3yE9,h'\?dsm6E&#I$H:~UcBP)&*c=0p"5N( y%:#d*C"+0BTf1eoS#2"yf2e<{~ŃēG`,dlS-1.2Ɩ@–,²mYlpnSEUQԩ39##2=OppԽݾ4>{ȵر4-T U(Z(ڢI|-L%,ϰ5J1C a"j(IN1Iz鮅|[3 ҬtGT&SVG,'bZ$$9(@8B1͈QXb!qɬ|r22Vq5b>As±MTB&G6R@ ͂cc^9~yceQ}A$Q 9;+QFX=bsUkoXD OA5 kNڧU/G@:UOu m_pFI9_b#/3+L c¸ eiNEsCľαW} 98c{pV2RQ*,UN\(i夑J)mpҫx )3}A?rs~iRYDrK cIR [%V'؇1΍!R r$! *H:^ePmTVnFm8z86>fȽ@JdPd2I$6,P =ޔ1d*a ]K1K1cVb@%v 3k2Jd I/0+O>ЙN g63ʙeWYg-gD1 EM@7*ŔNqtn|[ǔ#D0Kd4&:i'vmLsrU 2e8we $q~'~|4o}Mqw| bO"U =ꌩfTK3j֔x+9En/rFZX2wiIvcweQQ{.D% U8Y_%&"en3jU\"ɯ̮KFL iY'͂(U&AifK)K˧,> H[9+kx 4Ƃe1G)(3YfuUN4YE[抇'HHHXNڥVY,1eN!L**x拈g YM`[Wm cҞhLFw9.%.OQp;bJ{uيvHɟ1*|W#4-rK5FYQZcՉd)"^Ný8܌i,}RA*4* xeOh}VˇHv5GHrNͦLUmnzu Q0՘N4 l6~'6..q2db:!a08*:]zVg׈mjkL=cVC|B2 eYiGScit",fy#4 ["$NW-M 5gkfA NxxVo'hrđXA%8x3)-IdP9Α(ǝz,M(fuH3Xy(] hRF!@UR$P$ MAH2B0 d |L)iC:ab IDAT1G%$>G|B+\p\Z&3e2Uʔge*ԩ2k K F:RU(^H@N L'HrTG0PsŲiS 0m{qNmX(H>[3F3ъJᑈ>y2Hi-gnqح.2ũ2-v.uV;b99e%&˜anf ƹ%j(r05؈N6ADDy ?+;LELhc, sZ@nT bI`,"&'.H0jɔ*S*L|'Gsw{hqqO&?Tj@} {lhVF.#];eΒôP4M2hdܪqv)[LB  6qы5#^Pm⊊"p+)J@gv`2=0T[1 1e8 ##MXuW/zxk6:ll$(iN9[?[TX䫌:3l^a:}@Er{Y Pd}6{lب"孥E )T)C+243H1v먶 nzΧlp~hgП,o0[)1_u5J*Ό=,( ȫUyLK`iFb](nYAI/_{NٜRsGe$%)Nu;YIwJMQri0)FyJxrĞPj9-i@W;A33 ;ƨce})kn8 \,q+|^e($Lr[!r n[%%M sw.[cOrJjNY~!ս)=}zE,=x/bm(ĩ+m筳m0*qFX"ܕ9wqhۧĒB+pAXAʡY@v2m9^G@Ccc!`:~RI)Rd,) !KB^(B& "D. 5V#eę2٩Nj7\3w۬pJv@jhM^=b}; J"y ᧈRN 2ORP"Tbϼז3O5ܜ.㤎If&y-o HiJji*QϦʜ.}aRH* םֶ-p 6XqL1S.iXbG2SS([=^㊵Pr{o,8 NiaUX*zіOi)}#6,U`A)3V# 態WH|e7WNr@ *ɢ,$ PR "ӈ'6T)钦*]7_ݽeqx'v$GGG\p]^?q^WÛf4MQON@/2C6!<\{ "* ҠK//"~'.祗Dc͑#DRB`jE6SgԖԔ)v9XP"$_1VcO&vY_JsOFȦ-a%!5G|*ϷZ%,T?&&#,/HKľIpN|d"$qG¬+s3 qWg aw.saKaV,\rHѕdђ0ԫ.',sFbƅ<2*}0_S2`^0(}4ŀԧŀboɾ~X',CWrxVzEN%x$CFOkf{%XRDAR,yNX9fkGveo59*w9l,sY#HьWy q# 3)H%u+1F Q4wN̕G 2 If>K7ٔv'eQI\cU0 Ȗ4!ڄF}H$N0EА") 0 ȑ\PeJ@E~RP%mQ:Q}΂n2YVGdkyC"s$ U&I(@KLLD9'D%R,Өj:S"{!hHhHe8A,4>sQE*(r"(x@Z%Gh ("k$uҧ)LNYҜS[`)Pf!KcX!!Ϣ =: K5JP8UN6<,"6= "mꀺ9$-TNYBd4ICVa-y(K2)!POYxP}F*%rJ',N(3$UV0uά:jvx>J({spμp6sDRo yuDt"NK|mvZ#!{0E#jшxD:m8ȠH9 #Cp -DD^eG"J HD\&]dsRq޺I8F2F#ErZ!v9rER24 `9EK͗U\6L -ug9t622IdB$4@QR|\#KTF~ѤhZ' -ed\qKm"ӤhȨPkLp)&6Bu) AnXR)3QOaLc.o-a}!؏;L~8 Fa+W8n(3\mQs G }@#[JfPii^%)r`To0$FW-操UI26H"Q@|>2G3ַۿ}|h裏w|#=cν{˖eoU?O/~(?}|3OC}[󬭭}e{˯ykx'^x'_CZ?u=A@AJ E%t2M'teZ#ob{6n!l aJ$" MB$T,b42#9_:R@^yMv1˵V8F#E%E#C%%l<|3Cq NåK; &#FbkKKhK5rn9>U]eEzC_,q.K:ԋmO=9N͝bP =ke)ݲȫ*Ջ3kY* )cbRiDDE#a@,3WPH.sR38i@ 1ި0nf H.e!L -3b fJU=ev{R|q9(qe6МNk%K0f)`k>T,a7Pe26ٞݡe2[a^/1YT4FzFɘ&eѫvkC6ΐzF 1h2Ʉor>E-Mf*f]COGZ1dT m턹p`6\X,qd{Ld{Ǖ?7sq pf,ƌSԬ@eL'9"Tє5Su2p3Q h-X X f3pBݍiVN1Eeѣ[&7 _ 9ҙ?8̙ĕg-N&E&)HO>${Xje`ͻ j0 RGI ?(<VNq*/?oXS@Tv:& ϪϚO:EJМ}5!* ˜t9v5Ґ[mnNss<]j[)]֧6-m,(r$/| ӟ4/^|}Cض-eYv%O>^%kss%qʕk-};w^rv_;S{8}}ǿaᗲY ?HPH$T-!d+#._e~_Bh*Q2*S:ȫ*kȫZi X: R )+S9e=XOdn\DAX76#fIN U#S5$V,b"EOjaRJ/.;w-5pad7MFQ+wh\9RW0ceKpT": $6绸zmn,L0#J0& f?'dmLdLVq ctE9DcĺYYz<,=s<mY':ىF~[Y tZ=~y=z&P (eĆpJb)iY{lZ{ȦE V%$h6W ASuRg-4͎87C s%G)JXD! uin08k KvM^b:fcx7]\cuȕ:PIUxuI{Sk89 789 P%Bm4I`JSQ!EQ "K cڢJB!Tg(UɅ,1*T)^Uz+5^?4sBjJ>Oǘ)ffR<ȌQTDM" Np+|9!^H)ւl7"^䊸Ƌ^dP)T*c6brK-.7%`N928Vh-PSH|S ):)vݧ=ŕ=L%BS$C@j*VaB(/>E!3ü>Qxi 6A^M2!  D[R><>ReX+!V0UUN.dR^sͫ6ak×~grF.]xUѸ<ȘٲBЄPg'yky׾~؏r(/--/9Ϭ.;;;R~ܹs[F߷ApO×5:K}}ǷS0MR;g5`2gd5qa0E]aFvKMɤvH]0])F;cxAXqԡڜSCjrFY-D*SdV4_2DKıFđFNh䒌lDn*dJL*I; &wsṣ́=zK\3ɚ*4@q2挮}RM.1j!kfq6o Xvm؎$oibbd!F`wΫL^9N]5Ifk(5W4HnB)'#:FBm`g:aQ-[K laЕ7s֢}^B6KʀPKH* HXX>>}u@iܹs|B3b77??`cck׮O|߲__WW><Yc??Ff^Vx|u?0y[x>{Yԫ$e"KK9 Vֶ$mL4Q=pOn'6c͐MsBPPF4#F-FAqbjȺ랲%b;Mg|B`جq,wI}4ЙqiRaWg*D"HVn!eS))5iL#`SW IDATe G FMQ($!tCrK5Nkm$ ]{ z^iM*44M878L Ci{V-zNwMl*6>`y蘆80iV[U]"LF,IK $hC$[¬GQ(lLUI YYӏYuYYX>>9a)_,j. X4$̡_8]ZP( f2%V%n3$lꌦ2d8,M1∶?E'cZ'j%Z0ɪڛqαnRJ=6]w”9mr8ȩ11 ٿϪ(ĸ1ic 5 7i{CMe\aOJ N.i@䒂/9#$Tr 4DJH]=#ȫDɮQPh,DP@ ,34u*ؤ=VQ\y)μOJEϭ,'[FL*F,L5D(1~E7Z"V N|s|Ά8bEaV`)^~d QQƼxř&{G#mJP*STUK#։Sд1#VobRf)eyOjv_Mf |åw%]H@Wuu 9Ÿ8CkSf)VȤ2iVL+qG90Qʈ2.0"W4 P)ekrD4jcغF sC%)i1}($7"^Ry'£>OO6>O7u2g>{7~5y \|w߶=mo㡇B=<~g~%0oy_yL^>я7n;>O;oo++c=oaCBR.e< nq:tWiJ"0mu2w[e1=͕݅!FkDɜAkgeDq{\d[mnʼneG$mM4&6B y@r^8o "9~Ui-|LşArhg=L"äZѦ.Mh(CC=dXstFm}~/Q =4rvNѪ)S*ܒ/}<=e(ϓ2a8mr6/<_+ ""-b0"8OhJ}Sj P %qCcSƄɝ \abT jecNE[6尴ΰڤ4ؘӼj4>V`[Hd@wYK,ғ s4FiTNIPZ4bbPk|sMx5 -N/3ZnuA"lat(gugsC %ՌaDo .cc3m)kzC6dmAƴMuM~_R~??//}ز,?C}$Io0TU+_ _W~Ա^}K_e/sx _ǏQ0 /Я}~>O+)'h% $l2L,)'ִ@*2`%asYNv5v PUWA!-nK9iS Ez\dEɖҢA@BRY  rQ#9d2u(h2BЄlPvb3dS fHH0DAF/[!mkvw3In+,6}EGlE֌Y1gU{Km>NB9'-egQ6%uj.̀E6eR U#S\U(uog[IUe*C .Sʈ]! @ /9q=у-(@I3R|\lY}#u$8R\G-oUg걒܉#qb&GRZ] + "7JLS5.)1W1Z$>IfR-dJM!-u6S2"Krr٠%ZU!=u@[2RgZf(^I@)JI%3*Vi2b+Ђ -r,HDBi}lJb)f)f( RSӔ6+cM}, `ϦL% ҥMѐq45u1A.*B'm,aWl.dR-[0k`Җz1P bCX'ǠA%mizi'A$M MK٪rŌO͗Xjq<¨2w-EݐO z%N^[×L[FQ;㰝rNt&Dyd **)Д+wFFR伦Z0udGGU JC)R -U6.A6.!W R % :gƴ9C-͆XU6XzLUkEX{dUNmTH ,TH___)/~ܿ!=|" ?p!%Q:@NbS#žCu .A%eRhdVCF.z4dJTzdRrni rWv>RXjKv)[5`4h 4A Ye#4LҬQ0v" AN/+-c#F(eWv:"+5(PYJKȄLF~L- .9a H* r=Y18\@&J[zҖv8W pI劭[&gl&)} b)C+ˬ>GT;NKIJuىJR uPߪh1z7尻Ĺ6R.eV^o_~qsȫ-6b 9ϸ)OIsp- K}A-Jn}|B99i*:8f /FFi ĊS !Ԛ5vQ$l}D.E%5H NNz^8dZUŤ䨸e0c!b^!T!rαvz?K:bMqv1^oݗ݋o+PI pc.)$w` g]_"B(5PHbmtiFd$LcoapD1i}_& &-ӖQImr yF JNk -Ar.cZU+PHx{Q: swVNBE %OW }R(.)vf}FϾ憎BhMDE}nE/rWy_VBlٛ voc(~<6*uP/7*fӶL[[o8E&jB 9DRD @Jz+Ƃhm)]P6ۊ}fav4\3iTժG-ϕGP{L;[&억avYe-uYS'Y\w':@sʩN1)vG<|Yzʼnw7uIm"sF(GSyR"Üqc<#]P$n #qxF"Xp|3,##l=BfS;fSfwЇPdjUƔ2\'Z՜6t-OԊۆ8Y LCR[b.G\:g\PMh*&4NJĬBR[~5X0c)–"l)+v++.Wk@Q NZHZ{ǘ<E+/9:GWt~WHdJ.Bj%,RmKRZ(TB*6p7&lTh$ o+IT/,Q [% &4m q L?zpĥM̸8;q~NPvTBa|@:?0qKъc35?{k^;giRa(^E"[DC,;DF$Xm؄]ltm"wb'"}EV*4@3AAqaP:Rke0x澦koХM* ɖNA'ZE`ţ7<^1dMxuxfj/Q{ՖK o JYv֩K+opI1ڜ(Jٕ]ɈݫUD}UR'űFq2f<(~,G%7޿c/-Wx-~V?f3:R[цf>Cx!z"mbVh}BYyur,ib+,YP}[٪B ̤bX}Or5ҮAJ,;-@E l-t K=i^(KH/t!5ʧnjr%P InG ҠA}_2\O !i`qAh@*QaQP*Kiʴ6xy(S\}n#^rcU1-(W/oTF5(??]=۱:ρ eQEq[MN61Im(%h: ka $:bS#\+±"\-)"VUy;b#j[F( e\jO6 Q4DS&Y|{W[;u]{I{!*j&̻vEzx|b_LE֚.)eQ*UGEXˍİUDK;!Ia39~|œ轵fޒfPA:]-=Q%e8oqɌã[FGSvuHs`xR]ҳ6q7o;Ĺ.6CHƎ?grhI@g)q&~Pud:O8V2(*[CAKA46>jZ ƽ[r]Dzn"G3sn$f-q1Z\c9 P6 `JRSJ*R.EbuBoFF IDATmbfJԒ6lH51XMz@L_r|~|CX(C|K/p۰cn1kSKI:6XGFU;J+3d4UeZCeZ_FSt#CS24)!%!.!7Eu@PI\9Rkg3:hwşljgD>V5тނрR.h-cYPsT[l8ʦ)G;I(rR(| OMIi`glkǦ#4BA-i$TJ|D,l4RU0 Gz:ى7|¯6AfSOj[jMFUʏc2Xg!eUZI4ɯM&'< $!u E6$U`O݋h"ڐi&2!D˳.c&9$Ml.zQm΁7w U .SZI:׌9f_|emhz0CݔFD^ʼntz!2[ Y>ztVb:3߳O2>.gn*v{$B<,+]e%]0t@RAՍ-AJVH0{/f]: [qtrKs\IS*HJJw.G 2:O>7 |$#T9!'G)GєiĹ H^݋?Y4xzě%'o8 svKn4ۮ1EBI.4ZLҏepן%r` b~ ь5w]axDF"Ó y+rn1e2Yn"z( %X!d߹yz#Ӊ[N >3D'ѡItbuc̭sD8[6h;h7h;eb9Ip~qoHtzZkm93֜(%=-1}U/*n܎F!o6Oy={ƫs^5յl]۳1o\r]+?*e}-O?bq'|{|:w/ۼgXk]"A ߦ<fIlaUk;yLd8\J8"òCl#RCl+,?es:`WIR;l>Vb3gOѴEP1Ҧk,)AD:++Wmf[UPi2gYj\ϕuy ξW& ,1ԌJUX]bLrtBR3g%B:h$r 1fKʌFQ0I00I1Xgz/,f!p|1fv}HG."p{T)L(ˊxO??;|ӜO᧘#Cte]Xo/;F9n'`.WYҷ/% < .x\wO ѰVzПS9j7XP#͜>xq{}D贊{1xb~ĉzMpv~B8\7'.7)Yuto?rz|ZxJ(L峠?*)AĉiVbv%%rzK'rIf;ꇜW5漠2\J).m6n.]UqA/b ^b6r[S2ic+'Yax9RXa nqOC0ĵC,%nbvioWLTIxQ8cC&eLe*!ňMۡ2 tgR!cC@p'Mx)RĹ[uL°㰺Wp*H}0r =GjI& e5|A5e2oe߰j,t9jp6g2=g839 g9f&s˃g|źp - ,8`K}nȢEARZR$Mj[ 3K(s,NxsTyPN{mv \(]ѽ6hIxK~DA3[gDۅ@ \3F4U+X<`y1mN iɉ}ɱ}ʼnvԴLyLGu(a䣨8!` &C-/XeU mݜAM$BdJC"%(}'H}'l",$u RTQAV=X|k$A3 sbX=Gcв/kĪI,BeR ߭6-W5C{.9}Tlʠxc JQ_y)9 sţ,E 8=R=92=eICuڅ!E'*sMNu~ltsSe2? :-Si~':wOJwtd>DA+ ;n{'5sedeXjq$dT,3g.ja`-l0f%fogH F>o?P2hA/l:-RAtZj]&kLfKU^gMڤ:F 5z5OG#>]COwO*}75Gof<}}Ov D-u 'X]>~bΙt qD8C"٤kk:}(9C>['H&]`Ahz}VR:߆tf!u@HԙLԙv3,}<(jd8j&rjY%PZJqpW#^@䞵?O#K$RsL%Pr %D{$WxY*=3^(O dX2Hsz'qW Mퟆ.GK3?L8֜gzvV(&X$co6[:͆1Sox$HzTĆcSby/~xԞW4=㬹y{Y -B#.Oxuiϩs9'ǝ+)j\K8I5TF1rjjUAkBenF̸A t@*ZmzS!h)}1Uv暳+snCn117rWqN :M$+v2*^m[Vcy{@ #8;[FocY0f!t=P ) i4|w+SCgK&5\ 0O]M:c+F;F;}rr_ +V<3BwQhdz>;<_-PF:CVilya6¦׈4w|_~|_{??3 _+ʲg~g?HӔ__//q]__K_߳k~7??&"/|k_uzeYٟUU[[X.@E<GNi🞳i<ؼ\_hꪮ3<9g<Y}{~RD;Nk-UCI*)cbI# Hs *QQ(k:d@ 0?ퟲ3Uvǹhv<$$Bxɢ 9g#=Yx8ąA5aS,4B-Lqf>٩F:Ԩcj搚9f YGtn1G3+ƣI5*r MBlR&Ũ$VZJ+ "K9"-+P,dD")ydfY@%F ۓ}$@Z,ƪ!X;C`@aʔK:I )t>ue$e,4W8λ$E;x&1v:L%t[+9IVʃ}wD#i }Ј2?Q XK H>jb>z#+fkJcN&a!i9%yx|bPfҜF1d8aOIPN0e*Wa,C$$,VH aND9b@̴S У}S˦lGhd3jiB&dt9VT mL Xpw8:; F-aWV^7oefcT%{GHKCB3,v1g<v2}"(1WRgYh< (Cp3&%T.PCpRJ T@2L]"tY.'t7I5\KP14&)zz&8,ЉJ)6& )=oeBː T!JuTd*SMlЯ1P.}}o^я~ᵯ}-|#W??WWqSO=O<__[[s7/;>/3P._wؿgqv}s=GQ O=)T/}K|+_h|Gcz{)Eyg[kr/`_7Sk2tBπX!Ik!zbVM+$h z-Ž|#C%A"ajnfi V`!Dd {L';qNs鳾<]!ԕueDYY 4MдUFZB0Ɇ*-,+d:.l*tRLRQXlŲf30+wcS0 GJ+!r: b "̽k/Klexʒ3VP-P e|4@84Sm5T1 (ddxv҈Uq(G_Tf3I=R M+)b\ =Z/=hL}4m;>Ҝ>38Gw}VV;*bG2\@bF<.slpmrm5!PB3F_ZcA) )Wo5֎X?81@$I/uKi< :$P@QˑCV6*ĝy5ȪCɞ| yys]4%K}D2*m.07Ct$)HV*̤*}Gr$6>?2G(n PkG\7YY.Kez\f:r.3,d6"V>oET)vqBEb#nu>%rqد4ZS:怚"`w9v;xCBvQA0P)bXe'UWȝӋp%BMM0DBtܦ7^cvnȢ@.\ʭ)ruBYbef!,\/1\%Ӹ~M!i` yQiV@5g11c ?_' ԧO<~?mo{?M>/|(G?O~}slll~{[ O|gss[~yE>w2??i6|c3aaÔI0RVI] IpI_uEq ]Zpהnq(%KQlUK>oHjZK7#GU,HPAĠJ```WV^X8q#0˪ƛ5lf@d IDATqNͦ8`-y@0pW%=qq8iowBD#G4sD3iITg9)LtIHe٥tyAKu G(/YLUycyt{3Jv+ RNCb}ʃ9QHMеϴ( k3w+~&אcB6G<>FئFc1ڮ2ޮ*VS&i7y!xkCǞ4Fc$)Gs$)T.-91ivBͨ#CbWK蚄ޑH Pd,5M'6z{{{2~1_pxy56u8Ε[/pӻJ2R$gRW(K+ܳt3NXO8ߦPs;SjXQ;y۷.qt)uhY4nE, N0;!vXb~+ :@CѲ s#ZcKsl-z8xd_%9PHTӂP1t2ȻTDV ]2#FJ ȡ1,CӤG,8a  d{ OcxՕQz <WlKE3y9[^&vvv^v#xk'''\p};wz\)nenL^e38Y᧕C# \"HdNZJAFLCʌ|A)]f 4BJ3䞥 "M䲄jƠ bDdc<22a Ե3PmVPlleB'4H': IZIK&0L RQK*T Bdx: *3]8v |pb2.ꄱLt=$AIr,L%tT#Nu&y2L Bf i^ޥtMfrH2r%îzkc*1qB[Ѳz*}G-"4&F3ڋJD:R}2B%*7Gf K̂p;Xb1XrT &M6JMvf2vڣ16MU~`=) rBP@R!)j`. ?VK)^/J0,S.'yptX%֤cIE"*TRHeTRHd"ȑ„܅*ț̒K  9ϑDdȳ4@>MG%dTБz.}l1Ʀ̍ =\q* RpȐъ)ѳ%K dLkx5zɥUH=Ol]bU!u&T 6=Cc &Aj%C_I J$A.I.',$qO| DE9fPh3 Nu9kGuTS͌0ƢJ :Aj3Խ ! ) IH Ee!&P-%b_Z,.RBMSҔѩ( d5%2" DV/ct/ I j`*fPSCrZ sNJ!$AgH~؞fr'(i#2^w7@)V&, Icˀ&bHqED Juy]tB" -dpI2#i%//eDB_od(iXZ@<'YR\H2*z2鱂Xz@>vLUb26{?|q]rm8</{}駟f}};:_Ν;\|wr_V(Eh4鼬593V| 2"qYc:$ fp^0ˊ!RX,4&Ei"Rj1fӾY )4 JG0ٯ+*QvRL#E{8/p%=R`tdxdt`x$ fY"|2Ye|!SV1Qt o*uJUDx*.(08YxNDsDR7ԍucHccײzMN&CndkCJ[L*fQaXR=ER$-E"Ec|Dt ;D 8dxT)&յSMK J7-xlUq~rs]dD*!3ԚK/,9DJ*DJ9 =1f?d-9yzXS qp 658]Y @,Kd 58kt.",,#QX6 a!8q"B^dHzN IMbn85V RCA!accsu@nGbh# zYU/P2-eURRA:1emfl<7\\tPdenj -&y@6Fxir\Z礴AhK5M\gJK:ͬ:b"4+zc*c*Ƅ>FEn(10ew i%Fz#m*ʌfw@=G)%yšt%DɚnW/; 6CAb,d1/kؑGliԭ4cemPiOyu^ /GuV7(S68 QE#*g /"ozӛ=~:g>i~O~J%; ɟ EQַ7 UUnܸիW﷽U0d2o}뷽&nLox_x'{qgd/,km$ *=N2%p"fJb!N@ &M0@RI8N{eg.v =z]㊇,i3|FWZhm-n/YXpyqOy: B+,V5ƉF|ჼ\ųmd3FQcd)pF1s*Ճ)kc#^i&l)AUʐK\^k䣔JnjR($$±MmvmJ\%H=p5H]Ee 7u1a"65AjILM}yX%tL9%w#JG>:X A)ut=T+*F)ҔrcAy@SV12ThS]p8GLSQ3Fv2: 1ʄl~//r{t;Tc6Gw:esˤTJ3vrp)sY-CJVO AyyED)]<$rYY%$7M2 Ka79ҷm*))k#j!Bbʚ8 ~Eo,lRvH p7aWz#v5N]*Sc%\=,/ RLq]= ߪ0|Ν w:ef2Kޖ$u ji6uVO__7Mlmm.>w}c^ʻoyz'|{(x{~xY.Yr ?Fvy;g?|1o~k򶷽eqgqߊY3.X.R%'Jure+4 CԦ>eC*&LNR(oLQ#j!;W dS r*z;ǸӘV:e==*ząF,Cf*y JvhH7LDC_D.(g\j`{ksĎ,/ӟϷ}iU9HSY(7g)\dj)PHsrK)7ͻ -HAzyzVTo0 :d6K6jd ceK5P1eFyXSq5sG}SLL%9ҪdE9,g'-Q<ƹ/Q Fт'7Y,]4WיrIMalF~Zp>LЊO)E,#AjԬ1esc.ѵIuS"`8xyXRW] 2: Rs&{$#!g%'efe]bz7qD®nqADUe|̦u#%ܑ[WPv4S}/* &Yhfp803.7z!|*'[/sv^R5G6W4-*]! U$&#"a8Z :I EDm1ÎBj%8ʀ -19edYeH 4Sb +HqR yc3kW[ɀt+MvzFݪѰ 8IJtFҝǾ]^:^׽leggoܸ'>ے$ws|cck߷ W|w|Y۫_jy晗-oJۍ0 >OO}~ۓO>Ǟqg|3UOO;wh49q<{൯}-o~󛑤oQ*wDe䎆v׀=KLC5RJmDA^݂BNqZZ aM i0]\g#yQG%nj)ΰ_%äoangSXb͖ 8\GOcd1iQUU O1"kH6~=7~J,"/Q4j|~EΈ3z:E:oIRX٣mq*7QRVg""L|,|)w4S#y@;s%7WZ6Z%g=`Cg+\˖{S¸^cdVU<,wbZT&J֜6^@QR*r8ҟRt>Bػ̫0+L Fn:.3,1#L%T#Ε_bERlk%eOqXD%yNg6AndDnhJL+PRFl&:8$j8-FV ߰Xayb*:QZj:I=4)B3-f (Ȼ [CjDk蚏."@/BLg/ݡaEGwܧ=4NX҈J:ajKֵ}-*[ [ƽ)IJx:"-O1q yU %fe1r"RPMDhjfD9xFUtO``o},q3tQqbS6FDhi PUې:jҶ?*7McHYTMnxmFL+{ʳYy y&I2&[EY^*p_[s6Nw2v)I$IP+5BX($exmKH6Lpbq[4S=a͞fdG%(Z$hnaR~īx r\2. 2&HyZ QV\ϐo2<=!c|I~ݥ38IkK_oo??a??%s~׿_uW+L*w ԯYpK s"! @&G2rjAх> 40楻W՘3VEr2z6}El3Iˌ&,k X4ϛ̗ /e:PYZ֏k $C a43lȬ[I]NݡE^ѡ͌ Wh'}6C6#֣Cŝyn/p0&Ruv!kc: e( $H#6m_AdC9d]>$P-nxIsik >8gdg_dϹ@ryx01cRH\*VxS$S }eA&A#GB"G^U " =b0/X^| |1sm{hvdxIxM]S1l6t=vR)c7T*'[:2ǭ%Z+&afL*Sƴ1IjbJYұRHRB6yQD?p8^grB +ЅBW]Uº෨ IDATF(p's6C6^ƳYDdB!UUqe$ʌ$Wf8p]. 1ֹݽL38Ŝ6=yb$}}7_~MBgL %͠ :CNf R!H|O)JenFVRI)BF3x"W^}~~e+83 ~U~k^k^ߤRYES/Ї^Qq{BPjP`H ? \v/!9'5nt{ [_b{G.|Jku@ sQ7k,k QV 0ϹY=LYPi.X8enɐDIb4b4ERh0ʄ;yptTb>0Txpy7WXcGppC>j7Wѓ=NГYDWu/Ec/f\)jPks+M7_x8zX$KRa.Wy@U&!* U 2*79T6н7shM(74F*#ȭl xB Sn?xUg68npDT ѕ k*&K pDISj,q޷ɒqm@t6C܌/rst9C<~r!PSꌊ9f[aqH !^f&{QޤnACg`6ik5E^c|W_}|pǬqBth%g}g' wOHdDn (~c .2yyӔb &vz{? MHdx2zf -׸Z@.qDQH0±h3^VWO^P[fa9K1MNirJ!E.гM ER U, E QE,g[Mn?*38?y&O?4O=Q裏ַuں/{QofoCi f1egoy9y:5ڀ y0@Y'A`aɖ-eaɀ! \ %nlU3sĞq|p`]IvF掕{G}D(ķL6M-@Q>& b={fG17.pAoS Y56he2oS|I19ktC a6mdCәڙѴU$s٭ 'P Sb tLI |ط;(aҭ*:^eCB]ZgfxySgqQ5*ѧ9֣Hъ(Pr]mCD"PÿAqJ|Ya6.gN5f6ɡԯ/hηk)uZx~΋΂FoNC]v}콐`mBU2΋=.=UC 2Y31//ָm#-g{cT>XtmZ %=.cT=g6yMauVYROVԓ%ql ]ŷ…ˣƌΌ?hFsZ3if規iB&ādUYv+Ttv.Z@L<q3vF=r"~›WѴHZܜ>pQ4M3cSxMCXiܛӜ \T3q$b+qIm\j\Fyrv ;дLM*©6 B6YRgiUDJ)JL NfE׵Ӥn ,C1H4 4mB&T[UDxlhdK LȤ2 8,Ƹ':hPڴ%]Pw.k V<Չ M^P*|NVHc+%+PU8ZnnkJ#suJ] pzzCϿd_T {HWr4@Q?X|_o(cb~JfvƎ6d7>`ZcۋmBSl +iKJ]Rj)iALk27zUe}Qڤ7{e_%7kἉED4)eˠlLj=תH+VLΔfFӜR@8Ί"hϦW/pﳢJXSeEeƺQCm35* O&9^++W 8i4|sCJ__|O}S=DeTck0UxRvL֭*B3NJtY>87`xd[s[CzN+lI*,:ex^]BGJj|8j8Z,MUdiRWpr۹Sw)(U{6vunA۾LhKYGuV:j?GP7556ԍ5e1=;L6#.UFKI0d}mW¶L5نBHzNj[|=xѢϒFA9nvS. sUQ:xOY,x{mŵ"*͐ .yʿm$EQY"$YvD:QFp6a!szXbbr^}D1¬y iQ?q6v6C cZұn%kc2bx).Ȗm` *-bmyĖ|#~o4d=.*S|%Qɂ}GC,*mn7:3MkJ*MȢgeUQ TUhhiuKԹĴ9 3T7 qo"ma 5{9xZX-%Ye.E'6rWIb2VQ aKD9ЯLt<%D,lpIa8c` 3h)fJc&iژ[ P>j(v5<ë~ ]xƆg(*jFZ3DB۸ k}:[c:嘎3ӛqqrrb^E-ROdNԒ? 2Ú @( "U/N}u6xqYR57d=KKO/%$ɚ gR'BC%aRa젬 ("Zr#:ItE=cYDEkjzgF&Uꘞ2bcPB3t&'d#j%zhJs̬k*YDT6!j ueJTEM%DIhZI$I\j='p18ƘqV9Z`S`Za}Qg-.8gT 72~NXd)'Y$(3MyVT }wȁ8sã":t oUco2u XyfK5N%T嚶:}rXa$řFƪ%۵OD @zP8Bi)b+t$)@s CsvfMTg3v(jSLJ2O'혤Mn(fj*nbEyfILm0+n>Jvs҆Fi.R"VqT*hZFĺIm$?ZRM 61N}ldu = OPaQaiѐ2TS4Y dI)P}`JTVƙt3ڳm8J+G)o{):QD=Z |p1ʂj]iP 4e4.g.sA \>bX1H4nn %”(,BfP5 .Ӳ:XT^NѴt+K-*PEۉ:҆kI>׈68@Wst%GW HD g{mDvsk׳1 lnfhfnd\h}.zS#ja$(uZВ'M!lMSkD=AĊK֨[k<ͧiis:bB1*tYueUYGPe#"TQf:k_g>ә_8^%^ŴSZKք0\e2鑔&-++|ׄ߻.>Os?syΛ' Jg|?Ό2LC仰P):"YD Yߢ쫨VZ(uĩ0r[̂S {.~ƿ:6R_sc;'.f;\,u¥LVv R`dK x۳/NO88' eP8T߭q+]TZkܦS EDXy2P]h\O|0Gtt:]ɬ^v \hBNCiHEIN+dF8" KyoURhQ*턆g8pՌrEɤfbXz ]?;`vDc6GeD͸e2jn߆,U$*&M۝VL PgAGBSz^Af^{et1#]&4BwUBeYZ'%y*Ʌ}th2^if/RprУXпgpA΂ΜFsA9grZ6.~V!__}7M/Neخ2uW\q|ׄa}3UUm/^IiθwčZ )l*y`Pt3x ij"-[|CU8ԉ jZU%6s okdF!-g s^5:>֧uo,@'uTaUȄ΅6ksW=x;xx,l*n.Rsԧs5|c+e20d<˫<3k4чRr厠؁YI4EUKJEAsUH+NĺA\dbn{**@Q)Q"j+z1뚇g؝ўL}QAzh2[u0 Hmr>фM:nro&iSg`^0.9eDch0 2i.0:KL0ƢkLW/.j+팎3i5.>G!uCfn3yнד[~DS2jΆfoZs:b1osr=Em8W]U2py2gb^'m9%x )* GܽY<^s !7T`Ha(NlyC!*)|MKJD+Y"FRb9{n ѩ_rZ9{ Rtb lQdD6\LV8Ew%\|j*i .,(CHG)G>bwyE05Z| HZ ?3^sgjJ=T*կ}?+jB%Bd4BY(QDPdD%c x4qM90ωjZ5gfbdB#HKRS1)ˌZϩDT&ᩅ5ߧ:PiNȥ=\` DZL Hoa,mlD 6 dBŝSCb)HLdNJ$!(,H285Y%)ٜs8{Ht j8ZwC5PA%dZ0A aRj>GuJ=JC`h Q{*eR=e[KdKD %+Q%b#>$Zg5VxDMZJ!J NPnhAؔF`y̜ (]\[ftVztP3KFFqDՑFj@۶UA"r+R KtD*pK 0JG"P Q KYҗ#v Z\):b)YF .‚=pu͒ U^"aV5D- m%FrnUY=5̨\ӹ9wXĒh]M^?Aamo{Ç_/e?#?oUO}S|cc8rm>OqttG>xg?c^xg}w|3'c~ᐲ,Vo}ܽ{~w! y~1}}:οunIKK9W\q we*6j.kUjlK ؆QD-Njft7GRk*.QBWqʐ rIdL/ īx4lTGPiBӂma9Zj}溇v#8L:jartkVԊ |*>UfFFJɲ8.d0Uk8'N,&IɤC,M=o_,,gM`D/ыG;ꈲSDg ]0Xt co56G=Ћ&$T>mSȭ|aJahn4 -fB:%DلpBc8T){&$V%$tN}|Ѝ&t ^5ydQ v3v3S4tR;s6RE Fhm]RsA!5rD_sQ6Tw(jN4Qӄv~{`6#L dR2p? ț& Gxh'& VLWOggi?A} =VO|O$???yZ_E/я~/˼j5~__}%nfwOüFJ/h~;1K[L&R W\_i29Yzۄt|Tj!N혞3e>0Y^<˼\N#j~/4Em[.%Y R899V.d:<%MZ-}ENmfwvμ`Vi0 VFR AVDO[.sk/:g`(tt_],bv'#z)QgyU}ϱyZS/ќLqڠ`As9Y'Nh1Z@^0@JT@i- szspw_#c81F925/G%/Ƀ!7x`"uhsb'68b+$E sĺ$1\;F|JXu%1$XEJ0ݨaAU+KXNB9,5յ*ζ/slaibV&&2W(A5!bтJPn"wJL;d7?V?`vy4?(:Ojo oJnhS:%=D4og6Xaqs"G Ya e?d٨Tuۧq_n.xYy3f+/[Jէ-x&ts|-~1dzCL%x~fƣ䐣IQ'Bv]вjV+.ֻ]zZglfDśfn_Wm|ڵkoӟ4V =|~|}/Ї~ۿ}[[o~?D`}ض9񘃃>[_:??t:yW\_+@!g.˳:"2@q얘$H!@iJ)S<r[yPjFRאIԤ@-rM:Q :L1~BJtoُ1\&FO5]H9lTi9Uc/WT|.`H1/ g{ H.yͩVi_Tކ\DŽjYabYT䖊!b !M,t6tJJL)15˱"P)4Q!46xĆIfĞ=/B,$beq`(wrɡRT4t7Ê*O=_ Kaz3%]ex{IXHX$I(G)EzF3^ckqUmMMHb$)% J^RCg4SRS+,$0t֘6zFN)&+,Ba&SE*4ʰ@^(#{$AJH4A^yq 3O :+.*%VAT$l &Q]KɅDxh3&.l&O t;Gx"\?D9-)C(+↠Քzpv7pM\}np3,XSǑf9J&B|i]*0ThKJf75Ed6Xf "3ޔ}]1 ~YRlC5BoP2MC~747TBAS[pVԲ5s~³k"nW֕ Cky>uKUuSL%Ƭ 1wxN($~E)Uu^FUVTY5,I[8UC]Kgꆁ<.L5(Zu/[uXjLKp`<(R։EKlҀ"(FX*8JWt)IK1Z%AsbJ=g[FVd2a0/~exp3<1uo=o8˿0Їm]}NF#毯+| 2ɏl]Y=y{1R <3 2B1`b' Ġj 'mOdG߫;}3c(T͂(p:׽=eN}uvC['=,qVJXUSJ0;̔W 9{`иAݭ[L"\jg1#:7< M nK_Tkfd<0G1޳-FU]9jwguC&QI:--*_@E ]sL`5#d ҘqL?9_EٟKDaHF#|~+{;p/^-nq|tx"8LG , vAJD=x`G6qh62μ EdYXa-]ĥt[F&Nx@--49ʛ9z}gPܰWR{(cPt rߠfԙa.Pho F1xdnL6K'Ut|5Irt2 T#_& XK8IZ%:NK<ִ)r1ջXV1p <`ؼdؼwi |GyDx;ֆib4oZQ^/{&nj&0piV5bRQp-ؒx6>:L b\Kߜ%sLGj@۞㈐Rڈg%99?V0#"E*Rs4elBph9J[lQ""ٚ+lYlZ}&O԰-I<НbS4RH!p2 +F>Vy7rR](Ɛ_B2| /X4ANc L9+!<,*9z%9iqrrǥ'+4R%+5di\|0A3% Ps .@9+98{mCΜVAIAg/tHxDKl9xzH\ ؄.c^Ѝ8=[Jb,F<ĸ" AK9` `QReOlWrM 6( Rǘ ˬu9(U q#:Ŕ)%ttGcI[+RWF#TL ^&MeŐ F%ogx_ݠ9%O["FTIyH? e͆` &'wx- ;SSUd r)= Ź;dIZ,+jĸ *I:H;$Og.Mg^P%ٳ6g-I<UU@űj<ۿ__ _-nq[[~ ` NEc?cr zoMf+\8lȀ >> 9XpΈ%M _q1Z6Y?oNM-tk +tKO8sgp<5 :[zAum?ͻ &:a9mN}>(?xy\k2wL6+'CG~@-ngg{=&&K@RJTRದŔudl&R}|k#ogvze"L.tHZ BBhehJWeऱϻn&(P)(TUl1c*E[\8Kbł;)tazJ73-fTm1ךvj-)- ՚{kM ԎE nk`@@p'N#^w8TN9ksR]'utR]'L+sys?#/ppp@c߳[I~f)0Sl?1%**%h P-ijK\-"L|Hcy,˗m/\ұEP2s2Qⳡ!W1|LX[<{]ߐrϠͨտaHC" Ii)u0c9br|%Zy%geylCԠ\Hi^G7oogg?} _x 0q)WYUaq>9>//';wneկ~~җ#- sh^8$X7v,$%UV2Teyau${iMe:ieRe;\0W4dE+^ ŵxvxAY;7ީB(M99Sz |VJ":m./g!(MV87t}RʖXf +_O5 BnczJ^{\>)[yzLAI@b\!M,&)Xa*WHrnѫgԹ~BuW*RRh暖ӞPXsaY d/m+xÝK1CӟRl-9|pL\44%iU׻L{ Ms`6gFF)pUT6RBdҢ͚ 9)EE2v\(83Vw7C*S!VRݦLk i0yc -A,ypq#ס2Eי(|¡\`H -nq[~K%B+МM:,BKDMCلS qyy ADS Vam3MU~GL ݩ׶M9{瀳N9`[ :r$RAP++>7|G6?D 4RnFQOJ(]ܩ3Vĸ͐3C$ZSMIa|n}TveZvE1(&S ޥݴrRNnqn;9vc^%TR'F^Ŭ&siqlP$1e';diͨ0-Z6~eB1KMu5`6Xk J@vHBx- sI DOq cл9f+ Q4I0mw:'Nռ_ jN1f'3JӘIINA^*$}{OsFT곊ZO _v .u3H*8+5hEkF/#IG:}eg-=BYxk o. >xa]2R/i fJdVڌ"e\Y̹{R(E R(TW%JoV3%yU>~Ux*Tǒ!5S=: (E?O\e#O{ZZ[Ex-^O?_W> oum|HӬ5_lo*bYmdR 0eN)xI4C8y! HUqӝ鴧cSǥ2`"&ەyc~sM3ۛl-ٿ{B)4k5՚\=]ׯpk/8|1pIn\)ȭBMzE"\49'|3OÐz;_?}b6ڌ˰MX8dMaYTILjf1W&K3B׭*zDCj 5 DZl -n?7>o5%kl;k4Z6<+g#=Ć-8QH!mGl[$duOpM-HuD zBkmWCUtAS @YKH®dNi'X !1 xo@Pn A&k*!X6 ] 1c>&?A~a8eOX*,1vn>_Li' | QNKwo@Q+Z!2 A Eee 2m 1L!SsȌ.b+͵6bSU+/ MrJϹ?&B) UAWs,+x;`xĴjh˒p٬K65߰_RhjFhM\6rDhNL>W$qIB}V`g1/.3}#HC  vqy!/;\d]VwJҳ(z e5Y>EW)MmNw{M3Ȃڰ*),VjDqQ'>z2J.;ev%8y( 0 ݙ38ba)nFL5fT !a賜1)KA)J)Ȋ-nq[Q|tY?甍-}!wlIicXmg-g{<9[>[tґA22Iw *P)M0 c ]n!y^ެT߻RSTHqYP&.{]EiGt\",s,Jkr##9ucZ;'U u@c0tČ42o"& ڭ99uwKBr-"YXE>g=⅍4.?e'8gi9qGEx%/c81k'xw&WY*`٬|L & 1 WW:k"$ B)Uii8`:39{\#b ,6\kchB%74"5AD4 6FuvI ٖ3_ ҄NΜќ6g`^$Xm:e]zq)gt3s^KN{މH 3L<)ce-n6>W)9۰diXX6nIg3XNیdOsӌPP-D۞ԑ F 6$GQf!CyCo2_qޢ*UAZ*e + K*sg^Ҩ ×|j}sfN[ \. uNm"'ƿbJ]W` tΎz(8g?c?<`{^tNcL5 M TNpm'!Q  <7(b^oӻd8185v91范UoSf*IYչ1~H2|K+YQhBb[x XtPI 0I4Q4?}{tjVFbJcmfŴfra[bg~cZϛhMQ-BW)4\XJFCZ!ZQ' GmΫc;sJSUB -c66{L>оG%d$5B3`c45]e~IJC%{g{oݽO7*4$&QtP5Qgoa1Fg+6PiK5c)[+1%}cIʊqm"8zRCJ.42i`.+`.;L>HĆ\H*PD45J&zJl$MR$[ e "BGIpWh) Osg)e!lz&U)3"WP*ШDݚ TTJl&^;ȥ9 Rt@1ouHQBLTh,Mfn6vH"6S: Ťe mJ(HW__~/;ƌH0) (F*ol b1eS5mNkmY$,UPV*EKRVd"$J]ADGJȑ@-'5 vѹrdc"̰@hkJ X RPUIR!M M*b[yE/fXi+*E HLP)MpzDZ}j[_d`\2[DC*JlbjC%#1f8w̃/ vUKH.'O{4wEPHXڬeC&Dh0mg#|raD[#1oBmֽ9Sz'3ˬeu]f.EټljBOb C0)',I4Ď2H!\f!(Wq:tYw7!pFFPn1]VZ[m6$3THuEyw.ef͵gtٌ|ܨ<'%`Y)(${&$~l00]FeRԹDZy8a9k R!RJ}-?DvXG>edÔ)/{t9[n<1}~B Bh8L',a3 JhKr7}ʺ3j樱$^:[{Y{[{DK1i[\1]k΁yZٽd1ĦˢuZXXj*۞Ksv]2>!=/Fx7x:[% 4cxP=FK(\ q>t94zL(U-iKƖGFdF&YLU*Uk_oаBjXE6ddfv&*@ w `6%fVb eKz[cXb aAk,>?l5M֣3R_=KynPmtȠk'[{[8mB$^p/G'6zL"sSjT.ޥ a'#%fQEE.,֢4 54v8zCW'u_]mfɊ)&tKS6s>\f1Em",Iw@5vPss@k,rj`Ìwr<*&mC'x'~'bXN⸿S厵cX;=nOg\-/(YD2܂1dI~\o8QHyȧvp9ݘf_L1%$tQP bS=Vj%V]ϣPM/(TurOpL؈kFtX]axSNB* 1wi汋ڍB9t@jf؜R25GNxȏ$}l7vl3rRv̢Z"lOrz(WP;/RI9?69dHM[(t~g/`>st"8V/0<\zMѺKk.)ƿǸsBAೡ.?R:ii6Yics`L9aʽUIT;Ayŏʗl}w3Xhg|jt O*V'5\d@SjD* X6 R꠩5Ya89rl-)~ ~ sKrYh?ѬNP&+OTwqwKUMp^opИv6Xd4@Ì>pɗVΈ!Q-o|~O<Ot ?kՌk#zUm0 ~+Z0ڽpR@ Qe4U^iCڬ[Ոň#O6HAE%R,"`c.̕!sξcTMԆhmAZd"6 "u0[MX*!ucnXoR֔AleH1eɩr)tԉZtmt*j*ѵ *Eɶ(5 jgR/ h4Wi4( =-hqWYݤ_+.2kdGh.y÷W!#.%9!IJ10M~8ޣU>@EA[*GT.˴<,4:7[x'X*]'}-dVV0JhyUDqx$#.9_%?0w,>ק :K|)I! lsR Ji־tH["wtn?޾E= J=DGHՠn4ZnTzrX[4F-BO@ \@٬>7#/ :ש jn;&nAAϐ"Oءnϥmk GV1clKm;z톾\o6:U萘UCH !)6;E%2]g}IS740v_r]3V )ߨ3ގtcCSrβr5]T2vG*h:h:(z&8dz49r1i8l9l@Ī%*/IQ:7PK}I2A= 6SCbCQ6E Z4E9RIw~e|ڞig{)i%1j)i LeNub:pX!9{r|'xOV5M IKʿ3R!&Q=w֨:u4mS)~ٶ!0cUI񴔱@OϘ(36UH:DNHb8$KR;,1la6mdUفMlm:Dݐ\J*r#n@ڐ.;颶0S&UO0~ȝ p>Ф*212;-HtoqQwߑlvlE:I{6E"M"O,jUU_޼'\D }P#͒~a%mG0f^4W?l txnp#+8tC\{"ء: TcN,0)Xi|$K4L+ܠMܤJUݠLE 10_Ԙ &D*rЮ$tc5V)jgQ&RQ0JAnEa:L`%MҤUcG vbQok\gvt W`eU6XQan MKxgIy` a99q 0hM$D-Q2<L1KK$*`M hiBahH}jΌi69s#JFӨ͔l1尡uޤL1R*+bo8R*LOu6n\ q0Q'J֢mмB1Y]hhuMGlEDЛQ=z0nf~5mRfMU;`-j*ȕwz Vgs7LqIq Iq H6eȦ 죇zPFPBͻ'ɿ"fyDOxNlRȖmI+$*:4BY:5 bd=蠟v'Q)yP+LfS:l{'x~ﴹ IMxLx}ɲS ϥS:.W.H !I SSYeѭ8J~dlM ymK5SLs U1=S<dCaaȮ,xMq*%2RWT`cEi3($wL1,Ĉ#W@LyxLoبDžWI̪=dzSւrI XwIlH jq)qY_(I4 /TKrZ2bM8Yec]RGMD{32ԗ\XQ46M"#_s{ϻ(Y܍8׮90g|k~o̿qKFž㷓hcWO[ Ptr r}~5Ir^ƼZe2O?PTg!q,:15 >YnBҖ BjXEa|W74 vC%Wvʈw(B Rn6P){7{)H6Aɘ ,s,oqn2..xwqt:5漠?_M Z8@:0}/v~p+~woqw)/߿; %om%Pn Y"LQj؋xaξf c]˟uYOm{Cf5(7?h쫚dl^Y zU)vVbGS&) x`"uW/_=cvtwk±zˑvnqZ8|HTy)|4(ѩ:%NJƩ\`5%OBT\f7PJ^yyfL1ilS*3$ \j*hȏW_F?_#0O{rR4+XUQQ I9rnx&n묇[JKE!B5iQ?͖hD3NCm. 7*ef`%fՌv+`V)f **i5=ZRvkPPrؽySGְo2!?dK2-e(jYV,cu*m@`ݒ~ItT&d4al̙% MDJE/7%o'x'~N_N29g ZtJt@7K4chSliP/UJT*m iP46G d|ŕTQ>e_%N隔ETLC S0XMnR4bmuyc T6|OXd=F4-f[ೣ/VGx㮀|=$K,>3;fˡ{ĩM}N )[P&ahEK8F¸}~)}LC a#|[4j,ԩ]ZxJ…IY;Ȭi߮@N JMz@[O>O\oZ).i\ C _w_sֹn)*eqgr 5*B@!-zY&4dai*'jC;ȑB;ԺJdI1-Gl|^r|`#n@r6xml2ոIlt&X_XGSaj5۠jt`n'=Lcnc /=-УBI0$>Pv h$.SK账, Syў*`CQw{Iz$bPc x$1f&fYwd / ʄeN[1WS * Q~^Gң-[֣./OwbøaV)aW:ggĹǰ2S|"jU6FrTЫ8u"% #[,x{*@*Аbnϙ=6OSk)Ւj~_[{^n"~GDF x6`cfw<#`ϖ>>[&ngp>:|óTFPo -Aah% =)`dn[d%x˩2e(q6i IDAT+ r>I9~{4:Fp3~CxMpC)6ݒf0Z 6 'ј3~/1@b"4Œ*:qtgSaxXGث? l5a-/xۼ|]pȴ?bjP$fĚܼb)ŧ<Ƈ,-K{I:\R\jT4j\R"5{0 -%(#2e=v?g:9G_Ec{ر6CkΰcɜB1(\屲<6#"R`{N#,ЇCqϡqD+̦,K̼"jBn'Mp&75{{VT4FS*Na ͮmTTT9Euj[:I=O<'+XFi)T}Su#ZL`-e@X+~!4fАw!7`fP/ d: b en1ӘF좀/jЌA=* ՜QDdIG^QGkAk@P:S:_pHk[NW}F$bzSz ocޕ~Y>&gfʼns G^xoxὡn~mCڬ?._f5?f_.|Qy/[ <զU7%v v3awM{7`IEH)h ͢鳐OOPx菹|q"ᗏ_^ 1Qe\]XTV=sN&$ϒSa(SB$ߍߝ5dj3F [ͨFUXuҹ9x{&o8U B%Ařo6o&/WI99qo9vo9vn -R;uOì FZ8g^'~D<]aSJM+펙:>|-FS1]B~ՑX-xZ=}Dwߊ_Q:ԊFT<:1fsyEXsM؄ꄹ'U =/xbq}˛ox#^00BV>yf"cB5Y(6Շw݊_Ĩ_M 9߶[7/35.s6mD\Z-m.3^P `ixDt(Ш9q_ߥBqvj6$,,=V!k((.6 * . h5ة>a!`(gҖu:p9͏_׿d/9<%UR\( V15*Scy4FU<~}JXF5Jꏜ+BI/K!rbjW!Frʨ1S]M*玟\KMTMAUإXjL8Svx'x~¯(%EYgVG%Q*B-Ig  "u }vu MVDt4E{DMH 6^Hdyb l^𸝰}DW>vLqߏRuR:UnP: 3 t[ AEtQᱣŁHmےJU3Ga@C&3چ&>yex-/-x֖Zթ}b⃉`j9^2ފQ0g/ L& mfY:`6z$sxS Xc yI\\ϸ_;bR1c8b g1sd*!_+mG,Ym# 鰡Fߏ\]=wjEai.3m^ne-Ff]b1-M[Pde\ϘCfڐD- vvq_1=ڮB kf|~jO(PݚL-юg%yOTA) VZx*Y6 s'pq[1IwUiP`JHXi]fNŮ8 nz9+r;.hp>;:uJO_2L}WHܳjz,|Hкtw_p` #>W'x'xjeӢlZ33bI5I+da-(DI}7.k pw*ƯwUL:,D2S}U 5FdM54{JL '31DH|v4$x<0AVylS,;C0g%u#X/=/[gk`PQ `v|$p3|'&C9 ;<=,bI=O<',v_{5I]Wq=ȬT%%yټߝ fCC4.:2txkq'K6lɇ |ɊϿX;.yNYd[^ @dEXԡذW!W  T%-FAڴs*#7L[Nk֚}b꒮lw6WW*ګ {z?pf_O\|kv@0&[+ᇨjQ-4|ȡtmmFJO31yE(VbJT[íO|\r$7L m_0SQX%.Ss7Lѳhb2cR/G 3ԶPh̏fđyE05^cRwCƠ\[ԴOl#\+*]z+~ig}34q}EexadD=UNPrEN&zSS,%9#(`p2\tJH딴I@*3Aj5y.(sASQ_Vx;z5ްkp$Ȱhyhs/|z 4#NwGcn -IE1|6DI5DLKs8@$@*,og _Eqޞkā@FxeG}I-TJ fhrL V?Cs+䱤TcoDL;&b!F3^=֏Ư2$7M5~i}&j[:>PK0)jDwanу=yGGܘSTQ-l -uKGkW]tp$HY]]cO8gyD_2v<縸椼F%lug|mK̨|(1g%IOM > g^2Г-D#gHmԆJmT/v* QaZX W^upQ}B2`'ҿ5P{ E"4ٞ 5᳂q˅= [ g'x'(4;;^f]$<ʮ IY4 ՎvK'mR IiԞTjS1}{őyHcaP %lD{m A.vq- E.{t_66)1~<%YiPdҭ1.2aq}`TFmTkLBC4sJCr4,/Ű *]e'5~\J٠5$*UW&IIBREJƮQI}ᳫ:l>K9<K0EdF ԂVblislon,!y=dn =~1yC({yD8L;b٦y $[fH)MvUe9dwHS& L8[F^ћ0:VOd% cI^Me*(5, FU5jB[s4xq)J2K4Yz,1rBcъ=S߅l,.8{P 3CdPH\0{TJC1 5QO<O5~G>4g*q-QD^i! 5&Tw=N=שct@Zu"Q&5ZPa:)VATSv:ڎEF5S)n{ܼ|ƍxơS:&{+W.3ܘg|oyk~ۤ3&iϩɉw 4Ds^eJVs] D +ܱ'I99>a:)÷kgJfd@9f#N/>gɨ7FnMnd"!ل${rQ:3o7I]Mgozdc,4tKZE(% Vqqs)Ӡq:^)&3o@O7!Љ1?#MH '@QٟxG|<s7_`[G:e`qxmO,FcC-sJΎלo8;^3fgo{EJ[i6 )TH%ߩJ(<0/slY㤳Y锔=Rv5D].k%%h;PwڤK⤡njTBhP)j[C"M>MqHLmǭ<杽È2Xe)٭Nlhw9Rꫂb}LĂ`'d}lhj0/Ǭ䐀='5Ϫ78E48qg&{&=ފԶ;>s{D,>suB`@72ج15:&PЕd]pO̒#)wcg\/Bd yfzG׍Dg̬ p\#H#;lW)I(LyZ$}i@ؔ%>/P*`V EedjƦr936UEi􂡶B+bj[g0"r>*eFAI9#6edPD&$N<< \3;eW!ھnM2栏lm]BhzCm ;`{]kTBsE 2x'x{;\ b$G%;7CtԐZ@ibAyr2Wir)H]K;4nW1eҠ5V"kA7(kxPP .qeĜ.I[ |^Q,MF6s\tΰ;L5sh/}!Z4`h%EU:;:іgs&I3Np1$?eզiSZH$GhYMЯ+ s Z7/xK·Xg&5~xF$f'܇#6C,5 5fgJJ蔦FQ+؈OTH$-xp,!soB jFIV9lޏ +.Ot-{Ck!>l/礩C2)g̤SP!,#mUtn8C;6l 9I=ҡG20`(HȒ>9&dX$U'x'5~@hM{l&jnXܕGT{dcS}g B{bh6;CYL3|吏9o|A,]{K(6'c"Ө*A[Y8fpľ)]ZjdEv۶*㮃XUXaLhm)*ЧwaA J&: ]LtW&|#(7]lѲ%ݛ%Z24=`a #F=Uz]kA餁M4.<*QRQK$ۈ^]p֜e5y E'=H&NGWPSSKŒuBU ,-Cj B5*%:QEBC8T1R t0acoF]ħvϙCL3r(gȒ=8eC;/|8;Bxb+d1aDLuVz,b [2G  "QLV>9oWDɰ&h>>6 6 Q{:lqQf F5 Ow^ cA)TRg]YCՀMc*?0>2_`$f/yl@Xs-UԴ>dJrDؠgozΆSb2,Z|8VzkK2cU%yf]2,??YA͇ū6F2Ǡ lKMVTμU.z 5GڌHHZt.f o^4jc:R(5hwiꔍ!r+Y,;;ڒZQB QBgŔ{&bƄ~U}[D1`KX[U|\Bt G*1(D3b]n90{~qG5'\sJA|jQQ4ȁ[ ƑPyc1~7^3_Lx7/tq::gq@l\aHB icS:ۢV@-?sgFD%nu݋ UitzN(s|w3>_O3ad FƜ,4ѽg ]NŒ)fE|J""\*Rd$LVMo_|ϵ[zyq{|\@u^nXjs*6u*4y଍Otk O0W AB! U(ٔ=s9[#㞶mPBV$1YWJ]!,} k8)wUF]kXCż}cLBs~ɻ },w*jKFL?{s俧7$ >_4ʏPBJzᒡx`l3Pdż2?LxNY' ՚GR#BXJox|mr»|{ A>KF<0REkRG4S 9B|߽%WN}[moU~Vt$<?( aw N >ĥfT$|0&:g.X:%)4xW#v]a%F|H^3{|LnyO<O<'k4 :p!8A86a0`ٮɶ x_=3U~ʷkf'K<-x 'H*&w}je]ȗ"aenLh!>}\_N^[kɺTǘMJݨ̚ z¼&ڶDTۊzEԣhvEZ/WfMho -zKxrT K VրtGKsNOŨM# dy39bW!yeAU ]mKp,uDA"Vyд/qlPOc WP3}K"M[Ė죙rL ^[emvK\+y\Z"ssY`54Vx27bu( &'nl :|Qt4BQ|94ZeY{}Vvc8˄6?0.Ӫ/hMpa2cy)b+ z@ k#+qLt#0^3.Yw؝` vAg1xYSݡTʲJ~oYQIɵwpKp "{Fŕ Tij(4@jtbnY=jðgP{D@YEk0:%n@ Y}mxu-oKiۼZ#էm  9/w\gs(zCh-m3%v=RD}Vu oWw+z5"(4Q%bp!,0fAn{TiU5LTB 1qc1+iaSl ; y+H79۬Ã;fv:8JЉ8& .6.qs(}D*tv2|'Xuxwwƛ ֻ ݄Χ:aϨ*j*d+SAXl& mʡzV3J|UW;,;*3uդ;f1Θ1240H9oV#jQE_?ƤdȼsWs}OQP-\gX:ֆPْgy|hڊJQD8^J2P=As=GR8d09Դy`I5%GcqǑ}wvW1p'pA7uG(.h10,E -I3`{$x ɘw+>W5x/?2V %jV˸jp5>gإeR T@ k"e:C +DZl+FjFK VT`EtC/{d!X>ogm>m[>{xg{P*5WKrg񾠫l8~baWEyw /OKsa8GؒTMB1Is|cRjw$rO(4>Ub",&;/$BbE% b:sÑs0Y2H +1i#<#ʈK9Ie:ˊkF[|ǀbƯN[}z"⬹^gߒcr_OUS)xfeom" J)t撾uH:T;':hNqQ:נLjqb${'x'O?E*A=^H#Q)Qmm>̡R4*WꔆNϯ15/;ȅ| Qh,Q0=[b=`oNݛ_ːZ§ Yl{T`/Fc_QRL?H@KK敂s2=E3[;ATc'v oWɽ1eэd/6Kamkڿ? e昲6)*2ۊڿWj&*TBS*Y>`](ߵIԀ߶ IZ&ꌩrGܢ}k$wcjm԰x!RT¤g%S#g cwra60nK~Gޔ3bt9d#.%.?[яj>r^?+ul5T@_4@@OK"%p \ZhK=(MVM lWKu`bA! M09zV֨uVJy|?W;\_, "ί?!$נ*PtV {%$/?W~0~k+{{ʷK:@nB(/g*DU- /Wlʑm䴊¶ ]Fd+2t}{ Ɛq\B,rzBG`:Y;i-7%=cS䵅DPj[5`Mb\W٫]b:%[5 2{I]ZTXBEl,}8O^[uuvUc^چyGy'O]^ i{G\Gĺk "P-זl!nwaȹGHskJݦGShz?c8YQ>GյNār`JH>0@PP껲O)N %G¼hjlP5g:gz kφO m|Eg4>lN!(Z JGp! &uN$h>(sR|O/y~丸⨾f,(JCdזh3&TzYI.' 58Ei8g:SnjgނOL/m0%?JwOjz̊g.s7pWM@8K$;[oGzX 65+Bh5!ܟ***S2 ΋8^N{ ; ƶrZU`)?/JES2T,riSH\ZTŌ_35i*XjN]G|A|eS򵍡L7wL ܮ@kZEi;ZU~= +\1uC֊o,+ @A (9s>A}Yscu``p2`6%I"]sHXů[=cӵrĭ>ߣb7df^OȖ.~e3&qQ2/$EvH4̊IJiPY}主@U;BņP"jۏSe,㿘3 |7|w |gon-ز܌tw(2o#<#?Y~iLw̷wo>o'L;-sؾ{X+[?w 1'/W|y&B!WL2ņVHNQDh䉠a @R>BHr"xdC , Al`VaU3Nʈfj㔟u?BvЂ7 n<9$ZeZۥEL 1mը_=`uտ/zhxKEv@=rr3j* -O[z@+xV>+uJC<{Vї|od#4g;V,oww2mH[ |.GGgŗ&G% 1*=0|PWc[vTttnרFCh[Xx]ƨq}2>tO~k%t/?wો m[Ж*an ,6sB(JUjZꗕ.uMC=^iokĞVآdM+ZEe!t~ϵo18cxE$>w֧u"尼Ce+>4O/1P*T ̆lkm\}tOx/ѐhr4}oGJ"8"1ml%sl C}́rρvǾ1RM~wϨ >ݞ>O#/x>7rl;>=!ۺw!|?GyG'k4F#Zѵ5 Jՠ-h,9Ԯ9+K5X @5HG"-3lI,=*wTFÎ0Gwu$JOT{~ uLd# -hq7qnqG c%а WK[0?X1?>v1B[tBڸ,!W1N/ΟzkD+;Ҽ*԰MB:>wLJ kYuʏyaRBېI$.^!'3\d @HL =ucl"mKc8<>-jѠL'VumP7&umE>zΤ1MUuL|<&(sy"f-I( %BCMh$MmPDvNP*}Vʀ~fsPv:昫m05*ef %iReߤt^C(JL4KM"dIAODԚN[T 6Q=gNldGp\2rVJusDl0{)*HU 4Kʸ]V3/X#VeT#iQHMs}9*?c~[`ar4!)kbeQ^4Y>!MNkBJA.KXeT~K20OjjDEn.+4 rpџdF H8T9Rn8o8쮑P!CRxX:ňᐶ<RR gdb3kĴc QW&l5V +S*cтsU)zũՌKZz1YG3+Hf>O|Y? 5V'|пC|DQX&*lw8Uav"ͷJk9/UAתԝA-wjJuHstie.j+XmC 78m": QcQrB$aSǸ2fo7 WUL[^'A'RKŖ46nr;~F-uC2myYV v'f 9Hp;߮}\}JX_tu޳IT5#q±CD^Ek}D)-{LPYCdǍsȍss@* "C~Qo %ˇ#VHvg%Vg%lE׋W.6O52Lw' &D~5(mR30%Mg%iNg_H=:*+[oogXA7$y|#47 %>BCyØWFD&řA7Vxp[R. aKB :Ga<0d팟#h̔rͨI S)N-~:5-gRU&'y=SY==lgւuOi̓=OB86;6Ղ[mʽ7{ƒmJSiZ"u>˦BtNAo XV %5'NEK_pCW(1=+7# bW!BP񎰂3.qrY[!skn^XX}] ՠ`N2;`1qafӷږDt=! 4Qi\WTRE23ʌ#q4a fcb l AcjTA.-rvĬkBbVUgo(6 + Yauc>9?nO\$U@R Owsބ.񃔣z7V= Q<>_b5Ov{:}IsH6|*O"6PWcY"nP_(ߚT:wqd26qG3Ԧe #<#0q։ĭ$`Xsd9wLnδ3 v٥JڣM{$HGQBJmU,*effNXknvM!Q)B~0;JlPeG#5y*SQm0W_Sa5]>`}?`{IzTN<-hli K/3'DY-_ Ŗg-![%Vj4s3+:3w4Vi5<5"^JГ[;&qdNH%>iiS] p; sU#!DTۥe-HLUHUdIUx!['06h[kTسyfR4Y&VٝKzacD .%! lh*?$>GCTS>l nb : @ BBAh.:V; ߎ3A+XH:CaC>v'|+5!jPip{5AC* 5<;+&jTuZ8۔`O^`h.³SӉ 9J?di MiDCޚ#ƓEcn/\lcwƟUqG*Vؘ}G\Ԃ##=eٕZF6dEVtRAK=d٭@@4*}׼[Ec&uk4:yu6EgC Z nZ(1{5עN C4Y]pel=5J)4 ϟr9:&I|( }D+Q %QQ7*jS56*M5F'{lPh}ز.8Ri;$("vRGn޲kvs_V4F[k>lo̼U}ri6 ޡ5ZuԅA(favNQ8Gi: ÙSsSu!{g5,ݠw nRui*ֲ"B3u20WG a #|\# (1=X4W$=ĩ@L~b:f1c1C_[l:qpRf_Db7 0`x21,Ϸs SvDh[(z̼=nNN[Vr<#EsoPTޒW1K]x{vq XUX +yů#Sy=)-OZvI,>+k@dMn[J[qwVr1!|⠿hQPNvr1cܳLcy'R{Ns~^p/16&cSP 5W Tu0VzUOki6QÖ^?/߰XM,x@(j-6@ I7yGy'Oݮ?wHE-a}ҳ  o`-BH* 2@[4A+%hhmEz5 IDATlU ع #/׼pzog4N4FZzmExZd4FaCb_jWZʩuEAZBåyepƥ<8Ch-"/אpcwgL73ܼ*&&\-շ~rLymS%!h;=xR^56 zWR# m*LB;lvG JGO8Pn@Hᨹ ŏ"D+Q0V*7.w .J=Z996Z70Ơ*(gP>8缶_yU<oy޼e.1ˆrp9nBənf(ywIAyϧ֧|q/oB0+*[g vמ5eX6A@c8JX3TV ^R&fk|=ev1eaÔAd`t`4XQCfb=j&׋CLJsVe Y$K };Cׇ.Pzc>蝢U`9q +* ʕC,iR)&ZӢ%-+BwM]uGf r%^)oS=^p9]*r¼pWNHEE05&l-n?9x?И'SƠ-*`Y(]GGy䑟,?]>+~`p`Ŝ> -BJJŠR4b<̼)`LvO<_3rc}=]q4F|_p ZQkBsM#B Rr.Q).ŵ \0if~|y̏8,'o8x|WYFCdu{(lF-zS%҂ky@>9`vÔ D8|z0 ]/6WGSbS&UiR&zг\59`:dN`r؂FX1z FA1j~`Z>P7{G+7-S+.SF@[3V>dAGY'JZW-Xe;;e}=  ㇤GuDEQXJD{ uXjƌ[d XƬOXtc ߙLro~FЭQ K2Ǝb1sy0A9fWaWnn2w;odTlG[Td!%k\UDp1s* (ra oA6"~8Fi:,-=bz]VEQwQwQsE2Ej uC$gm*OBg [/񫘮UUT6|?)*c5#]C:eL/N Z:/_3gP`(g jE~Gu ZbUXA9.эeO":BbTab.&)ޔ6XڔIX3Uv(Tm&O c唭ŁGxS @}Qg[+UEsF:FdFo0{%4%8"ADڤZCT9w۶l\~Z}dF|$5lwҔG1Er*YkAdq~䢸d׼5kE_^c5 îua+|§C%H #RIgcBW]4 ۴?f,-/ %(IGZ({>˰]42[#z:mرHe\)t\j/m;xP*cs}6vJ![hԲ V Ba'DI4tbI "7~zĿ( W6&l@(H35v42DP y WXaFKfUlG]!|[킩dƴ~ UQ5ʪ>ATDrL) _h?'0}6Ѡ'߮ED),>A!aċn0zxH㜴c#0NJ!d2_;>k|LSR!ь N?`zwOW`)u".>`zS ?a3pkϨ1<5rڠd5rZ45^]jEbY~*C2\A,<3d6 !$zf} [ȅfh6ґsD#}5[2T )))Fx y~S`(y}(K>9H6O=6i#[U*cFۈxLxLxLXCAqmM$;a-MVCgɉ@]XnƗ\}m8stpop= uc^)BMUb{l>P [EZK)%i.1&zy0 -A`~nǙhʇNIn~_sfR `86FȄ䌌9/9䚡TcʗiHX1 dMe6 Í9׌Í?}{gy0~ą+՘_~7y|wiLEd 6g}8Yq5q<*)tҥ!tpkQbG^1:ܣ4r]4Vp.n8\CyRRnwHc?w"L42djl>Խk3O7Fn!uٖ^=(u<&yɸsλ(3F,CĭlOh>{r %3VebMs΢+Td"=2L#似[c?}{;^?icoP8dKM( D\ޚruzfJQ}+F+9uJ6lXiS<@ Y!Q BvRa_l@2ff#fOX}B*t\G[\!/;.D1$lRX&2ƉZ# ScKy,)lc?0yW|'oO(*U(&Îf}wX39rd`X2yZK|ԩJԙJWhwM(hc R6` wj>e,9ke}uCL\ ={us]ѥ\hAd^*ƽu{,-%UJܘAܚY%%`.˂y0!yko}7gc|\0hg[dF$Ahvt$+||,j jK2ejK7X3 ?k'w>Z'"dCU6 l@oJ9@>3<̏m'+ ]`[ҝQ)eF+T  T;TbߨttYn(Jd㰿Aڐ(։k}]¸C{t2H܀pOv0WwxMH!i<4ǔP*$+Den3ڪ_HrЙu7n!LmJ:$Z*TayN~f||f/%;N$X0A61؂7Y]Bc) XI}R=.W%^%1//xԎ LS*TMv}y*}j" &[cq{$x[ ["95a5 .`n BCZyuqĤ\0(פ^+jFm"kDs(Ǎb8@4 n0nww"Sv%LFdY:kP-ż!!j/WL[J]6ToiJR(t5)k6=̙T %bsTZ#UJE>VUz)Q}Q%ڶD\CzX>mW'r{q(fEfHF-u,PEy@p4R$\ReXnɸq1֗xz& tjIE/J{aLv]Vэp1Y b&cf刢U PV+B{>|CJ4DI4>03J0:^ghZJ 뱏;5wi#:NT j -"LIub,;apٖ>+DCL_l0nU '|GuOՑJag^TRRTJ[lTMBT$A-X5HFi.^iھ D;4&ˌ1]w0$E2$a13>Q]"ZIY9v/EO?2<1hm٦mB'}c FE8!C3<3~*{\J]3qq[$ޙ a.eGv( TM5r"=L4Hѩ- q! /;XO q=#jS)TA\.悻sq`23/P0;h$2W>TԢ`Z<0-xrǻ)<=LGż}i'fDkvEG@.t!Ӫ&}` aSKTS>_p_r_>~R U",;C)#8KFM3KCdb{<vGdc:E*6i+cJRR6nK׬4Q8@k괖Kc9ԖKSPw9*P.qP{4G5FU9R挃-RaJZԉLH+0 00<dI({lu,3}|b4cqT{X{Bt#r-eh8I#Ӝ+X} s djt N\\QvƬ?wN])B|D脹Ku e!D)P.V)kUī;ʑBS(*HAos2Ŝw)RZ%dˀ ]~=~uLR\pi]si]s?2̦#f?3vw]PflF&'l"zU Ib9fMH!rJUwlQfQB SZ*y i, tZH4kr%Q:ს6JRm]ԥ@eN% ZvGD*T5i熮b.y(NOO)"Fȸo;q4z@5m4m UW ]0r$4 MC8 N/@t[9Qۜgy+?¯D#x xyh9EʏfSZPlP%Zߠ4ԚNXDJ64.dVK4 DA!x1vKᩴPDE#Kƶ^r%z^EΗ|~Xv*k;!sheaQO)_՟W6(9)J!WW\߼߾~sz+z'+niudZ E@ȅN-$Z!L>oWWVK>OϿdtϯ"x^_P*ibŇ(P IdI'ۍ v@#otc6EkԪ<QJ*1F*Ф])b<(<АhP>Ʈd[(Vi&t;'sL7"UU:fZ?QTz9z#'-y__?W?",$B kTgWڎ3Q>2(EAK7H4HaCtZDMKTH^8d:8i*EP VMS%]є]/0Io~4͸O=^G4_mg_FFs֠58-@'s w_6GNf/)w9M:E:y|0ʈVHT`Uk:丞QHI_'$=M!UdAhBRJ42щL̴Y}DRmTjU[vKvC4)G(t-fqsC(`e E FTB,db=G}mHj / %8Ly0-Ô< LOVhiqPQ E6^$XԲr$:b<:ZCZ٪JژȢFjdFs]_xɛ#JY4T*u+ 5zF5BhjB 70@)@%U 4Tt'C2=4A u,xhW")ѓ^bV ՠY ՠ!)uQ& c5:avq(wsݑ̰N[-GzDGI(+:hBUeXX$BG14_E(XEc1&ku2( g5)LGAZ d>-V# :ш3sFRb[KhSiSJ1SJi{63H6-^7Gԥ:25b ,10J\Re8dNX6CVZMg_:4@j"Þ|̼yGUAar[8ed:szٴE:bCM,*c]Y}ـy3&u +e=M,{ωL2b/w(/CNQkFR4F帧{^{Nl@@#ġ{@(@IB Gu%X']Gh9bxxq˷zzfHflՇ1AppJBijFHvM晤{,2`͘tf ̈́ypt8n l3kmut7ĵö)ladԚLEwY.lNb8iE<AQMv8o͏N>FƮF9c剱ȑĨ]-sT+Ǹ"mcTFk#Yc|-2@+hZZj0{V>Ċ%7*+â?fQR>n*Ԧ=m\2C쑾7Ƙw%O>A7tϺ#H' QM6i}a`вmW̌1zR u_XVj1OvsG&Eq2gxi@tE9vڢD$r: =1( &Au)q>k'4?gvxk$,VŢ-F*0:GS@X#5װ0GleIor^wHˣie0*; 46yr+6e['[&'XeHA&sUd< >WPr/OU"$~d:;5 Myxʎx|8b^O(rZW[eĺM`yV@KtYJ]l6RVoJ'ۃp$.{<t JTFB52yA}].QI1c&Yۤ+tkQJ*Bny5{NmLh$MęC9TBk?Ugy]4 |ZT*:Ҝh {vf}-ҩ\ű#^zˏ޲;_0 %;.R]{]{Ʀ\UWHeMdI>0h~oby\_s~}ζ a!*Li1!.0 a]G-FW;͌ )k4eSʵ cb.2\9mG[.F)iV,$9Xp+1[#ku(|_Ki}hEK4toj!cm"R*[K^o37'|gdO#S6倻z/: ]}'d"}V1ta(NTy>a1ˏXC\yAdCr6Roe:axe_ݢ-- $P^J]Ї _yxH0+O:]7q 47GOPl!O ]Cjc L|xb5*"|LQM!=ҭ- [ě J~J2=P -O 5*2foWԺ^iF<>&;䕎f迓n[:GK3aiO[N;w-qE(Âҕ C 2dN8v_6IȻ-,PI~K`vz: ">/AZI*0#O58`LH=.{%ꔯ) 16- K-#}µ,2gjFYFYhMA_]`i{rMQAQKL-CH+Nx;r }ŇL95jv@=nV.Ϲ[qqsL_5۫.oXEWj=wLO<,O ޢ)%<ԿԿsZdk2E#u242I PQR:UR2m~Ȼ,J552)&{\Ժd~]לy=xgGǢ&e+63<3D_h˿ooiۖ??ϑ$釟+<6h'DI,#ud#SpF:> `1(Kyj8dڻco$ET+AH1Q8RPME b~w^r(䆀8a xʎIx? Z$Q2ukzcຆY $d]`1(Q -r\%qءƊK!^Tf;@*LPTRdqc:U@ZVbG m^-ےYcar[2C+DըfRU7V3 ^oQz<:l~Nj,R2E;L3EjJ0qk{:F` VvZNy:aNV;|{g,Yn$L9e`Ho4SJBe%ة8TqI5Q )C[S1UH-ֲٻ _5uQf}P5 i"FC1fJZH[qK{C :Bd j uܝ eX',emI=Sk)dS}Uhh}8'$A1CӠRTdQVs\pZ{QJ~mDsh"űt UIꊪDdIl>pHP=J/QS P;Bo|г O1! -v/fx>'[f?$ 80p$0W57o-MDӈK`4]0 猫%zŨZ1LVĚI Q6eeM$E%ùC/Q ĕMYiGIlC6>ti{[dԛW#TmI kʥBI #Uygy+~w??_knoo/I4_7ßٟ=3 ]9V#SL1pn-GsICZm˦y[e)&KmdA ZMQYm$J*lN[l'cl'ubAj3V&q_3WGrQ Qh4̙jGdr$O˷D>M䰊NhuFF^!emeYXUC倢q=b[F g 5'#~AŸ\ķtbI^0`U$At>pN }FHe !W*RdM5 NGԨ>&1Qp{r4Tc*hVN4LFzdtĕqI'3 :k`mj;ūs{a7}zUP2$St7b;# ܂ttIHy݈4WtK:y ,w=y-zΌ5Cw^qk2r-].w7C 8kbQy[FG uz%`ZnSupG-{jKmbm%L#\7ԃ= G->b??p1j1jU1dN'14tZ zZT#HRz&'s8{G-<^^qA}DLLq 5>%frJHNήۤ)֨JT1 bG!O+WZB]ڡA@d{s^St)hJ' SYpA zXV$5`k&/:3 IgԤi4梹f"JIު5bC˜> Xݥ2lC[6S$Sc_R6d:GPz$?Mhe)IC'nh$FƜ! ,z\\D7{7\ׄެeԈ5TJ; YAYT T"6KѾx8o ߚa4l5a40TYmvEpmmUѼdyQ5і9*C_bz{PeʆDѐɖX'c̮Fߐ>%dܔ t'܆̂SAG5G5k%79L'تJYF`a qZ" Z$4-g\]!kqhq_p]\p$"An(djR$I4n-[\V(yG~5WKfM+`[G)l:Qj{k%ȉeأ$ U&u9 5rM4к_G-ϗy5߼fR?Tä3nk\YiI~8M*uU ےlmpX5[r~FّzzPu}܂cW#7;|$MdZ SwcF[X#<7d!!ȠYQ ex!UP-mK! MfOW@ +l<,Ƕ<#,K%ގQ`Kߜ{ˇ)\{?=ew}Scʷ~o>g^zDzA|,Q"(2OBX`Oxx=5׾|1, IDATތ?\bO\vakÆ b4cԣY]b0`/A CB^z ˄(nQ _c>#QjfJ׿Q3w\e^˥! LDkhmY2b+LȢ@ QJ)o2ݜT6^P#KUܶǙqC3['6;q29Ma+zD]9qCG#y9 vfo5V]^2N8q& ( ,q\9ܷ+ߤPdtmyMGZѐwDAdDIdďuq['u3Ӽܣ=d6;cƓsgAÒ"^DL@b JZmNfM'[} ۷oF_{ֈ)}*P~_bZrDcbݯ!l@-:{ b{/B(J*/p=8i0{L,6Ih++ʜ29c85BDq"8H3>eȴ9d:1^7lfʐb/9x//?j# I?h)*KXl(n\q:7;d$u-nnOY &ql; sڽyϻ/Cy)=/VX16Fts C\Xl6J߅l05O(,xs%y\ԥ=adi4tG+A>Z EWE$λG9Vl}Ǡ{i!3ҧBny<<#woOL졇7X8]fʀ26:+:ƒ}ch;]+dukˀ  -š2*i@ OvХ{I۠h((yN^ҭsZł*/Y *MPRT(kSFWԣkx{Q@)Z \c7(谦!DsN5$ M_Q}go ks5L 4έ1??7& Ҡdgp'|xlVw˟ٟeɟ~kћ1 Hx"D_?n؊汗Zr!^/L/L.DIU6Zxevx7Gs Y%JIq>#/yxC_, ܧ,$V6/gk7xC._L ;,0NFDĉ:kɂCư~mZ ʳ p2 Y&50+YDpO? !VGGpYTjuTA)cHBsPn"QU⚆*CH1&)qfKo vRgG=MiOS0-P 遳5A%v=éh?mpwz MXҒV #+ņU}4>&- ű((ӟbQTĪFĩJFS6Yhw?ſ%*mO#HCK$@t,iy][d9f_ՐC}m||>߿6Jkfx_)aED80۝p;n|GW|\|#s^XxӺmWe8`-5uNbRP$2U#r !Fg&LҐu =ӂefKs~q5^ӌ4hO#<;v CXI+V(v >  Tu><?;W__[[l6~__77vMS SW*d ҹFvٛ9wn_8D}r~!Qilȝ <: _% OB D ueuBg4٪MJ@J ʈf{(yIy07,(屔@*=Pw  UM1ˎ5%=1z-+ Il,=YV#K0=i[ 2l7d#6zJEY,.%Fpe=fb:aC$/4Va?P5嘍#&rL2KA7"t30cz OoxFޗ[AqXl(iN[^qrڿt0,hEaUj55?M!P&+4]j'~a*mr,)YMnst7d_r`?c!" /j0 <rA]P7w:k^%BΜw<&?_B%'üa˦h:a5u慎4`}$~R#~?s)21c['.:,ԣwľjp6Nΐ9EheZFk5R]ٝF0vَ'x8&G|Kg^D;_dU1'g7Cy\鲐;,{QHl V}f%OνftλG3Ɣ6; ?P6dLZi8R"eW88{p= L6QǜGkz_r=΢9ī94 T#[ Ѭ-PQݥӜ|doLGh dDZJd,ŚTDD9Dk EF.>cO5$P%P$(%`$< OlBMb(!';rtʭ|J"Ju*/1䐖b$#$\" 7%eݢnbh$V4G*#R%GQsT%\8PAc EWMG'Ƿ'Luϸ|Ɵ!/+a#(8).^PIJN:e[VO۔:XD+tRjD3ͬ8UOSI+-sL1,6oOЂ?Ojw4MeMdwR-|Ϊ1ʣkbM#*6-*v>'xmy!gҘ:f%rr9MėHMqf*C ?fEIᤅ8+(?1'#&uQ~>;m-PdX=8z>= _~e\(- *Q=cIֽ %Je y?69m/i;k:qa';i^06Eªhj"2]g:wOJ|)cT5#.M^M1U" DD4 vۻFZGsGF'ƌޔr/1.NgߝodZ -9K^d! u <2״-sMl%(PI|{[3$ ʮcMUKrCz}պGQ9'k`4ǗͲt9J&эIt00uBҴPw-BA r';}w@̘w-"Z%PG2zx_D~qfo ;9I^{g4'A@@!GR;N.g ;N3yMyL'CFD¢ZWb!G|Œ{ƲJ;wpq1$8̔\/Tgw:g3.pB׮5?mnjo$pݽZY3t4kEZg⎷Vj{Fr_pfs=l2~A%t>4 KEA% P)QĮ릉}q3>q(/Nܞp8jzB\$XĚIlY[rR~~Ma nhvΆ`$wU%L!l^[s^?O◤]O/?COHFcnЊo[wKކ/2;cwx,E'9q{ϩs;-u"`+t,Ecq˂ 84psOch}__gG(aDlsI:) i(njZU(q+ ;eח"%5.:.-ֻ%x2ƭc"_Cv. ?#}هYw|n\,%74@Ⳋ,˨*BS34'CW367hOk9%g vbx9uS88Om AjRoP턚Q:)>_SjZ { ab&v:谾~aCWL"s:9O|7xwo(Ut&cucI:Ľ8wPTID kƭU(+y~<# Ec1Vj,tDqns͸p]1_ 8ěIS@d% 3zΔ=ŴK*WjԾ. ,72C,5 anlmmʎFߙ#N_)ijh=ݩva5hEB%a -bd9agX֠QP",Sdc5Qaj `* -ps[/)7*u~H:jv)Y=ڬp^gʾrÉZ*YNɞ~bkp>B.򅅥d ČgߙаY]>OX4KUq~WeYhuZW4 V%%"=(+S-(S iqxBiTJ^!eFX" ]x5܍/֥J)+hUS t d( i#̼=.Ϋ3}V27QNABAaL#[ӓ3RHPv# P)n'Bll:HEG "%*5,Њj'%T\Aq ;T#=[M&!w=6imPT*TQ̕1ܕ2do̶Cf+?_G.2QEڮ)~!L$"6IK,I#,rC.jE҃b(M+@ImfY&tEf1̷}cfj1sǖk$6  m70BEDvPu:9qdKH']Եf0ݣ;*֐Kq#P?JHkhIa4$ sH_uC>$20z08*24YF[ \r/XU-XKTQ/c~4!:zHFFfRUꙂ}:MK/$#`pCGi܀hFFH@via*u!` UcR 5UɌA~rcț+4;Gw$S !Ռ]^#<# ?Bq aG4 M*Tj]l{"W Eˋz >]ʤWxzAǍ":[R5[S֨VD?4|46s_*udMIH5RM/ lf~S֣&iXG1 C7rd*P9UQ}}e}e}B [`kWuS%uTP 0LAiLP鈕.h010&ooe}ѦQ}t֛o{st`etk68p32WsrYsq}Â[5bio,EauX\wpzb`xhxFܳǴV rS~XdX>i[Z.V4 opŖ qop99xJ[E&Yf'kbgɟyi+&b&mTe+:gnrȽ2BF=c¨@^-ET m1MGI,aV픞? ScIBd䜆 EF *`#_B[bkQ':>DUvtZ2oF1V?rc,b2!m:d=thvU]f= ۢĠFĮ*d.?aIhw|>)yM¸0a<Q(jJ7kC2Ymle@VD$%sIؒ8ąC9d6{[qH~2t {~D6iDfD$EhE'[,]BckxF!BiSOJKnT>~+e7?Z31߿{3oGyGW5<+Q4#Fφ Vm.j?h,FcTՒf8m8ϰ삺+NVƷ:>OQ{רuR9?:AI^Гsk*QS*Q)KwtnWhѶ5缮^!X|u͙qηminkclFL=Eg-oe3XfJa2t L[tY` )%0j:eReSL EVd Q!Ӗk[W9\׺CiV(^"=א*'^fY<$w-ʆNȆM J4m'hpw##a1vXȕ  xiˈy:`Y( s +ZIW Ka%/zYLc (CzEst=/># ;(yG~MxZ*%ɆBlò/D_D\K `0x_CF7D].8!eKrS_dby%"xT>arb ^&uRŪ %2e}B`N 2%Ab"`"PKQ">ukyS^ȵBQ݂C^X+2G\V -;1o67kW}n/9OG E ~SG~s2nGXNK&>qa7\O=)==u/[t7o9_#ē{acƉ{IYdvʃ1-(~yyo?q$F}ߩ8 *N ^Fx}XZ-zF ꊞp/0Xuxu/׼<' Pg =tT!jҩ e,_qϸapbo >fy>m-G0v0)$&5q;i|gwzXeg.nmMmqn(Q-hk׼ _g'l qBp4Njk-U)lb?TF^WhQE/QW0W:|[kN_U~+ GZ=vcSxlW>̾avooNEAJm!CrE^)%:D(dTNŅI:Ih%ba'~s/FeS3jtBUI_Q q/(=jS ?] t4 pyK 0fuMщbUB#gvY;l[7M MGxεDF55RPNa1rAw| 3d?d*LŒ3٥ j@G]SY q"6,ba8M|gM`E[.hl6ť梅(DY+l.\6_z/*\4࠽4iTNkh;K[{Gy|_.JiAf[$.K¹Gh]N[doLB%X 6X-0uB_r1=G41F#CwsFFhb)%{ &YɩS:,c) Wc4QO ` hkZu@[9= xN8|Ϙ1)mLM-56t-~+8(h*FP{ X^+%q)QըQsdEc^tY]nwQf*ןi֚V;F 炨@Zit9!Q]L3EsK/1 ۋwcY^ڭF P,°I2w(:UK jsʸ]/9r0hK3cP" 5hMN Y!hwєz(2J'jF_x|"4l6F'gs[zs!˂Doiw߳m;K:DM:DE})=[VyI+Z,cj'PD)%jZ@֐6&}i4ln#ʱBwoΫkd͝/W(ftXqMQ, >#,$asQ#-Qc\5H\q$.QD/4J3$#$"d]$(s\cNϞ3yeND!4DHS_ݰltXVvMFuZTafN!,A6)R[XubaQ7;3"s'CBi|:Ƕzca. E'[w;*_%-f43+z6<ԥ,u  ETu E':'zDO7vUp/ u\eȴ=ڭ#<#SFmh S-AjIORNTY|| LC&"_5po3FL0!"3t6]:3z Jhk||>Z/gXGs+kk bQyLE9a&H`h%>bý;C$=H&eOLvUUSj B \=mҴ|H^6QrܧH5W}>3OO>dW й2.̱#+43NzFk;Ρ"P}UhIJ!,~wbKapOkb@b7z֌]G@_!][Uvc|mM@3.{kZ5Ō5sqa1F UP1T&]∘vC"kipsPjeݙere3LQ)t,vZ ]F`51~ƠVv/w8@ 0٨3qWwGvUf~0rfJ_Ny~FKbb,ٯ/% uA\%r٨I=bR##sϵqьik+$~%Lk) ,P Ի5żc1=x>gru1b!dɺjmY%'OL)7՘L0 0HuQ_Phb'|a |W}DmlV\2oya3P.W 4W\ic8 %%pQi?SZ=64':O<[b+ zƓ7|_&U,>3>O(p2C HES+k-w|{e3jl.ymPHɥAXWX1n޳oݳߺgdpܯL  r<usWa VtkƓ{\WBN 0!]ӊ.vG_e"EfO2E"gwo۔1LKʀ5]⦇,sAWfM=9xv͆&೒mb( o,<:~Qzp;'\v<#<򿆟V쯝g#ΡH9連Φ*D*ҴC?ĴSr c4J4Ja k':Ί2K,r<-MuCG[UtX2瘋K CcPwU kuB9Gőe5n4@odxF5p?Psq~:=eeQS*uK`vOV ]9M3x[%\"!1-R$L u.V BꤶM`)ѳp"b˩: R*AqC7]Hn/ѕzWRM+e.kId貤X-%"; 9%j21lKCO]sszDZXEoo-݋vUD ]m$FEA. UyY&لC!w1NWfegNLRHpvIc--pJk1Z QIi8!O[~ЈÝH! -u;uSLWDJH"l6xD8di"t7+%~s8Ho:&Ymn-]DQ#t(,,ՔEPt/N,iJJEJu[PC5(HHkT)UevjT_V b2.;`;&wj9fc6=`%;hI ;9F?NJRF1:gϿgOܑUˬHWn5p,PJ +ewE[I =E3psh}SoZwbm9fy(n;:e_ aY{ϛ4߷)WQ1m?s6妇9/a%hZI JUPNJAku=#<?_+ aKnFBPd 4ښ R)9/KCrt -_Orah6ԩAa䊆ʚ=垁2e_1施j]49|_?VOC!5]{{Q 4:8T 'Gw2 #C':DV~ꢠP4ѤuO1Rp 5ʺ$شE-Ca=j2:.SD 0oUռC0iQj:iS*ѴA{[ZAwip" AĆF4YW-e'sJS4u>}q kY].Z'\(ľ肺-hk,W>и_/͌!~eГst7לQ[~yNpljImvONBMKi.1 !8jےF;[SUT˂*7(S2ձ)՚rE{K8ZҰ)N@1c߸v%f1hud1kw[%vVV#6`K\mYF&y!DKxa;n:lE](7i7:HU"=K[eetB i!ޓp gs646}@ڬ6r+yffcF8JfA_mi'M@{Њ<=۰sYJ챑YmF!#H@8D%Y0 G| _.zIأ{c1! & }jIYq~whiŮQeM-6ВihM<6S퀪U/QD( sH76>[2 zWoh%8TI*Yʆ(I YUi6Z[ iD캉nmE K*YsGs \};m̰UtDi$fm}dpwg0ۍpN#ocXo4NI* 8^<# UR"ۅE+jBYҠB_]ي'59+z]K P?&ɐ? 9= CԊW kr5{#8/_xʏ V-/ܷ\#5AAUH6KGz^׊EYԕ4~ٮ* $h(Mbץ4TΖq~&7czsNWHku4z~MO{Ko1!2FCfd݌l s ?G(yBM^j$-X-˺W>wŘ '+G1*WQ yQ11n &G+Kq:Q{rS }wVo0]Q{~i"$_bRYcz5jQcFQ%UP'iEh-6F{ʄ}už6!LVR h`2aM,3y73"3P`QU[ݽv2 ɺMJ$  c||vWmD gw'G5zozW,eӴ#+))69cMNY<'/ =Ǯ̜U*\ZJqR  ==#P[W=0_ΆDT$ٳ>30v X SuNCOy>B}ħ%ߤ.;kC3+0SڤhnLM:"Z'H`J?r^spp&nYˀ>-6hh f> `$`{proj h:ը}`#3^<{K-lm3[;G5#nkbl0qs_O%\v <w`~QbO|"rMICFȿh*O< Dm $U7I)v!H~@n@.-<=sng|yy~ëVȺѶ}ŠAkfNgI "wH }2/{L3cތh ٕL~<9>5Xrtu;-Q0 xaIj }dOecXnIoNIEA^:ŮXK!,BCTt%-kCZҷ sC9zPscf cE-kb);eE=@SVR8:4Q{hEKن  rrl͈[㜅# )KH]C)AzP"d1┑8b*S Zl]S>Ýe2%e[]30t%^ n;/8 j6zTv"aB6~qۻsm$3$ZEkMyY5 ,+{:ћCԘFeVeVCP' 3;SQ^aX5EbiE>uGVK4E;<]58*r3GD:(L+G)2Z%G{.׬;6pB{\Q6ﰏ}&U.g *(-4R;,[BGY`G)*&}Zk1R}G]ʞWDWfU;6.tY 12D3#o a:N$8c%Óqo(Od>cubB2zԍNXrTK|/4B#=ViQ~Bw+m1zkS%5UnSW !] -yXA 4]1tjà&myRЇ5ձ3 l[+"]a`臟nk Y%]m4 @nuMjߠ $:Jh ݭؗ&E%{ V [2 +sWbKHmduXfA /l&>E{aaO<ϗ[7cNd3CD50?я<9 OpYpg8{-K;E1QƊD[3 Wv{2NL' "alØm B]bfsEo`v% EaApqk)pU!IqDǠF! HSK4WwvAgYgyJ56-6ɤ $|>qņ-1 c֡J0^QqQ!4UXh![ޔ9fYqv8?fc564VMk]!hJ~IQû ~1jkx=n{{t6 2`z NBhVŰ;vƥD6jC(7rC/\;[=z(aftnQ挍fqedlwXh].QxڄyKmn8oz{,3nS%F"1 vU tf=/hΒ䨘QfPjQ @OK88"4WXeuhӳ\R1ΘŘv5즠s8_ fuÇ"YLؚVs I0u>3 aFh?nZH]yEi3`G( 3ь3펁9!rwaNJW0U'SbsI4xpss~*j>zd`At.돜~cd8MfBg ٿم!FSsҿ{)Ɇj3Dmc^1LgV%WMOK-3[vBM87L?r9@hR0h&udP&eˤlE|'YV|3}IefhGV$IO}ƧM-NNXɘ6qsb1#FℱvLA.9]5ucSj`v!4F?)REd+iHޞAМE(G/"ĥҥ@" ^CxfL8׮QaBϫ<տM'x'u M ?d46IՊIZ1A'$w c~o䳀c:WK^ gį΂0;ܪDbbC.+EU4=CPuEٷ(Uߤ[fGLrq36.]~R6@q~+¯ Q3VG6%ΗqN&: 4$I3st5v\0<1cT v)2)RgT}ft(p䜃N2[cFi&94sQٖMa+k _|n0%Є++S뜴ptGK)ђ;7؆!HOvG7jjC'o\RK8o` CĐ%nPxQv.lk *eCA#( 9 H>Yw &:"~`WᏸaWUFRLK~p>}BRdJ+XC}³oКl'bicv+cu+6igilYf4kyEaz4Q چWx%~zUbkQAx-$֋yiw!Q[Yt]^kA./='M5cI|SV_q%so.n x6ĩvOZy[̰Bo|'0J+Xc!s]6oM2ҽ]r2jCe>̼YseMi05I!F$6=/,s~e;[i|gp\::cPoIH#EiI2?`|]sY-Sf9c>wK{"^cU tq(윈1X9KWc/G##Sw, ܂W .5k:|~g=vUщ.Zf цa8B`GD0)msO<OFW|/ϘG )]}@קdGW.cwXT]̄{X|kaC HN©rV'Vm^tXri2iujfڶyuLlcfQЂ#ź11rA+,8# m̀;N#dWf `"G ƻ܏ϩmil-t[sBk254O@SPyd&ncn.ItT+6B"jB; ٽ θSg-OݞQK;R&[;fc81i#*UCP8pQ_sV(m<јb֒W)\cxp54 3 S9.x:kEd˰Ғ[DA@@!]$}ciK>s@3}"p$l0t‘[a%mִSVzAh ΘZNY,>5~xABQ[̗}funyߠE7AJdo81yeDzIϙQIk1y_%3e]k+|=!'kYMzN2MkТ=h0;%wxcFN ;4j4*4U?^ LyUCZi>Ws?RQ'9μMn䏱1vc5ݐ!htC*޳,ܘ:V-lW-ʥKq'|_|E\WIof0Ma@BC!@3!p$ypHSPl.ۥvR& M2д50mrjm,MhX&ީ= 9"{M,ɽvʃ~ʽ:cZ+bsÕ/̠Y4c92x~/ak2ޜ|ԙ@8iGg KK;,u ">g1wJr\O5ԕ}~<ǨP  h@ 1oN ۫elr֢}KۘQUX>Vɀwsnw-ι^pВ;zjG 9d=,pPU ;-6͚hS%]ҁCyLp$VV0|G{-( <c(yܺN\4\48Qk 0%}5&-|ҧ|f!zVM긌Cz朞9k- ✻ܽ@+$?_I[Nj]vJ9&8azꔇIn=Xq>w`vf`%FPԜctxXqظ&SnEI\jiPIvɪ he_[aŰ?u%w;Bv Y-Injas-MuaQw6? 0ku~C5vN)W lG/GzGGc"yƖ1w; -~O<O| 9̦"R$_y#w\xyߤ8')o.UbR.^,6ӣ>Ǽھ\>kF`8%_x,HZkQmR* ˫(KVtKٔ߻uDl!d Qt; >뼥 O\veңuz=|~J !|KyOмo忇6?W͟Ė5/G Eo{P6Ρ2<]-{L,т r ł~W-Y]fVFLC~xK?dz@KQH0 9yL"?}8b6ƒfu8 y-=ohȟZEo(qւ 7=O<Ŀ?[:o{sO|EHWQ%c%ZAv #",>X1e#u).EbS&IW\#~v{hs~ZF7&1868Nqr`PTav jˤ z(FasиYV+D~z- @<. Y{zNS b ffRNuJe+SGnp#B={~B 1 Mt8nEaaY.,^(}F݀Jwmo,k^t+Ba[hq3얳;;[ N|#b_XraXĪ+pyI(?~[%ww;jL_Vȗ5'W`XЪ Um5{T#5#|z@lEĸ _Ψ[:MӴ4Xg֏\;:ن`aJy6W(S XM!taKA/ㄾ;NK.;qsn242Fh%X]Ee%Iõh14Kvj&>EYk(hHKrMraQ&P]!7]Vu1 raW zKQMК͡%Һ9=rQț=Y2êj|2uiPLv{>Z0 {Мphk؛>W\@23L!S12 S0kE2NU-(9aYu)n6ԆAidYm&ڐ2e@C93|b=i#mjkPt ҷh:j(*ڥi[h+3#C: -ʠh UEY?VDb(lkS'[`C:|2.SaTf6)60Ӻ\s wTVn5vg-h#7]H"nW)xL|!ZlZɚf7@h ^׿`\Sb'x'~lh}`agKX"R|?8aM`.w UQ?+.%e}ZQwUP &O.evꮋ2,IvR,']dp܌Mf'!d|<N hO+ӊԑA{8st)4 aJl2*4PMʽDE~zL3y{'5qkvq:zumދ(v$G葛Qy{Zњ솯oox.$1|6Th6Vww9 ̰ R-qX\UW[X{‘{N[$rjQmMXT+نN b`X UӷYw2#إ.2'8~x"- ňWPJ.zLŐ0T7=ʿSF㢍6D9#:ob|j0>6Oe tƠ ,JߦMYvCTȶWqB[h 2qGfO -mI_PYmc5ƮƜ(^F~i3<Z@ (|BXM>ȕK2K5i RT¤0lRvZ=VE<3k>i5{N䄢q5IpҾ# -œQK:n(pUU2c}C9y[cݸVH`\׸^e(_Kf,܊sbSYdꠍ%ӨenRzu8uԍ)#D]jhD0}nKK3A3b \0FT2 j鬌c=rˁԸvJj;|21f3pDq~M$Lv~k%KaX:|vmzMma-p-; )kl&?&`0 T2TuX$x'~ +,Qoz]D >w5]$VcT8] iTZM6Y>.,Hq,']-tyh$iJs\/L̀^*^E-v #*bCMH4Ji#]kp{5V}jࣤ BğD$Z*[XS]]unoa89 #~ fUGt=oA^x uZ]+[J=ꖿRh{,-B>-(=Jag$\\qE=Mq]cNjXzQDߋ^ٷO~6At%p"ni9ϵh-fzgYyy?O>xW+h}K/w{tC[lhlP5Yc5FƳZ=&m2ёF(MИ:i{gIp9o9f9|[diM//Ҩ&şߟ֣㇆ ܠ^( ˥[(]C)TW0=^7_o ǭ %inNuăqăYP%;!qp-A76A8XaVv..x]}ߒ &kȡ2KL+ǵS<+Ag6B[;hKߝz/O'ŏ/w([jzrx'~ m*S*&݀i¢ :ԛz!C6HKL᭴jpj -cNlV(b84XK&΀HBX-F#>]c\ȩzbv|HҊ״5-kM(TEYZTIUY<ΐv1mpA5)MP{Je}k Ȭ*/,`qf}, ]gk8^=R: jy8_'9`(\ Y q-çmFޒiY*[C:?Uc3n3VوBQеIhT KDĩfLcZOw@U;oy\WMM%MDMl8D̓qg튝A v$vd1ZPvqBgj"Rgv٤JL`9x-aku0򌾻ޡvwFDr4-!Vce fTƳxf8 zz+ˈ-~6^cF+hPJwrHu0sWeea G޾c<.xV1P)P9Y9^)`ّ IDAT3<3O ?S|!ն&( JQ#G 4GB+$N4US)MA՗%%|Åĕ@i\+W\/"$:θS(Rs pedSl%-<@.j\#[A$Ѽ/i(tQ  EQ*u$#9tWj!im/7DESDTt Uaԛ2MOX}6;VO;<:[k?Z>s<~;s.4&ģ=:+&u!.ic0cʿ5)*&a_vh0RSgVz|_9~Y4Nv]/\/1'?񷲉.LkN?ԿD?1X혬\loQ%,QÒQ⬺"㟟_($/ zO7TlyRyi$62Vl.[O3.llll]v|]dAZÍ{Ƈ[>ChNѴN{t>{km>eYd.KʒcJmc˯x/%JS{\FH0q+ܻ=rb2N+ި{njq>?'XaB_Q**Re#HJ}HMHcn|7|Z3M%pc)j#oJxj]On0T(^h_hw|oG5G136朻7-=MTЏ,PUB"7UZ<3R* n9q޽Խcd,KL"ښ=U&.e?x[#MHW%g-R?0 Vb%R(uR$]<_#H#A:&Ш].d-u8"[X$3ѠoQ c_y0 O ɫ#RDž8\}'z|ҚBs3Jgyg~yb_Gq3y"4A۪Ǯ-zlycXh{Q $j&|+*PL*($v-$$/u$ԺnbTrlFFXJPYsh]_K ;HmPe ]%tī:zإ.rb,7clh5-3I Zj&ZfF5@TөMH,BWQWMɑՊFX]Vs[>$L8Ɗc:Wie{vіOL6 dn,:y/mM(ĘDAl.bQ2|CӥMJE]GiO0<2t5Gw2t3GvIabHB@ }6Mn9Ɛr" )z22¿c{N[l7D)%Aatk#RD%rY#^1ӑBĪEZ$Ş>nCz̮쐣*9f!cZVP52fh"PKD(R`7,5ؙ]ʄ옉DIc 6p"< ÿVi%*>-9999!UF5Ab%SE=zEIJy ~EPPd E(aŠ2Wt=';NFwTd(jA[3EA5rnKjs{}N/}R$p-(%TK^DeWHyC.MEtC*dN3sbcQw)G-=eC/dԥ,Q.dľD*+U)w 5vmo1߶aہM&A KpnVl3<3l~y?t2F:f-ɓh[RݗdVA712ftOvtG;~ЪrM-BM m#2nSV0w^pj6S6-ulvV kN'ƚc{bHj,WE]%zrnt/qZs:u,[ j)]p>vvQ.{u{]:;b򤎙OFT#"V<@x1K{6{\kOkx+MMBS*6mY&1XWᗻQ$j[m_=nt@7AJkc|f&a2'7̞N䊦/7z'34VNIs,r\<wLsF̝ 8au,>i7e48⤼笸㴼g1sc#\g\1^.u(mΈ[_$NhCr$Q"Rg[(nGqF9rR"5Z3sE~BÌ1IK/2/"*4)c$o9TCu-E$iyrGk0x0֘U0n5 \m靭(22S a+w}p'm'c>o G#03N?k0UŎŒSG-. &-4'r"uܭpHbʆygy/V⿰*|WtJɒjӐ>Ԥjưfښz3o? AcY"U I#tƮnp{}w>%p{2,ql?pvv;ScR%m;~c?;+yK8s~֩$psohK>P9,cI1Q2!5:,mu੍?ocsŻx z ʖ0_sr!2;<[D$!cZl>=sGGoCNkȀkiekٵ;l[)C ?n܀DZzo?;7[}Cf>e=}ˋO G+$e%*v+Ҕ)MTD6 TcFyQp> Woo{KhiS,5tŹo##Xy<QKO3qXYcnK~Rߡ_鿞-ɣ#mvl lc5Ajj"GI+DРFۍ8;%{z>ij́[hnA SԣwgY0džbinxyT;MIu-2~1>Hѯr_帧=w]pҺU˪s>qC^o3Zo=: ݷ[2 E(\إz^{gy/Vٱ:.41!hl3 9;98V2UP2EQ4*ys+<3y|f7 tjWqt:D5G}gM:=莠ƌ5g-R]-2Ug =KvS,aXz$F5+yp05 ̑X)U\ֈ?v7.ރEoLv\9ge}EBՑ0F}k=^6w=>I)..+CVqۜq\JkF8-V&jR%h84Z<#Q!W$HjJʹqk'7Rm&":&S)!3& KsZ&l&$^ R 9rcND"{bKyBG1V77e@c`rI#?h1 jG;uP]͸丕O h%ZQ m>/3Ϩ= +A~Y}̵ôS@V+T@+sԨiC1VbZ$RP'^%[$K(u- (PI F\Ej?oQ=HeKl)-qTӪ}G?uv,!=3E*QE*Q. D rQV§oovy|[G~']CU=ILy*l;lQPA?qODwE-2ĢGt- Lxe0^iF85RB>P]ͿWUZip7Vj)(CVZHoeBAHPWa^gyg~bC?_O|sGaLP0fƗI]nsaAI2P(sPBU#;:ˊ &ԺD*JhCBSJ}`-ս*uY,{CV^[$I]N%Hf3Ԭ$dmj&-}R?Z3YMD A*|]ᰦ"$7(R&e(z>JQ_He {A>\WVՈ꘦U;Zbl,KF,Kd&yGeŀ[79jLXv]`vc12+cy"XZF(ZfqMc{G:֞W0\} WX},7r]E/=v^->ZA* KeYDU;^RIpW0VxM+8j'&GӒda1$+>9WTD|jbC./=fw(=M+Kџ6zS 9)fTǜL/OL9^tAU+A0qٸ]ySgZHDBKE(z/6^XY0cGs>p5 #m&=D"b0\1Z+z(neOAZ:m6VbԠ cnb:@]qdV O%@(R.2LU3D85M TPO%jWl+ڬ!ℐ m̵vIx}=Kv4ZIjDI5#ng_޲z8qVϣl[~l;fbfFnt#)s"Sz-JϝwO;V̀ [ꞎ5ֳ1ِ).;lBŭs+jJd48~#W1?{߿5 ~[_Apy!5L7dQRi a/j= IDAT90%i0;ȯG-=E 08\D Rw6r:l5/, Y"\`7Ŗn^)}ŧV1mgޚ9RbO'USN1Éi;.6_x}MlcqCycs\(MKhvxh5lUcNc[q>2I]*I#:cg%2h^xgOwO#&o?w8ݐo|G[Aqھu3-3oX]q}Ơb^0|`Yzp&2ro7%7 ʷtnHݰ3xorst0x0ngKŠJU&񐟑I_BZy(ϸWH] sIިlhliQ {ar10cX'Yď6ɃMXڄCxP\4-jP]P ]|%"fW_--N(2ޢrUOR7#< 9E+B+D0{~<3 ._AA\ME1R:5\{hւf-Oė:OJ}bnP\ @  "{Z=Z T)5Z(%BQ({ )Lu(}g b_!aV~EJ4L)ԹDUɤ9lg,!7N0h$e d[][EJ9ҞhepDP^,y @3Kz*%B :_WZH 6jgGR {oAu#(!'ٌ&oaa56Fn*ՊG'?PEF-A#CLp=›ED% fqEºgMTseQbc@ rPS]r.JP8o ]WFlmI27<ԧ'cĤ1Uf\7\_a{LcO)6T2՟oʫ.)BwrL=vBJM½/\Tw_k7 Yb- X5-v7vtӚl' :c. KA- ] pe>)Q@[?oٕ]fLVlyD2-fLM)ESuAvxmz-g;Uf/=bCO߽Aut0co{5l?8tR`Q W|ڽkH㪾T3zƞr?Ï?9>E..IwXcf)V1bIO_|T[h VZkJ kF$챈y=E! d0i b .>)FtW1Wgҝ10)Bwe\s,'ƕ§Jn=3<b6xا:Y}v~$kdG: |"jRb>jDmaEXaL5O  ,$1,,U= h rvzrQf-[5g2+.)̓NޠKH4(䘤Y~Jj/.O$O;2.9?]1!=3bݙYTEe IlW(orR0H@n`Tor7\ǯw7%B A MM=`S N%K6Jh{:g.8kbMB"YgrU!%E)}{ťж?18^ v8+G'lY&ܵ.(Fs>FKZVhU[E -HlEk;x^o6 5d`FVmmw([=k{R*(N<IdWtL7>3r%]go埑􆡵/0̔!MR 2CF&m-N&9ʯ sR8S[!s)QP BhG>0okə,={Vz !E[PF:.B[ܤ1=[<s- #x#OJ3/tIDkq슡慴1ӆI% R#&D54$=FҐ1::TMѡ;RafT+FŚ!yG%j!mA7{ )QnK!❇9o*UG%B-=XFԠt_žk\ ,Ysɬd^YOms$2^/\<2;LDz!Q'Cd2rY%CRϣV1j`k+T͙t+Tr7da~&9٧1* yb&Fg`A;vK`PMymdqYs)f\R3,1e2n~fΊY=vv¶IV=vumPјah`“>h4bՍf'G2%](NqjjŮN;~8fOS^}='xzF:m4j/fx1lY GFc$'̏'`U:9Zl>S)\t;A#-y:)tBu8 OX >CA V\]-x-缶4χ)>40/pa`[+橕9vD:)QΙp!D2Fgygy#xXs>r~f YuCV݀M9ۘw:'>DN}W܈;;n;^w+̮aN0W5)WD]!ƊJ# ICD"h56ݗ⧔IC ~[5+ںm ڮU[:%:no?2:&nZlF=/oyH콈t!эt4tV2ԖA-qF|{o~iȽix+莀,1[c{ Bj@}tFӑ O?|us](T2cAlG}\2GMIt΢nZTwc6EOmqDJqR=7?n#:QG ('Sn_sȢ,!S.(p1TŒN@\gL92ES $A{fs|l'/wSNu/g kc>ۛK ~_?6j+[,ߝL)~m$Z3NN_t@kA$Îx~bW:D!%}[=sC~6Y Kcx2LX0ݕ~iiNJ'>n~2~GB/ ~dy xmԡ ;^ᴘbCORD?pb Kњa*~8aOo}!2kxΘSƆ }ιy<4_ t_cm&|?G~AsU{.{.~k]DO[1~j+.#R'7 A> G= FF?TdJ.3obpR>ғ;F^X#FĦ병}6ϦSH:sVս J:Zl>Z.AB7ӑ:LC-5E{4. T$AC6 k(!o:W{~OaB:T逮/VŚX[gGd JB#g/S`;_5-:3<3?.~/>u@P* Jة /϶ć1}5cz>l0cψXnG }`h/+w1 <sdž!\c"Y#Vvy!Tbctʠ Dj` RXbG^?0}H"4HƂ:t 6pCl'F;19p'#,c}ʝKw@("b&G;`#TG^0X;GtkZ&Aڄ1Sc|ڼ$S6{{R>S=容&=2'u|v  |sBZDjabz-fGZ[opԅIԩIӡC >}? "E.n'A#aayS56!w$;%`P_Qd>EOXdΕA|iuc15c|Re_c_/s=#Gç"H+^轒\͸<>RY #ܳ#0kjYErgs orήS$a|Q@k7dBCR#DK:Muq]{>06tɫ# @A+>,_%gۨLLs(Θg〉rbs?% $aĤar_ܐ;|QIiTCR.=e@m8Bqses϶sRumq ȝ!P:>'%C c#ux<j2eՍk_I:jTK\>r=r>|$SMMKWTPX.ug\M3 %δvjAa00&*Sr'#nqj3| 'cޘi9hCuHZa(LƆ햷ڷ@I 3uٶDMʠu +kBg z-*b?=3<#k #M Y_0A#M֢&B z^{b{O|K_ =/ξlRx;):Tx0Dl2{R>p-o%qsĒ Fn~* [zRp8W3.=Oј3f1T|ZxV{`-ya0Fvy(+7P6őKj`c%Yb%= Ra-u[je Պ~w2~*9rј6S,~·-uoh?Y-Gūy+Mm 0)t_D#o_ros~ V%_ǿ|7㐽{/d`o%+tq*NFٰ2uń0S*N]HH]և!t&=&()X3|;,R-$BZh٘r˚u{2="쳫4, G;FD||ߌI2gXD#y;fY}7bsL\HWsu&ofMJ[s>} Αp6Gz״׬58u0S^\W$_WR)]X/Ư=?]a5}cõ~/.x9S6 hnyY~榼%tŸ~ IDATR:m>dc+7aogygwGk\ Ρ!BD BM(N+;KК:i.`P.ۇƣ4L4k4!k*)[*iJ ٘4EEe_;6Q(pFT]AޔDETqD{W W9O|`opbs_cW5Z ڗ/]ufԘafvϠL=M9 D# ڦ̢ZW#i㝲؜") J(~ګQhAh&eSS;-`9-vT/Pa%5h-mpB6 X)`v jfaz8e%&И&] ]*Ns8`q:_*1EfH;BRFo[9][5pL+E*(;,&;Ōs1gũ+reCl>{-&$%aπL<=-b9pX}i|!:#%q#G*ߤغ[s,thDZ4M")Рĥl=ʣGY~14IC&$3|GXFMRь-֨_ZEf#bSTt]+c_a z'htHawYS ҐbS= 4Ka5~x$?x w 쪤m@jEbh ֢i~1LCQFؚS ޕ+Sv.vycڸe*eŐ 6G,ewOdf@iz44 ʢ&MAi?W3<3x_&T1Q}iZCٹKә(ѣn`=AI>2thd&#vm Ǘ>8}9V@&QѽӐKhԉ>1OYBenj i~x~Sѝe;-0IэÐ]F\ ~:_yH7?U7&ĉ 5Jy%1{t!񴜽govtIi,1ξ"xpR'ox|qA&(7 ޤ tFlukHԞX"/[?+6CQjE "7#1)txMS-%CI|^1HI[9;9q|}H! O^w'$J*Ġ;%Sd c6Vs4Q) u-#!>xcs\5-ޖ^#c^2̖C0KϘ<<#Q3Gv\1<.KFǓMk̶$+^S6;8C1h F+ K#0Y1fƬ:\ۀYl(Nϲ`-f`Z<:fQT=|69UAlnWL%/>=ɀtUǪ!t.b</49$(]C343I &l-,p,q'G8eR.rmЭuʠ[ IG%J~ ʙ3&#^b|~:R&jBzY.0AԦQUQʧc%tRC[(ABfxw7/qBg5vB*"($ .@[tFdR7չᢇu^c iPA$^řur߾j6Gс}=|I2gmt@R)L9'zzoZӀ7 +p 3Т?mEWH14(l yj[ ~Z2VŒyr9 F5ÂN$s+f‚Z0eNOla*u6&,Is9lS.mOg6ё텆h1ӭ0ìiRi.3G/Sp VBIzjEOߞ̅oY|2{~ZϬ^w + PW[*%S&}=k?9b>^kpw%ҙ=ƄV\u)남N P6BHn)JPNqlBd+{~Z,bS A4Pw:4 {sd;͘#9uP_4M~kܼ]K ͣk4ˈ͔h'3^kyc󁱵pjtjJ,Z2J0;\"W$BR? BocY^RDCk)ג<3<̏šf4ZD&aRKՐNMHڄ\G[~Pokƃ;,+OWS)ɬ8Z/I-~j dIm@::Eq~*K٠蝅AU2E:eW<,.ЕDN渱HF"UÈ-3ut6`ՌXGl}vۧ>f!8\_#nC(+Q*slS:Qcy-F0~Z8>X9#9c{KxbBH͠3uۤC%P8AAl1EŰyb, rPdxKEfH *0K8 mLu碤A ;̤1 H:{"zLFDŠ<$l(z]6s625JhF:i ,0KٵD5us. c}ߕ StF&|Vƀ{Mۧ.SngA~Ge\3퐛i=ՐY5徺ssW8z8ME[Y;Vوy5徻X3K.#MM9`f_Ѻ,dmU` ): "R)ʰis4jl`P`5v2hM[[M^2\.^=J}5ys^ϐe/yo[gpX<1u,6`mىCbJsfҮ0-͞0huV7NvY6 IbHs5&+]C>:~z,tK FD!2{([+/3ZSQ[dV5TGKXu1s9FaBǢXNKʤ4ʤl4Ejj"TBl!3&cR -h ,j|HhH:5&rBh`h0@%VHdya~|y+czl{-& %=m/@zXb)N4jtz=3<̿}~ru:tֵ)V*<-5FI>p[9&caȯثfþT# Lz-xKo! S4CtaCSMk4%fs0B!K~El UJRctA%߸1pd`P6Ym,3\Tpp41ge r;Œa<v)Qݫ>[cuvRz|=,>A9vɕϡkTk 8qq }aI'9V")Uؽo{(j)E峊#aC%⨱%& 1gGm>17, CtQ&;#fXC6g7I]u3sSP]ak17Șdu@4xGϓ7bXz#Vƀ'Z(]Jr*i0TE3<3;5~ۀ?WDvQ=k.vh45:NۙE, Ծk(욖m^O?d#}Zf>*̦5-g&sDZJ"jXxޔ{O{()h ڲ9O;=QeʜH3/ ~1~eՂ\`(k1`{8w>hb.pÂQ{k\{?Њ Qr#'/xqxɋS̠MIi'|Epkk T`F 5M'&QT?Exr\Vr9)d{ɚ d0r@V)}kŽɚ!M4i##2lra30' vܩ]jul*GPقԴXr̭eY gWoq9Ѫl=D L{=4Ś ٫xSCn]}*j\G2f}xus;,.2h.ⰢMx}063üncޒng-  sg1=}%?oG]qEܡ$a+agԧ?_4c^ "M1(-Euc>7.:Zj؞) lt47daltvjdθqkGWF@EW69htnewXՠ`lBhAXCX.w&s|MÈW%\WpU" o>bxFłp뀨e~1?k63v1֜J("m,6Є}itOPwu5 7K DXR9Q4( ;cL6x\ysѥҊCl9O!锘ܐj;=]j-)/s92\qa8"`|M[Q gI맺1+ {{?FPUIC0 Re hj*;cOluh6z*YO:=}jҡdnr93_C}[jSۧv:r\)sfUFs%ۄip"Z6.Pҟg]nen`>r^#m2szl,Fc"f%3LY" CxrCXDʚG=W|V{Cܼ0!OTA({xZLC.r >QۧטGDW ٪ R1}>^%;f;R@ZK&9ѕɔMe(U)]kFҋg83Ym*OXf#l:Csc IDATB.S31FcP|i|L*j$`?7cv 5I0".1t3:C5qdSnv_t:P([|t?C۹S,QոŲ$\.f椡&ւX+bmk1P}~2 >KѦPӤ||ռgMvz@5~+,"؋Ȼ#-5/Psk4zgy晟?_gZ`Z#5fP`1 /әKsλeZ`Y[3)G-3ip~AueBu3jbr; G<+c߾g`Ͱ휶bǾgEᘔʤ-V J:z],M) m \ DRvѲE*å4,rӠH%DP '+^9;\V,]'D4،:l&~l+Vwk<ٚO1qww=937o;n;o'-]M‹AX?h">  ;}Ǜwb2^N38Y/K:'hU+3|B\ xL1:ޔޜ5a43*:S\{\\= k5~ՌS&$ xsp{GyLxUB'\2=r8FQ=5UBP[WǸFej0dKB[HLY"m石[73pol sUV%m㯴 } y7rѦ)R! m͐H4M3{~ٲGwwNgg= ]]5iKg|;6s:tïL޲۝`*>OƀV47ks^hagy+^gqppO+0 6 oQab:GF )ߍύEg}j뀘CXuS8ue"d?zkFG VNͨA2h3sߜscdW}:\ywiBv8ZkEImK J|/E.s!pu}m&sqHll KbA1{`?2< < YDIHd86~<3|? .`mTfҨje؍J~ 6ef3]V q冑+?Rv3#o;̺JiE[-=ëzs:ފ\+ (,VlGHDl-L.PU@kAPA5Vgxm矍?>^a VI1 ]VmB]tJ굤%Mox/_y\;;RvUE̡w\̎n+ezʑuۋ{Fzh>|[|-2eJ@G )/[^ȰJ􃤾y/bA۹S֘V'V i ?҄ ' ?mvM2lsRlmցfȮ 1>xo><=b~g~gͥOWMc'ݏ|^#bMl<1+#\ z^wsrno͇ c>E+]6}' ϛܟ3|X}qwE_O6$V_^Ꞷ\Kr aMԍsK_)VQ"R@&1tvV^w:\͙:r:{-iMܒDaJxkNSؒBc_lKlx#.n.7>Gv_Gr;]]rS소^>)GGg,d2`H3<3gk'{ "D; aea2*G/ UM$$ٵRS<%<ɣ^P n['|¢LP&ڣhYTm 횤h2UhT Y`0Թu4Kzpjv$i;h~NpMa~)xC~X%hs~Ig"#V[|<{MyȤGj@bh_7425HMrHMڕ4FҔk\RVJXmVuH< 3\=(& B񆽯nȮFuj*SC`xMu &]fFaftXMaP խukVIA;&Hɶ#~d7zXWN@(VΠ;r `9n719NQiCɂ7u-)[dfkdW#6, +Um"l Wh\9&WSg&hy-f'1%كMh=ڤM%qt\B$\KBw}k 3R%{K[dZ2D#Yz`3Mp/#.L,&"_'L!R4VlkS0Bjvъiw uaVM6Ej(jgyg?5~{{7l4iht 1nSWgumQO') cZUa%fuY%5l~L9lM7a3`m^VX{#KV'&u_R$+X&S5.rnԱqs&yoާW#:d2ktFAI6$bMFJKdrejJ%I D9D2`E&k\64YowШXspsjrbAn=hl#E{{, 5Ft l)ִ\AC9.aɖ6V]oLkܰ׸a=b RP "n4w^MDHrm=Cݐ$>~d3{$:$˓wKv^@J9^ޢ wP_R2ۦ H6UAbW8˘3״%ҩw  ZڷmZlpꀸ&t&bă3dA'mX=17u1i1{bE=40>(,663 .c. }ǁ:qmVKL",01pIc6+ռzdh^[h")R h7Ь["eSqb3}ba}!* q@7*$o<3<3gm_/ LYO  ?ZT鶀4: Iы5b&$]bf>s9j A~DkH֠V Oj-U}>oC[PߎhX\mܪi$ EBswosvsQ I v_y9s8:ht=.o_ryw1瑏$*F_* H1F1iKs~WߠҊU^A5֘YI`Eh_Nl#fk̃=Mpi`c93a#8"Q IFzi''k F4HUcȒɰMưfEXS ICbВL$%>+Zl0)hbjEikQi}B`DÝZ4a 5~vרQEZ:?IUK,&˄i+Q|![3eRl K)SG~1oֿWo_yG~e֏-Ab%ƺX6!w;,m򩅙ńG6cp=;ܳ%<0 E%A3"؍h!/'Bd*<ˤIDv@eH,+EʊǤ3)LcRL*i@gj$Ic pG/ _7UTKZ BaTx* ɨ<Ʋ[u)%Ea`xb'UPy5|Oo[g-ڷіE 6sSs[HKf 3-V~=Z.z\ގ~ǘꦴOR6k4if1.?8n3{X߳o\r79rڸD8ǜq̓at)n +ʠ򡢚Ti E %n@~A6оI*fyao5L0h9enS6EpЩu<3<ߋ3p VV 2(HikR"35 4ҨQf4J))3A>1CWIJӞ |'}W'\xvD3[tV4%fhl5o %qm||!%cS CxyB7>bl9rS|wE$f"T ЙBG =(QaDFQаִ}0d9`ftY R&%Lg-UNʐr\rԼsq\ZEK kϑvE+XT-VFڦ#BU5FU2l<´"ex2E:%:CMT-$ۢk+ ENU+t)!OQ^^ib3}LUQH a 5div+YPvبB:a5a-+,K2lc?hے{c;$MHh7xNB_rydbRl#c욷Vl"*ȁ\6jES#uSQU[R$n58FFQǣropi%;Y( UTȢBʊdtA M{Լ86N9rC,F9Ld¨`[)0(PJs$TI[.i.)*ZP!)0ɅVTh[@%ȅMT4(#E\LQftz ,(&Kí&rp>~V+fU-1k*u&Ȗ%bM6-qņ-;[vwXv}>}>pr4>btЉ0:S6 -]2סY4!':7ć-6yT*R)X/ne̴?V/~˰{)8h \% ;i-gtkҰ#+ts6!O1n6g/y 3:,=k (5T%z%)sl#A2ig :֌΂vwAH.u`4NHBh%0)0eP (JYu=u6)&QyN4NQОp0# ܐhl13{D^=̱Dq^5j\|zEBc`Q#m/-ƇE.$JPZ$k2yԉi\2Κ?E*S"JJC9TR>)&kdg|ۓ+> wQ]‡Ub0TLm~lb^ aOl"٠IBQyXO|_;F9?=&وalV,ܦmj/̖6.#Il6eZBS7 VL 0$SJ <5~憆h|2Qw IDAT~^q_\Q&7oޤ⎗_症SZX܄L<~w/?~Ez|꯼}Wsтy2MR$O$qy^`|(1? TBȃ_c6rL/ŲS,S HIAD :8lp>% {={=B?`!, Vq] " ]y+ϱTkE6B7%-4&F "gcos~|^g۩]"v~1&A O?HԺ5G{gtnYmE阘rֻ52 ƔӧHħM8y/o6>'M;4yxj5q~yǠ5%ު2$eCQjIiH!0+/3UU=S&u,Og=ZZ"e,8/9/9.\vxCF4c/{ɲ^lfs1<#"ʬ*|[AZH%ԈZCXX 5* =u?L2#2ffvթhDQ?fWn~e"*C2Eb-8,h!M@JN)Q%&6"LE R (;L8>=B\Ki .}ҞK"6)wDp+D@NNAْ)Le3QA1op9h %. .ʥ-#֘>B.0N~r-/f??c4q=~~7|?o_e~7Qq)m?s8ɤw$Щ*kTQSM!0Ĕ"/;/3E@h(H=g $!V4Ɯnck7BH+*e(.q1 (^JPɦD&HJZeiE-gpwޜݽ+p"@*ZL6[.&(uC@hFdH͒"sl\nv$R(eE5_#j*R"U)Q"BU#5bX!5(R2.#':Jcb~h//2/.>Q)Cu2 {{XbǸTDMs4!C +,L#+DʅBy BdJUX(=ʣUϑFc"S6%`%FcV1jI/ɮ/Jj)A`7Y^,A 5:BQ E"@jBjdD*DHTB*YC4+,+gL)Mʄ(M DF +U4rE@6#`4aL:(r5h+l5Ч)v%\sxŻGlۗ̌SLh#Uu -.]j*jF rA©p"b!#Z5f+6W$D t5ƒ7 "&uT"CEd S٭._)&1KB'ɊlAqBS6d lWӖ qaGJ*TDJ[%meAw:z|/mX`M YX$HdԀVhFjQPԏ@)$Jh$JIU4Me~9qbiS5Z!Rڒ45ū\]B&1lhjл5r]%M@mUJ[P2B)k*^lFh/ڄNui0Uhȹe85\6~2H L*P2!9zщv [WT@8L rd: m pT':@Y F(:ZhV Vl lV(ui1BL> W!e#.\qW)!kRIóܭ9 wo ,. Bl[ dTD0H&ܠET56t+ÑC˱|`9iE){'zDٖ9c1ao7XTM$'csA"I#w" *M{ǔ(BfSBc -1!;w=2ƭָZS#4O K d lPĂs>/#B7-,ZŬ#V9*^Jی!#oz?v6 sh@)dE,&?Ikb,p* :95$AOREL9*_X3Q{>afH^iB A |na';\8\:F#jQ6Ef_wr_Nz)QBsn!K9sPsWyM,LӲϴ+ڜO+\r}9d|Mp0,B,uhO0 0Zqi`YY-u{oo|4t~y>zku_)W"eT:e]f译)Q5y E*&f^!ѼxEkMŏT\HԂL)(TiDTYiDG9ovM˨Kf [\\wJ=K(f;%{9UKeMll'l猦;M+ꉅ7k'hxT3eL0 mcg<{yHwgAow1+˄m{LF;(fXl,q]9ndS\]q|q1 zք6ST 4JT T D[@^8ic#v+޶N#+2E/6JPI. / .F\h;\\Z;\jCRY#SrE&:jv9bfvMټ?$A1UX'.Z ^#Qc|V>)|r{Kʧ|)f#EJIE^L.߿ .B]"%BcPSp(sÕI@9;#NW¾(\VHg2JOh,L(25L%m K$3`AHEfgg&O||?}oΗo2p9:WS[iJ1kNpfSCsȂlqCCNLJDW_p?Dۊ9^sT­|%}V@+9*/c,b|sM~hin*})G'ggYmrZ/8{ MO9S'|9EܡDVe{7,eHCtnjKMO9[@)R-E$(Ü0Ü;3W/O9_3ԵȪn񺺇dh{NHsoJdKx ~F'>mBk|X[6c{6L;g98{ObV6iW<9~m o{AF؜]_XŔr/9WP2sb+b*o6^]1~* Hj **K(s3J0a /eY/4Üǘ%fQ2u⤄AF-s*Qnc1#j@H%3(w ws 1b!Yå%ʛ #$1))eutp+6)uuӛzȑ' HR˴z>MʈYRfU]䚂NP .7ٍ2_aTvduDuq6.Hb[Kz, Z.Oķ8JAUbJdrITHr+ȗ(:ŵV]i="+@' ք`e u'[!i;c"Ťۚ!  PKP5ʆ@]Q>QaZ \ &nn3'G,]rբN{|9PpӳMa SffwݛC j"* k%,Xm:hF҈ш#61„vt>bڳ9^X!T-rEgWT}fS裵cM v7EU1jɿsk1UY# ~\<zpEHA7e*@,.WG.,%vlebwf=fyFfq~!uICDT vd\ۼq(ɑ(Hk1.d|Sꛝ!jjj7c\<(kO㇌-b͠%Bf&v(q>SPYSt~uBѕW=VMTiB'UM(*xd(9|Qi$TmªMKuRkutOkr2^n,m@bxn Q542S!-R@k2Qc\l*+%+vpLǙ2t/E_~ARj.}ҧ*6c(zS&j0QTr$-w R3GnfByĩI웬›x+IHyZU]dNPrD)+H UǴP1e5oy= 7 MfҐ(*E${ Ff[ `n3wBY$Jmqs>}߶"xb.I7`j 9!V .],;Dؘ ,5b{v璝qy2d˓mƗ{s{sVtXL.E0;,f=>J)RcWތ?2~ 3TfvJ$:)RMNI Z'khEFK[1u_7; w8NcUZ)}k®=oM8p|*FMչm:IVYA;P9PO Qr4:BnTURYl1~Ytmb;_o ikv+_ |Q1E>dTl#ʛ%i-gPE G$G lJ0Pw`ADBE*D-mGM3irn[epsok:E%63!D7ILMg&͘W(oȔ-qcUZĹpcRҺ&TVƨ={9uk(a%5X.I r* 䎀ڗ%'8#}ٴlcw)% ER̈)şԔx-r-?Q~j??}_OO=[_W?w)n<<k ?̱w_8(K@)d~AX(WiP ,g(\Px#>aO8gY7Y՛0EƊ@%xQ-r"5f~#~p~pJMdkK d.Gg' ''pizjlvS(/R"R^}g]@.-{LWO}_yc޼}7ܽϳ6#VZ@I]Azc9)Zw ,b8_K)*3O-Nm2×Ny9ϋ=͈ IDAT!Ͻ7y~Ԥ$D$D%lL4)s1?l}pE/\p`0a~_}Wg?>+N{{hlk6l#R<S!LZ΂ک:mR"u(R"B- +%6.WW]zŒ;H2S~Eu(qXVw֚ֈGηwqv}݊pbQ#\J۬jQy~ 2_~{H/? [n[nS~rɯ7}k_cX/kL.? R Fr_r S) EE(SX-QdS@INZ Q rA!4MB$-RY@kd@ _!fAk4Gi$@tU^rL&ma6}RHԗ1LdjIi,& pYaIP-Mfa ;a&Q`B ^)RDned-DwŬK0)2L*.`\uN,(Vt)d-c3)LlV]d_OœzU H@I 2nɘY@Rj\D;|~%y>~lpm!%%NsM^y[[+̚ ,N'STJ? s C sL&t 4# 34#Ɣfct9{;,EGןR%.]jh ,y* }(4)% I.1Ud4D4PUP\k-|!5Dl5ĪBl1VB:s;.-f.hV\ۼq,8I]bPSpUR*a8Ii$>J\0z29;x&U%b ?8l{+ix:1T-m vE+xU2USwOJQQHE _M>n9jV9u)RD2B!$kb]ҧ/SF6b>EEC5g}>7͢0S ( 0: b!nTfy`&iS:Ƽz![u.b7|F8+W#W;%T.Kv¨U^ :2j-rȧ:[Y!f eu@ڢk^+1wK"!꼜c<PNe.;\wrQГ'Oؿ{9r3Cvs+'"֨ZP; >S,]RFJZ9~®{!  "亠7 (`/;!u2Yw1K&Kb1 aSD|W=^wgykf+2f@(+ ++\Lum3lrÍL&M.m`e8FYyOPٛMv՛ (Xm^ t_iJܥi.i W  ^B0j0m>u%nhEsZ^ fY- kR)R1YJ.cǹMTj4 r3t*] NZh9I4{x.ޡK,n]`Xc>S ѡEZDCpfH_1uF+exQ˔D̡efĢ8i#>C܇%%VGdOP*Q+e}KMa6L1BjY`U7R"-Lq5rNK! acs'8wIVOBzέ[n)nVN?[1yJǜ)&u,3>^4nCHGliF$X”tɑrőzI\8S_& 56~5t2A'Sub`90:#?{HdAFgԁ; Cv9{s.vYeAA2L-m(lhl{4mg2ZY>oz& [!jGD 47[":%5J~!SH|]+ г11~7s|;M6'Xlt@945oOx~rL>s]ġ ]d"Ba9FE61d~69tWLLdF ~V']^]w GQ =&LZS"(Q*`L <ʛR^b]Cter1 z<Г1Ncv:||6_?<~0[!5q5 ɣ!) ߶JuS&2Y(ԖJ[IrHgj^1T& ( 8l+FJJKRnKRrYw9)Bm𔐡5EEdAlSb^bF/<7\;.ql%qn3NX^'8lim G(b/)nq}9)Y.UI0oB8S6E.-.hpފΘp RAd5zcg֎x{gVhq`ShS9ѩJM(4BhSaM#qf "!]Bc/.)mIїT=,<ڀʠʡ.Yqmvh䨔hhHB8 81(ԕ@">A4ÚuK cMBZX}}@Nb%rD9j#4mVB[Vhn)mQ)Q,V*ӂr1`)eLkdX#6 R#] K2Ci7JN%?h䩠l""LdYO<OFbG'%R]-mcq=rUALǂ5dddD2^yŽrA(PXVJ"¬2+=B_G5[.[.l3;?e|s8f m0]B® Bc7dq\.۔{74;R$Lҏ"hApj*))#I}/h>j@ ^~RkF 䖓#S^pܽ3ҙpL89Yh;J)ΦQ )Ԡ*RLZTaAEXdE,;b)b+1q+x2[e8u_mmKYWws(g}2;NdYyrទ2aTL{%\t%C{H2z+4k~ˉӄW5B+ ѩH-L1P_n1@ۢi*p-gP^4\w\w\hV ؘ-Jm>b#fq.$bUYyʹetY:,[]<5+sDB,c>~ݬ62B ?'xKrS~Ἴܺ|x*JQ=>!>Z@-X>73s}UnL|3K(MotyD("x}Vw}wE\rF^IVheI^sq2Smкcq˜ℭ"97 5; *@rla22wNAowwruJ鳔}pFΔ 2CK QTPVDPJ\_**lXkQS[ZIɎ]p`<;%v{ A8AMvhvIU.+ڬAP"I9]21ҦZF!$MBw!evY^hVA97Dw ,چ_rE/5gbLuPiuYRMCqF.HP;aLؖ>vⱽUNA8 BM]CO<O]@zĘ` N`baZr?//5C̾&Ot|mϥg$8Z̅@1Ki;5W sNx2DSR ! 1 EDQ.P UZjTr.3*Ư5?|oAŵsɭqɍr+D":ԁ%؆j̱ _M7K{W wq:{Bj39<<,,0I40IՏ}_r  r*S!-m"lZ {̫{~|Cj7|k6!1ubGg #8{.7ߎx%ա²R>oqD oB8<ܟۜݏJ_x5KFkN;[δ1#gbL;=&A]VT3Mlz9؂ݙ3^ г!t;8Q=@W 9O<OOgk45vhvcDj*J VYȼA%"֠6@s32U QPԕJS4ZG Ղd-6*/-N:`\rjMyf?}{Ťz[%JPV*E&qcS JW%n}TBu8 1űR$-r#YeM]ES4(uPv5\?(N@|{> owgxa/c]N^svu;v?X]feYQRZP|_S+**Q?mV*Ԡ K{4@IJRD5^B!(V&(nMn^cftKuSljilLܤKwѸ)}}Ț"*|ci'_"mj)P_4(1]HYlPe)Rl=\h(@65jS5zc4ZS%1dt{+jyzϳOw|VGBiJaК5,QYTȪFT5e( 5C8 $]}e њS|^|SZ$ES2056juѡ)u$Bz/Qn1gH?Lw$+ \P*UGjV*;EVH"o;}fvK=Ci )s>pP ma/ 6w]^RL/Ęq.N5Q6}\\2[EGqʄ!+,KmAa F祜g\y* }N]8) IDATnP VtA[ !`CPm ,G9hX6FBrP+ġB5hU 18ncVΟ='Y$dg! 12EB#e[wr#>V s(5"&TVl* 76Ce'r\4TۣvUAŖdog:%*IeN=Ne~Y(%_z{4CAA1k'U r\did!M )cW[ՠ[5Yi8 )NO<O;Ίkn6W'ex{ kNjz[f;5]#:u!ChC@9&XcN XuY}K3BC9cĔ8uH8v$=\5FftW=(dx^ݱ[!ۄ9a~y9".2@<ѮRT@1+Py8`0IO'L!͐〩=DUʎby:g8&Qlbi3%-%cdUPkZԚ&$E+1kZ1-cOl )jL5'#<7r#{TQ#{df:¼?c;BMldAWBP Vo*xÐ~oI_ӲvxM:obTh5RY+95$;ncEŋޒ_0U)5b,$Yv~+ :]#J媺*VV!n+Fepaأ 0=3u§ E)khԂC,$B';Ds|jPAh '9`AW]<G&vCnl.Y23۬[iM)?ّ=E)nPu[" !BW9_PJ U{,f It(=~}{ t͑iEw>^s8JLVLgmw-6- t-]sKGۢ;O<OòcQX%YRjgާ,k63F)4; yZ"KeʵJ5ը*bo-AG.Kϝ~ţ~JO]WIztl!h;)qvG\;ҡ1`#Ymf9sƓsc5Z+E9RQS5 I//6"qW N GYm6Za#˂A9kB%͠vߡK}%iMqݘۓ Bet䚁V:, OȪ'Ĕ9)p𘝟P+ŖZbK_@9ԱBөw w:ID%~O{c[1#/ߐ&==(+O^mr2|19g5/z\׈ACrwb%.Ġث+Iv0rB*-&J4[5`y]O|1dlx'<',>KaУ 06-xIϣHsf.)~0H~p*U9Vy*7xCNN\\7LgWw;nPt,.9U%9&31QG6tI,)6Q$bXc&tNtOtOmR m?r>r~LJMTdNN0qN;'Lftcn-v$y4&1&ob!g˅yǕz$܋-p{=O3猗gL;cwh)UVdȢ*$ij2S>N%M&/,.+6#f͈i3"m 4 tQe1C@@%-yQe @=(q2= W9[t5#;2Bb 팪D+\^XQ)zgt[w :\WEV;Pb+T{jQhTU~g[\C[wƽƎ.aDFC䐹:O}a V…6M#di٢$\#{opFW85b)f}݇b&!Cc S3Ac)-mZSQ t+"}yfjHD#.бs;Wg3~U\s#D_z|5ө 9sNzW>_}>(/e .G>?>@бBε)pE#Ox'x?HrtLw;h2A5 |ւuCX3=sIiُ1mA.4D%O2S4\JtWDaf:{#sMl7xޢYt ~?!c^%5*U嶾b_^2Y0Y0^X݀M \AH)3&$ao4a>xz)Fj-z CͱɀS jKX?UJEA65ZU%jUBZQUX U a,ҾJk0GIz"zL Ak,CZ]h`Ȱ H6b-ꪁFKrMq~|`8#&œ&L'LL'̶'ў^6[Y"Z1PIhOZLJrggԧ57 )ϸYyónx,}'4]l#1Bf( cod9Ȳ9(6 I<`)oИ0՜n%J]NseW~kCZ$EZIgB^:ުo:mզr#LTY$!JP J*4Bɂ yANo ]ȷ }czLCe礆VR4Łn,Ҏ=W3.]e'EʎJfXꆞ@A[h}QBg2x7hQ%b}b q=zl.eqέ]>H 甯_8:TXD}a>u]ݝJ~#%'P풶ВkvS|^7+>QEt%+y*2.O_p9n{B1Griw,5 eS9*oJWPZU#[5 66nMhjW-=mI1̹U{|മ9|W$ctDc5LSr4hҮK;r9HCv-P(Gx6. $XۄM|Ϲu=O< ˀ}Ej./9;AjHk{o1G1@J9C2rtVVta?41E̎іxQefAonKP'ʠBKae%T;\/}w՛,x.p !L8AFR5 Q>s\{߻?߻ .6|v{n6:ERGDXr` sN1'Θɒ2)ZP?VUDdNiǙHs2HsKG4>|"OKKY]ViSKZ׉h zy4}-&M;c*iPq>v. +]p?eB6oGўX}!5cVVUhZM<3L|6&WרzG9+5!(D uY<.CcvZLCt#a YKG3.Q$S5R]A;ܩ3pv ufBrKa$h# Gu27<+nyVp>ilUO#%咵zZ6e[h]ATk8<])߅s~vf[Mk P@sdN,&1kpNCl8jVf.sn$+  9[FƌMb}0G&C!KrAR+`_lf.gK:͂ 0nC?JNK~ \I*!&#D"BFbᲨ,>2Q?6@ _lk]#IHTGGSxU}O& 43Wdq4~yki}%vUh4u4Q;˰;IyX0@TQUH -B[!k_%vs*ǜ*cN1Bs4@ İ@U1 $!]X,!ҮN;sO<O4q:Vą823vd!thmQbRxȐg]X9;xJӈpo!&⧽u)Cfhu5k6҃K-`^¾$ Vyꄖ3/ᦤHV+&J嘆*䂙,-tsymmQ5EuI f`1jGH Uget:֐C6$OzKxAZB5؉6)YxPT)Si aLLs~zϠ^P;]8zG\cΘi!)MӀ F&)61M".Zfb20Om;L3CHW>U*h/#Wڐ{IQ(x{*pPۈf#ح zrX]3o״ Y7.VbabSqW2^CfcP A, fd]:L#{kv0 IDATU+N͜g תXmVID:Fif< ?b ۆ4Ϸ_p ʃ|sǩ䴾UɤJ`yЇ\|d&)vz+(v#,-c}a}& .j@e)l>TȥIXdt5ceJ;\cG "J*,%e[UVhzM(\hj̟By. pG*(c7>ӎA V}>:Yem[,:U!:j pI~鳹Y߷^{y# OO#nKX;z¶ARHAu;oT):  :ШTRQq8`D`*9G<|d?̿6pMX{H\19ؖ+>]?cGL#6\<%_LGL-gK N +*Л jT)& FgR&mxy"Ғa1U7g\9|T`S*q堟VX ׉h BxVP}jt}nբ:P mv77<]dp fuȬj1[l4+O@ԴO5 ,jy,{>]oxJ|mǩ5̛rcȂb0لLS1qiC@T@A!d(:Q(ԋdQR+EzGΑfHjg.imREize٣#V(Tj**pcrߚ |8k>pn\|`UyFL!zn"^x+z50 "tIȯLEщ{'ȻVJʧYs^1n U'{Σ{Gyʯ5ԕF[MhqEU82Ŭ3DMte<}۫!u?h^Eyy|On{8(By,hM#^X+j2q嘊tTڿU~^dD?f-;kkaE$Cb9lņSFL]7-{6m$AcI wGik|i9gOx4Iyu똕aiuIR{x-TB j|NGp(!~m1֨֘[ƭ{O|OQ׈Aī:ū}AndAf$MܵVA'__nl}s[~s )N)ܔ=y:kP5b!):֠{Fk޻aUk$Ceq1g[NXκIZuШ@$Z#1dCbs5/j:LE)5`z`ɌIpW?p^_+~ŏ~KpLVZR-K< _~=/~Ƈ/XI7a~>yHLOA-kb[~1~@jyPuI1،h"-bX,(rԾb`M1u2Ijw3|;-xzHRZ:em ucHѡh zHUt2NF7n-yTxGq񔻭TM>ɽGUO1׈z-_{>.4`\tNw|[s~圇ȍ 1h)ʉjh#NċO5O jEU;[ECj.(UkBEq7X$Tdku؄mq* V ?yS#cRZ 1dcGx=Biy)($҉&a=v^jȩeN%'WL~{MY״5m}.Jٙ&{#<#G|%XNk%xVtJvVunvH: :,=S4gZ||d:`9BS*3nUhRdUNv! UX^TS"VI/ Ȅx ڱ1lF2 RJiPb" {B'WIBkę-oWpFCq OFPK\CO5DC!]( &P7WVQwʙrGā}gl /6HrKgnIJ &Z$ޓ̰-8-:RTAl?mר0R]FN (`33:P[T X!N<ا)T"=Gp>f5n?5ҁ*# Yq6cjT#3A"JtƠCJjm"iD44J șHl;#%32{ƣ;̤ T@c`fK~3L0 -o],S@dXM%_!AAnlOؓ}#e[>Q֔R 5GRV:aiܗG\r^ S"]P> PEڮP,7ޞqoʹ\*M'UD%vrWD  5?.@Qkh@ A*U&Ea&j,i;[*{'!֝C jeCSJrߡlMPNJf>ۄL0tCkĞwɻ!LLkb f.vuaA=bnTdR5) S O."@ko.KEB(UIAUE4QуAt@``ȚNwA({|;pk^D~h,:t5!I}OgZ0)V/ L?0n)(FU4htAm44UMe4yY˜†b`O Ĝ XJ7yGy?ʯh MvS57M#mAna܅ƺa[Y€)C˄ <]ˣێ QqE\ܬBV2;c&ԎzaV T(5|N)nXCV65hu7m眹ayu/X6f-CֲMfJZa~7d [L}cH F9=xN?1q˳';~F#\OڜmjUxvOSd)}ʒÒ3zTG4X6zeu ݟ:Z?Zpc oz^4dsb}"7LAJaz<̫/5-vפ;E(%avx,{F\;L˳>LuM}QS9^qڽwIobblȺ5dt l{}@.PGw(#u7Zidg{ )Ն:RaZے'xj|bx@dK_<Ûsnc.32ѱ~8ߛ?a277-ʮAz b 8aNQf(ꜤY ugu[Rĕ;#<#Wk!/!x% _o3n:|z;7'DG8 ! Pgp~BѨdNjT72jP]Xt"%{3(2#2sٽ`A[RmRe)\>pl,7S6ɡtQjTRZ`T9FU`9^ED|0`vrq݆k家ɚcL,6 :B\Sf>酅`Y9Aufܻs:O+zCjԮJԮBrcsy{CKڃ5xNϜ:k-`G<+lV_)hrwf1n1niyBkgXUXۂ8%EX>Ra3G<0bY]MШ 4R!-2"Im vIT2 ~1~Uzw0~Za9]ugK)EW#-P5jR56.屎7'IvZ&ΫpMжVF+%vp].N67:l@ `e F{W8WTBe_q##AkdžnBnn\Oϸy8W^w ͧƔ,djqe@u+Ml?51&XIƧ-Hua21(张4|fR(-bR0Pvşhj3_s_Փ˟8;re [!i3ړDAw-+n8 :ǬW.J:ᡁkSF77/Q(D/^9.ۨ>R2i~9ٳ<{aJb;T~#BҎCt*5b'цv?DnDwQTIRgmɀibHP]P*Z①گx|GyzeADj\!lXc>=0 cy 1aΤь g{'ad8j^VVԴG =( BKpW*P*f&iCܓ$CR)6GY-ٚ0]s +tB+!Yip0?}CnH00L9}v=HgZ$ǮF-+$JATAnT~ю$Mx}.s5dԢH lo=#< ^YG I3h0記(蠘ච@OtK l I&-c&!_,5# aoD3KtD3K4֩ntk21 4@N Kmuؼlq}:!" tn#"P <90HpP@JY\tPtg9jk;at 8mӧR\t (nh5f[eXeUeV;`GޓHtj,6h*r`jwTs(E5gt%}ժruX`EIxYR5شBm6v6i frPVMβKZ;e27[kkGxaqLq.nAQi9bw4;.uww{[κ75-GQ=1G)dNɌîvt;;ly8r1z3f*Ѩb*0^gh؝N{( WjL0 :Cm/IpQg(eTJ6%{}g8+ȩ:A}Sޚ[9MVU%VP+; -?(X JCxAn8\rҿĺf"oq􌁳Yxɢ19|č3[sqah8c_{lQ (o)dNS)N;sowfXByi>JKb FTLd+lGwMw7t%!tS滅2uL!sGdl6sOؠk]?T걎:r0)CY1y^J) LDz.qp@tA'*ض6vv0qp.BzEc < }򝉲i 6LkN  m-lݍͧ1x>i>^'ճ7=ճ]i#uKQ1Ay-/w(q>PX--i鈋)q񌏫s>-Ι/4+nsDyӕ-Cf;8f}%h_lIn=V Mh8UWՏM7&{|#pvnJ2YgmVYu֦rRs#@T˚UnM,߄Xi}uԹĹľ椹fɜ !vrr:[!0$ ]֎3/G?(a1W1˦CG IDATבk\!{'(M"`&cwxk(V1&*\$WyR]ؔDx;Ơ`p˳mGyGʍ)WTP PC0CÉ߉ρ{XV[I4Woٗyn0]1:"W z jp[W9jAђhv^|1y ͹ڦJR^>?dHlxQj:zSV3h覍cL1</xPw(6$đ:%]f()HiwCl;a=ioHWX`z,ݬ ZBS 26PI] FM-R˧b:yR{ЛB¥D\~-<[ *ﳺGzm.} a5( mmuéyo-nnߟookzx\w~6;9Es?ÈY3D- 4D * Ԡt&n9 nx9/@'I7t hCd:l€u|[g|?}=guCH bқq *TVktb4|`TLt: 'kcF۳s>=47Am7^eeyեZj0R+?N>6sqɥH <ނOڀT)s  ={c6Kt7v>v>a;+{[,=#,VEK2+Ax 1.9n OC`)9uy(Q JAv5'55up+"ܰD?S@1% װP}P|28g4}t P #׬3z|cc:V` agT/X۬q:=g5lP JGy%ВZvY\mx~ft8! akFRbk%OyȎztFTkn1?VmeE\)!*)TkZf[ wkD(1;Y/BA4I`xS-5x ?ĨQ٣'Kde\4!&:sn-ARzaץ< + BjᎣޏˤ.f6͎Ov%qaW1ie5/t5Oѯj+|m!t ;Yc<׭Y:0! hA%r]'ML$*htвuM #JuN H$x^Job(25fuEGكlb~6ӡ[to$ tn-O6 &'dO ϲڪ&_ۼ_xoDFR|ϹkpJQ|wȼgp5òY&]XstnGyG~R$ۆ$h}A$I€/LU5y90 LQTFI%b+aMC֠5#dQEE<4YkĄ =eNIslIv7q 6JbHVLE۠Gk`X,M̖ `0ܗ{W|*^x Uj`OI䍸7Fk6-6- >X:󊄠i[b=`c4O(Ϙ,{,~xEZ  t{ t9pn}vfavXB;|ٯ[[th) \;%5afE&%lKXVB{%_ 1xN/ыmh="ˣ&;2QEk4z2e3e?|ܭF=#1 v3~rWOqRОIMQN=W42 Ѱ3~@h +i}`>p2nӍq\+*$:j`aa,>,>Hö2b^qK/KŅ[=g pi*&md&W)7W}n;h]im]s3F՜QyQ"¼>xL# eˮU G7]ۯX>V'X^<[1oOd=0܍'6BR:c)MVȢk?rl]qb]rsyŧ֒#g3~;1 :Y,:lbm}{ Q!3&C~1bG>S|PuF^pg\plcc]Σ.*JduY=bm_ɧG{+=;^w]^vYX~P4ſ>3.QuJTf _O&zŇzt:DBPPМJST*~S U{^ɏ|_h/KZbry03<3G5~a5[`v vEق(7ݨ6 JM5U ~ClI5FLC9kPzA=k(gFX M3T\ \@Ib̲6dH*+8ܴi<(O#&`lJool q@r T& \q/ d(SC nkbٜ֗f` h=Ƕ X[?5P@Ԗ@mQδgUv@VD`E %]cw=|7 Gڭ9ka۬u,ATBDZ5 : ;䡍6hEC(V&U' ní?ʧiiJa4mиe-Q[/7 J਌V*A*\GD OA56(R8M^8ԩdivOhUk*qePWʈ{Dp{'`q98f:اel)JMcdȪ3e"*S82AV jdf:5/$GјʤP.QӨ$Eajܭy`-+VMo" u"YD2Ĩj̪3Ѥ-E>ؘ!wkVF(;uepXm⸅)f쓾 Ў$ eawbuܦq$W1WnϦLI~>?'(EQhQmdsAͥgcm͆P[:Fa>Vz@*thbZѬqcѝŰMB"Z+ޘh߰:|eyjc4JMCHU @6I#z9#|79ϹeH ,鱶Bz#t):4Gmb?eE\$f "BbݪZT59_PZBTȰSl*45r+p)*r^;kpk Ӈ>-mxcj-xOtGs6'e  (`ۀana,Ffq, mf`sC|ȗ MհU=wgygo@z5~Bo1h!EP%T>>T&~{KjKc%;ԅG~g X edԏ̓Ye4I2 bfS܌X{}K Sa+<@HjSR:%}n#n#DU0<0n88#f~evWbVYv}bf"WwLhxjs',oCV!ˏ!"x9zy'U^E,&{Rd,.he4`pQ끽=xFLP/s9#ݚ %5J LU7T\   n@/k^ixMSȽGKi-#wDz@BeH>'s6U'uW{jG17M.'`,z,z,]FvK"=*#2E9Hiզ5zeAybx,[E++Q)EO&;Mb{F9GYon[դE4ԣ%Ry66XO r9sl3 CC~?GV^Ն bܝp5b޷H]T}cTEvMl0*Bsxtn{[QF8{Uգބ,z>#6 =k]kR߽]. f5Ȉf5 šn1+ŏ[@cr<&1,ZM.Vzo׿69<`k0^--fkU]4-}q.jHr=;bv9R:vHIj<S1iYHc`VS~4ed435eTD4)I"\CЯSy|_xy߼G+JaPh&fp=mb1@ם_xK)t&bds uD+ǠǕ{je0 f=yǗ)+nse3ux=G/xaXUXiZz7UU~X~1gGy~$vbO+/Qk[~|{gme4y5xW'E.jS4qq O?M#GڰhcW4jK%'--˚NFRhZ#2j!qe[=3en[sB'O\ҍ˃=d|NpHy~|ɻ|,.E)c%ϊ͌3lW-#"?@)ga1܂\<#){`F'& '#G'w2{L>r5''5Yɞ¦կYoyx=s=oͫ |sAxl5`u`B =]pX]b>Ĵss?/7:oȟ63<`÷b2£%%ˊ)}źX89 NJT%>jf"ĄDѨ @4$I:: U`~id$-6sF=rOt#,М4)*$wI\P1( )akbr6)JL\XJ⮇M+2FY)]wAXʃ1!<0:Ȧ䴹EfþР?餐sH IDAT)Xc7qq3f슺(24nC!Vi6lkZ[f]cIx VAYE[De4x^Ah+ʩΡY[#tԤ[Mbku,r,̴K9N55kJV9}洴QBX=.t=\cm1CzaȬC.lmsȥ~FPh0> 3.8?a;G=들Ɋ5ee4xl4E ԥ(LҤJ N33@ *Wtydhc)+~ۊiK;LBK錖on]&\UZ;ZEhBj, ".>ѳ%c!z ()")e6xV~k'xz"ʛZ3*;Ba<xygyow/_ߐv1{9U _R.DI\m3fPQELs뀷'(< |6=:ԡF h)xk K{??g̲%[,w!-QmUaxar! V1Ó BoEZ\o xX@@.H J,2\/#E*4h+~Lڱ3$3I$c<.8AiiuB Q7M#VUJa {$jL8e{ʂ.Rbbrerc5NGP5*1a ^؟VZUHDTdp}1KeQ,ЦlYThJLU!)b“"1;V젇ۛߟs?2b{>gm\qUud-ypp LP~.wo[- 2gW%buʕ:fk&ZO2Ax ~J`lqǧ;XfEee2[ Y_D$ }Q=jGR4)t9_o'a~Pvl*1얄 )~raa=b٣֬]E|0킮+v=ٞlC\6DːK&c.Ǭ;4KAj> Q"hu;V-fKPh5[Oqm 0Q1j0 ¬H-=GN]lRmCaV)4Az㒸.Rh"- !1TF8\7=F3cglG @ BY:0`NuHRGlj46r( d׽ a@mDFoi[EbAU$'KEZd4(,J 0A[pb#_`t*.Ѽ${2GTD[i{OڄK nš&Y?@>:ͭ`}Ryp‘v0h?rҾ8ؿ9h̘zѼs"lYSa؍}gyYwԹ@S9:)H:?XI#"D?Do /Kap$PdXj0PkгCE]~a% /iK9N0) flk"ThSޒNſ\bDZ3Hˀ};9 W=5^3~ۢ$=~5~=fnS SJЎ$zOaYF] [』K>Roҩdqb^̖UIiGaqOq62i0޿$)n{ع ߮5qIyg0 H]ʹAԆ3dˆ TKи6B(tٯ-"=̳H]!Ccބ/'<-՝K[0 :cϊG#G6C[ErL\ZhJ=HeNW/9oH#u0MaQ!)d}Pb +*%IM<\z4>T &JkhԨAC̗ѧeР ::U Wt^n98q^adAeKGq!|4nl(خ$')v]I9 e>I5aܺ/|̰|̱uc}|֙ǦYӰAXwY~Ccd&r <]PGskÔ ^#WDG*->YB:ۍr;bQwB<<@< SmE{s+yR3t|rFmVTÚuMU,UKfgyg#?KR=!Zdz VG5 UDgSeUR/SDi^d ݀4S̀lЃo0Nub:v=o8*B)h%wʀUnu۫#+j k[9/Ic/m W|Xb>To ĸz| 4ۅmvȺ]~HJTVbQ(BTR8?HSmbZ%š@]evծsR{?t(cn.[3""ˣ1%XRC9тzD|.h m@4G2sI'.R Rph f_Ś}S>/XE.&Y{ˈNuО`T)gQ.mxgs4itzfԺ[qH(&ܢXX$F$IbX;Q+Vl"ShuVÄ бf4s( \Sz-yy{CӇۥ$U!jAX U[5HgygM5~7KhAg\T42%mufڏČTrt&l% I$\VMVlMf3o~l-׶ޖrxCg`ɞwǾsdl6?z0BkN+Nk]%2fc+~}Eyvv8A8ԺX_s>?fqdYw̓Ϝ)Q!)BYU545ȌQ 86WEu>v.0ٲZ>qЧ.Ia8cw (~ IkJlF\V|[xգߩxqrQe;S6[?䊓Β1@q-OGCޤԻ:NPٷ%4cF*x㜎UɼlDa ^~ ¤Md-tz%#<#V͘O(On9ǐù92CU!sFEIIJ 4!}Fv $9$1 L{Fƽ/ !o~ ֠?@BAYB 0kW } 7= 9Qi65PZQ@")iKdEc X .j;qqW FQb-CS-79|΍<^ S ׼R"iAu7O'ې bb9 s\r Il1iڥnà]qchi.a'+×_Qmw , \5onT"kÕ#I1grSC(zǖU]_ Y㐪_(DM$[ұLΌKDROrZ0fN} bX`zHOxncDB*dȺidg_`֌wrF"'Zs0Ha}*L-=gijs]EW75 :11ֈCbAu.6=V T)"7/4[tvB B#!5hg6zUhx.8a#;R w{veȼsU|A2 |^t^<,eJ;nO!E6tOf\O0g!FTK}RPE/)%PcݢCЉ@H0fT2:D7ffP<8K"a)R4D%&jkb;>WǽcGy䑟1?[7fΗԥECulPyTC{h]Az&Cv㳘o#>)LYpwQ \XG\~oR jSN xPXm%*Xg?dۜ.d]DrҖ˫p9ys32̀ل=E-$gCQVgvUC«pHr"|?`2ؐ}`Ŝkr}ʅ"[4$'1k`<+SS=T]cꐨDȥrmGzG![ص!k5\ f2q#)Gݘ"^; _FCc;dCiW;EHM+r rЭDJ?t,ч&ָ%d|'6TC\嘷eL:b؟6ԊN/T;ގ첓vY@$g0-dvu7:.s:nB褄nB1xm}Ր4}V$ˀSGZÚ=㎢y PeETM"qW* S!厮̉%k` 5*]d/9[eo̿Q+k|H=1ڜLO aY5 7._7L!Su9,:ĖAd.FKF^_?Ÿ3*sAt\;R= !]CtX^>لDuh#l mÒPdAN8^` g Xfl賥φ>qCkԼA//&nNdFxsѭQ}W+ 0zEzn1iirI\$j3ji)hdn{B2sWM5\kɜ>L:GyG~lDIf=iH@ (oB,Gs4I  |r̹a-eHbgP/]m)!0 y1in9*ؼΩ66, ӌ_fFsjl9d8H!VL^fL^ƌ^$`Vפ_ ? >e)~7@R'CÊ5֚~b• A"eCEsba}nazCcLxoTC~2|~0_gH86`xdW Fk.bG%Ƥ&:d~Տn~4QEYK:Q2 F+e{LĦ)=tCnA@_X/[sF4|*KN="vKtLﹿ9n! Q@jc=1df}LqxX00Dgkg\Kcrs?>?bS-z9S"oCH~s{sLxlK糘Aw0 L<)j7bz#vuHz#n魠At{ZtjvE]a+:9xr'K6c_?A麬'd;lwL}vgqTȥF,5anM[ceIzsgޏJϡ W+KEY^(pYFK:IUH7RP6P֐%`t?] +x i#G}I}IKC-o9xUq%i `}/b DA\SMA(hBk! 2ֱ" ^wWᜯɛ5A;4PCUlx"M[#WaCg7\ .[ś񉯎~ WL U E eKt(XF[ZIT$FQy io{N9z@OmԚHAkdBɼhhBtLN\Z~>`gO>eÅ#h}1]'6Em,*mrm#676jnwq؁eߞ):J#`i8R:~(iM9@fuꀡ&HRːԶV=D 5@_Ubc(V 6@@` ~asΌi}O_pt<#<򿏟[φ|/dD|?gF# :1 }FZI+~Ak@I,>.>7)OZ.ӅQ>4dw0>9bQOHMm]h]7P.6!P}&hҚR L[MZ[y@Cu |6ֈPl؏ tF hƞ8/lҧwb9oZ..N^h%;:4`ӏqC|1&;Fd%$;03'uQ6ʦ^BAa:|<<:p5lUu*`N>^Kn̜s{1_gc$}9bԔ0k˪ǮQ=t c#MY8Ks^~JJ$)nUTn]VU lQtwnKcML8 i~옕;>' /p+h&Хt\ `TXn A6X}l˧ln1bLbREF,*%tAtdr#nukl!M-,'l.֥L\tPW ֜c)LJ!s|vK\tV!6@%.VD%8'dLf<=xGB4R}W%Q?JvR6M7_;y8̪ 7C}cWzf>eZscawz[! j\& TFp%DoSYxC8gdMpXvPa%TTj*US+cG~gS+olLcn?ò XEG CIUDO{7HAm8E[6$, F|LF$wN2eӿeIOi氋]G&lJ"J<œENnЬmP>RwfN!К1(ОNtEʆLn{<#n9!|3O(z¼RV~D0siEeNW5lm'."P Fb%IC}eP_JDYz#`' -LTGI,BD5c IX6c<бD<0(i;7Lpa6S25fLe9ݒ B~&2v@4`OK->+Iϕ8M;d$vHnKJ>lZfsdhDyfDlmuI ]Q7l\3z!n{Mwt)0#2:eJXuY7Z#tZq=TΒK$W'WLK>7 6dCw2&"n" ^OR|; N)],˖;MzI4{ͱr|ٖhCo%6D1e%*LYJ 5H]ܞ[dEݚH6/̙)NTac'|θ)YMʚ+.wS8.YcPM1͙F7h}uTC4sY:u,F ÄAHE)+vĶY[EeX|% I>lAaSMdzjnLƸa%ʓ^© *a\\}_wjΜ 1l1Wo|wC S3i[:[_xco 4Z1jVGǬ,';VV ! Iŵ4K,DBߏGy䑟-?[w{ocPg6չ8T8aIuք~LCm*l*m_^rS 41#M\ gGBԁZ|\+\ݾF9F r Cж܏@.hT44B@Jvhe [@MBDo/>7dMV@P{_IMZxg#|4s13>054Im[ԎEOAئ`_1+5o%_ZKlOF51!X#cߌI}A/+89\q|a-a{ՇaY I뀫*QqLZǠ c ];GEGK[4‚`ft//9̌ j m^Qh4Cc vWj'Γ+P?%,^[4E[CsR{3~6crqO[k&SM2'+QAiC a-F%|w{s{/ r,6k, FH&C`'673 E_0 JU -ecw&tzgd-7Ch9џ/2ظ=nډC6Ovͻ ?[~s_ֿkvMw^qHijm@F-Ki5 쒣K~uq,|7x9(i{/Nr*-sAYݺE? }*aS$-Z";lԡ]ʭ4*54)FivK.}rz6 Os qd3*Vb%kӈqˆ&ZAЕB *u, ѯ%_ {+I!*_8}ص~oVUcKV8Vʀ@&*Еo1I ,\75hLbL*~zW S424°.Fw5VZhӠ  ˣ]P₀i;`;"jnh,4*jQRP.t0Ė W`*6ti(Ys%CCJWh=mkBd"=3$퀬R,Ke( |fcnD5q.pKzx2)vV",PDKU R]t՚Z[SIVMe` ɱ EM OQ[T94errYlUP%:%$هq+DWT4MaYUVeU9`Y#'ABlMlS%I̶m,ѵ9%>0 ΉwG){I_GK&'3|D(J#4TҢaZCgICnب!Yl<{m ;`zI Y1f󰙰4 "o=( 0F䘍}ԁQ( <'|dͤ笼d]J0i2(onC^5XI8$kIw$ͱ sN8eEQCUxMnM푧EK<Јgc}/3Ž1+ԂdP=kK1iA4}وwޥqhH1MAxE,!ELlKQBT u ڑ92F Q? CfEN*HeڇpLLhA"B2 /.I0oY0&-Ot (]ұ:h-ԡGʂ(ts D^iZlX(ۢ6`} gG]6 qP%q(g'aKGyG~T@M0ZP,K H7.O+@AKo=_}@qe谓D[EZ"2FNwӵS~BH8 ~'gE>+ϊ/23#rǜ1d~j}`cD8%fDeFW2i&;[6]SLQ"eKD$EKC&CC*Yr=;fvz6&YPcvX4CE؍ʊQ`. :֎TҜ{}rD:\Ζ{ڤ Ƥ ʙ ATB.r%PCbSH3|'g/siM}`q6;M~_0m )F3}еqřya 7(k, >tq>afh-9s8+_azHoT;$ )kjJ}*mYdzVB`LNkSЇ6R})M.\b? v}/?r\qF#̈pYޛᐼr?'}ny9Bk1x:4wEa%|>vc䀕Na/";L.рh&-U767-/-trQoѯ+!W.hC!m,ll80穀EEw]jom\=ٲ0}_GAh&MaQ%& Ln2=v!TL֜?u|" +[p%ee΄. AɎe"gLvƠ]ּѥ80988y`fNy<}0ؘ}JOϤa `B IJPd{<.`3##rq EAKSO/eBR< ,I_GOOGi8Xámo{@P!G-VTrýdYD\@$7\g\g\g#At[/E,O'^`t5[6!e"VE4-UHEJ2[9Ɇ UE}ICACI;^p_G+~@3  ?\nSo}un<" I&b ^?=Pr!6;CgcY=x`91pvJOZj Vbx`?o鿌95oyÌ*OOӰ&6R ?pjEL3c\)mVǣkyyDb)G,L)6= IDATŚ5tlV}Ř|HvgRh[MsSR5,>WGjF=P!YHGYcn-R)#ulm)\VGҝ?g9@ h}g1rzƚÁ\{'+Ξ9=y۔_:bҨ@cy.¥Ճ|%9x!/ _ h#6uMDUlt/<ϯIKg#E%IO,l,ec*[B7&<AMpVr͹!vl#2[Q EZ+B?{%dt_ŨیMAKtЌBXN4N뒺.I߅#S)h J lɀUݧvLU슚5NØa0wi&Co1rzqəԿ`&9LU4Bjj" 㮁w<#<򿁟۷ȐJa5VUcvV;E(JaPKD>|AXihQ5qQ=)C)-*ib6MEVԺ* ]BJ Aؾ#[(!q10V5kzƆI{# A;B#i8D ,Ge){%I,nݫ$"3#2g_|HsduW΍rr`UxZRėȑbb׶{cv|TA);y} _YBFST]Fvx*&CWHM@~z[fBIÎc(MtYa9*did~ef M}GW_v< d7X.k%]Ed.RAunPQH=^Ȩa稖N8N[Dmj?1R;q?dSPmAž`!=B7 Vej)lo- ʻ6eEHlP66oð='sMZЈJH¬2<r[Qi_;g.Vk^ f3Ck(jtrnK!-ؙfzKCbq/&TJ#X*LA=c:5.Ob;b:EՂݮMR,y IYY&$Jfjb k6 8b*vh£wp!7& 9h$]0fݚꤢJFZhnIU,I޺#HF5m8eT;z1[NyX۶Y]3FgM>381tg`|0b^#\chqy}Njnfq;fcxiS eUe8*!&gC<(UszVbZsmGq'7O"P%VJR՗p!==Ү$ml9h93>tCO&JBBk *Kc )F;+XwHS|oYd}V7mvC^li"Z8bʐ~?Yj=ZeNu6Sb:ϊA_,i!L($YwY=4Sw?R;ⓩBh !p ALCD!w)r!)Q!;QҦxg$7(0}q袡m!f4̨ؕ/6 f|`2HdLv^!jE4.R~=Zz<&;|f}B6w;݇}eZGނt|IR:іhG?ےUTj42Cɾ j5[>eˤuʗ0cڻg}`ڻ' 5.FGUit ƛf -EX6>bb]ծGx O*aJ1P k%GG'dſP1(y0> }>F'pтhI.'z+1 赶[8d%Vqj5~g,uas4;]a7nv'{<7R8x'x߅_/9VwzW}z\X{GQ ba>N,6CUHŖtSꓚWg|.n5;+eɳ/$5 ӷT-vcrۄBAc]pY3H>GH8RT  0<.|ǻ .Gli~~zc1峧F"Jѯ "%ud&F\?ÕMU([ h3o2x|ϋcV1o"QFJWR I.zSu&$A j Tơr wp (G#*76MMqW&6Y|#BQipoAjL|>S8G5iQE+רSZ}Ar"mX}*KcxN%EN9רR'H@<,0=Ɗ+ZÀcǫH>#6_i2:3q̡8iA8vIUNp !&7 :hhOtup9 -,GOs, KX?EԑFI*Q5F5&ȑ~dLj3~h{> mm7? ج\ 4J$2Cnf\` w&H6'6$s |O4H^ZNgl􁳯/͜)3>9:'1&?v(c !`"h\.f=ߌgi%MWoBF*N~`vICAGLgGf)֢ qX>3EQiYy5$ =+qdCZ*B4L+"3]vf58 9]$T9Р%Fe/;||+ y7abv jP;l1eX2)ڮI~pm1a& ]q0 "(h!_h; i}>L#{p.]xXR':O@& + !5  O(:PD1H(  +d\#cb?ڗԤTԤ8^\?~=WaWz}0VBR#TEZZĞb?QJEI?_S&fR`i9:R*&H#CC]WԪ`&~C!s#BPc8uCe~\u?H8|~gˬ&MYdqpb"l1833gpqfÐz|>,^|}^ED 6o'|9? $%B*V rQ-Ѭd;A75!m1U(^[(S&[G~Jحܯ YuIv[ ^p]&*44Pqx)C{w|9>{>I>ژ`_dLb\z#Ldm7> }cIuQ$j,%v;BZJ$,"Mڤ&e"옺Q{X&u AI Fz/o5[FRm lk99޶X?8<\~cz9#Oa}C4%N+= +W4e'Cj2)#v٤>\{'x G~(qjq Wg\qzA?EĩGY L7;dr9 N#U |lrѰZVok."k/L=nFgv>.NZX3: o("9hHln#n#C0{e XY'33 "[c\weJY%>e0c_>ڠDhb6£GIkx;9 cDu J&aa #V+g3~LfcjGP $u ~8kGF=EoB]ME琧Tu6}1h g(hZ`)1:F@B?URѬ,-a?o)~8m}:3֖t.UͺzE%%韪 !AduQ5$  u찵&A0s3إp}?7F%bg % ,hA6;, jGmyQ=~{/\KaϙFB,mVuY5.8jwv62O/.ɇ"<6inq d}r2PIIb:9(f=RqfggD :KʞFYQ傤Ȱ)dEDD+螬h!RUU;b_xb/|j"WwM"h/q9o:>j,sreNMʳu)LoJpY٭0[[wKq+`j@ve"g_&G$=t:ܹɎ= C}ޙBzڀlr;s&qd\Y,ċ6:۔ S3֋SYiAwǠ0miRjrO5@5zuc4x;`pӘÐ>qs{Y@5/V V{RtQ Lêڜ^stGNo9Wj J]Rt4R݈۠kX͌_AR*ԬdF4-k}^j.: v(0z#I\\ݝ#*E5{ ucŇ|@ wmMyd=-/_;j3밟X8-GP++ [ s2PP=r|r2y5y .0v-1nwbND1F81J挓t9T#0L0 ʰHmuaNNjeBGZIQ QTHr b ,2$ ύpG ŕ5c6".t;cE%! &WA᷋[P4=yqsq]ێC6q#EODHh-sS0LKe4bCXg6f粝 LʓTcJ+Vsbc}el6L!BI?@M ۪9acxJ,scHsP ش;"m|K,rZHsli #^?~Ǘ^1/yQa.'į _e`3 ޿pM+0o9=St;-N2z9?guwS@}t>MU* ҫE&[aL\϶W;ٖ!ƹyb{eh1xvqk"x'Ó{'x/X]?~|?~{^O_9*nU/)66E#YxwCTK@KZhe>0ߒd.&89M%{47\Mk4%$=WqgM֤ OggӃsy!߱O}!Wt5jD=Qj j%%ʔHskj{m}7?rmG~(NV_i(swBMz/BW~E5kuou_&X$)-l>` B6k.?W/'X=99#3MbP.9*vD0Y0J:K{.&o] xK׏ +C}CL\n9chEp+ˌz`4}m w<?p^qB jCZĞM[Ğjaq;j'Oܺs dRI EI3>G9ZY`&~AIN2fsFN/biZ:ؤ5j":p+tj AVEn!2Ÿs V<~&w7)薈qJ|#'d…\1\  R4 D ',8V3kԯvYuL/s˜*X2jeP)Ih˯@ 򹃘+T-%öl 34U8<ÆFאMC>!}XgHsș}w+Rո"f؛sqvɷėҩZ#b7W 7HjssoGdx__'ql&u,bۡ [͕~>ho</ȺF%uVPu^R0߷X  z/%-*s#N!!"6Bt̙wG&a0jW< 'x'~b|{jwt,#%rd5Z>8cq[; ="ʣjjIR:2Q IDAT,]&Mb屜=CjZP5Th!;!meR4jSMH]L(i \oOѭyPSBO b@".Ԃzfgt,._u*JꮆHDW#ج&^C?_.t:@z]UQ.7W]xne Aآ5ǃs+%bslaةw.$ ~z!(IJԺ@h)Vvj+ )ԦY}ɶV L;g/iy[l+#|aԊM=$RԘ%cB [+AwE50 țFkDB9!?"- )Jh(ۤ>jRi-yݏ )RtwAhGH&MiY/E sڧ`kRWa%#5GSG{9y-LQiY؞b:ґvTi#3g?.Im&ɕIh UR!J00Lmc&8t4/YZ<^̗.e"zT/2j7fl&o,87܄2EUl26ɕ=AuϜ WO7g|;]op׎pLi\XD?ӈSvkg7|]쒰d'mITYEyDR91+Kݨ(Mc`wXke-quIPSgdCqJg1C v B`@MX4yNMؿ`-/CKc1$6duIX+zxF|(Ϲ/P^Pc;NY,=`J61xų{N'9|So=J l2,!VNXjS'8u%G$|6qU!1^chx kr,[ qٔlGS.GŨōx_7.ɍKiԮlǗ_J!?Wif[ZvQwy#Gۏ~.1{'5cw~&61x7!W\_#y~O<OR  eYfeZB+[D,x&y&%aRvO˚T Je}ʢ.%ElXݵ6N6u%JFLlNM[Gz8H տ ?bAzR P昭 bvfzs/Lأ 柾 ~n10]|Wm3MFYfvoKPu^ ۚ2Ȩ2L].-sȡJa1[z|h~Nd4vz1(An0WCl_~R;F]uA Z;!_iW>gσ1APb6 nx'$sOnhs $%=ŐԈ{wʪ!vlTށ"-ìU0U[[N7j#cxyo紾f\dD>0':\k@6Y})D\R $шw O~i~TO7_Wޞ)LYnN_]򛯾y< s"%5]Քj$(է  gKN8jxcݛ y0Q&Cq?] )lRJPj Ftgc39gؘ bI_,5|_}.p&RBc]Hiy)s֯EM! !1lݓ%ޒ%nQKq-Atw#n/m#F_>7 '3x٪bQ[9mq @!3gLzF_v|,g]E;rP*o dgIJ:. '{_399t(?}kR-t([0LoG?Wǔʠ^q_N/>MWttOO}6W\\&hs'X2糯/7\tUsCXK#'x' (ne& J@C^֙{*]efhed6¯tIJآnH:=7QBj5SY&nHD( k5^kYJHFjTD 7nD8b uXAB$KK$E9ΖB)*mءۨ44 ^?kJJ$$BI 8g՘'"iU$VEBM!ftܔ@,(*R .j$ F !SRSBy6PDZ! W%4d&v(Xeal$ Yj4B 4!| 5y:d#ِէNZ8R@JS[:0+0%ֶ eRU#jAh愍 1vbsE R%tl)}zuxč:&Q*F_ %meSMB岫&A$,[UWdz^StE^4r`AlSkúeNZT))TYǔ"t-%>fDDPFiUj-BEwarTǿuu3=L27+"!$ \V\0(;H rAdGO& fޜ7s$P[.P &0>bF`(BpF҂R% Hږ(1/^q lkպ 3NHCL*D*j|)p)S$6 0CrzP31DDR,t&8Y1lr-ԪbyU ׆xʵV8Vd4Ȍn͔B!!dC[q4 1 $@HɨMcUuJNictF JiBJW7RVe(CcT{aM`XxXxNP.5AA+بf;L'Hf*X LdXH"EL$B2d"$[T4rR*RB{_PѤsFGlJDQ^]Lh\~%(]E!LM9_G/ {=6CAhD %hZ$Խ|B>F#B "qL?xU^M n%<> 4hMUdœkEx  EmM4Vī%6iRNdb5 0{7 )aF˜3Ƌ( @ PQVmkCP)0?ɍ0-Oa8 ?Q6AzB(F>E)(]6^*y)( b{k ݫJ~Wk#Shv`&ZSf 2Thg`l8yD.L ^VѪwZkDU0&PQ?V!-Ke*A6g\*1A[[W@n"5[(-J}>Fz:Nȇ tnPu: Nm@Q1P&FgD[TCH$$E%oI]I 듔6&qa|F )B}T1Yꛇwp/2H&6BCl0_Fr%pe$x1/KR1_^8/ E]γu.nJJTS!N`0f%pbVK//˛ĩ1A?P$Vl$>a$NyD𿃔bQ)F k z >R'4"=bR;P[`>D%Awn<4EziѤѨdCTEG=϶SIE'X!l'D$S%1NS]G5:4M#=yp"$UrS69%Äf_/B7C_11+QJueDZur7S-%#F!LJ_ CFt"+1WX@RuLRx⮍_^m?Wl ) }_:>^.^^6ir!偍HaUV"=$JLkX_bq ]tL"yym'/dN6*Z!t]ib/zhK^ k=BarC(1_G0e)0%[p T-d Id!$0JDQbF o¶t!=qR ( ( #BAAhK]MfbHjI/HԆ&z*x*.DĤ2 m`*J'UJACRhp%.$Q">ab$I&QBD-*(H(GHR1XA5nU# L1V'w1r1z0ɦz66;X`7Bx! <1V,3R}+Maji|?Tbi!4עL$rlvlWGJHeP.?cZ13KDΣz'Sʨ!]6Rk"1ա\VBϓts讅_1rjj;=%.Y,n VA*R2>$&|aj TE4R%po ^'r!U" B9%!Q'EN2n@oJI-r<* z=7R!F4ylRJŌ8N8NEe\φ$Rhݕ0ݶN P%E&,Zm 3bf諄QUaXAvtlCDɶ$6)^|w~V0}91B Ie$3YRȚkZkvSq6_qUZVZeRAJMڧhA(+ϐ"mQ6YȓmD~ #jiCka IDAT4YDl:kk[-Kil[Žx$eCjCK'-"2tHGhP&\"V,-[Y"}a?jNe͆w(l 6" !$C(Jnb0~QMHuT02.D@U#h2z)#*RGρiz"iTj>~\M5!*C万9(-.C~̎cs5A xA줆 a%C i զ5Kmt;.dMk<-_hf TrD\"I)ÏH$9bJHdbcbGB.N0 (- &$T%uDZeZj&׆z'B!79)B1M_uT 5RR}2KP Q6LaRuäk 5Ґ*rZEtFb6 ˆyU)bnvP[\7q|\1MTV4FP1C8RdV(&%LIR(3[3ZHrO~:C눆K!#ӤRv!IUKKdxA֭qqZ|V{FU|@P54Fh0Fe 2AZ-6b-4ڂWQi Ũl08TEL4.8L6,) f )Sxx o eVj-';I=G]0a2{=;2Πb'F6_G.%3b4HF@ "iʕEbJ_Y"hlHvTH)#aqh^Ieygm8"8v*  7વϒteh6t=]E-/{YAn!$k!YCx ^$6L̬ab$'-}LW3lꁽYݿX h :\G;qtuӸ22R'aH(9FpJC3&i6H *E(砒jv JV;WjfhUEo 0'dӨQ2rQEĢ(D?BAava j.R797Q%fX_N(پC8<%@vjg45Pk2^dtJDExo>AAصvo͌vvvյIA<:yNm#40 "Qr$ѱHy3HN.aHJ@&Run&bc)Zr^ KPXH[Pq 2t1Ls:OOU(i 03 LkfZ.0[y:P6~2L>hfh:TѩJ30HsDeBStTvhcL3PV)TCgkKԪZl%Mt`~/%DY2F Wn#7fD"Ӡ"Z[ s^3^E]#Q(l%Fs ^l`2 ac28IF6')=d(| 0:%TI%~^Zm:RF!RBv37`}`#>H"&YmbS,TE$(TcJbZbF_AȱiE꓃4tӖ즍nL P$6hs@σ!A2 h D6F*5*`KAyLxɄ(AT29 DtJٟF5::UJ"Q}p||MUYBljk_'tya01e]YsK- ZMAR2|MyW9R'ƺI@&1^HSdC꟡d)406|~;:&aJ$L+:&CI8DbBk-i+GW8! ThcHB:6[6)F2!3zo`_P.XXDvR|ł, :q}:'벱Ib1'$ $5R;m6_UjM|AªLmXg?,x&xI|rxZ(| {K\^  l - [Vظq#'O``7Z{[=_pGG[Imb2Mmzy듶 u5: xk37[?? G~|{叵VV?E6Z~30ߠv]0r{ma~xmzYu=Ukɛ^mϣͭmoǢ.ڝ[`e?I=km{~7Vm}wmGK폚}A̫|w _Um2ߏ6j^cigZk=/P1eWZuxVAAx얉ԩS馛袋} 2uԱG}4O=|{ ATewq122‰'aƬYƎϚ5kAAA[&~pYgqYg;ZOxS[eҤI{タq뭷h"}6FO{'[XnLSN9}s/3<… Yv-SLN㠃}=u]<<#c߮D {=[km^G+;w.=Gq_~1ѯgʕ@l=[AaO%~+WdܹR)8Yr[GC% 1uT W;~inf⊭6wqg}6&MB4>OUOE_nf$Ik---w[n裏~?ѷ ž`v? /0}EnuqWrWа1їfժU<\zXAyG[[mtWrEڋ wJQ7v'VAq?aǍ|rN9:=ַm93g>0MZ%Nswr}q*3\s Xl˖-(\AAhK^?\s {.m/^̣>:րm1C4%1gV'r<b1b'pO>$ rG]A{\e\.ڦMꪫ8I&[UDmtI'q2g\K.r[]r%g?o`}/D_S-?[AaO TPKx: {1< ¿EQ8p)oy|km9ŬS{g _/5-/}Awпys:)   l   w  w o~ G{Aagإ"AAAx{AAAʼnOAA_HAAAʼnOAA_HAAAŽgm+9၇Vfw{D  k#*~]'? K,a̙osRO΂ۖ0uT{6mX‘GO9wYI>1{L:;ydkgsG3oųwkCϼpxn{N%}_"{2ߠx<zJtC{  ۭpsܹ${h|Ok{!W:/,: .'Յ3u>u7̡a7}tNޕ8> |wsroO?mSgrN?>/1:;S .Onr; ~WcH7pgK^p!ozlAA-Vȏ8k_#GD QT ${}rt3o3o΢O‡Yc{WSf^̍ߖxN?|'ep/ra)_g/x5S| O5vvwգXǤ&YX_n|W8xYr%RbH>s>Μys8q2444^~e^~e  oI}x3 >2$$J:_u\| dwk6/o|4=<3`|Yx -^1,8Tᏹ XtN9d˷+;%q~壹gvr>\gpK̓wZ<HcZw^%F2JD#[;XdkG=x^<"X_+HvZW/נ@kInB Ї>(§?iw('ts?3-X_(')AA]gK{_\3'~#HA0pqNK^{OW]9~878o='n:H_[SE04Nu)iw,y_ck{pq{a;w~8FYx쌱xκ{ |XN,<~ܺ'|qx~s}f}3@׿3w5NoYl6qF ْ$.H,=s:  qY+'ZHw-n }V^=_J|zb1"]8s PO޳8tfv<{^n.  v+9I s])^/.<}KTqn? rԵwеTܶ/}p_.Z?x8ţ,3>Ofʧ\z!,<~g079n_O?z0wKeP0u)xdIŧncq:W*_>]信6Nzb"YhVye{ j񇧟ǪzxhNS[~  ®[\} 0Ƿ3ky!Xe r̙3%|#rwr/rβ#Gç{s?i_:/c㌻%w,cG0\u1s͍uQ}s2n8G=|*i?r>{Nґܼ|9s ;0θ!n8~:ZzNՆ{{2/eH$#4%"E]v) `/"nE*^zp"y{?Yj*3i]6?p=OsZg鮟 =dYib U\,g BǬ~ezhi  l<:d>1CD1\8k>:($a6uuu},>|>\Չ:X#%Kfo]ʂy's}+Y8gg?;oO?_>MƍKY{n=\ s`m#8wsp͚9ο'ϪUbќЯ>k4=)_΢e_rXogZ^Klɼ72w|$7}($BL}TBsMlE}l:4$[g';VD)Uliؑz`.'p\}}Yzc1$3̽O]]ƚÎ帳#.;%MUPF3t]敁V}\WAAصoKɽ>B̈qw{t?d}Y A:fƏ~&xa/ClVyő_ܥ \0|4z7w\p6N>E79\?{Oi/o{ܶKtX<?M'\Og??1-^U_Xw<~E|ۗ34޶l,q7Hx2oXj'y'HU-d7%,&lC*F4Uq=ߣ8T]4.TN]ə>t\gGlڴ#L^4U_>ʕ+4W{dY.Ʒ8܋l~3` uŏXp֌A #UΞwmeɒ%t|338뾕\wa|s[%}_ir.?d~C\~ܸd^0#ϙoyO<_.~Oܾ߉3a9f5Yݧ='}E?N=EӸirN=n\^u ,8NR?X~u'=kqȠޖ{/*KOuݿf*0L:@}M!I&bKu%ݣRnh!65F8R&Zfii{2Mz\1IDAT,cbUq>d<Ͽx ?nw<XsG'u)t]ulq)U;  »=Mn9t>6Z)&tT&t0xK/"$3Wifߟ#"-tL[~IFvۯ+3gr-sͩ'&F=[Ƀ}E>̩G -qQGl;OUn:HμW.1 _ʦ{Tڤ'-ҼCz7yO#˓i *T\ wv($j b(:>z.kGKAAw{>y>4sX,o[$mdT,YI}#/3udk#vU[Gncr7M+38{Xd9'}>i~fM;`?nGx~ cI߯^ܣg/civrn8aZ;0&|2Qq,6j1Yd2y晬X#2-xg8C1=8M%BaVtiU RBcP.!h!j-vtk8V(҂ nvɒpI1)>3̙ew>͏} 0IKGms-nai?vsƷǿ5RS[KۍaCIEDDDD?f_slvDt!`ۑLYY91oSApBakǓ^PK'вr\e>T?9ƁC|1Mц=zpMknݺqw3覛1ObTX hϨ1X aQ0k[_\?ԥtt ""Ҏ:m v  Opg;HNv&%+NSxt[$YX?ϦT&g-WFvZvCm]PvW^XAќT< DҷHs1C^k'w~fjz;uw:zvaea[6^[c.~0 /.K/1St%!wac`e47âO}}y8y`-7xC^o}1Q6t;ig*v _lkn섹\.[ąKȚ<ŦcWsjb|6Nؔ695 v&E 6{0}~Nl 67ssUGksòqe@;hG[x∿`u9} :|zý}}:zt!w8y=L>gݡwð[ӳ[?xO vө_ >0c_s=~M^ E=Js&$}k)i-&;-Y%8'WJ$ë+ؿ9kmz 3'<=tKYa/3=EΌq,}mW깘ë0y~Ы#9͉I8U<&ѩw=z>#FP]]Muu5a6!5Ϯz΢27+'̡Ct#h{taEfߠtN6È,  W/ak]ɼLKwSԬP/$UPoɾٳg9ik/_ gsYSF1kK geIQy)vz.E㬿ז?[cǗ_y @᯺cQ'|T1~9xrʕ+yСC۹J֩0ӧsrYin`>?^'::@dNi.\.=۶y׻u6+W ~5Q1|XYŇ08]\.m )B-].mZ\.]ud==q)H[Ç SǏEW_ۏSǏQ\Rʸcy,"""{|ZDP\R ТUb':WODDDG/ ""rettuDDD ""W6uDDDDDD.s ~""""""KZeO"+ͷ%e.uDDDDDD:z\DDDDDD.sQCDDDR֋}vynjNwt=""""""'*3!{gz}IDDDDDD"=6H8S'pVwHa""""""v'*9} .b hX(l.%*:.]vD""""""Jr1@(YaC&?srMD~]IENDB`traitsui-4.1.0/docs/source/tutorials/images/image_LICENSE.txt0000644000175100001440000000165211674463545025074 0ustar ischnellusers00000000000000The icons are mostly derived work from other icons. As such they are licensed accordingly to the original license: Project License File ---------------------------------------------------------------------------- Enthought BSD 3-Clause LICENSE.txt Unless stated in this file, icons are the work of Enthought, and are released under a 3 clause BSD license. Files and orginal authors: ---------------------------------------------------------------------------- docs/source/tutorials/images: application1.png | Enthought application2.png | Enthought application3.png | Enthought code_block1.png | Enthought container.png | Enthought interactive.png | Enthought mpl_figure_editor.png | Enthought traits_thread.png | Enthought traitsui-4.1.0/docs/source/tutorials/images/application3.png0000644000175100001440000132631311674463545025210 0ustar ischnellusers00000000000000PNG  IHDR~@usBIT|dtEXtCREATORgnome-panel-screenshot7w IDATxw$eO=yv6'`fŬ"b:<Ŭ(NOO(*<A<Č a6N+aw]_gj}kvf Qaoc {oL   Aa\}Za˞σq7BD*@-OAfѻec#E!9}Z{DQ8< @r ܧA sKYƛTǻv;WG|A_% p&o]9yK?87gCiumká Zcd۽K]wlj?CRMF?3`$IBS {ٳy7F|;<>esb}~7|&Aݷ_{uoKfg^={mε3q>gu0Ő8y=~nX}ײWoBRBM7x72>FdbbL&Yg!'_leV^~rG@נZyۯ}ĺ+>p-}s9ʿK_;k>~eG==߮P'#֛: qW_Dד]u,oK]QbDz0#>睂ѳ ؽ MwzA=342=p!ޜm۽sU3' g~p%<$~9~e4[!Lb;e:SpJFIOo ~w39#sn{4l8 RoqůbGnvM_6:~wѩ*|L~{x`kovXj3MwQCKyo_Nzۇx[Mo@9y?]wq?1'TrUvov@Ke1#Ncc>j?/~[8=r#(<Zȋ?C[|xݧ3NAC/:':ZUq˵_1k}VbSٶo+qYk_ߘY -nW7O̬]Uyc8K|jx;X9FW/\:Lz=T>D+y3c{J;Cbǽk7$z.cU dQA] [vg['>kǏRulf٬=qs#{׭an'>khv%~n~s=$tG6@ 84=Š)ݗ_KU9~f) <6]wkrh>&'y΢8I£e m1zD7F~mE) `i|\feD* @\by @O_?wnisؐsqh_600Z6ڎygbo˾#0AvY7&ȻZAsh9>妳OsfsrwٹΝnt?Ib!5;sW}pH*xCQ.yvSAxvu߯Q?0Y٧|}|}Sc8^jú*GBU$f =G.P\t$9[ ㎦R;i`s-a>%[+!N|>=9cIgDZWAf#MgwNͩ蛵g/}).ٺG̿gKv/;y6HҮ?!|s9ccAxѥгiW7pc)w AcW菘7y5?4#~p!huN ŰszUk~= MňS/xoz뻸fodsO1&o<}vRN_8vucUl pխMN{IKA$IH>/"I/u[Ifg=8?cǤwܶl|ds9P$ί<)/?OG_}|.O?sclo)zsZ bn;}{73WF|{W(anbLZ3^&^~M46Ý![+Gnk\y.1K?G߿ )_w{.Hl) Mjv\2n+=|NK%2G_«/MǞs]% yO8-xOzwTܴ}j=is_ְS޴dT*-??Z n?|.I\g~ߌ;~DRX߹/~?a3}-L}ō׳_vLMfe΢3(oߺGXĒY:$cn_ul(9MhܶCڽϒ7ܹ٦DLaPEyQa/u{fM^dϾ].D|К{Q}3Zs o'onsOy9n,Ӣ 5Gѻ"S*(Oa8 Mgyժ8Y:$ڂFDLE$K;%/_i1?g "ow+t]X֧0=۟h*ɆONj"E=*K{Gc^VC,tnD,AʔYԣr_mw^.10NRC iHyQa/mP/;BO8+,V҆N=~<t;gp:[Ph|9Ig$[Qd5l <ϟV|)?dO;dy ꚟ3{C_t6^I%Kzow12:Cwv̶ϻZO1 %6 [Z[jq@ھowC=+Kda CX\ץh:Db;Ȉ!- O]wN3{CAx%{oeճNܧ^u\@f7w]\& <6tCAxb;% o7)>wJG89oo!   p\ױ۴&AAAa?Pt;AAAD2}q_gN(AAAgr~yGw   SHAAAD' OpAIN*p+8'<Aav{__H {mN<4ד_|tAUU9h٢ݯ$?A1sⷷ|'FAD' Ox݄._&œOAlD'<}%Ggt3R$“HA/WզW^>n)'x:Wo;GgD'<)OAF]&FO%;aOW^#dN甥ns9@7B@|  < ]mzKtʉ{IOAxr  <\m  qIV^g^ae]k^^Wկ~0 LAD' %;sy3IE;̿ٴiW]uW^y%ׯk2AAx:I +O|_%ɐx/~=.A(;x њx;?<8Y$~r-[? y=.A=}< xkOGl]u@7Mv_zj AigժU{]%}k֮ϟoV!i>Ox>?;H0OfKTϹ_i y;g=G|s>t C/}D"1Sٟ }댏OPc;&~lܸK0::ʼy[n?!zPXb!lL&.F] ۍv,ڮEKLbj6DU!F.bZ1FnizyThS+ir #ژ93k+*NdD$p"[.!hiBڀޝ&+QȀ8t$p2$b :xBrlbK1ڝIh*8   tL)"T H$Ic<榩{|W風tE"@ Ud%5@BB[)-C+z4#xh=>!G *~bFa|X&"( ,2t!r1KTQ.g${$M L葋94$u)ASJbc >*>* !vd&Ф"(*{ ~[%B0TYMKm,ZXƌ:u_,H2H2vJ#K*XR"D"!Du Rݩ @g HS="="="Pԕ$ %tfJB@88t0p1pw(!!22AC!E۝~]Y.6bc!F6&61lU4hBL۱0^N{bFqk0D""Bt uRJ\'4Hu<4\i3qĐptph:-DP J2AA&jq0zKۡb52 XLJ$K3AG|Qxdcm|TJ)J9JixILT24Cu.!t@zqMr%Mr_Wԋ:FӪh $dd[2^'|@ezf[Eb%,g5_}=d#=ݮs[~|븮˹Oqߺu~?p בekW+_2jr,^5>яw_WRIgpg Λ;7|.7v“M9oO|0 +8c @:oL "CȅV^o>w>o@2$a5IZ麱[ڱe[ %t!k3mb670FF6x-k?OqŒq&8c,>ޅlw[1!Mlq ŢffQ?$k5:!Pp0K0%Ku)KIH5d=Xп,ן ߜ$ߘ"ל t&A.V^W3Y륰&KaMCY<5%$A<떕.rm Ս,T7@Xy+,cma~ńjU>!5 5 5@Fԕ u5CCMh&I-qE}}u X6Zª/!~M+FQig J63M Ecb.F%4!ID Xik6ࡍ+3*< gM3L0&aIJ%@(e`*61&ĔKeX> 毡K%= [҃D{I0;ye)GYSrT,5%M]MQSR4颛.ᢙ. iksTdA @ޣ&9j">~>:a~m>m~m_xE8;p{r8yܞL:7pfߧOwimYݩ9&>$> >D2> PPCX!TO.o7rMaiڝ v'MJhXI +c%5Ȣ[M"T{W3#$}\zg?) 91t|%_abbVK/搃]6ݖpeOqOpַ<3wu7]pA:S\viZtk ϴqozq_=]y,ʕ ===]/i3>ɡG51NbbkbPSzmpOGhI4TH3F!QhtZc&a|S!tIl"[2xIkj- EvTGg,DZe2y` g@'2Zui|Tdg|*G!G!-A2"vLƨLq\J.C!G4U)[4hIN۝&i#_`L^ e$ASjM!Ӕ-ȑhu8(n@SKغEk*t4@qDdI6Y%(>QۃE\B"BG$3"TdMr`&d\XbZRS136L3&fi-^(dS)sDDfNF֑ŠbK)Rhy÷1M4E4E4I4GH:1e*&H 6ZVe#jJdXU {:i;INo$S~NDm$)Nh \J<'&&".3>zG~7ɤq7Ja|֡;%v?f'Duk~4ΟWnDQ?;B:S:ltr,RY?n96$Xtv9<;\mK;qIn]WSO=SO=Q-P2Ӊ'uNؖ**): iJYҫ,>4W*2z)Ħ7! !/l188ƊXr_fi>lFr{e`(GkABHrD>[bGV<8yMBy<։|9$@@-Sw-nk(k>)I dI;M@K=j=Vgm| uں1uO21 #(9rrjEnwܢ5J*R\l`wcU.loPa6kP!c8RNxLtBӰɪe)Y"c8L9H45@c ]E#v(9nt\`Kcg*Fe}8AU0#*({Z}r!dJ)7 6&*cu(ȽPE؆AI) g^0\ i74$z!kIj,װ4Zh-ˢl,bMykY; qɨe22B*8"J^y4D^$|MTEJL(*=t( èSRCn& :؞䓛Yp-r߽0錚L$X4E#T$NoR+&۫F:O&m *ELTYdÖ%-x |/zgOwz<= ;$d_3pE_c{_g_u~8o]1ǽ~z#iz6wټ7$~{봳ӵ7z_ȏwYe/%LjY1W7'']۳#$'@|$^J8wB&-ӂ^ LLO<5<%6ER nQsl2 ?}[DJ/:$-lx n=eR~0SP&f7%DEbEE!P 4 uKs Aiq"-4ҽ3&b(:dҌT,ŠBOja] QZE5Pp:j>&ёb0@Ǣʃ.@p5 TMIzkKe=DӻI{:9Bo0 XQ%P| YT PTT'-HF ȅ꧙tq< װC61rS .HP@Ρw:ݫՐ^c09ƒtßԨi&CDHEwQt SmPkd2y Qa::-{-cy4&S0[A*DfltdM !:2a"G."f6MLDoCv&qĤ[2 $G2&;m햁@'Ұ1U\NaPi橷l!=" !4+: !mWݐXhNBnb$41U'Eѩ;1ɨ O*1J-?F[ђcHJzhuI4 gW3 TPBY|NjQӔhmCz:2] $(^xL1)8 NQ'g59 *| B15}2Җ:r:P,!A1;FB j^qu$!\D:F RU0JÂVu 0"MnE>Eo}1ߦ(Gs) ,\` (;ֳs.qp9]L͂@`>SS{봳ӵ710 _{q+rW:3`iq&>ssw>osfd<Zx1ffCH_88f!1K"&&2i2Д,BEW\]c6} KLm<4<ݖ/l\N#$(l11a84[PiTTm=z4UFP0:M ښ6"tLHf^̒z <[m[ ZQb`QQ"N&7c=ʂe$@Mm# |";C`w'Yie&{4"e YМΔ*Jk)wo,8sSܜb*jͧcxERDLF1EJmcƨ9 c c 2uu0 `V&jGt4# ]$|G@t@N7K)RxU&/KOҟ?>N^.נ65CmkiH((H艐=]:X62aEReȏsrD/gd|K(iV5 c1c [3Խ,0J 5E2F H6ַQyDn\mq?c_؟eS~&zfd)6cKqi39cvHHoMY7NՁ;K/]9:ض+iY竗|<,2<4i̵{>ŗ\kOz#,[n?!O$OOS.y2!' Ux ؚF@TGWM }Ц/>I0,\`lX=(^PiUƋ=47&٪'42I$v'f*"* uf+шRJS= =FT7YԶZ>:WleA[IP3Z&Dx~ m`,,N۠ߜ`d>[TW5S%Jϑ7IldVNg?,a+G$Iam43$V%F#`#>ڈ6s1t[4]wla,وxHo-Jɔ i&ӷԎ%3‚( ӣd )Nʨ jFatuR   DeNR @t A|1҉*K{0n 0f2n P u 'tON;EKԓ|-zc,MPmO4GhL܃(eT^DA BhҚHPО8 u vLdiާѸ_#p* eKeՃ~h$4% WUc؁E,)қݢ4н^ ?dæ8Th$ 8#1y&dH& %B0Y͍r?ݛ2'KLleQ|>&||C؅!8+M)Pӌn^=FYS8݉a'įjZx25qT\e1&R!dW$HB.YfYn faU R2&#6zpG0V1:T+QF%EN "c JErd,?8H߲&Ç6 ̤O#0,.qF]k\!EL 4LhD#9F*O#D%ed4X@V3+hS,B\x\KI' _DQ' p#IfZ-[k}n_R~5w}0 <,.KDQ'?il7Nc9X|W}۳.?c8cvw}]i,|2殶S;IБ5Hӷp~~ŸO!Piiq*J -O5HUo?{o#[^##wX"[-2 f ahѴA 6g$ )٬fU;ߜ#c<"ؔ,jBM+3yb8'o- >)]㢶&kq4.lIZʤ#MmVWxs~7Q \WuYg%fK޿⭟;v(Ҧ6Mnd֡Z;F'`_~mx_aS(#ni&q1kf%{/x;8Uy ڼjF!{_ 3z OK0ZyPuj>0%')S3f:N=JHFRؔC C4Lk l0k0;-EG,,Ҧh}Ϗ~i[#dyyW+R D37EdY`+B.[rvDKid7-jEn5AcMpӯR}O4HsG݁#x4"Ed˅>C oOy{+ѿO(ߗ?ƫܟ?~_֏g~o ~g>ƯdYm__/s~o|_ongosf?կƏRu{?s;ᛇo`nrMӇtF?^sP;{`=O}t:R*2ٱqǓgrM\s'`hL;3Ր{=Ҩc?؞b3eo|Fr37(1 NJ$j_]%N#GFOljqS+<3C!h0)pIeifě %=g[`[%#cʜ ,ѳ%qnҹM JvSw)kuFhҦz2nkgˡME]D,#Erz9`{$:mbQuFw#-02g잇]5UhW¶yF{lE_)彝NM̢ 8Q%#{^0TV@{CA wR2hVl[+"Gpv\cd5!fcl m-7{TeĮea7jHM;梂.dcƚf- mNn!9;p= ?k쾉5( -C~i|IFVX Dn` wzm8TŦRIBx$È͖b`Z+t#2'/]Q91GAQZ'X'xS*g+O'wQ&:bYe[4 ʁ@*=H ?YSn)t {xCY;Z \h<کCRήEynQ/L1L+TD__3LY =TI LʎX^fm|pV̐GYpNlX4IS[n6t 05< (, eŀ3GFCf sM%R 1hUM2rԨ(jB=9 V@yw}nPո;PF5 GRu|@VTKuvy>v`\˵+ zL 8BASt.1ZIY\Ӫ3?}-|Ei+?_SG9Ώ77'_/(Uޏ=?wj+,?XbnZMg~6YXs\1e[};h//2ˌܛ8axr._w:"9X IDATc't}dVV RdW?e wV{œHdT67)7{\uޚ`Šf.W?$]-s %o_vަ">&-61Ǥ&c,>ٙGKCvaѹ&#] TmPrCF$EIA8l͈DN\\6\,C3CqiSSݲV ; (˂.֠0g# gAORshE2!l]\GtK`ޏ^(z9URZ!u8OQGO 7PLxm`>8Oyyʠ>ZvydEwL`P1uZ2"j+@8!٫!/ <|FYm%qjtS`++ r gP6K_b50i456;yab[5*c ̌mV){5 W WY{t^JxM(tnIH>XE)dzPG| ^ifcAd ?O\@[q(y~wWXg[%H6W_nvxypϘ}x#^.x|G  ?~S,}Pv"j B H5|HK/@Zb(K`:qCaISAXajKG\9=,jކwzO8(PjL <" F5Ϛ+1dɐgu[JWM S#=wI!mpꚠK{E" XSjϦTǵ6a/bk$Q!Ϻ$ТhP4w0P{,9skrksP*W@ g%x9 eA$yM2AKZ^u]xPJ,bpWCԢZt8Qaz·Ɓ{XX)YaCtܬXvk@d%Z *EX46If#.4#f+y@>s9(~myV sH㐬YD@zy;|η͖DbD-d~(o\VI.mZ'܊ivĸf:b<]4ZHM=V]V?Z1%?wA.\r 4Ю$RTkݜiO\ ܉@ n a5rV;b`ӂ5 %můQ5L3cM8K[)u9{i'?ȱ~s$h\Xh6yېƥ-]pF -R=  ؉Bs}Lՠ-*2%_;w;wQ~3r线O1 M;1P}(L 6ǚvcQ5Ո^=1y>$.ׂzwqH NSEVM@لMӔTj;"ۆEChDaLƸytlٙNVk(# IG9'./r񣈿ڙP}?/// wq~H~#$18QEg}0 8dbL?l_S["taܯ+F1A8XPt[ H@& [HuaG)SG 2#x]mo<= |ThJSHDHW&ql-r]j1E?Џ}c1)Nk7n=qqp`PCpB) x>{%gc/'$q!wtjT@| 塔@Ns ډAaI0X]d_ִ_. %'%'DZ{>Ǜcdw}'$kco7f]0.i <‹V'+eYNVq'N{lI$,